diff --git a/.babelrc b/.babelrc
index 73803b050c24..3ba0e83fa1a9 100644
--- a/.babelrc
+++ b/.babelrc
@@ -2,8 +2,9 @@
   "presets": ["react"],
   "ignore": ["third_party"],
   "plugins": [
-    "fbjs-scripts/babel-6/dev-expression",
+    "transform-class-properties",
     "syntax-trailing-function-commas",
+    "transform-object-rest-spread",
     "transform-es2015-template-literals",
     "transform-es2015-literals",
     "transform-es2015-arrow-functions",
@@ -21,6 +22,7 @@
     "transform-es2015-modules-commonjs",
     "transform-es3-member-expression-literals",
     "transform-es3-property-literals",
-    "./scripts/babel/transform-object-assign-require"
+    "./scripts/babel/transform-object-assign-require",
+    "transform-react-jsx-source"
   ]
 }
diff --git a/.eslintignore b/.eslintignore
index 87837497a07e..ebf7c8163c53 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -1,4 +1,6 @@
 # We can probably lint these later but not important at this point
+addons/**/node_modules/
+src/renderers/art
 src/shared/vendor
 # But not in docs/_js/examples/*
 docs/_js/*.js
@@ -9,6 +11,7 @@ docs/vendor/bundle/
 # This should be more like examples/**/thirdparty/** but
 # we should fix https://github.com/facebook/esprima/pull/85 first
 examples/
+fixtures/
 # Ignore built files.
 build/
 coverage/
diff --git a/.eslintrc.js b/.eslintrc.js
index a099d6bfca03..d6a276001495 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -3,67 +3,50 @@ const WARNING = 1;
 const ERROR = 2;
 
 module.exports = {
-  parser: 'babel-eslint',
-
-  extends: './node_modules/fbjs-scripts/eslint/.eslintrc.js',
+  extends: 'fbjs',
 
   plugins: [
     'react',
     'react-internal',
   ],
 
-  ecmaFeatures: {
-    modules: false
-  },
-
   // We're stricter than the default config, mostly. We'll override a few rules
   // and then enable some React specific ones.
   rules: {
     'accessor-pairs': OFF,
     'brace-style': [ERROR, '1tbs'],
     'comma-dangle': [ERROR, 'always-multiline'],
-    'consistent-return': ERROR,
+    'consistent-return': OFF,
     'dot-location': [ERROR, 'property'],
     'dot-notation': ERROR,
     'eol-last': ERROR,
     'eqeqeq': [ERROR, 'allow-null'],
-    'indent': [ERROR, 2, {SwitchCase: 1}],
+    'indent': OFF, // We use Prettier now
     'jsx-quotes': [ERROR, 'prefer-double'],
+    'keyword-spacing': [ERROR, {after: true, before: true}],
     'no-bitwise': OFF,
+    'no-inner-declarations': [ERROR, 'functions'],
     'no-multi-spaces': ERROR,
     'no-restricted-syntax': [ERROR, 'WithStatement'],
     'no-shadow': ERROR,
     'no-unused-expressions': ERROR,
     'no-unused-vars': [ERROR, {args: 'none'}],
-    'quotes': [ERROR, 'single', 'avoid-escape'],
-    'space-after-keywords': ERROR,
+    'quotes': [ERROR, 'single', {avoidEscape: true, allowTemplateLiterals: true }],
     'space-before-blocks': ERROR,
     'space-before-function-paren': [ERROR, {anonymous: 'never', named: 'never'}],
-    'space-before-keywords': ERROR,
-    'strict': [ERROR, 'global'],
 
     // React & JSX
     // Our transforms set this automatically
-    'react/display-name': OFF,
     'react/jsx-boolean-value': [ERROR, 'always'],
     'react/jsx-no-undef': ERROR,
     // We don't care to do this
     'react/jsx-sort-prop-types': OFF,
-    'react/jsx-sort-props': OFF,
     'react/jsx-uses-react': ERROR,
-    'react/jsx-uses-vars': ERROR,
-    // It's easier to test some things this way
-    'react/no-did-mount-set-state': OFF,
-    'react/no-did-update-set-state': OFF,
-    // We define multiple components in test files
-    'react/no-multi-comp': OFF,
-    'react/no-unknown-property': OFF,
+    'react/no-is-mounted': OFF,
     // This isn't useful in our test code
-    'react/prop-types': OFF,
     'react/react-in-jsx-scope': ERROR,
     'react/self-closing-comp': ERROR,
     // We don't care to do this
-    'react/sort-comp': OFF,
     'react/wrap-multilines': [ERROR, {declaration: false, assignment: false}],
 
     // CUSTOM RULES
diff --git a/.flowconfig b/.flowconfig
new file mode 100644
index 000000000000..6b1984b12984
--- /dev/null
+++ b/.flowconfig
@@ -0,0 +1,43 @@
+[ignore]
+
+<PROJECT_ROOT>/examples/.*
+<PROJECT_ROOT>/fixtures/.*
+<PROJECT_ROOT>/build/.*
+<PROJECT_ROOT>/node_modules/chrome-devtools-frontend/.*
+<PROJECT_ROOT>/.*/node_modules/chrome-devtools-frontend/.*
+<PROJECT_ROOT>/.*/node_modules/y18n/.*
+<PROJECT_ROOT>/.*/__mocks__/.*
+<PROJECT_ROOT>/.*/__tests__/.*
+<PROJECT_ROOT>/addons/.*
+
+# Ignore Docs
+<PROJECT_ROOT>/docs/.*
+<PROJECT_ROOT>/.*/docs/.*
+
+[include]
+
+[libs]
+./node_modules/fbjs/flow/lib/dev.js
+./flow
+
+[options]
+module.system=haste
+
+esproposal.class_static_fields=enable
+esproposal.class_instance_fields=enable
+
+munge_underscores=false
+
+suppress_type=$FlowIssue
+suppress_type=$FlowFixMe
+suppress_type=$FixMe
+suppress_type=$FlowExpectedError
+
+suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(3[0-3]\\|[1-2][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*www[a-z,_]*\\)?)\\)
+suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(3[0-3]\\|[1-2][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*www[a-z,_]*\\)?)\\)?:? #[0-9]+
+suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
+suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
+
+[version]
+^0.37.0
+
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 000000000000..5de9012e125b
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,11 @@
+**Before submitting a pull request,** please make sure the following is done:
+
+1. Fork [the repository](https://github.com/facebook/react) and create your branch from `master`.
+2. If you've added code that should be tested, add tests!
+3. If you've changed APIs, update the documentation.
+4. Ensure the test suite passes (`npm test`).
+5. Make sure your code lints (`npm run lint`).
+6. Format your code with [prettier](https://github.com/prettier/prettier) (`npm run prettier`).
+7. Run the [Flow](https://flowtype.org/) typechecks (`npm run flow`).
+8. If you added or removed any tests, run `./scripts/fiber/record-tests` before submitting the pull request, and commit the resulting changes.
+9. If you haven't already, complete the CLA.
diff --git a/.gitignore b/.gitignore
index 348b88dc414a..7cf76ab52073 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,9 +15,15 @@ docs/code
 docs/_site
 docs/.sass-cache
 docs/js/*
-docs/downloads
+docs/downloads/*.zip
 docs/vendor/bundle
+<<<<<<< HEAD
 examples/shared/*.js
+examples/**/bundle.js
+=======
+fixtures/dom/public/react-dom.js
+fixtures/dom/public/react.js
+>>>>>>> 4a37718... Remove examples/ folder (#9323)
 test/the-files-to-test.generated.js
 *.log*
 chrome-user-data
diff --git a/.travis.yml b/.travis.yml
index bfbdfeaa20a1..82ecf2cc87b3 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,8 +1,11 @@
 ---
+sudo: required
+dist: trusty
 language: node_js
 node_js:
 - 4
-sudo: false
+rvm:
+- 2.2.3
 cache:
   directories:
   - docs/vendor/bundle
@@ -25,8 +28,8 @@ script:
 
         GH_PAGES_DIR="$TRAVIS_BUILD_DIR"/../react-gh-pages
         echo "machine github.com login reactjs-bot password $GITHUB_TOKEN" >~/.netrc
-        git config --global user.name "Travis CI"
-        git config --global user.email "travis@reactjs.org"
+        git config --global user.name "$GITHUB_USER_NAME"
+        git config --global user.email "$GITHUB_USER_EMAIL"
 
         git clone --branch gh-pages --depth=50 \
           https://reactjs-bot@github.com/facebook/react.git \
@@ -36,7 +39,7 @@ script:
         bundle exec rake release
         cd $GH_PAGES_DIR
         git status
-        if ! git diff-index --quiet HEAD --; then
+        if test -n "$(git status --porcelain)"; then
           git add -A .
           git commit -m "Rebuild website"
           git push origin gh-pages
@@ -58,6 +61,7 @@ script:
           -F "react-dom-server.min=@build/react-dom-server.min.js" \
           -F "npm-react=@build/packages/react.tgz" \
           -F "npm-react-dom=@build/packages/react-dom.tgz" \
+          -F "npm-react-native=@build/packages/react-native-renderer.tgz" \
           -F "commit=$TRAVIS_COMMIT" \
           -F "date=`git log --format='%ct' -1`" \
           -F "pull_request=$TRAVIS_PULL_REQUEST" \
@@ -67,12 +71,40 @@ script:
       fi
     elif [ "$TEST_TYPE" = test ]; then
       set -e
-      ./node_modules/.bin/grunt jest:normal
+      ./node_modules/.bin/grunt jest:coverage
+      cat ./coverage/lcov.info | ./node_modules/.bin/coveralls
+
       echo 'Testing in server-render (HTML generation) mode...'
       printf '\nmodule.exports.useCreateElement = false;\n' \
         >> src/renderers/dom/shared/ReactDOMFeatureFlags.js
       ./node_modules/.bin/grunt jest:normal
       git checkout -- src/renderers/dom/shared/ReactDOMFeatureFlags.js
+
+      echo 'Testing in fiber mode...'
+      printf '\nmodule.exports.useFiber = true;\n' \
+        >> src/renderers/dom/shared/ReactDOMFeatureFlags.js
+      FIBER_TESTS=`\
+        NODE_ENV=test node node_modules/jest/bin/jest --json | \
+        node -e "\
+          var data = JSON.parse(require('fs').readFileSync('/dev/stdin', 'utf8')); \
+          console.log(data.numPassedTests + '/' + data.numTotalTests)\
+        "\
+      `
+      git checkout -- src/renderers/dom/shared/ReactDOMFeatureFlags.js
+      node scripts/facts-tracker/index.js \
+        "fiber-tests" "$FIBER_TESTS"
+
+      ./node_modules/.bin/gulp react:extract-errors
+    elif [ "$TEST_TYPE" = flow ]; then
+      set -e
+      ./node_modules/.bin/grunt flow
+
+      ALL_FILES=`find src -name '*.js' | grep -v umd/ | grep -v __tests__ | grep -v __mocks__`
+      COUNT_ALL_FILES=`echo "$ALL_FILES" | wc -l`
+      COUNT_WITH_FLOW=`grep '@flow' $ALL_FILES | perl -pe 's/:.+//' | wc -l`
+      node scripts/facts-tracker/index.js \
+        "flow-files" "$COUNT_WITH_FLOW/$COUNT_ALL_FILES"
+
     else
       ./node_modules/.bin/grunt $TEST_TYPE
     fi
@@ -81,6 +113,7 @@ env:
   - TEST_TYPE=build
   - TEST_TYPE=test
   - TEST_TYPE=lint
+  - TEST_TYPE=flow
   - TEST_TYPE=build_website
   global:
   # SERVER
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9b91a675b5db..4e01ff3eb8c6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,433 @@
+## 15.6.0 (June 13, 2017)
+
+### React
+
+* Downgrade deprecation warnings to use `console.warn` instead of `console.error`. ([@flarnie](https://github.com/flarnie) in [#9753](https://github.com/facebook/react/pull/9753))
+* Add a deprecation warning for `React.createClass`. Points users to `create-react-class` instead. ([@flarnie](https://github.com/flarnie) in [#9771](https://github.com/facebook/react/pull/9771))
+* Add deprecation warnings and separate module for `React.DOM` factory helpers. ([@nhunzaker](https://github.com/nhunzaker) in [#8356](https://github.com/facebook/react/pull/8356))
+* Warn for deprecation of `React.createMixin` helper, which was never used. ([@aweary](https://github.com/aweary) in [#8853](https://github.com/facebook/react/pull/8853))
+
+### React DOM
+
+* Add support for CSS variables in `style` attribute. ([@aweary](https://github.com/aweary) in [#9302](https://github.com/facebook/react/pull/9302))
+* Add support for CSS Grid style properties. ([@ericsakmar](https://github.com/ericsakmar) in [#9185](https://github.com/facebook/react/pull/9185))
+* Fix bug where inputs mutated value on type conversion. ([@nhunzaker](https://github.com/mhunzaker) in [#9806](https://github.com/facebook/react/pull/9806))
+* Fix issues with `onChange` not firing properly for some inputs. ([@jquense](https://github.com/jquense) in [#8575](https://github.com/facebook/react/pull/8575))
+* Fix bug where controlled number input mistakenly allowed period. ([@nhunzaker](https://github.com/nhunzaker) in [#9584](https://github.com/facebook/react/pull/9584))
+* Fix bug where performance entries were being cleared. ([@chrisui](https://github.com/chrisui) in [#9451](https://github.com/facebook/react/pull/9451))
+
+### React Addons
+
+* Fix AMD support for addons depending on `react`. ([@flarnie](https://github.com/flarnie) in [#9919](https://github.com/facebook/react/issues/9919))
+* Fix `isMounted()` to return `true` in `componentWillUnmount`. ([@mridgway](https://github.com/mridgway) in [#9638](https://github.com/facebook/react/issues/9638))
+* Fix `react-addons-update` to not depend on native `Object.assign`. ([@gaearon](https://github.com/gaearon) in [#9937](https://github.com/facebook/react/pull/9937))
+* Remove broken Google Closure Compiler annotation from `create-react-class`. ([@gaearon](https://github.com/gaearon) in [#9933](https://github.com/facebook/react/pull/9933))
+* Remove unnecessary dependency from `react-linked-input`. ([@gaearon](https://github.com/gaearon) in [#9766](https://github.com/facebook/react/pull/9766))
+* Point `react-addons-(css-)transition-group` to the new package. ([@gaearon](https://github.com/gaearon) in [#9937](https://github.com/facebook/react/pull/9937))
+
+## 15.5.4 (April 11, 2017)
+
+### React Addons
+* **Critical Bugfix:** Update the version of `prop-types` to fix critical bug.  ([@gaearon](https://github.com/gaearon) in [545c87f](https://github.com/facebook/react/commit/545c87fdc348f82eb0c3830bef715ed180785390))
+* Fix `react-addons-create-fragment` package to include `loose-envify` transform for Browserify users. ([@mridgway](https://github.com/mridgway) in [#9642](https://github.com/facebook/react/pull/9642))
+
+### React Test Renderer
+* Fix compatibility with Enzyme by exposing `batchedUpdates` on shallow renderer. ([@gaearon](https://github.com/gaearon) in [9382](https://github.com/facebook/react/commit/69933e25c37cf5453a9ef132177241203ee8d2fd))
+
+## 15.5.3 (April 7, 2017)
+
+**Note: this release has a critical issue and was deprecated. Please update to 15.5.4 or higher.**
+
+### React Addons
+* Fix `react-addons-create-fragment` package to export correct thing. ([@gaearon](https://github.com/gaearon) in [#9385](https://github.com/facebook/react/pull/9383))
+* Fix `create-react-class` package to include `loose-envify` transform for Browserify users. ([@mridgway](https://github.com/mridgway) in [#9642](https://github.com/facebook/react/pull/9642))
+
+## 15.5.2 (April 7, 2017)
+
+**Note: this release has a critical issue and was deprecated. Please update to 15.5.4 or higher.**
+
+### React Addons
+* Fix the production single-file builds to not include the development code. ([@gaearon](https://github.com/gaearon) in [#9385](https://github.com/facebook/react/pull/9383))
+* Apply better minification to production single-file builds. ([@gaearon](https://github.com/gaearon) in [#9385](https://github.com/facebook/react/pull/9383))
+* Add missing and remove unnecessary dependencies to packages. ([@gaearon](https://github.com/gaearon) in [#9385](https://github.com/facebook/react/pull/9383))
+
+## 15.5.1 (April 7, 2017)
+
+**Note: this release has a critical issue and was deprecated. Please update to 15.5.4 or higher.**
+
+### React
+* Fix erroneous PropTypes access warning. ([@acdlite](https://github.com/acdlite) in ([ec97ebb](https://github.com/facebook/react/commit/ec97ebbe7f15b58ae2f1323df39d06f119873344))
+
+## 15.5.0 (April 7, 2017)
+
+**Note: this release has a critical issue and was deprecated. Please update to 15.5.4 or higher.**
+
+### React
+* <s>Added a deprecation warning for `React.createClass`. Points users to create-react-class instead. ([@acdlite](https://github.com/acdlite) in [#d9a4fa4](https://github.com/facebook/react/commit/d9a4fa4f51c6da895e1655f32255cf72c0fe620e))</s>
+* Added a deprecation warning for `React.PropTypes`. Points users to prop-types instead. ([@acdlite](https://github.com/acdlite) in [#043845c](https://github.com/facebook/react/commit/043845ce75ea0812286bbbd9d34994bb7e01eb28))
+* Fixed an issue when using `ReactDOM` together with `ReactDOMServer`. ([@wacii](https://github.com/wacii) in [#9005](https://github.com/facebook/react/pull/9005))
+* Fixed issue with Closure Compiler. ([@anmonteiro](https://github.com/anmonteiro) in [#8895](https://github.com/facebook/react/pull/8895))
+* Another fix for Closure Compiler. ([@Shastel](https://github.com/Shastel) in [#8882](https://github.com/facebook/react/pull/8882))
+* Added component stack info to invalid element type warning. ([@n3tr](https://github.com/n3tr) in [#8495](https://github.com/facebook/react/pull/8495))
+
+### React DOM
+* Fixed Chrome bug when backspacing in number inputs. ([@nhunzaker](https://github.com/nhunzaker) in [#7359](https://github.com/facebook/react/pull/7359))
+* Added `react-dom/test-utils`, which exports the React Test Utils. ([@bvaughn](https://github.com/bvaughn))
+
+### React Test Renderer
+* Fixed bug where `componentWillUnmount` was not called for children. ([@gre](https://github.com/gre) in [#8512](https://github.com/facebook/react/pull/8512))
+* Added `react-test-renderer/shallow`, which exports the shallow renderer. ([@bvaughn](https://github.com/bvaughn))
+
+### React Addons
+* Last release for addons; they will no longer be actively maintained.
+* Removed `peerDependencies` so that addons continue to work indefinitely. ([@acdlite](https://github.com/acdlite) and [@bvaughn](https://github.com/bvaughn) in [8a06cd7](https://github.com/facebook/react/commit/8a06cd7a786822fce229197cac8125a551e8abfa) and [67a8db3](https://github.com/facebook/react/commit/67a8db3650d724a51e70be130e9008806402678a))
+* Updated to remove references to `React.createClass` and `React.PropTypes` ([@acdlite](https://github.com/acdlite) in [12a96b9](https://github.com/facebook/react/commit/12a96b94823d6b6de6b1ac13bd576864abd50175))
+* `react-addons-test-utils` is deprecated. Use `react-dom/test-utils` and `react-test-renderer/shallow` instead. ([@bvaughn](https://github.com/bvaughn))
+
+## 15.4.2 (January 6, 2017)
+
+### React
+* Fixed build issues with the Brunch bundler. ([@gaearon](https://github.com/gaearon) in [#8686](https://github.com/facebook/react/pull/8686))
+* Improved error messages for invalid element types. ([@spicyj](https://github.com/spicyj) in [#8612](https://github.com/facebook/react/pull/8612))
+* Removed a warning about `getInitialState` when `this.state` is set. ([@bvaughn](https://github.com/bvaughn) in [#8594](https://github.com/facebook/react/pull/8594))
+* Removed some dead code. ([@diegomura](https://github.com/diegomura) in [#8050](https://github.com/facebook/react/pull/8050), [@dfrownfelter](https://github.com/dfrownfelter) in [#8597](https://github.com/facebook/react/pull/8597))
+
+### React DOM
+* Fixed a decimal point issue on uncontrolled number inputs. ([@nhunzaker](https://github.com/nhunzaker) in [#7750](https://github.com/facebook/react/pull/7750))
+* Fixed rendering of textarea placeholder in IE11. ([@aweary](https://github.com/aweary) in [#8020](https://github.com/facebook/react/pull/8020))
+* Worked around a script engine bug in IE9. ([@eoin](https://github.com/eoin) in [#8018](https://github.com/facebook/react/pull/8018))
+
+### React Addons
+* Fixed build issues in RequireJS and SystemJS environments. ([@gaearon](https://github.com/gaearon) in [#8686](https://github.com/facebook/react/pull/8686))
+* Added missing package dependencies. ([@kweiberth](https://github.com/kweiberth) in [#8467](https://github.com/facebook/react/pull/8467))
+
+## 15.4.1 (November 22, 2016)
+
+### React
+* Restructure variable assignment to work around a Rollup bug ([@gaearon](https://github.com/gaearon) in [#8384](https://github.com/facebook/react/pull/8384))
+
+### React DOM
+* Fixed event handling on disabled button elements ([@spicyj](https://github.com/spicyj) in [#8387](https://github.com/facebook/react/pull/8387))
+* Fixed compatibility of browser build with AMD environments ([@zpao](https://github.com/zpao) in [#8374](https://github.com/facebook/react/pull/8374))
+
+## 15.4.0 (November 16, 2016)
+
+### React
+* React package and browser build no longer "secretly" includes React DOM. ([@sebmarkbage](https://github.com/sebmarkbage) in [#7164](https://github.com/facebook/react/pull/7164) and [#7168](https://github.com/facebook/react/pull/7168))
+* Required PropTypes now fail with specific messages for null and undefined. ([@chenglou](https://github.com/chenglou) in [#7291](https://github.com/facebook/react/pull/7291))
+* Improved development performance by freezing children instead of copying. ([@keyanzhang](https://github.com/keyanzhang) in [#7455](https://github.com/facebook/react/pull/7455))
+
+### React DOM
+* Fixed occasional test failures when React DOM is used together with shallow renderer. ([@goatslacker](https://github.com/goatslacker) in [#8097](https://github.com/facebook/react/pull/8097))
+* Added a warning for invalid `aria-` attributes. ([@jessebeach](https://github.com/jessebeach) in [#7744](https://github.com/facebook/react/pull/7744))
+* Added a warning for using `autofocus` rather than `autoFocus`. ([@hkal](https://github.com/hkal) in [#7694](https://github.com/facebook/react/pull/7694))
+* Removed an unnecessary warning about polyfilling `String.prototype.split`. ([@nhunzaker](https://github.com/nhunzaker) in [#7629](https://github.com/facebook/react/pull/7629))
+* Clarified the warning about not calling PropTypes manually. ([@jedwards1211](https://github.com/jedwards1211) in [#7777](https://github.com/facebook/react/pull/7777))
+* The unstable `batchedUpdates` API now passes the wrapped function's return value through. ([@bgnorlov](https://github.com/bgnorlov) in [#7444](https://github.com/facebook/react/pull/7444))
+* Fixed a bug with updating text in IE 8. ([@mnpenner](https://github.com/mnpenner) in [#7832](https://github.com/facebook/react/pull/7832))
+
+### React Perf
+* When ReactPerf is started, you can now view the relative time spent in components as a chart in Chrome Timeline. ([@gaearon](https://github.com/gaearon) in [#7549](https://github.com/facebook/react/pull/7549))
+
+### React Test Utils
+* If you call `Simulate.click()` on a `<input disabled onClick={foo} />` then `foo` will get called whereas it didn't before. ([@nhunzaker](https://github.com/nhunzaker) in [#7642](https://github.com/facebook/react/pull/7642))
+
+### React Test Renderer
+* Due to packaging changes, it no longer crashes when imported together with React DOM in the same file. ([@sebmarkbage](https://github.com/sebmarkbage) in [#7164](https://github.com/facebook/react/pull/7164) and [#7168](https://github.com/facebook/react/pull/7168))
+* `ReactTestRenderer.create()` now accepts `{createNodeMock: element => mock}` as an optional argument so you can mock refs with snapshot testing. ([@Aweary](https://github.com/Aweary) in [#7649](https://github.com/facebook/react/pull/7649), [#8261](https://github.com/facebook/react/pull/8261))
+
+
+## 15.3.2 (September 19, 2016)
+
+### React
+- Remove plain object warning from React.createElement & React.cloneElement. ([@spudly](https://github.com/spudly) in [#7724](https://github.com/facebook/react/pull/7724))
+
+### React DOM
+- Add `playsInline` to supported HTML attributes. ([@reaperhulk](https://github.com/reaperhulk) in [#7519](https://github.com/facebook/react/pull/7519))
+- Add `as` to supported HTML attributes. ([@kevinslin](https://github.com/kevinslin) in [#7582](https://github.com/facebook/react/pull/7582))
+- Improve DOM nesting validation warning about whitespace. ([@spicyj](https://github.com/spicyj) in [#7515](https://github.com/facebook/react/pull/7515))
+- Avoid "Member not found" exception in IE10 when calling `preventDefault()` in Synthetic Events. ([@g-palmer](https://github.com/g-palmer) in [#7411](https://github.com/facebook/react/pull/7411))
+- Fix memory leak in `onSelect` implementation. ([@AgtLucas](https://github.com/AgtLucas) in [#7533](https://github.com/facebook/react/pull/7533))
+- Improve robustness of `document.documentMode` checks to handle Google Tag Manager. ([@SchleyB](https://github.com/SchleyB) in [#7594](https://github.com/facebook/react/pull/7594))
+- Add more cases to controlled inputs warning. ([@marcin-mazurek](https://github.com/marcin-mazurek) in [#7544](https://github.com/facebook/react/pull/7544))
+- Handle case of popup blockers overriding `document.createEvent`. ([@Andarist](https://github.com/Andarist) in [#7621](https://github.com/facebook/react/pull/7621))
+- Fix issue with `dangerouslySetInnerHTML` and SVG in Internet Explorer. ([@zpao](https://github.com/zpao) in [#7618](https://github.com/facebook/react/pull/7618))
+- Improve handling of Japanese IME on Internet Explorer. ([@msmania](https://github.com/msmania) in [#7107](https://github.com/facebook/react/pull/7107))
+
+### React Test Renderer
+- Support error boundaries. ([@millermedeiros](https://github.com/millermedeiros) in [#7558](https://github.com/facebook/react/pull/7558), [#7569](https://github.com/facebook/react/pull/7569), [#7619](https://github.com/facebook/react/pull/7619))
+- Skip null ref warning. ([@Aweary](https://github.com/Aweary) in [#7658](https://github.com/facebook/react/pull/7658))
+
+### React Perf Add-on
+- Ensure lifecycle timers are stopped on errors. ([@gaearon](https://github.com/gaearon) in [#7548](https://github.com/facebook/react/pull/7548))
+
+
+## 15.3.1 (August 19, 2016)
+
+### React
+
+- Improve performance of development builds in various ways. ([@gaearon](https://github.com/gaearon) in [#7461](https://github.com/facebook/react/pull/7461), [#7463](https://github.com/facebook/react/pull/7463), [#7483](https://github.com/facebook/react/pull/7483), [#7488](https://github.com/facebook/react/pull/7488), [#7491](https://github.com/facebook/react/pull/7491), [#7510](https://github.com/facebook/react/pull/7510))
+- Cleanup internal hooks to improve performance of development builds. ([@gaearon](https://github.com/gaearon) in [#7464](https://github.com/facebook/react/pull/7464), [#7472](https://github.com/facebook/react/pull/7472), [#7481](https://github.com/facebook/react/pull/7481), [#7496](https://github.com/facebook/react/pull/7496))
+- Upgrade fbjs to pick up another performance improvement from [@gaearon](https://github.com/gaearon) for development builds. ([@zpao](https://github.com/zpao) in [#7532](https://github.com/facebook/react/pull/7532))
+- Improve startup time of React in Node. ([@zertosh](https://github.com/zertosh) in [#7493](https://github.com/facebook/react/pull/7493))
+- Improve error message of `React.Children.only`. ([@spicyj](https://github.com/spicyj) in [#7514](https://github.com/facebook/react/pull/7514))
+
+### React DOM
+- Avoid `<input>` validation warning from browsers when changing `type`. ([@nhunzaker](https://github.com/nhunzaker) in [#7333](https://github.com/facebook/react/pull/7333))
+- Avoid "Member not found" exception in IE10 when calling `stopPropagation()` in Synthetic Events. ([@nhunzaker](https://github.com/nhunzaker) in [#7343](https://github.com/facebook/react/pull/7343))
+- Fix issue resulting in inability to update some `<input>` elements in mobile browsers. ([@keyanzhang](https://github.com/keyanzhang) in [#7397](https://github.com/facebook/react/pull/7397))
+- Fix memory leak in server rendering. ([@keyanzhang](https://github.com/keyanzhang) in [#7410](https://github.com/facebook/react/pull/7410))
+- Fix issue resulting in `<input type="range">` values not updating when changing `min` or `max`. ([@troydemonbreun](https://github.com/troydemonbreun) in [#7486](https://github.com/facebook/react/pull/7486))
+- Add new warning for rare case of attempting to unmount a container owned by a different copy of React. ([@ventuno](https://github.com/ventuno) in [#7456](https://github.com/facebook/react/pull/7456))
+
+### React Test Renderer
+- Fix ReactTestInstance::toJSON() with empty top-level components. ([@Morhaus](https://github.com/Morhaus) in [#7523](https://github.com/facebook/react/pull/7523))
+
+### React Native Renderer
+- Change `trackedTouchCount` invariant into a console.error for better reliability. ([@yungsters](https://github.com/yungsters) in [#7400](https://github.com/facebook/react/pull/7400))
+
+
+## 15.3.0 (July 29, 2016)
+
+### React
+- Add `React.PureComponent` - a new base class to extend, replacing `react-addons-pure-render-mixin` now that mixins don't work with ES2015 classes. ([@spicyj](https://github.com/spicyj) in [#7195](https://github.com/facebook/react/pull/7195))
+- Add new warning when modifying `this.props.children`. ([@jimfb](https://github.com/jimfb) in [#7001](https://github.com/facebook/react/pull/7001))
+- Fixed issue with ref resolution order. ([@gaearon](https://github.com/gaearon) in [#7101](https://github.com/facebook/react/pull/7101))
+- Warn when mixin is undefined. ([@swaroopsm](https://github.com/swaroopsm) in [#6158](https://github.com/facebook/react/pull/6158))
+- Downgrade "unexpected batch number" invariant to a warning. ([@spicyj](https://github.com/spicyj) in [#7133](https://github.com/facebook/react/pull/7133))
+- Validate arguments to `oneOf` and `oneOfType` PropTypes sooner. ([@troydemonbreun](https://github.com/troydemonbreun) in [#6316](https://github.com/facebook/react/pull/6316))
+- Warn when calling PropTypes directly. ([@Aweary](https://github.com/Aweary) in [#7132](https://github.com/facebook/react/pull/7132), [#7194](https://github.com/facebook/react/pull/7194))
+- Improve warning when using Maps as children. ([@keyanzhang](https://github.com/keyanzhang) in [#7260](https://github.com/facebook/react/pull/7260))
+- Add additional type information to the `PropTypes.element` warning. ([@alexzherdev](https://github.com/alexzherdev) in [#7319](https://github.com/facebook/react/pull/7319))
+- Improve component identification in no-op `setState` warning. ([@keyanzhang](https://github.com/keyanzhang) in [#7326](https://github.com/facebook/react/pull/7326))
+
+### React DOM
+- Fix issue with nested server rendering. ([@Aweary](https://github.com/Aweary) in [#7033](https://github.com/facebook/react/pull/7033))
+- Add `xmlns`, `xmlnsXlink` to supported SVG attributes. ([@salzhrani](https://github.com/salzhrani) in [#6471](https://github.com/facebook/react/pull/6471))
+- Add `referrerPolicy` to supported HTML attributes. ([@Aweary](https://github.com/Aweary) in [#7274](https://github.com/facebook/react/pull/7274))
+- Fix issue resulting in `<input type="range">` initial value being rounded. ([@troydemonbreun](https://github.com/troydemonbreun) in [#7251](https://github.com/facebook/react/pull/7251))
+
+### React Test Renderer
+- Initial public release of package allowing more focused testing. Install with `npm install react-test-renderer`. ([@spicyj](https://github.com/spicyj) in [#6944](https://github.com/facebook/react/pull/6944), [#7258](https://github.com/facebook/react/pull/7258), [@iamdustan](https://github.com/iamdustan) in [#7362](https://github.com/facebook/react/pull/7362))
+
+### React Perf Add-on
+- Fix issue resulting in excessive warnings when encountering an internal measurement error. ([@sassanh](https://github.com/sassanh) in [#7299](https://github.com/facebook/react/pull/7299))
+
+### React TestUtils Add-on
+- Implement `type` property on for events created via `TestUtils.Simulate.*`. ([@yaycmyk](https://github.com/yaycmyk) in [#6154](https://github.com/facebook/react/pull/6154))
+- Fix crash when running TestUtils with the production build of React. ([@gaearon](https://github.com/gaearon) in [#7246](https://github.com/facebook/react/pull/7246))
+
+
+## 15.2.1 (July 8, 2016)
+
+### React
+- Fix errant warning about missing React element. ([@gaearon](https://github.com/gaearon) in [#7193](https://github.com/facebook/react/pull/7193))
+- Better removal of dev-only code, leading to a small reduction in the minified production bundle size. ([@gaearon](https://github.com/gaearon) in [#7188](https://github.com/facebook/react/pull/7188), [#7189](https://github.com/facebook/react/pull/7189))
+
+### React DOM
+- Add stack trace to null input value warning. ([@jimfb](https://github.com/jimfb) in [#7040](https://github.com/facebook/react/pull/7040))
+- Fix webcomponents example. ([@jalexanderfox](https://github.com/jalexanderfox) in [#7057](https://github.com/facebook/react/pull/7057))
+- Fix `unstable_renderSubtreeIntoContainer` so that context properly updates when linked to state. ([@gaearon](https://github.com/gaearon) in [#7125](https://github.com/facebook/react/pull/7125))
+- Improve invariant wording for void elements. ([@starkch](https://github.com/starkch) in [#7066](https://github.com/facebook/react/pull/7066))
+- Ensure no errors are thrown due to event handlers in server rendering. ([@rricard](https://github.com/rricard) in [#7127](https://github.com/facebook/react/pull/7127))
+- Fix regression resulting in `value`-less submit and reset inputs removing the browser-default text. ([@zpao](https://github.com/zpao) in [#7197](https://github.com/facebook/react/pull/7197))
+- Fix regression resulting in empty `name` attribute being added to inputs when not provided. ([@okonet](https://github.com/okonet) in [#7199](https://github.com/facebook/react/pull/7199))
+- Fix issue with nested server rendering. ([@Aweary](https://github.com/Aweary) in [#7033](https://github.com/facebook/react/pull/7033))
+
+### React Perf Add-on
+- Make `ReactPerf.start()` work properly during lifecycle methods. ([@gaearon](https://github.com/gaearon) in [#7208](https://github.com/facebook/react/pull/7208)).
+
+### React CSSTransitionGroup Add-on
+- Fix issue resulting in spurious unknown property warnings. ([@batusai513](https://github.com/batusai513) in [#7165](https://github.com/facebook/react/pull/7165))
+
+### React Native Renderer
+- Improve error handling in cross-platform touch event handling. ([@yungsters](https://github.com/yungsters) in [#7143](https://github.com/facebook/react/pull/7143))
+
+
+## 15.2.0 (July 1, 2016)
+
+### React
+- Add error codes to production invariants, with links to the view the full error text. ([@keyanzhang](https://github.com/keyanzhang) in [#6948](https://github.com/facebook/react/pull/6948))
+- Include component stack information in PropType validation warnings. ([@troydemonbreun](https://github.com/troydemonbreun) in [#6398](https://github.com/facebook/react/pull/6398), [@spicyj](https://github.com/spicyj) in [#6771](https://github.com/facebook/react/pull/6771))
+- Include component stack information in key warnings. ([@keyanzhang](https://github.com/keyanzhang) in [#6799](https://github.com/facebook/react/pull/6799))
+- Stop validating props at mount time, only validate at element creation. ([@keyanzhang](https://github.com/keyanzhang) in [#6824](https://github.com/facebook/react/pull/6824))
+- New invariant providing actionable error in missing instance case. ([@yungsters](https://github.com/yungsters) in [#6990](https://github.com/facebook/react/pull/6990))
+- Add `React.PropTypes.symbol` to support ES2015 Symbols as props. ([@puradox](https://github.com/puradox) in [#6377](https://github.com/facebook/react/pull/6377))
+- Fix incorrect coercion of ref or key that are undefined in development ([@gaearon](https://github.com/gaearon) in [#6880](https://github.com/facebook/react/pull/6880))
+- Fix a false positive when passing other element’s props to cloneElement ([@ericmatthys](https://github.com/ericmatthys) in [#6268](https://github.com/facebook/react/pull/6268))
+- Warn if you attempt to define `childContextTypes` on a functional component ([@Aweary](https://github.com/Aweary) in [#6933](https://github.com/facebook/react/pull/6933))
+
+### React DOM
+- Add warning for unknown properties on DOM elements. ([@jimfb](https://github.com/jimfb) in [#6800](https://github.com/facebook/react/pull/6800), [@gm758](https://github.com/gm758) in [#7152](https://github.com/facebook/react/pull/7152))
+- Properly remove attributes from custom elements. ([@grassator](https://github.com/grassator) in [#6748](https://github.com/facebook/react/pull/6748))
+- Fix invalid unicode escape in attribute name regular expression. ([@nbjahan](https://github.com/nbjahan) in [#6772](https://github.com/facebook/react/pull/6772))
+- Add `onLoad` handling to `<link>` element. ([@roderickhsiao](https://github.com/roderickhsiao) in [#6815](https://github.com/facebook/react/pull/6815))
+- Add `onError` handling to `<source>` element. ([@wadahiro](https://github.com/wadahiro) in [#6941](https://github.com/facebook/react/pull/6941))
+- Handle `value` and `defaultValue` more accurately in the DOM. ([@jimfb](https://github.com/jimfb) in [#6406](https://github.com/facebook/react/pull/6406))
+- Fix events issue in environments with mutated `Object.prototype`. ([@Weizenlol](https://github.com/Weizenlol) in [#6886](https://github.com/facebook/react/pull/6886))
+- Fix issue where `is="null"` ended up in the DOM in Firefox. ([@darobin](https://github.com/darobin) in [#6896](https://github.com/facebook/react/pull/6896))
+- Improved performance of text escaping by using [escape-html](https://github.com/component/escape-html). ([@aickin](https://github.com/aickin) in [#6862](https://github.com/facebook/react/pull/6862))
+- Fix issue with `dangerouslySetInnerHTML` and SVG in Internet Explorer. ([@joshhunt](https://github.com/joshhunt) in [#6982](https://github.com/facebook/react/pull/6982))
+- Fix issue with `<textarea>` placeholders. ([@jimfb](https://github.com/jimfb) in [#7002](https://github.com/facebook/react/pull/7002))
+- Fix controlled vs uncontrolled detection of `<input type="radio"/>`. ([@jimfb](https://github.com/jimfb) in [#7003](https://github.com/facebook/react/pull/7003))
+- Improve performance of updating text content. ([@trueadm](https://github.com/trueadm) in [#7005](https://github.com/facebook/react/pull/7005))
+- Ensure controlled `<select>` components behave the same on initial render as they do on updates. ([@yiminghe](https://github.com/yiminghe) in [#5362](https://github.com/facebook/react/pull/5362))
+
+### React Perf Add-on
+- Add `isRunning()` API. ([@nfcampos](https://github.com/nfcampos) in [#6763](https://github.com/facebook/react/pull/6763))
+- Improve accuracy of lifecycle hook timing. ([@gaearon](https://github.com/gaearon) in [#6858](https://github.com/facebook/react/pull/6858))
+- Fix internal errors when using ReactPerf with portal components. ([@gaearon](https://github.com/gaearon) in [#6860](https://github.com/facebook/react/pull/6860))
+- Fix performance regression. ([@spicyj](https://github.com/spicyj) in [#6770](https://github.com/facebook/react/pull/6770))
+- Add warning that ReactPerf is not enabled in production. ([@sashashakun](https://github.com/sashashakun) in [#6884](https://github.com/facebook/react/pull/6884))
+
+### React CSSTransitionGroup Add-on
+- Fix timing issue with `null` node. ([@keyanzhang](https://github.com/keyanzhang) in [#6958](https://github.com/facebook/react/pull/6958))
+
+### React Native Renderer
+- Dependencies on React Native modules use CommonJS requires instead of providesModule. ([@davidaurelio](https://github.com/davidaurelio) in [#6715](https://github.com/facebook/react/pull/6715))
+
+
+## 15.1.0 (May 20, 2016)
+
+### React
+- Ensure we're using the latest `object-assign`, which has protection against a non-spec-compliant native `Object.assign`. ([@zpao](https://github.com/zpao) in [#6681](https://github.com/facebook/react/pull/6681))
+- Add a new warning to communicate that `props` objects passed to `createElement` must be plain objects. ([@richardscarrott](https://github.com/richardscarrott) in [#6134](https://github.com/facebook/react/pull/6134))
+- Fix a batching bug resulting in some lifecycle methods incorrectly being called multiple times. ([@spicyj](https://github.com/spicyj) in [#6650](https://github.com/facebook/react/pull/6650))
+
+### React DOM
+- Fix regression in custom elements support. ([@jscissr](https://github.com/jscissr) in [#6570](https://github.com/facebook/react/pull/6570))
+- Stop incorrectly warning about using `onScroll` event handler with server rendering. ([@Aweary](https://github.com/Aweary) in [#6678](https://github.com/facebook/react/pull/6678))
+- Fix grammar in the controlled input warning. ([@jakeboone02](https://github.com/jakeboone02) in [#6657](https://github.com/facebook/react/pull/6657))
+- Fix issue preventing `<object>` nodes from being able to read `<param>` nodes in IE. ([@syranide](https://github.com/syranide) in [#6691](https://github.com/facebook/react/pull/6691))
+- Fix issue resulting in crash when using experimental error boundaries with server rendering. ([@jimfb](https://github.com/jimfb) in [#6694](https://github.com/facebook/react/pull/6694))
+- Add additional information to the controlled input warning. ([@borisyankov](https://github.com/borisyankov) in [#6341](https://github.com/facebook/react/pull/6341))
+
+### React Perf Add-on
+- Completely rewritten to collect data more accurately and to be easier to maintain. ([@gaearon](https://github.com/gaearon) in [#6647](https://github.com/facebook/react/pull/6647), [#6046](https://github.com/facebook/react/pull/6046))
+
+### React Native Renderer
+- Remove some special cases for platform specific branching. ([@sebmarkbage](https://github.com/sebmarkbage) in [#6660](https://github.com/facebook/react/pull/6660))
+- Remove use of `merge` utility. ([@sebmarkbage](https://github.com/sebmarkbage) in [#6634](https://github.com/facebook/react/pull/6634))
+- Renamed some modules to better indicate usage ([@javache](https://github.com/javache) in [#6643](https://github.com/facebook/react/pull/6643))
+
+
+## 15.0.2 (April 29, 2016)
+
+### React
+- Removed extraneous files from npm package. ([@gaearon](https://github.com/gaearon) in [#6388](https://github.com/facebook/react/pull/6388))
+- Ensure `componentWillUnmount` is only called once. ([@jimfb](https://github.com/jimfb) in [#6613](https://github.com/facebook/react/pull/6613))
+
+### ReactDOM
+- Fixed bug resulting in disabled buttons responding to mouse events in IE. ([@nhunzaker](https://github.com/nhunzaker) in [#6215](https://github.com/facebook/react/pull/6215))
+- Ensure `<option>`s are correctly selected when inside `<optgroup>`. ([@trevorsmith](https://github.com/trevorsmith) in [#6442](https://github.com/facebook/react/pull/6442))
+- Restore support for rendering into a shadow root. ([@Wildhoney](https://github.com/Wildhoney) in [#6462](https://github.com/facebook/react/pull/6462))
+- Ensure nested `<body>` elements are caught when warning for invalid markup. ([@keyanzhang](https://github.com/keyanzhang) in [#6469](https://github.com/facebook/react/pull/6469))
+- Improve warning when encountering multiple elements with the same key. ([@hkal](https://github.com/hkal) in [#6500](https://github.com/facebook/react/pull/6500))
+
+### React TestUtils Add-on
+- Ensure that functional components do not have an owner. ([@gaearon](https://github.com/gaearon) in [#6362](https://github.com/facebook/react/pull/6362))
+- Handle invalid arguments to `scryRenderedDOMComponentsWithClass` better. ([@ipeters90](https://github.com/ipeters90) in [#6529](https://github.com/facebook/react/pull/6529))
+
+### React Perf Add-on
+- Ignore DOM operations that occur outside the batch operation. ([@gaearon](https://github.com/gaearon) in [#6516](https://github.com/facebook/react/pull/6516))
+
+### React Native Renderer
+- These files are now shipped inside the React npm package. They have no impact on React core or ReactDOM.
+
+
+## 15.0.1 (April 8, 2016)
+
+### React
+- Restore `React.__spread` API to unbreak code compiled with some tools making use of this undocumented API. It is now officially deprecated. ([@zpao](https://github.com/zpao) in [#6444](https://github.com/facebook/react/pull/6444))
+
+### ReactDOM
+- Fixed issue resulting in loss of cursor position in controlled inputs. ([@spicyj](https://github.com/spicyj) in [#6449](https://github.com/facebook/react/pull/6449))
+
+
+## 15.0.0 (April 7, 2016)
+
+### Major changes
+
+- **Initial render now uses `document.createElement` instead of generating HTML.** Previously we would generate a large string of HTML and then set `node.innerHTML`. At the time, this was decided to be faster than using `document.createElement` for the majority of cases and browsers that we supported. Browsers have continued to improve and so overwhelmingly this is no longer true. By using `createElement` we can make other parts of React faster. ([@spicyj](https://github.com/spicyj) in [#5205](https://github.com/facebook/react/pull/5205))
+- **`data-reactid` is no longer on every node.** As a result of using `document.createElement`, we can prime the node cache as we create DOM nodes, allowing us to skip a potential lookup (which used the `data-reactid` attribute). Root nodes will have a `data-reactroot` attribute and server generated markup will still contain `data-reactid`. ([@spicyj](https://github.com/spicyj) in [#5205](https://github.com/facebook/react/pull/5205))
+- **No more extra `<span>`s.** ReactDOM will now render plain text nodes interspersed with comment nodes that are used for demarcation. This gives us the same ability to update individual pieces of text, without creating extra nested nodes. If you were targeting these `<span>`s in your CSS, you will need to adjust accordingly. You can always render them explicitly in your components. ([@mwiencek](https://github.com/mwiencek) in [#5753](https://github.com/facebook/react/pull/5753))
+- **Rendering `null` now uses comment nodes.** Previously `null` would render to `<noscript>` elements. We now use comment nodes. This may cause issues if making use of `:nth-child` CSS selectors. While we consider this rendering behavior an implementation detail of React, it's worth noting the potential problem. ([@spicyj](https://github.com/spicyj) in [#5451](https://github.com/facebook/react/pull/5451))
+- **Functional components can now return `null`.** We added support for [defining stateless components as functions](/react/blog/2015/09/10/react-v0.14-rc1.html#stateless-function-components) in React 0.14. However, React 0.14 still allowed you to define a class component without extending `React.Component` or using `React.createClass()`, so [we couldn’t reliably tell if your component is a function or a class](https://github.com/facebook/react/issues/5355), and did not allow returning `null` from it. This issue is solved in React 15, and you can now return `null` from any component, whether it is a class or a function. ([@jimfb](https://github.com/jimfb) in [#5884](https://github.com/facebook/react/pull/5884))
+- **Improved SVG support.** All SVG tags are now fully supported. (Uncommon SVG tags are not present on the `React.DOM` element helper, but JSX and `React.createElement` work on all tag names.) All SVG attributes that are implemented by the browsers should be supported too. If you find any attributes that we have missed, please [let us know in this issue](https://github.com/facebook/react/issues/1657). ([@zpao](https://github.com/zpao) in [#6243](https://github.com/facebook/react/pull/6243))
+
+### Breaking changes
+
+- **No more extra `<span>`s.**
+- **`React.cloneElement()` now resolves `defaultProps`.** We fixed a bug in `React.cloneElement()` that some components may rely on. If some of the `props` received by `cloneElement()` are `undefined`, it used to return an element with `undefined` values for those props. We’re changing it to be consistent with `createElement()`. Now any `undefined` props passed to `cloneElement()` are resolved to the corresponding component’s `defaultProps`. ([@truongduy134](https://github.com/truongduy134) in [#5997](https://github.com/facebook/react/pull/5997))
+- **`ReactPerf.getLastMeasurements()` is opaque.** This change won’t affect applications but may break some third-party tools. We are [revamping `ReactPerf` implementation](https://github.com/facebook/react/pull/6046) and plan to release it during the 15.x cycle. The internal performance measurement format is subject to change so, for the time being, we consider the return value of `ReactPerf.getLastMeasurements()` an opaque data structure that should not be relied upon. ([@gaearon](https://github.com/gaearon) in [#6286](https://github.com/facebook/react/pull/6286))
+
+#### Removed deprecations
+
+These deprecations were introduced nine months ago in v0.14 with a warning and are removed:
+
+- Deprecated APIs are removed from the `React` top-level export: `findDOMNode`, `render`, `renderToString`, `renderToStaticMarkup`, and `unmountComponentAtNode`. As a reminder, they are now available on `ReactDOM` and `ReactDOMServer`. ([@jimfb](https://github.com/jimfb) in [#5832](https://github.com/facebook/react/pull/5832))
+- Deprecated addons are removed: `batchedUpdates` and `cloneWithProps`. ([@jimfb](https://github.com/jimfb) in [#5859](https://github.com/facebook/react/pull/5859), [@zpao](https://github.com/zpao) in [#6016](https://github.com/facebook/react/pull/6016))
+- Deprecated component instance methods are removed: `setProps`, `replaceProps`, and `getDOMNode`. ([@jimfb](https://github.com/jimfb) in [#5570](https://github.com/facebook/react/pull/5570))
+- Deprecated CommonJS `react/addons` entry point is removed. As a reminder, you should use separate `react-addons-*` packages instead. This only applies if you use the CommonJS builds. ([@gaearon](https://github.com/gaearon) in [#6285](https://github.com/facebook/react/pull/6285))
+- Passing `children` to void elements like `<input>` was deprecated, and now throws an error. ([@jonhester](https://github.com/jonhester) in [#3372](https://github.com/facebook/react/pull/3372))
+- React-specific properties on DOM `refs` (e.g. `this.refs.div.props`) were deprecated, and are removed now. ([@jimfb](https://github.com/jimfb) in [#5495](https://github.com/facebook/react/pull/5495))
+
+### New deprecations, introduced with a warning
+
+Each of these changes will continue to work as before with a new warning until the release of React 16 so you can upgrade your code gradually.
+
+- `LinkedStateMixin` and `valueLink` are now deprecated due to very low popularity. If you need this, you can use a wrapper component that implements the same behavior: [react-linked-input](https://www.npmjs.com/package/react-linked-input). ([@jimfb](https://github.com/jimfb) in [#6127](https://github.com/facebook/react/pull/6127))
+- Future versions of React will treat `<input value={null}>` as a request to clear the input. However, React 0.14 has been ignoring `value={null}`. React 15 warns you on a `null` input value and offers you to clarify your intention. To fix the warning, you may explicitly pass an empty string to clear a controlled input, or pass `undefined` to make the input uncontrolled. ([@antoaravinth](https://github.com/antoaravinth) in [#5048](https://github.com/facebook/react/pull/5048))
+- `ReactPerf.printDOM()` was renamed to `ReactPerf.printOperations()`, and `ReactPerf.getMeasurementsSummaryMap()` was renamed to `ReactPerf.getWasted()`. ([@gaearon](https://github.com/gaearon) in [#6287](https://github.com/facebook/react/pull/6287))
+
+### New helpful warnings
+
+- If you use a minified copy of the _development_ build, React DOM kindly encourages you to use the faster production build instead. ([@spicyj](https://github.com/spicyj) in [#5083](https://github.com/facebook/react/pull/5083))
+- React DOM: When specifying a unit-less CSS value as a string, a future version will not add `px` automatically. This version now warns in this case (ex: writing `style={{'{{'}}width: '300'}}`. Unitless *number* values like `width: 300` are unchanged. ([@pluma](https://github.com/pluma) in [#5140](https://github.com/facebook/react/pull/5140))
+- Synthetic Events will now warn when setting and accessing properties (which will not get cleared appropriately), as well as warn on access after an event has been returned to the pool. ([@kentcdodds](https://github.com/kentcdodds) in [#5940](https://github.com/facebook/react/pull/5940) and [@koba04](https://github.com/koba04) in [#5947](https://github.com/facebook/react/pull/5947))
+- Elements will now warn when attempting to read `ref` and `key` from the props. ([@prometheansacrifice](https://github.com/prometheansacrifice) in [#5744](https://github.com/facebook/react/pull/5744))
+- React will now warn if you pass a different `props` object to `super()` in the constructor. ([@prometheansacrifice](https://github.com/prometheansacrifice) in [#5346](https://github.com/facebook/react/pull/5346))
+- React will now warn if you call `setState()` inside `getChildContext()`. ([@raineroviir](https://github.com/raineroviir) in [#6121](https://github.com/facebook/react/pull/6121))
+- React DOM now attempts to warn for mistyped event handlers on DOM elements, such as `onclick` which should be `onClick`. ([@ali](https://github.com/ali) in [#5361](https://github.com/facebook/react/pull/5361))
+- React DOM now warns about `NaN` values in `style`. ([@jontewks](https://github.com/jontewks) in [#5811](https://github.com/facebook/react/pull/5811))
+- React DOM now warns if you specify both `value` and `defaultValue` for an input. ([@mgmcdermott](https://github.com/mgmcdermott) in [#5823](https://github.com/facebook/react/pull/5823))
+- React DOM now warns if an input switches between being controlled and uncontrolled. ([@TheBlasfem](https://github.com/TheBlasfem) in [#5864](https://github.com/facebook/react/pull/5864))
+- React DOM now warns if you specify `onFocusIn` or `onFocusOut` handlers as they are unnecessary in React. ([@jontewks](https://github.com/jontewks) in [#6296](https://github.com/facebook/react/pull/6296))
+- React now prints a descriptive error message when you pass an invalid callback as the last argument to `ReactDOM.render()`, `this.setState()`, or `this.forceUpdate()`. ([@conorhastings](https://github.com/conorhastings) in [#5193](https://github.com/facebook/react/pull/5193) and [@gaearon](https://github.com/gaearon) in [#6310](https://github.com/facebook/react/pull/6310))
+- Add-Ons: `TestUtils.Simulate()` now prints a helpful message if you attempt to use it with shallow rendering. ([@conorhastings](https://github.com/conorhastings) in [#5358](https://github.com/facebook/react/pull/5358))
+- PropTypes: `arrayOf()` and `objectOf()` provide better error messages for invalid arguments. ([@chicoxyzzy](https://github.com/chicoxyzzy) in [#5390](https://github.com/facebook/react/pull/5390))
+
+### Notable bug fixes
+
+- Fixed multiple small memory leaks. ([@spicyj](https://github.com/spicyj) in [#4983](https://github.com/facebook/react/pull/4983) and [@victor-homyakov](https://github.com/victor-homyakov) in [#6309](https://github.com/facebook/react/pull/6309))
+- Input events are handled more reliably in IE 10 and IE 11; spurious events no longer fire when using a placeholder. ([@jquense](https://github.com/jquense) in [#4051](https://github.com/facebook/react/pull/4051))
+- The `componentWillReceiveProps()` lifecycle method is now consistently called when `context` changes. ([@milesj](https://github.com/milesj) in [#5787](https://github.com/facebook/react/pull/5787))
+- `React.cloneElement()` doesn’t append slash to an existing `key` when used inside `React.Children.map()`. ([@ianobermiller](https://github.com/ianobermiller) in [#5892](https://github.com/facebook/react/pull/5892))
+- React DOM now supports the `cite` and `profile` HTML attributes. ([@AprilArcus](https://github.com/AprilArcus) in [#6094](https://github.com/facebook/react/pull/6094) and [@saiichihashimoto](https://github.com/saiichihashimoto) in [#6032](https://github.com/facebook/react/pull/6032))
+- React DOM now supports `cssFloat`, `gridRow` and `gridColumn` CSS properties. ([@stevenvachon](https://github.com/stevenvachon) in [#6133](https://github.com/facebook/react/pull/6133) and  [@mnordick](https://github.com/mnordick) in [#4779](https://github.com/facebook/react/pull/4779))
+- React DOM now correctly handles `borderImageOutset`, `borderImageWidth`, `borderImageSlice`, `floodOpacity`, `strokeDasharray`, and `strokeMiterlimit` as unitless CSS properties. ([@rofrischmann](https://github.com/rofrischmann) in [#6210](https://github.com/facebook/react/pull/6210) and [#6270](https://github.com/facebook/react/pull/6270))
+- React DOM now supports the `onAnimationStart`, `onAnimationEnd`, `onAnimationIteration`, `onTransitionEnd`, and `onInvalid` events. Support for `onLoad` has been added to `object` elements. ([@tomduncalf](https://github.com/tomduncalf) in [#5187](https://github.com/facebook/react/pull/5187),  [@milesj](https://github.com/milesj) in [#6005](https://github.com/facebook/react/pull/6005), and [@ara4n](https://github.com/ara4n) in [#5781](https://github.com/facebook/react/pull/5781))
+- React DOM now defaults to using DOM attributes instead of properties, which fixes a few edge case bugs. Additionally the nullification of values (ex: `href={null}`) now results in the forceful removal, no longer trying to set to the default value used by browsers in the absence of a value. ([@syranide](https://github.com/syranide) in [#1510](https://github.com/facebook/react/pull/1510))
+- React DOM does not mistakingly coerce `children` to strings for Web Components. ([@jimfb](https://github.com/jimfb) in [#5093](https://github.com/facebook/react/pull/5093))
+- React DOM now correctly normalizes SVG `<use>` events. ([@edmellum](https://github.com/edmellum) in [#5720](https://github.com/facebook/react/pull/5720))
+- React DOM does not throw if a `<select>` is unmounted while its `onChange` handler is executing. ([@sambev](https://github.com/sambev) in [#6028](https://github.com/facebook/react/pull/6028))
+- React DOM does not throw in Windows 8 apps. ([@Andrew8xx8](https://github.com/Andrew8xx8) in [#6063](https://github.com/facebook/react/pull/6063))
+- React DOM does not throw when asynchronously unmounting a child with a `ref`. ([@yiminghe](https://github.com/yiminghe) in [#6095](https://github.com/facebook/react/pull/6095))
+- React DOM no longer forces synchronous layout because of scroll position tracking. ([@syranide](https://github.com/syranide) in [#2271](https://github.com/facebook/react/pull/2271))
+- `Object.is` is used in a number of places to compare values, which leads to fewer false positives, especially involving `NaN`. In particular, this affects the `shallowCompare` add-on. ([@chicoxyzzy](https://github.com/chicoxyzzy) in [#6132](https://github.com/facebook/react/pull/6132))
+- Add-Ons: ReactPerf no longer instruments adding or removing an event listener because they don’t really touch the DOM due to event delegation. ([@antoaravinth](https://github.com/antoaravinth) in [#5209](https://github.com/facebook/react/pull/5209))
+
+### Other improvements
+
+- React now uses `loose-envify` instead of `envify` so it installs fewer transitive dependencies. ([@qerub](https://github.com/qerub) in [#6303](https://github.com/facebook/react/pull/6303))
+- Shallow renderer now exposes `getMountedInstance()`. ([@glenjamin](https://github.com/glenjamin) in [#4918](https://github.com/facebook/react/pull/4918))
+- Shallow renderer now returns the rendered output from `render()`. ([@simonewebdesign](https://github.com/simonewebdesign) in [#5411](https://github.com/facebook/react/pull/5411))
+- React no longer depends on ES5 *shams* for `Object.create` and `Object.freeze` in older environments. It still, however, requires ES5 *shims* in those environments. ([@dgreensp](https://github.com/dgreensp) in [#4959](https://github.com/facebook/react/pull/4959))
+- React DOM now allows `data-` attributes with names that start with numbers. ([@nLight](https://github.com/nLight) in [#5216](https://github.com/facebook/react/pull/5216))
+- React DOM adds a new `suppressContentEditableWarning` prop for components like [Draft.js](https://facebook.github.io/draft-js/) that intentionally manage `contentEditable` children with React. ([@mxstbr](https://github.com/mxstbr) in [#6112](https://github.com/facebook/react/pull/6112))
+- React improves the performance for `createClass()` on complex specs. ([@spicyj](https://github.com/spicyj) in [#5550](https://github.com/facebook/react/pull/5550))
+
+
 ## 0.14.8 (March 29, 2016)
 
 ### React
@@ -88,7 +518,7 @@
 ### Major changes
 
 - Split the main `react` package into two: `react` and `react-dom`.  This paves the way to writing components that can be shared between the web version of React and React Native.  This means you will need to include both files and some functions have been moved from `React` to `ReactDOM`.
-- Addons have been moved to seperate packages (`react-addons-clone-with-props`, `react-addons-create-fragment`, `react-addons-css-transition-group`, `react-addons-linked-state-mixin`, `react-addons-perf`, `react-addons-pure-render-mixin`, `react-addons-shallow-compare`, `react-addons-test-utils`, `react-addons-transition-group`, `react-addons-update`, `ReactDOM.unstable_batchedUpdates`).
+- Addons have been moved to separate packages (`react-addons-clone-with-props`, `react-addons-create-fragment`, `react-addons-css-transition-group`, `react-addons-linked-state-mixin`, `react-addons-perf`, `react-addons-pure-render-mixin`, `react-addons-shallow-compare`, `react-addons-test-utils`, `react-addons-transition-group`, `react-addons-update`, `ReactDOM.unstable_batchedUpdates`).
 - Stateless functional components - React components were previously created using React.createClass or using ES6 classes.  This release adds a [new syntax](https://facebook.github.io/react/docs/reusable-components.html#stateless-functions) where a user defines a single [stateless render function](https://facebook.github.io/react/docs/reusable-components.html#stateless-functions) (with one parameter: `props`) which returns a JSX element, and this function may be used as a component.
 - Refs to DOM components as the DOM node itself. Previously the only useful thing you can do with a DOM component is call `getDOMNode()` to get the underlying DOM node. Starting with this release, a ref to a DOM component _is_ the actual DOM node. **Note that refs to custom (user-defined) components work exactly as before; only the built-in DOM components are affected by this change.**
 
@@ -97,7 +527,7 @@
 
 - `React.initializeTouchEvents` is no longer necessary and has been removed completely. Touch events now work automatically.
 - Add-Ons: Due to the DOM node refs change mentioned above, `TestUtils.findAllInRenderedTree` and related helpers are no longer able to take a DOM component, only a custom component.
-- The `props` object is now frozen, so mutating props after creating a component element is no longer supported. In most cases, [`React.cloneElement`](https://facebook.github.io/react/docs/top-level-api.html#react.cloneelement) should be used instead. This change makes your components easier to reason about and enables the compiler optimizations mentioned above.
+- The `props` object is now frozen, so mutating props after creating a component element is no longer supported. In most cases, [`React.cloneElement`](https://facebook.github.io/react/docs/react-api.html#cloneelement) should be used instead. This change makes your components easier to reason about and enables the compiler optimizations mentioned above.
 - Plain objects are no longer supported as React children; arrays should be used instead. You can use the [`createFragment`](https://facebook.github.io/react/docs/create-fragment.html) helper to migrate, which now returns an array.
 - Add-Ons: `classSet` has been removed. Use [classnames](https://github.com/JedWatson/classnames) instead.
 - Web components (custom elements) now use native property names.  Eg: `class` instead of `className`.
@@ -108,7 +538,7 @@
 - `setProps` and `replaceProps` are now deprecated. Instead, call ReactDOM.render again at the top level with the new props.
 - ES6 component classes must now extend `React.Component` in order to enable stateless function components. The [ES3 module pattern](https://facebook.github.io/react/blog/2015/01/27/react-v0.13.0-beta-1.html#other-languages) will continue to work.
 - Reusing and mutating a `style` object between renders has been deprecated. This mirrors our change to freeze the `props` object.
-- Add-Ons: `cloneWithProps` is now deprecated. Use [`React.cloneElement`](https://facebook.github.io/react/docs/top-level-api.html#react.cloneelement) instead (unlike `cloneWithProps`, `cloneElement` does not merge `className` or `style` automatically; you can merge them manually if needed).
+- Add-Ons: `cloneWithProps` is now deprecated. Use [`React.cloneElement`](https://facebook.github.io/react/docs/react-api.html#cloneelement) instead (unlike `cloneWithProps`, `cloneElement` does not merge `className` or `style` automatically; you can merge them manually if needed).
 - Add-Ons: To improve reliability, `CSSTransitionGroup` will no longer listen to transition events. Instead, you should specify transition durations manually using props such as `transitionEnterTimeout={500}`.
 
 ### Notable enhancements
@@ -202,7 +632,7 @@
 
 #### Bug Fixes
 
-* Immutabilty Helpers: Ensure it supports `hasOwnProperty` as an object key
+* Immutability Helpers: Ensure it supports `hasOwnProperty` as an object key
 
 ### React Tools
 
@@ -733,14 +1163,14 @@
 
 * Upgrade Commoner so `require` statements are no longer relativized when passing through the transformer. This was a feature needed when building React, but doesn't translate well for other consumers of `bin/jsx`.
 * Upgraded our dependencies on Commoner and Recast so they use a different directory for their cache.
-* Freeze our esprima dependency.
+* Freeze our Esprima dependency.
 
 
 ## 0.3.2 (May 31, 2013)
 
 ### JSX
 
-* Improved compatability with other coding styles (specifically, multiple assignments with a single `var`).
+* Improved compatibility with other coding styles (specifically, multiple assignments with a single `var`).
 
 ### react-tools
 
@@ -756,4 +1186,4 @@
 
 ## 0.3.0 (May 29, 2013)
 
-* Initial public release
+* Initial public release
\ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 1063ee428e32..87f3cc0ca908 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,100 +1,5 @@
 # Contributing to React
 
-React is one of Facebook's first open source projects that is both under very active development and is also being used to ship code to everybody on [facebook.com](https://www.facebook.com). We're still working out the kinks to make contributing to this project as easy and transparent as possible, but we're not quite there yet. Hopefully this document makes the process for contributing clear and answers some questions that you may have.
+Want to contribute to React? There are a few things you need to know.  
 
-## [Code of Conduct](https://code.facebook.com/codeofconduct)
-
-Facebook has adopted a Code of Conduct that we expect project participants to adhere to. Please read [the full text](https://code.facebook.com/codeofconduct) so that you can understand what actions will and will not be tolerated.
-
-## Our Development Process
-
-Some of the core team will be working directly on GitHub. These changes will be public from the beginning. Other changesets will come via a bridge with Facebook's internal source control. This is a necessity as it allows engineers at Facebook outside of the core team to move fast and contribute from an environment they are comfortable in.
-
-### `master` is unsafe
-
-We will do our best to keep `master` in good shape, with tests passing at all times. But in order to move fast, we will make API changes that your application might not be compatible with. We will do our best to communicate these changes and always version appropriately so you can lock into a specific version if need be.
-
-### Test Suite
-
-Use `grunt test` to run the full test suite with PhantomJS.
-
-This command is just a facade to [Jest](https://facebook.github.io/jest/). You may optionally run `npm install -g jest-cli` and use Jest commands directly to have more control over how tests are executed.
-
-For example, `jest --watch` lets you automatically run the test suite on every file change.
-
-You can also run a subset of tests by passing a prefix to `jest`. For instance, `jest ReactDOMSVG` will only run tests in the files that start with `ReactDOMSVG`, such as `ReactDOMSVG-test.js`.
-
-When you know which tests you want to run, you can achieve a fast feedback loop by using these two features together. For example, `jest ReactDOMSVG --watch` will re-run only the matching tests on every change.
-
-Just make sure to run the whole test suite before submitting a pull request!
-
-### Pull Requests
-
-**Working on your first Pull Request?** You can learn how from this *free* series [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github)
-
-The core team will be monitoring for pull requests. When we get one, we'll run some Facebook-specific integration tests on it first. From here, we'll need to get another person to sign off on the changes and then merge the pull request. For API changes we may need to fix internal uses, which could cause some delay. We'll do our best to provide updates and feedback throughout the process.
-
-*Before* submitting a pull request, please make sure the following is done…
-
-1. Fork the repo and create your branch from `master`.
-2. If you've added code that should be tested, add tests!
-3. If you've changed APIs, update the documentation.
-4. Ensure the test suite passes (`grunt test`).
-5. Make sure your code lints (`grunt lint`) - we've done our best to make sure these rules match our internal linting guidelines.
-6. If you haven't already, complete the CLA.
-
-### Contributor License Agreement (CLA)
-
-In order to accept your pull request, we need you to submit a CLA. You only need to do this once, so if you've done this for another Facebook open source project, you're good to go. If you are submitting a pull request for the first time, just let us know that you have completed the CLA and we can cross-check with your GitHub username.
-
-[Complete your CLA here.](https://code.facebook.com/cla)
-
-## Bugs
-
-### Where to Find Known Issues
-
-We will be using GitHub Issues for our public bugs. We will keep a close eye on this and try to make it clear when we have an internal fix in progress. Before filing a new task, try to make sure your problem doesn't already exist.
-
-### Reporting New Issues
-
-The best way to get your bug fixed is to provide a reduced test case. jsFiddle, jsBin, and other sites provide a way to give live examples. Those are especially helpful though may not work for `JSX`-based code.
-
-### Security Bugs
-
-Facebook has a [bounty program](https://www.facebook.com/whitehat/) for the safe disclosure of security bugs. With that in mind, please do not file public issues; go through the process outlined on that page.
-
-## How to Get in Touch
-
-* IRC - [#reactjs on freenode](https://webchat.freenode.net/?channels=reactjs)
-* Discussion forum - [discuss.reactjs.org](https://discuss.reactjs.org/)
-
-## Meeting Notes
-
-React team meets once a week to discuss the development of React, future plans, and priorities.  
-You can find the meeting notes in a [dedicated repository](https://github.com/reactjs/core-notes/).
-
-## Style Guide
-
-Our linter will catch most styling issues that may exist in your code.
-You can check the status of your code styling by simply running: `grunt lint`
-
-However, there are still some styles that the linter cannot pick up. If you are unsure about something, looking at [Airbnb's Style Guide](https://github.com/airbnb/javascript) will guide you in the right direction.
-
-### Code Conventions
-
-* Use semicolons `;`
-* Commas last `,`
-* 2 spaces for indentation (no tabs)
-* Prefer `'` over `"`
-* `'use strict';`
-* 80 character line length
-* Write "attractive" code
-* Do not use the optional parameters of `setTimeout` and `setInterval`
-
-### Documentation
-
-* Do not wrap lines at 80 characters
-
-## License
-
-By contributing to React, you agree that your contributions will be licensed under its BSD license.
+We wrote a **[contribution guide](https://facebook.github.io/react/contributing/how-to-contribute.html)** to help you get started.
diff --git a/Gruntfile.js b/Gruntfile.js
index c3ee8c20d644..9a16c85b275a 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -23,8 +23,6 @@ module.exports = function(grunt) {
     'compare_size': require('./grunt/config/compare_size'),
   });
 
-  grunt.config.set('compress', require('./grunt/config/compress'));
-
   function spawnGulp(args, opts, done) {
 
     grunt.util.spawn({
@@ -52,10 +50,18 @@ module.exports = function(grunt) {
       grunt.loadNpmTasks(npmTaskName);
     });
 
-  grunt.registerTask('eslint', require('./grunt/tasks/eslint'));
+  grunt.registerTask('eslint', function() {
+    // Use gulp here.
+    spawnGulp(['eslint'], null, this.async());
+  });
 
   grunt.registerTask('lint', ['eslint']);
 
+  grunt.registerTask('flow', function() {
+    // Use gulp here.
+    spawnGulp(['flow'], null, this.async());
+  });
+
   grunt.registerTask('delete-build-modules', function() {
     // Use gulp here.
     spawnGulp(['react:clean'], null, this.async());
@@ -74,11 +80,14 @@ module.exports = function(grunt) {
   grunt.registerTask('npm-react-dom:release', npmReactDOMTasks.buildRelease);
   grunt.registerTask('npm-react-dom:pack', npmReactDOMTasks.packRelease);
 
-  var npmReactAddonsTasks = require('./grunt/tasks/npm-react-addons');
-  grunt.registerTask('npm-react-addons:release', npmReactAddonsTasks.buildReleases);
-  grunt.registerTask('npm-react-addons:pack', npmReactAddonsTasks.packReleases);
+  var npmReactTestRendererTasks = require('./grunt/tasks/npm-react-test');
+  grunt.registerTask('npm-react-test:release', npmReactTestRendererTasks.buildRelease);
+  grunt.registerTask('npm-react-test:pack', npmReactTestRendererTasks.packRelease);
 
-  grunt.registerTask('version-check', require('./grunt/tasks/version-check'));
+  grunt.registerTask('version-check', function() {
+    // Use gulp here.
+    spawnGulp(['version-check'], null, this.async());
+  });
 
   grunt.registerTask('build:basic', [
     'build-modules',
@@ -98,12 +107,41 @@ module.exports = function(grunt) {
     'build-modules',
     'browserify:addonsMin',
   ]);
+  grunt.registerTask('build:dom', [
+    'build-modules',
+    'version-check',
+    'browserify:dom',
+  ]);
+  grunt.registerTask('build:dom-min', [
+    'build-modules',
+    'version-check',
+    'browserify:domMin',
+  ]);
+  grunt.registerTask('build:dom-server', [
+    'build-modules',
+    'version-check',
+    'browserify:domServer',
+  ]);
+  grunt.registerTask('build:dom-server-min', [
+    'build-modules',
+    'version-check',
+    'browserify:domServerMin',
+  ]);
+  grunt.registerTask('build:dom-fiber', [
+    'build-modules',
+    'version-check',
+    'browserify:domFiber',
+  ]);
+  grunt.registerTask('build:dom-fiber-min', [
+    'build-modules',
+    'version-check',
+    'browserify:domFiberMin',
+  ]);
   grunt.registerTask('build:npm-react', [
     'version-check',
     'build-modules',
     'npm-react:release',
   ]);
-  grunt.registerTask('build:react-dom', require('./grunt/tasks/react-dom'));
 
   var jestTasks = require('./grunt/tasks/jest');
   grunt.registerTask('jest:normal', jestTasks.normal);
@@ -122,13 +160,18 @@ module.exports = function(grunt) {
     'browserify:addons',
     'browserify:min',
     'browserify:addonsMin',
-    'build:react-dom',
+    'browserify:dom',
+    'browserify:domMin',
+    'browserify:domServer',
+    'browserify:domServerMin',
+    'browserify:domFiber',
+    'browserify:domFiberMin',
     'npm-react:release',
     'npm-react:pack',
     'npm-react-dom:release',
     'npm-react-dom:pack',
-    'npm-react-addons:release',
-    'npm-react-addons:pack',
+    'npm-react-test:release',
+    'npm-react-test:pack',
     'compare_size',
   ]);
 
@@ -138,15 +181,12 @@ module.exports = function(grunt) {
   grunt.registerTask('release:bower', releaseTasks.bower);
   grunt.registerTask('release:docs', releaseTasks.docs);
   grunt.registerTask('release:msg', releaseTasks.msg);
-  grunt.registerTask('release:starter', releaseTasks.starter);
 
   grunt.registerTask('release', [
     'release:setup',
     'clean',
     'build',
     'release:bower',
-    'release:starter',
-    'compress',
     'release:docs',
     'release:msg',
   ]);
diff --git a/README.md b/README.md
index 982d5adb074c..523f50187bd3 100644
--- a/README.md
+++ b/README.md
@@ -2,11 +2,9 @@
 
 React is a JavaScript library for building user interfaces.
 
-* **Just the UI:** Lots of people use React as the V in MVC. Since React makes no assumptions about the rest of your technology stack, it's easy to try it out on a small feature in an existing project.
-* **Virtual DOM:** React abstracts away the DOM from you, giving a simpler programming model and better performance. React can also render on the server using Node, and it can power native apps using [React Native](https://facebook.github.io/react-native/).
-* **Data flow:** React implements one-way reactive data flow which reduces boilerplate and is easier to reason about than traditional data binding.
-
-**NEW**! Check out our newest project [React Native](https://github.com/facebook/react-native), which uses React and JavaScript to create native mobile apps.
+* **Declarative:** React makes it painless to create interactive UIs. Design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes. Declarative views make your code more predictable, simpler to understand, and easier to debug.
+* **Component-Based:** Build encapsulated components that manage their own state, then compose them to make complex UIs. Since component logic is written in JavaScript instead of templates, you can easily pass rich data through your app and keep state out of the DOM.
+* **Learn Once, Write Anywhere:** We don't make assumptions about the rest of your technology stack, so you can develop new features in React without rewriting existing code. React can also render on the server using Node and power mobile apps using [React Native](https://facebook.github.io/react-native/).
 
 [Learn how to use React in your own project](https://facebook.github.io/react/docs/getting-started.html).
 
@@ -15,11 +13,11 @@ React is a JavaScript library for building user interfaces.
 We have several examples [on the website](https://facebook.github.io/react/). Here is the first one to get you started:
 
 ```js
-var HelloMessage = React.createClass({
-  render: function() {
+class HelloMessage extends React.Component {
+  render() {
     return <div>Hello {this.props.name}</div>;
   }
-});
+}
 
 ReactDOM.render(
   <HelloMessage name="John" />,
@@ -29,76 +27,31 @@ ReactDOM.render(
 
 This example will render "Hello John" into a container on the page.
 
-You'll notice that we used an HTML-like syntax; [we call it JSX](https://facebook.github.io/react/docs/jsx-in-depth.html). JSX is not required to use React, but it makes code more readable, and writing it feels like writing HTML. A simple transform is included with React that allows converting JSX into native JavaScript for browsers to digest.
+You'll notice that we used an HTML-like syntax; [we call it JSX](https://facebook.github.io/react/docs/introducing-jsx.html). JSX is not required to use React, but it makes code more readable, and writing it feels like writing HTML. We recommend using [Babel](https://babeljs.io/) with a [React preset](https://babeljs.io/docs/plugins/preset-react/) to convert JSX into native JavaScript for browsers to digest.
 
 ## Installation
 
-The fastest way to get started is to serve JavaScript from the CDN (also available on [cdnjs](https://cdnjs.com/libraries/react) and [jsdelivr](https://www.jsdelivr.com/projects/react)):
-
-```html
-<!-- The core React library -->
-<script src="https://fb.me/react-0.14.8.js"></script>
-<!-- The ReactDOM Library -->
-<script src="https://fb.me/react-dom-0.14.8.js"></script>
-```
-
-We've also built a [starter kit](https://facebook.github.io/react/downloads/react-0.14.8.zip) which might be useful if this is your first time using React. It includes a webpage with an example of using React with live code.
-
-If you'd like to use [bower](http://bower.io), it's as easy as:
-
-```sh
-bower install --save react
-```
-
-And it's just as easy with [npm](http://npmjs.com):
-
-```sh
-npm i --save react
-```
-
-## Contribute
-
-The main purpose of this repository is to continue to evolve React core, making it faster and easier to use. If you're interested in helping with that, then keep reading. If you're not interested in helping right now that's ok too. :) Any feedback you have about using React would be greatly appreciated.
-
-### Building Your Copy of React
-
-The process to build `react.js` is built entirely on top of node.js, using many libraries you may already be familiar with.
-
-#### Prerequisites
+React is available as the `react` package on [npm](https://www.npmjs.com/). It is also available on a [CDN](https://facebook.github.io/react/docs/installation.html#using-a-cdn).
 
-* You have `node` installed at v4.0.0+ and `npm` at v2.0.0+.
-* You are familiar with `npm` and know whether or not you need to use `sudo` when installing packages globally.
-* You are familiar with `git`.
+React is flexible and can be used in a variety of projects. You can create new apps with it, but you can also gradually introduce it into an existing codebase without doing a rewrite.
 
-#### Build
+The recommended way to install React depends on your project. Here you can find short guides for the most common scenarios:
 
-Once you have the repository cloned, building a copy of `react.js` is really easy.
+* [Trying Out React](https://facebook.github.io/react/docs/installation.html#trying-out-react)
+* [Creating a Single Page Application](https://facebook.github.io/react/docs/installation.html#creating-a-single-page-application)
+* [Adding React to an Existing Application](https://facebook.github.io/react/docs/installation.html#adding-react-to-an-existing-application)
 
-```sh
-# grunt-cli is needed by grunt; you might have this installed already
-npm install -g grunt-cli
-npm install
-grunt build
-```
-
-At this point, you should now have a `build/` directory populated with everything you need to use React. The examples should all work.
+## Contributing
 
-### Grunt
+The main purpose of this repository is to continue to evolve React core, making it faster and easier to use. If you're interested in helping with that, check out our [contribution guide](https://facebook.github.io/react/contributing/how-to-contribute.html).
 
-We use grunt to automate many tasks. Run `grunt -h` to see a mostly complete listing. The important ones to know:
+### [Code of Conduct](https://code.facebook.com/codeofconduct)
 
-```sh
-# Build and run tests with PhantomJS
-grunt test
-# Lint the code with ESLint
-grunt lint
-# Wipe out build directory
-grunt clean
-```
+Facebook has adopted a Code of Conduct that we expect project participants to adhere to. Please read [the full text](https://code.facebook.com/codeofconduct) so that you can understand what actions will and will not be tolerated.
 
 ### Good First Bug
-To help you get your feet wet and get you familiar with our contribution process, we have a list of [good first bugs](https://github.com/facebook/react/labels/good%20first%20bug) that contain bugs which are fairly easy to fix.  This is a great place to get started.
 
+To help you get your feet wet and get you familiar with our contribution process, we have a list of [good first bugs](https://github.com/facebook/react/labels/good%20first%20bug) that contain bugs which are fairly easy to fix. This is a great place to get started.
 
 ### License
 
@@ -108,9 +61,5 @@ React documentation is [Creative Commons licensed](./LICENSE-docs).
 
 Examples provided in this repository and in the documentation are [separately licensed](./LICENSE-examples).
 
-### More…
-
-There's only so much we can cram in here. To read more about the community and guidelines for submitting pull requests, please read the [Contributing document](CONTRIBUTING.md).
-
 ## Troubleshooting
 See the [Troubleshooting Guide](https://github.com/facebook/react/wiki/Troubleshooting)
diff --git a/addons/.eslintrc b/addons/.eslintrc
new file mode 100644
index 000000000000..4837c85257b3
--- /dev/null
+++ b/addons/.eslintrc
@@ -0,0 +1,5 @@
+{
+  "rules": {
+    "comma-dangle": 0
+  }
+}
diff --git a/addons/create-react-class/.gitignore b/addons/create-react-class/.gitignore
new file mode 100644
index 000000000000..1b9b09e4d723
--- /dev/null
+++ b/addons/create-react-class/.gitignore
@@ -0,0 +1,2 @@
+create-react-class.js
+create-react-class.min.js
diff --git a/addons/create-react-class/LICENSE.txt b/addons/create-react-class/LICENSE.txt
new file mode 100644
index 000000000000..91b8f6f76ff0
--- /dev/null
+++ b/addons/create-react-class/LICENSE.txt
@@ -0,0 +1,31 @@
+BSD License
+
+For React software
+
+Copyright (c) 2013-present, Facebook, Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+ * Neither the name Facebook nor the names of its contributors may be used to
+   endorse or promote products derived from this software without specific
+   prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/addons/create-react-class/PATENTS b/addons/create-react-class/PATENTS
new file mode 100644
index 000000000000..9c9f8e87a8f4
--- /dev/null
+++ b/addons/create-react-class/PATENTS
@@ -0,0 +1,33 @@
+Additional Grant of Patent Rights Version 2
+
+"Software" means the React software distributed by Facebook, Inc.
+
+Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software
+("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable
+(subject to the termination provision below) license under any Necessary
+Claims, to make, have made, use, sell, offer to sell, import, and otherwise
+transfer the Software. For avoidance of doubt, no license is granted under
+Facebook's rights in any patent claims that are infringed by (i) modifications
+to the Software made by you or any third party or (ii) the Software in
+combination with any software or other technology.
+
+The license granted hereunder will terminate, automatically and without notice,
+if you (or any of your subsidiaries, corporate affiliates or agents) initiate
+directly or indirectly, or take a direct financial interest in, any Patent
+Assertion: (i) against Facebook or any of its subsidiaries or corporate
+affiliates, (ii) against any party if such Patent Assertion arises in whole or
+in part from any software, technology, product or service of Facebook or any of
+its subsidiaries or corporate affiliates, or (iii) against any party relating
+to the Software. Notwithstanding the foregoing, if Facebook or any of its
+subsidiaries or corporate affiliates files a lawsuit alleging patent
+infringement against you in the first instance, and you respond by filing a
+patent infringement counterclaim in that lawsuit against that party that is
+unrelated to the Software, the license granted hereunder will not terminate
+under section (i) of this paragraph due to such counterclaim.
+
+A "Necessary Claim" is a claim of a patent owned by Facebook that is
+necessarily infringed by the Software standing alone.
+
+A "Patent Assertion" is any lawsuit or other action alleging direct, indirect,
+or contributory infringement or inducement to infringe any patent, including a
+cross-claim or counterclaim.
diff --git a/addons/create-react-class/README.md b/addons/create-react-class/README.md
new file mode 100644
index 000000000000..42114629fb54
--- /dev/null
+++ b/addons/create-react-class/README.md
@@ -0,0 +1,5 @@
+# create-react-class
+
+A drop-in replacement for `React.createClass`.
+
+Refer to the [React documentation](https://facebook.github.io/react/docs/react-without-es6.html) for more information.
diff --git a/addons/create-react-class/factory.js b/addons/create-react-class/factory.js
new file mode 100644
index 000000000000..39477cc3243a
--- /dev/null
+++ b/addons/create-react-class/factory.js
@@ -0,0 +1,872 @@
+/**
+ * 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.
+ *
+ */
+
+'use strict';
+
+var _assign = require('object-assign');
+
+var emptyObject = require('fbjs/lib/emptyObject');
+var _invariant = require('fbjs/lib/invariant');
+
+if (process.env.NODE_ENV !== 'production') {
+  var warning = require('fbjs/lib/warning');
+}
+
+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 (process.env.NODE_ENV !== 'production') {
+  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 (process.env.NODE_ENV !== 'production') {
+        validateTypeDef(Constructor, childContextTypes, 'childContext');
+      }
+      Constructor.childContextTypes = _assign(
+        {},
+        Constructor.childContextTypes,
+        childContextTypes
+      );
+    },
+    contextTypes: function(Constructor, contextTypes) {
+      if (process.env.NODE_ENV !== 'production') {
+        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 (process.env.NODE_ENV !== 'production') {
+        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 (process.env.NODE_ENV !== 'production') {
+          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 (process.env.NODE_ENV !== 'production') {
+        var typeofSpec = typeof spec;
+        var isMixinValid = typeofSpec === 'object' && spec !== null;
+
+        if (process.env.NODE_ENV !== 'production') {
+          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 (process.env.NODE_ENV !== 'production') {
+              // 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 (process.env.NODE_ENV !== 'production') {
+      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 (process.env.NODE_ENV !== 'production') {
+            warning(
+              false,
+              'bind(): React component methods may only be bound to the ' +
+                'component instance. See %s',
+              componentName
+            );
+          }
+        } else if (!args.length) {
+          if (process.env.NODE_ENV !== 'production') {
+            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 (process.env.NODE_ENV !== 'production') {
+        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 (process.env.NODE_ENV !== 'production') {
+        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 (process.env.NODE_ENV !== 'production') {
+        // 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 (process.env.NODE_ENV !== 'production') {
+      // 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 (process.env.NODE_ENV !== 'production') {
+      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;
diff --git a/addons/create-react-class/index.js b/addons/create-react-class/index.js
new file mode 100644
index 000000000000..6e771c599238
--- /dev/null
+++ b/addons/create-react-class/index.js
@@ -0,0 +1,30 @@
+/**
+ * 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.
+ *
+ */
+
+'use strict';
+
+var React = require('react');
+var factory = require('./factory');
+
+if (typeof React === 'undefined') {
+  throw Error(
+    'create-react-class could not find the React object. If you are using script tags, ' +
+      'make sure that React is being loaded before create-react-class.'
+  );
+}
+
+// Hack to grab NoopUpdateQueue from isomorphic React
+var ReactNoopUpdateQueue = new React.Component().updater;
+
+module.exports = factory(
+  React.Component,
+  React.isValidElement,
+  ReactNoopUpdateQueue
+);
diff --git a/addons/create-react-class/package.json b/addons/create-react-class/package.json
new file mode 100644
index 000000000000..fefca448abe3
--- /dev/null
+++ b/addons/create-react-class/package.json
@@ -0,0 +1,47 @@
+{
+  "name": "create-react-class",
+  "version": "15.6.0",
+  "description": "Legacy API for creating React components.",
+  "main": "index.js",
+  "license": "BSD-3-Clause",
+  "files": [
+    "LICENSE",
+    "PATENTS",
+    "factory.js",
+    "index.js",
+    "create-react-class.js",
+    "create-react-class.min.js"
+  ],
+  "repository": "facebook/react",
+  "keywords": [
+    "react"
+  ],
+  "bugs": {
+    "url": "https://github.com/facebook/react/issues"
+  },
+  "homepage": "https://facebook.github.io/react/",
+  "dependencies": {
+    "fbjs": "^0.8.9",
+    "loose-envify": "^1.3.1",
+    "object-assign": "^4.1.1"
+  },
+  "scripts": {
+    "test": "TEST_ENTRY=./index.js jest",
+    "build:dev": "NODE_ENV=development webpack && TEST_ENTRY=./create-react-class.js jest",
+    "build:prod": "NODE_ENV=production webpack && NODE_ENV=production TEST_ENTRY=./create-react-class.min.js jest",
+    "build": "npm run build:dev && npm run build:prod",
+    "prepublish": "npm test && npm run build"
+  },
+  "devDependencies": {
+    "jest": "^19.0.2",
+    "prop-types": "^15.5.10",
+    "react": "^15.5.4",
+    "react-dom": "^15.5.4",
+    "webpack": "^2.6.1"
+  },
+  "browserify": {
+    "transform": [
+      "loose-envify"
+    ]
+  }
+}
diff --git a/addons/create-react-class/test.js b/addons/create-react-class/test.js
new file mode 100644
index 000000000000..fabcdcb6f545
--- /dev/null
+++ b/addons/create-react-class/test.js
@@ -0,0 +1,527 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var PropTypes;
+var React;
+var ReactDOM;
+var createReactClass;
+
+// Catch stray warnings
+var env = jasmine.getEnv();
+var callCount = 0;
+var oldError = console.error;
+var newError = function() {
+  callCount++;
+  oldError.apply(this, arguments);
+};
+console.error = newError;
+env.beforeEach(() => {
+  callCount = 0;
+  jasmine.addMatchers({
+    toBeReset() {
+      return {
+        compare(actual) {
+          if (actual !== newError && !jasmine.isSpy(actual)) {
+            return {
+              pass: false,
+              message: 'Test did not tear down console.error mock properly.'
+            };
+          }
+          return {pass: true};
+        }
+      };
+    },
+    toNotHaveBeenCalled() {
+      return {
+        compare(actual) {
+          return {
+            pass: callCount === 0,
+            message:
+              'Expected test not to warn. If the warning is expected, mock ' +
+                "it out using spyOn(console, 'error'); and test that the " +
+                'warning occurs.'
+          };
+        }
+      };
+    }
+  });
+});
+env.afterEach(() => {
+  expect(console.error).toBeReset();
+  expect(console.error).toNotHaveBeenCalled();
+});
+
+// Suppress warning expectations for prod builds
+function suppressDevMatcher(obj, name) {
+  const original = obj[name];
+  obj[name] = function devMatcher() {
+    try {
+      original.apply(this, arguments);
+    } catch (e) {
+      // skip
+    }
+  };
+}
+function expectDev(actual) {
+  const expectation = expect(actual);
+  if (process.env.NODE_ENV === 'production') {
+    Object.keys(expectation).forEach(name => {
+      suppressDevMatcher(expectation, name);
+      suppressDevMatcher(expectation.not, name);
+    });
+  }
+  return expectation;
+}
+
+function renderIntoDocument(element) {
+  var node = document.createElement('div');
+  return ReactDOM.render(element, node);
+}
+
+describe('ReactClass-spec', () => {
+  beforeEach(() => {
+    PropTypes = require('prop-types');
+    React = require('react');
+    ReactDOM = require('react-dom');
+    createReactClass = require(process.env.TEST_ENTRY);
+  });
+
+  it('should throw when `render` is not specified', () => {
+    expect(function() {
+      createReactClass({});
+    }).toThrowError(
+      'createClass(...): Class specification must implement a `render` method.'
+    );
+  });
+
+  // TODO: Update babel-plugin-transform-react-display-name
+  xit('should copy `displayName` onto the Constructor', () => {
+    var TestComponent = createReactClass({
+      render: function() {
+        return <div />;
+      }
+    });
+
+    expect(TestComponent.displayName).toBe('TestComponent');
+  });
+
+  it('should copy prop types onto the Constructor', () => {
+    var propValidator = jest.fn();
+    var TestComponent = createReactClass({
+      propTypes: {
+        value: propValidator
+      },
+      render: function() {
+        return <div />;
+      }
+    });
+
+    expect(TestComponent.propTypes).toBeDefined();
+    expect(TestComponent.propTypes.value).toBe(propValidator);
+  });
+
+  it('should warn on invalid prop types', () => {
+    spyOn(console, 'error');
+    createReactClass({
+      displayName: 'Component',
+      propTypes: {
+        prop: null
+      },
+      render: function() {
+        return <span>{this.props.prop}</span>;
+      }
+    });
+    expectDev(console.error.calls.count()).toBe(1);
+    expectDev(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: Component: prop type `prop` is invalid; ' +
+        'it must be a function, usually from React.PropTypes.'
+    );
+  });
+
+  it('should warn on invalid context types', () => {
+    spyOn(console, 'error');
+    createReactClass({
+      displayName: 'Component',
+      contextTypes: {
+        prop: null
+      },
+      render: function() {
+        return <span>{this.props.prop}</span>;
+      }
+    });
+    expectDev(console.error.calls.count()).toBe(1);
+    expectDev(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: Component: context type `prop` is invalid; ' +
+        'it must be a function, usually from React.PropTypes.'
+    );
+  });
+
+  it('should throw on invalid child context types', () => {
+    spyOn(console, 'error');
+    createReactClass({
+      displayName: 'Component',
+      childContextTypes: {
+        prop: null
+      },
+      render: function() {
+        return <span>{this.props.prop}</span>;
+      }
+    });
+    expectDev(console.error.calls.count()).toBe(1);
+    expectDev(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: Component: child context type `prop` is invalid; ' +
+        'it must be a function, usually from React.PropTypes.'
+    );
+  });
+
+  it('should warn when mispelling shouldComponentUpdate', () => {
+    spyOn(console, 'error');
+
+    createReactClass({
+      componentShouldUpdate: function() {
+        return false;
+      },
+      render: function() {
+        return <div />;
+      }
+    });
+    expectDev(console.error.calls.count()).toBe(1);
+    expectDev(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: A component 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.'
+    );
+
+    createReactClass({
+      displayName: 'NamedComponent',
+      componentShouldUpdate: function() {
+        return false;
+      },
+      render: function() {
+        return <div />;
+      }
+    });
+    expectDev(console.error.calls.count()).toBe(2);
+    expectDev(console.error.calls.argsFor(1)[0]).toBe(
+      'Warning: NamedComponent 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.'
+    );
+  });
+
+  it('should warn when mispelling componentWillReceiveProps', () => {
+    spyOn(console, 'error');
+    createReactClass({
+      componentWillRecieveProps: function() {
+        return false;
+      },
+      render: function() {
+        return <div />;
+      }
+    });
+    expectDev(console.error.calls.count()).toBe(1);
+    expectDev(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: A component has a method called componentWillRecieveProps(). Did you ' +
+        'mean componentWillReceiveProps()?'
+    );
+  });
+
+  it('should throw if a reserved property is in statics', () => {
+    expect(function() {
+      createReactClass({
+        statics: {
+          getDefaultProps: function() {
+            return {
+              foo: 0
+            };
+          }
+        },
+
+        render: function() {
+          return <span />;
+        }
+      });
+    }).toThrowError(
+      'ReactClass: You are attempting to define a reserved property, ' +
+        '`getDefaultProps`, that shouldn\'t be on the "statics" key. Define ' +
+        'it as an instance property instead; it will still be accessible on ' +
+        'the constructor.'
+    );
+  });
+
+  // TODO: Consider actually moving these to statics or drop this unit test.
+  xit('should warn when using deprecated non-static spec keys', () => {
+    spyOn(console, 'error');
+    createReactClass({
+      mixins: [{}],
+      propTypes: {
+        foo: PropTypes.string
+      },
+      contextTypes: {
+        foo: PropTypes.string
+      },
+      childContextTypes: {
+        foo: PropTypes.string
+      },
+      render: function() {
+        return <div />;
+      }
+    });
+    expectDev(console.error.calls.count()).toBe(4);
+    expectDev(console.error.calls.argsFor(0)[0]).toBe(
+      'createClass(...): `mixins` is now a static property and should ' +
+        'be defined inside "statics".'
+    );
+    expectDev(console.error.calls.argsFor(1)[0]).toBe(
+      'createClass(...): `propTypes` is now a static property and should ' +
+        'be defined inside "statics".'
+    );
+    expectDev(console.error.calls.argsFor(2)[0]).toBe(
+      'createClass(...): `contextTypes` is now a static property and ' +
+        'should be defined inside "statics".'
+    );
+    expectDev(console.error.calls.argsFor(3)[0]).toBe(
+      'createClass(...): `childContextTypes` is now a static property and ' +
+        'should be defined inside "statics".'
+    );
+  });
+
+  it('should support statics', () => {
+    var Component = createReactClass({
+      statics: {
+        abc: 'def',
+        def: 0,
+        ghi: null,
+        jkl: 'mno',
+        pqr: function() {
+          return this;
+        }
+      },
+
+      render: function() {
+        return <span />;
+      }
+    });
+    var instance = <Component />;
+    instance = renderIntoDocument(instance);
+    expect(instance.constructor.abc).toBe('def');
+    expect(Component.abc).toBe('def');
+    expect(instance.constructor.def).toBe(0);
+    expect(Component.def).toBe(0);
+    expect(instance.constructor.ghi).toBe(null);
+    expect(Component.ghi).toBe(null);
+    expect(instance.constructor.jkl).toBe('mno');
+    expect(Component.jkl).toBe('mno');
+    expect(instance.constructor.pqr()).toBe(Component);
+    expect(Component.pqr()).toBe(Component);
+  });
+
+  it('should work with object getInitialState() return values', () => {
+    var Component = createReactClass({
+      getInitialState: function() {
+        return {
+          occupation: 'clown'
+        };
+      },
+      render: function() {
+        return <span />;
+      }
+    });
+    var instance = <Component />;
+    instance = renderIntoDocument(instance);
+    expect(instance.state.occupation).toEqual('clown');
+  });
+
+  it('renders based on context getInitialState', () => {
+    var Foo = createReactClass({
+      contextTypes: {
+        className: PropTypes.string
+      },
+      getInitialState() {
+        return {className: this.context.className};
+      },
+      render() {
+        return <span className={this.state.className} />;
+      }
+    });
+
+    var Outer = createReactClass({
+      childContextTypes: {
+        className: PropTypes.string
+      },
+      getChildContext() {
+        return {className: 'foo'};
+      },
+      render() {
+        return <Foo />;
+      }
+    });
+
+    var container = document.createElement('div');
+    ReactDOM.render(<Outer />, container);
+    expect(container.firstChild.className).toBe('foo');
+  });
+
+  it('should throw with non-object getInitialState() return values', () => {
+    spyOn(console, 'error');
+
+    [['an array'], 'a string', 1234].forEach(function(state) {
+      var Component = createReactClass({
+        getInitialState: function() {
+          return state;
+        },
+        render: function() {
+          return <span />;
+        }
+      });
+      var instance = <Component />;
+      expect(function() {
+        instance = renderIntoDocument(instance);
+      }).toThrowError(
+        'Component.getInitialState(): must return an object or null'
+      );
+    });
+  });
+
+  it('should work with a null getInitialState() return value', () => {
+    var Component = createReactClass({
+      getInitialState: function() {
+        return null;
+      },
+      render: function() {
+        return <span />;
+      }
+    });
+    expect(() => renderIntoDocument(<Component />)).not.toThrow();
+  });
+
+  it('should throw when using legacy factories', () => {
+    spyOn(console, 'error');
+    var Component = createReactClass({
+      render() {
+        return <div />;
+      }
+    });
+
+    expect(() => Component()).toThrow();
+    expectDev(console.error.calls.count()).toBe(1);
+    expectDev(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: Something is calling a React component directly. Use a ' +
+        'factory or JSX instead. See: https://fb.me/react-legacyfactory'
+    );
+  });
+
+  it('replaceState and callback works', () => {
+    var ops = [];
+    var Component = createReactClass({
+      getInitialState() {
+        return {step: 0};
+      },
+      render() {
+        ops.push('Render: ' + this.state.step);
+        return <div />;
+      }
+    });
+
+    var instance = renderIntoDocument(<Component />);
+    instance.replaceState({step: 1}, () => {
+      ops.push('Callback: ' + instance.state.step);
+    });
+    expect(ops).toEqual(['Render: 0', 'Render: 1', 'Callback: 1']);
+  });
+
+  it('isMounted works', () => {
+    spyOn(console, 'error');
+
+    var ops = [];
+    var instance;
+    var Component = createReactClass({
+      displayName: 'MyComponent',
+      mixins: [
+        {
+          componentWillMount() {
+            this.log('mixin.componentWillMount');
+          },
+          componentDidMount() {
+            this.log('mixin.componentDidMount');
+          },
+          componentWillUpdate() {
+            this.log('mixin.componentWillUpdate');
+          },
+          componentDidUpdate() {
+            this.log('mixin.componentDidUpdate');
+          },
+          componentWillUnmount() {
+            this.log('mixin.componentWillUnmount');
+          }
+        }
+      ],
+      log(name) {
+        ops.push(`${name}: ${this.isMounted()}`);
+      },
+      getInitialState() {
+        this.log('getInitialState');
+        return {};
+      },
+      componentWillMount() {
+        this.log('componentWillMount');
+      },
+      componentDidMount() {
+        this.log('componentDidMount');
+      },
+      componentWillUpdate() {
+        this.log('componentWillUpdate');
+      },
+      componentDidUpdate() {
+        this.log('componentDidUpdate');
+      },
+      componentWillUnmount() {
+        this.log('componentWillUnmount');
+      },
+      render() {
+        instance = this;
+        this.log('render');
+        return <div />;
+      }
+    });
+
+    var container = document.createElement('div');
+    ReactDOM.render(<Component />, container);
+    ReactDOM.render(<Component />, container);
+    ReactDOM.unmountComponentAtNode(container);
+    instance.log('after unmount');
+    expect(ops).toEqual([
+      'getInitialState: false',
+      'mixin.componentWillMount: false',
+      'componentWillMount: false',
+      'render: false',
+      'mixin.componentDidMount: true',
+      'componentDidMount: true',
+      'mixin.componentWillUpdate: true',
+      'componentWillUpdate: true',
+      'render: true',
+      'mixin.componentDidUpdate: true',
+      'componentDidUpdate: true',
+      'mixin.componentWillUnmount: true',
+      'componentWillUnmount: true',
+      'after unmount: false'
+    ]);
+
+    expectDev(console.error.calls.count()).toBe(1);
+    expectDev(console.error.calls.argsFor(0)[0]).toEqual(
+      'Warning: MyComponent: isMounted is deprecated. Instead, make sure to ' +
+        'clean up subscriptions and pending requests in componentWillUnmount ' +
+        'to prevent memory leaks.'
+    );
+  });
+});
diff --git a/addons/create-react-class/webpack.config.js b/addons/create-react-class/webpack.config.js
new file mode 100644
index 000000000000..88e3142ea6f2
--- /dev/null
+++ b/addons/create-react-class/webpack.config.js
@@ -0,0 +1,61 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+const webpack = require('webpack');
+
+let __DEV__;
+switch (process.env.NODE_ENV) {
+  case 'development':
+    __DEV__ = true;
+    break;
+  case 'production':
+    __DEV__ = false;
+    break;
+  default:
+    throw new Error('Unknown environment.');
+}
+
+module.exports = {
+  entry: './index',
+  output: {
+    library: 'createReactClass',
+    libraryTarget: 'umd',
+    filename: __DEV__ ? 'create-react-class.js' : 'create-react-class.min.js'
+  },
+  externals: {
+    react: {
+      root: 'React',
+      commonjs2: 'react',
+      commonjs: 'react',
+      amd: 'react'
+    }
+  },
+  plugins: [
+    new webpack.DefinePlugin({
+      'process.env.NODE_ENV': __DEV__ ? '"development"' : '"production"'
+    })
+  ].concat(
+    __DEV__
+      ? []
+      : [
+          new webpack.optimize.UglifyJsPlugin({
+            compress: {
+              warnings: false
+            },
+            output: {
+              comments: false
+            }
+          })
+        ]
+  )
+};
diff --git a/addons/create-react-class/yarn.lock b/addons/create-react-class/yarn.lock
new file mode 100644
index 000000000000..bfa348083598
--- /dev/null
+++ b/addons/create-react-class/yarn.lock
@@ -0,0 +1,2823 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+abab@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.3.tgz#b81de5f7274ec4e756d797cd834f303642724e5d"
+
+abbrev@1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f"
+
+acorn-dynamic-import@^2.0.0:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz#c752bd210bef679501b6c6cb7fc84f8f47158cc4"
+  dependencies:
+    acorn "^4.0.3"
+
+acorn-globals@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-3.1.0.tgz#fd8270f71fbb4996b004fa880ee5d46573a731bf"
+  dependencies:
+    acorn "^4.0.4"
+
+acorn@^4.0.3, acorn@^4.0.4:
+  version "4.0.11"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.11.tgz#edcda3bd937e7556410d42ed5860f67399c794c0"
+
+acorn@^5.0.0:
+  version "5.0.3"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.0.3.tgz#c460df08491463f028ccb82eab3730bf01087b3d"
+
+ajv-keywords@^1.1.1:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c"
+
+ajv@^4.7.0, ajv@^4.9.1:
+  version "4.11.5"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.5.tgz#b6ee74657b993a01dce44b7944d56f485828d5bd"
+  dependencies:
+    co "^4.6.0"
+    json-stable-stringify "^1.0.1"
+
+align-text@^0.1.1, align-text@^0.1.3:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
+  dependencies:
+    kind-of "^3.0.2"
+    longest "^1.0.1"
+    repeat-string "^1.5.2"
+
+amdefine@>=0.0.4:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
+
+ansi-escapes@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
+
+ansi-regex@^2.0.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
+
+ansi-styles@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
+
+ansi-styles@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.0.0.tgz#5404e93a544c4fec7f048262977bebfe3155e0c1"
+  dependencies:
+    color-convert "^1.0.0"
+
+anymatch@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507"
+  dependencies:
+    arrify "^1.0.0"
+    micromatch "^2.1.5"
+
+append-transform@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-0.4.0.tgz#d76ebf8ca94d276e247a36bad44a4b74ab611991"
+  dependencies:
+    default-require-extensions "^1.0.0"
+
+aproba@^1.0.3:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.2.tgz#45c6629094de4e96f693ef7eab74ae079c240fc1"
+
+are-we-there-yet@~1.1.2:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d"
+  dependencies:
+    delegates "^1.0.0"
+    readable-stream "^2.0.6"
+
+argparse@^1.0.7:
+  version "1.0.9"
+  resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86"
+  dependencies:
+    sprintf-js "~1.0.2"
+
+arr-diff@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf"
+  dependencies:
+    arr-flatten "^1.0.1"
+
+arr-flatten@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b"
+
+array-equal@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93"
+
+array-unique@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
+
+arrify@^1.0.0, arrify@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
+
+asap@~2.0.3:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f"
+
+asn1.js@^4.0.0:
+  version "4.9.1"
+  resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.1.tgz#48ba240b45a9280e94748990ba597d216617fd40"
+  dependencies:
+    bn.js "^4.0.0"
+    inherits "^2.0.1"
+    minimalistic-assert "^1.0.0"
+
+asn1@~0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86"
+
+assert-plus@1.0.0, assert-plus@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
+
+assert-plus@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234"
+
+assert@^1.1.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91"
+  dependencies:
+    util "0.10.3"
+
+async-each@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
+
+async@^1.4.0:
+  version "1.5.2"
+  resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
+
+async@^2.1.2, async@^2.1.4:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/async/-/async-2.3.0.tgz#1013d1051047dd320fe24e494d5c66ecaf6147d9"
+  dependencies:
+    lodash "^4.14.0"
+
+asynckit@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+
+aws-sign2@~0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f"
+
+aws4@^1.2.1:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e"
+
+babel-code-frame@^6.22.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4"
+  dependencies:
+    chalk "^1.1.0"
+    esutils "^2.0.2"
+    js-tokens "^3.0.0"
+
+babel-core@^6.0.0, babel-core@^6.24.0:
+  version "6.24.0"
+  resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.24.0.tgz#8f36a0a77f5c155aed6f920b844d23ba56742a02"
+  dependencies:
+    babel-code-frame "^6.22.0"
+    babel-generator "^6.24.0"
+    babel-helpers "^6.23.0"
+    babel-messages "^6.23.0"
+    babel-register "^6.24.0"
+    babel-runtime "^6.22.0"
+    babel-template "^6.23.0"
+    babel-traverse "^6.23.1"
+    babel-types "^6.23.0"
+    babylon "^6.11.0"
+    convert-source-map "^1.1.0"
+    debug "^2.1.1"
+    json5 "^0.5.0"
+    lodash "^4.2.0"
+    minimatch "^3.0.2"
+    path-is-absolute "^1.0.0"
+    private "^0.1.6"
+    slash "^1.0.0"
+    source-map "^0.5.0"
+
+babel-generator@^6.18.0, babel-generator@^6.24.0:
+  version "6.24.0"
+  resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.24.0.tgz#eba270a8cc4ce6e09a61be43465d7c62c1f87c56"
+  dependencies:
+    babel-messages "^6.23.0"
+    babel-runtime "^6.22.0"
+    babel-types "^6.23.0"
+    detect-indent "^4.0.0"
+    jsesc "^1.3.0"
+    lodash "^4.2.0"
+    source-map "^0.5.0"
+    trim-right "^1.0.1"
+
+babel-helpers@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.23.0.tgz#4f8f2e092d0b6a8808a4bde79c27f1e2ecf0d992"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-template "^6.23.0"
+
+babel-jest@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-19.0.0.tgz#59323ced99a3a84d359da219ca881074ffc6ce3f"
+  dependencies:
+    babel-core "^6.0.0"
+    babel-plugin-istanbul "^4.0.0"
+    babel-preset-jest "^19.0.0"
+
+babel-messages@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e"
+  dependencies:
+    babel-runtime "^6.22.0"
+
+babel-plugin-istanbul@^4.0.0:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.1.tgz#c12de0fc6fe42adfb16be56f1ad11e4a9782eca9"
+  dependencies:
+    find-up "^2.1.0"
+    istanbul-lib-instrument "^1.6.2"
+    test-exclude "^4.0.3"
+
+babel-plugin-jest-hoist@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-19.0.0.tgz#4ae2a04ea612a6e73651f3fde52c178991304bea"
+
+babel-preset-jest@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-19.0.0.tgz#22d67201d02324a195811288eb38294bb3cac396"
+  dependencies:
+    babel-plugin-jest-hoist "^19.0.0"
+
+babel-register@^6.24.0:
+  version "6.24.0"
+  resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.24.0.tgz#5e89f8463ba9970356d02eb07dabe3308b080cfd"
+  dependencies:
+    babel-core "^6.24.0"
+    babel-runtime "^6.22.0"
+    core-js "^2.4.0"
+    home-or-tmp "^2.0.0"
+    lodash "^4.2.0"
+    mkdirp "^0.5.1"
+    source-map-support "^0.4.2"
+
+babel-runtime@^6.22.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b"
+  dependencies:
+    core-js "^2.4.0"
+    regenerator-runtime "^0.10.0"
+
+babel-template@^6.16.0, babel-template@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.23.0.tgz#04d4f270adbb3aa704a8143ae26faa529238e638"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-traverse "^6.23.0"
+    babel-types "^6.23.0"
+    babylon "^6.11.0"
+    lodash "^4.2.0"
+
+babel-traverse@^6.18.0, babel-traverse@^6.23.0, babel-traverse@^6.23.1:
+  version "6.23.1"
+  resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.23.1.tgz#d3cb59010ecd06a97d81310065f966b699e14f48"
+  dependencies:
+    babel-code-frame "^6.22.0"
+    babel-messages "^6.23.0"
+    babel-runtime "^6.22.0"
+    babel-types "^6.23.0"
+    babylon "^6.15.0"
+    debug "^2.2.0"
+    globals "^9.0.0"
+    invariant "^2.2.0"
+    lodash "^4.2.0"
+
+babel-types@^6.18.0, babel-types@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.23.0.tgz#bb17179d7538bad38cd0c9e115d340f77e7e9acf"
+  dependencies:
+    babel-runtime "^6.22.0"
+    esutils "^2.0.2"
+    lodash "^4.2.0"
+    to-fast-properties "^1.0.1"
+
+babylon@^6.11.0, babylon@^6.13.0, babylon@^6.15.0:
+  version "6.16.1"
+  resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.16.1.tgz#30c5a22f481978a9e7f8cdfdf496b11d94b404d3"
+
+balanced-match@^0.4.1:
+  version "0.4.2"
+  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
+
+base64-js@^1.0.2:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1"
+
+bcrypt-pbkdf@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d"
+  dependencies:
+    tweetnacl "^0.14.3"
+
+big.js@^3.1.3:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.1.3.tgz#4cada2193652eb3ca9ec8e55c9015669c9806978"
+
+binary-extensions@^1.0.0:
+  version "1.8.0"
+  resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.8.0.tgz#48ec8d16df4377eae5fa5884682480af4d95c774"
+
+block-stream@*:
+  version "0.0.9"
+  resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a"
+  dependencies:
+    inherits "~2.0.0"
+
+bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0:
+  version "4.11.6"
+  resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215"
+
+boom@2.x.x:
+  version "2.10.1"
+  resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f"
+  dependencies:
+    hoek "2.x.x"
+
+brace-expansion@^1.0.0:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9"
+  dependencies:
+    balanced-match "^0.4.1"
+    concat-map "0.0.1"
+
+braces@^1.8.2:
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7"
+  dependencies:
+    expand-range "^1.8.1"
+    preserve "^0.2.0"
+    repeat-element "^1.1.2"
+
+brorand@^1.0.1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
+
+browser-resolve@^1.11.2:
+  version "1.11.2"
+  resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.2.tgz#8ff09b0a2c421718a1051c260b32e48f442938ce"
+  dependencies:
+    resolve "1.1.7"
+
+browserify-aes@^1.0.0, browserify-aes@^1.0.4:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.0.6.tgz#5e7725dbdef1fd5930d4ebab48567ce451c48a0a"
+  dependencies:
+    buffer-xor "^1.0.2"
+    cipher-base "^1.0.0"
+    create-hash "^1.1.0"
+    evp_bytestokey "^1.0.0"
+    inherits "^2.0.1"
+
+browserify-cipher@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.0.tgz#9988244874bf5ed4e28da95666dcd66ac8fc363a"
+  dependencies:
+    browserify-aes "^1.0.4"
+    browserify-des "^1.0.0"
+    evp_bytestokey "^1.0.0"
+
+browserify-des@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.0.tgz#daa277717470922ed2fe18594118a175439721dd"
+  dependencies:
+    cipher-base "^1.0.1"
+    des.js "^1.0.0"
+    inherits "^2.0.1"
+
+browserify-rsa@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524"
+  dependencies:
+    bn.js "^4.1.0"
+    randombytes "^2.0.1"
+
+browserify-sign@^4.0.0:
+  version "4.0.4"
+  resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298"
+  dependencies:
+    bn.js "^4.1.1"
+    browserify-rsa "^4.0.0"
+    create-hash "^1.1.0"
+    create-hmac "^1.1.2"
+    elliptic "^6.0.0"
+    inherits "^2.0.1"
+    parse-asn1 "^5.0.0"
+
+browserify-zlib@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d"
+  dependencies:
+    pako "~0.2.0"
+
+bser@1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/bser/-/bser-1.0.2.tgz#381116970b2a6deea5646dd15dd7278444b56169"
+  dependencies:
+    node-int64 "^0.4.0"
+
+bser@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719"
+  dependencies:
+    node-int64 "^0.4.0"
+
+buffer-xor@^1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9"
+
+buffer@^4.3.0:
+  version "4.9.1"
+  resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298"
+  dependencies:
+    base64-js "^1.0.2"
+    ieee754 "^1.1.4"
+    isarray "^1.0.0"
+
+builtin-modules@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
+
+builtin-status-codes@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
+
+callsites@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50"
+
+camelcase@^1.0.2:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39"
+
+camelcase@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
+
+caseless@~0.12.0:
+  version "0.12.0"
+  resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
+
+center-align@^0.1.1:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad"
+  dependencies:
+    align-text "^0.1.3"
+    lazy-cache "^1.0.3"
+
+chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
+  dependencies:
+    ansi-styles "^2.2.1"
+    escape-string-regexp "^1.0.2"
+    has-ansi "^2.0.0"
+    strip-ansi "^3.0.0"
+    supports-color "^2.0.0"
+
+chokidar@^1.4.3:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
+  dependencies:
+    anymatch "^1.3.0"
+    async-each "^1.0.0"
+    glob-parent "^2.0.0"
+    inherits "^2.0.1"
+    is-binary-path "^1.0.0"
+    is-glob "^2.0.0"
+    path-is-absolute "^1.0.0"
+    readdirp "^2.0.0"
+  optionalDependencies:
+    fsevents "^1.0.0"
+
+ci-info@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.0.0.tgz#dc5285f2b4e251821683681c381c3388f46ec534"
+
+cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.3.tgz#eeabf194419ce900da3018c207d212f2a6df0a07"
+  dependencies:
+    inherits "^2.0.1"
+
+cliui@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1"
+  dependencies:
+    center-align "^0.1.1"
+    right-align "^0.1.1"
+    wordwrap "0.0.2"
+
+cliui@^3.2.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
+  dependencies:
+    string-width "^1.0.1"
+    strip-ansi "^3.0.1"
+    wrap-ansi "^2.0.0"
+
+co@^4.6.0:
+  version "4.6.0"
+  resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
+
+code-point-at@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
+
+color-convert@^1.0.0:
+  version "1.9.0"
+  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a"
+  dependencies:
+    color-name "^1.1.1"
+
+color-name@^1.1.1:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.2.tgz#5c8ab72b64bd2215d617ae9559ebb148475cf98d"
+
+combined-stream@^1.0.5, combined-stream@~1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009"
+  dependencies:
+    delayed-stream "~1.0.0"
+
+concat-map@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+
+console-browserify@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10"
+  dependencies:
+    date-now "^0.1.4"
+
+console-control-strings@^1.0.0, console-control-strings@~1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
+
+constants-browserify@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
+
+content-type-parser@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/content-type-parser/-/content-type-parser-1.0.1.tgz#c3e56988c53c65127fb46d4032a3a900246fdc94"
+
+convert-source-map@^1.1.0:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5"
+
+core-js@^1.0.0:
+  version "1.2.7"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
+
+core-js@^2.4.0:
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e"
+
+core-util-is@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
+
+create-ecdh@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.0.tgz#888c723596cdf7612f6498233eebd7a35301737d"
+  dependencies:
+    bn.js "^4.1.0"
+    elliptic "^6.0.0"
+
+create-hash@^1.1.0, create-hash@^1.1.1, create-hash@^1.1.2:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.3.tgz#606042ac8b9262750f483caddab0f5819172d8fd"
+  dependencies:
+    cipher-base "^1.0.1"
+    inherits "^2.0.1"
+    ripemd160 "^2.0.0"
+    sha.js "^2.4.0"
+
+create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.6.tgz#acb9e221a4e17bdb076e90657c42b93e3726cf06"
+  dependencies:
+    cipher-base "^1.0.3"
+    create-hash "^1.1.0"
+    inherits "^2.0.1"
+    ripemd160 "^2.0.0"
+    safe-buffer "^5.0.1"
+    sha.js "^2.4.8"
+
+cryptiles@2.x.x:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8"
+  dependencies:
+    boom "2.x.x"
+
+crypto-browserify@^3.11.0:
+  version "3.11.0"
+  resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.11.0.tgz#3652a0906ab9b2a7e0c3ce66a408e957a2485522"
+  dependencies:
+    browserify-cipher "^1.0.0"
+    browserify-sign "^4.0.0"
+    create-ecdh "^4.0.0"
+    create-hash "^1.1.0"
+    create-hmac "^1.1.0"
+    diffie-hellman "^5.0.0"
+    inherits "^2.0.1"
+    pbkdf2 "^3.0.3"
+    public-encrypt "^4.0.0"
+    randombytes "^2.0.0"
+
+cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0":
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.2.tgz#b8036170c79f07a90ff2f16e22284027a243848b"
+
+"cssstyle@>= 0.2.37 < 0.3.0":
+  version "0.2.37"
+  resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-0.2.37.tgz#541097234cb2513c83ceed3acddc27ff27987d54"
+  dependencies:
+    cssom "0.3.x"
+
+dashdash@^1.12.0:
+  version "1.14.1"
+  resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
+  dependencies:
+    assert-plus "^1.0.0"
+
+date-now@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
+
+debug@^2.1.1, debug@^2.2.0:
+  version "2.6.3"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.3.tgz#0f7eb8c30965ec08c72accfa0130c8b79984141d"
+  dependencies:
+    ms "0.7.2"
+
+decamelize@^1.0.0, decamelize@^1.1.1:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
+
+deep-extend@~0.4.0:
+  version "0.4.2"
+  resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f"
+
+deep-is@~0.1.3:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
+
+default-require-extensions@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8"
+  dependencies:
+    strip-bom "^2.0.0"
+
+delayed-stream@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+
+delegates@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
+
+des.js@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc"
+  dependencies:
+    inherits "^2.0.1"
+    minimalistic-assert "^1.0.0"
+
+detect-indent@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208"
+  dependencies:
+    repeating "^2.0.0"
+
+diff@^3.0.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9"
+
+diffie-hellman@^5.0.0:
+  version "5.0.2"
+  resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.2.tgz#b5835739270cfe26acf632099fded2a07f209e5e"
+  dependencies:
+    bn.js "^4.1.0"
+    miller-rabin "^4.0.0"
+    randombytes "^2.0.0"
+
+domain-browser@^1.1.1:
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc"
+
+ecc-jsbn@~0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505"
+  dependencies:
+    jsbn "~0.1.0"
+
+elliptic@^6.0.0:
+  version "6.4.0"
+  resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df"
+  dependencies:
+    bn.js "^4.4.0"
+    brorand "^1.0.1"
+    hash.js "^1.0.0"
+    hmac-drbg "^1.0.0"
+    inherits "^2.0.1"
+    minimalistic-assert "^1.0.0"
+    minimalistic-crypto-utils "^1.0.0"
+
+emojis-list@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
+
+encoding@^0.1.11:
+  version "0.1.12"
+  resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb"
+  dependencies:
+    iconv-lite "~0.4.13"
+
+enhanced-resolve@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.1.0.tgz#9f4b626f577245edcf4b2ad83d86e17f4f421dec"
+  dependencies:
+    graceful-fs "^4.1.2"
+    memory-fs "^0.4.0"
+    object-assign "^4.0.1"
+    tapable "^0.2.5"
+
+"errno@>=0.1.1 <0.2.0-0", errno@^0.1.3:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d"
+  dependencies:
+    prr "~0.0.0"
+
+error-ex@^1.2.0:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc"
+  dependencies:
+    is-arrayish "^0.2.1"
+
+escape-string-regexp@^1.0.2:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+
+escodegen@^1.6.1:
+  version "1.8.1"
+  resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018"
+  dependencies:
+    esprima "^2.7.1"
+    estraverse "^1.9.1"
+    esutils "^2.0.2"
+    optionator "^0.8.1"
+  optionalDependencies:
+    source-map "~0.2.0"
+
+esprima@^2.7.1:
+  version "2.7.3"
+  resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
+
+esprima@^3.1.1:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633"
+
+estraverse@^1.9.1:
+  version "1.9.3"
+  resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44"
+
+esutils@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
+
+events@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924"
+
+evp_bytestokey@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.0.tgz#497b66ad9fef65cd7c08a6180824ba1476b66e53"
+  dependencies:
+    create-hash "^1.1.1"
+
+exec-sh@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.0.tgz#14f75de3f20d286ef933099b2ce50a90359cef10"
+  dependencies:
+    merge "^1.1.3"
+
+expand-brackets@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
+  dependencies:
+    is-posix-bracket "^0.1.0"
+
+expand-range@^1.8.1:
+  version "1.8.2"
+  resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337"
+  dependencies:
+    fill-range "^2.1.0"
+
+extend@~3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4"
+
+extglob@^0.3.1:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1"
+  dependencies:
+    is-extglob "^1.0.0"
+
+extsprintf@1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550"
+
+fast-levenshtein@~2.0.4:
+  version "2.0.6"
+  resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
+
+fb-watchman@^1.8.0:
+  version "1.9.2"
+  resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-1.9.2.tgz#a24cf47827f82d38fb59a69ad70b76e3b6ae7383"
+  dependencies:
+    bser "1.0.2"
+
+fb-watchman@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58"
+  dependencies:
+    bser "^2.0.0"
+
+fbjs@^0.8.9:
+  version "0.8.12"
+  resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.12.tgz#10b5d92f76d45575fd63a217d4ea02bea2f8ed04"
+  dependencies:
+    core-js "^1.0.0"
+    isomorphic-fetch "^2.1.1"
+    loose-envify "^1.0.0"
+    object-assign "^4.1.0"
+    promise "^7.1.1"
+    setimmediate "^1.0.5"
+    ua-parser-js "^0.7.9"
+
+filename-regex@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775"
+
+fileset@^2.0.2:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/fileset/-/fileset-2.0.3.tgz#8e7548a96d3cc2327ee5e674168723a333bba2a0"
+  dependencies:
+    glob "^7.0.3"
+    minimatch "^3.0.3"
+
+fill-range@^2.1.0:
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723"
+  dependencies:
+    is-number "^2.1.0"
+    isobject "^2.0.0"
+    randomatic "^1.1.3"
+    repeat-element "^1.1.2"
+    repeat-string "^1.5.2"
+
+find-up@^1.0.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
+  dependencies:
+    path-exists "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+find-up@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
+  dependencies:
+    locate-path "^2.0.0"
+
+for-in@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
+
+for-own@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce"
+  dependencies:
+    for-in "^1.0.1"
+
+forever-agent@~0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
+
+form-data@~2.1.1:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4"
+  dependencies:
+    asynckit "^0.4.0"
+    combined-stream "^1.0.5"
+    mime-types "^2.1.12"
+
+fs.realpath@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+
+fsevents@^1.0.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.2.tgz#3282b713fb3ad80ede0e9fcf4611b5aa6fc033f4"
+  dependencies:
+    nan "^2.3.0"
+    node-pre-gyp "^0.6.36"
+
+fstream-ignore@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105"
+  dependencies:
+    fstream "^1.0.0"
+    inherits "2"
+    minimatch "^3.0.0"
+
+fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2:
+  version "1.0.11"
+  resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171"
+  dependencies:
+    graceful-fs "^4.1.2"
+    inherits "~2.0.0"
+    mkdirp ">=0.5 0"
+    rimraf "2"
+
+gauge@~2.7.3:
+  version "2.7.4"
+  resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
+  dependencies:
+    aproba "^1.0.3"
+    console-control-strings "^1.0.0"
+    has-unicode "^2.0.0"
+    object-assign "^4.1.0"
+    signal-exit "^3.0.0"
+    string-width "^1.0.1"
+    strip-ansi "^3.0.1"
+    wide-align "^1.1.0"
+
+get-caller-file@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5"
+
+getpass@^0.1.1:
+  version "0.1.6"
+  resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6"
+  dependencies:
+    assert-plus "^1.0.0"
+
+glob-base@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
+  dependencies:
+    glob-parent "^2.0.0"
+    is-glob "^2.0.0"
+
+glob-parent@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28"
+  dependencies:
+    is-glob "^2.0.0"
+
+glob@^7.0.3, glob@^7.0.5:
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
+  dependencies:
+    fs.realpath "^1.0.0"
+    inflight "^1.0.4"
+    inherits "2"
+    minimatch "^3.0.2"
+    once "^1.3.0"
+    path-is-absolute "^1.0.0"
+
+globals@^9.0.0:
+  version "9.17.0"
+  resolved "https://registry.yarnpkg.com/globals/-/globals-9.17.0.tgz#0c0ca696d9b9bb694d2e5470bd37777caad50286"
+
+graceful-fs@^4.1.2, graceful-fs@^4.1.6:
+  version "4.1.11"
+  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
+
+growly@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
+
+handlebars@^4.0.3:
+  version "4.0.6"
+  resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7"
+  dependencies:
+    async "^1.4.0"
+    optimist "^0.6.1"
+    source-map "^0.4.4"
+  optionalDependencies:
+    uglify-js "^2.6"
+
+har-schema@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e"
+
+har-validator@~4.2.1:
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a"
+  dependencies:
+    ajv "^4.9.1"
+    har-schema "^1.0.5"
+
+has-ansi@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
+  dependencies:
+    ansi-regex "^2.0.0"
+
+has-flag@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
+
+has-unicode@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
+
+hash-base@^2.0.0:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1"
+  dependencies:
+    inherits "^2.0.1"
+
+hash.js@^1.0.0, hash.js@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.0.3.tgz#1332ff00156c0a0ffdd8236013d07b77a0451573"
+  dependencies:
+    inherits "^2.0.1"
+
+hawk@~3.1.3:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4"
+  dependencies:
+    boom "2.x.x"
+    cryptiles "2.x.x"
+    hoek "2.x.x"
+    sntp "1.x.x"
+
+hmac-drbg@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
+  dependencies:
+    hash.js "^1.0.3"
+    minimalistic-assert "^1.0.0"
+    minimalistic-crypto-utils "^1.0.1"
+
+hoek@2.x.x:
+  version "2.16.3"
+  resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed"
+
+home-or-tmp@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8"
+  dependencies:
+    os-homedir "^1.0.0"
+    os-tmpdir "^1.0.1"
+
+hosted-git-info@^2.1.4:
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.4.1.tgz#4b0445e41c004a8bd1337773a4ff790ca40318c8"
+
+html-encoding-sniffer@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.1.tgz#79bf7a785ea495fe66165e734153f363ff5437da"
+  dependencies:
+    whatwg-encoding "^1.0.1"
+
+http-signature@~1.1.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf"
+  dependencies:
+    assert-plus "^0.2.0"
+    jsprim "^1.2.2"
+    sshpk "^1.7.0"
+
+https-browserify@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82"
+
+iconv-lite@0.4.13:
+  version "0.4.13"
+  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2"
+
+iconv-lite@~0.4.13:
+  version "0.4.15"
+  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb"
+
+ieee754@^1.1.4:
+  version "1.1.8"
+  resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4"
+
+indexof@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d"
+
+inflight@^1.0.4:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+  dependencies:
+    once "^1.3.0"
+    wrappy "1"
+
+inherits@2, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
+
+inherits@2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
+
+ini@~1.3.0:
+  version "1.3.4"
+  resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e"
+
+interpret@^1.0.0:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.3.tgz#cbc35c62eeee73f19ab7b10a801511401afc0f90"
+
+invariant@^2.2.0:
+  version "2.2.2"
+  resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360"
+  dependencies:
+    loose-envify "^1.0.0"
+
+invert-kv@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
+
+is-arrayish@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
+
+is-binary-path@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
+  dependencies:
+    binary-extensions "^1.0.0"
+
+is-buffer@^1.0.2:
+  version "1.1.5"
+  resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc"
+
+is-builtin-module@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe"
+  dependencies:
+    builtin-modules "^1.0.0"
+
+is-ci@^1.0.9:
+  version "1.0.10"
+  resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.0.10.tgz#f739336b2632365061a9d48270cd56ae3369318e"
+  dependencies:
+    ci-info "^1.0.0"
+
+is-dotfile@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d"
+
+is-equal-shallow@^0.1.3:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534"
+  dependencies:
+    is-primitive "^2.0.0"
+
+is-extendable@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
+
+is-extglob@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
+
+is-finite@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa"
+  dependencies:
+    number-is-nan "^1.0.0"
+
+is-fullwidth-code-point@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
+  dependencies:
+    number-is-nan "^1.0.0"
+
+is-glob@^2.0.0, is-glob@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
+  dependencies:
+    is-extglob "^1.0.0"
+
+is-number@^2.0.2, is-number@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
+  dependencies:
+    kind-of "^3.0.2"
+
+is-posix-bracket@^0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
+
+is-primitive@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
+
+is-stream@^1.0.1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
+
+is-typedarray@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
+
+is-utf8@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
+
+isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
+
+isexe@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+
+isobject@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
+  dependencies:
+    isarray "1.0.0"
+
+isomorphic-fetch@^2.1.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
+  dependencies:
+    node-fetch "^1.0.1"
+    whatwg-fetch ">=0.10.0"
+
+isstream@~0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
+
+istanbul-api@^1.1.0-alpha.1:
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-1.1.7.tgz#f6f37f09f8002b130f891c646b70ee4a8e7345ae"
+  dependencies:
+    async "^2.1.4"
+    fileset "^2.0.2"
+    istanbul-lib-coverage "^1.0.2"
+    istanbul-lib-hook "^1.0.5"
+    istanbul-lib-instrument "^1.7.0"
+    istanbul-lib-report "^1.0.0"
+    istanbul-lib-source-maps "^1.1.1"
+    istanbul-reports "^1.0.2"
+    js-yaml "^3.7.0"
+    mkdirp "^0.5.1"
+    once "^1.4.0"
+
+istanbul-lib-coverage@^1.0.0, istanbul-lib-coverage@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.0.2.tgz#87a0c015b6910651cb3b184814dfb339337e25e1"
+
+istanbul-lib-hook@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.0.5.tgz#6ca3d16d60c5f4082da39f7c5cd38ea8a772b88e"
+  dependencies:
+    append-transform "^0.4.0"
+
+istanbul-lib-instrument@^1.1.1, istanbul-lib-instrument@^1.6.2, istanbul-lib-instrument@^1.7.0:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.7.0.tgz#b8e0dc25709bb44e17336ab47b7bb5c97c23f659"
+  dependencies:
+    babel-generator "^6.18.0"
+    babel-template "^6.16.0"
+    babel-traverse "^6.18.0"
+    babel-types "^6.18.0"
+    babylon "^6.13.0"
+    istanbul-lib-coverage "^1.0.2"
+    semver "^5.3.0"
+
+istanbul-lib-report@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.0.0.tgz#d83dac7f26566b521585569367fe84ccfc7aaecb"
+  dependencies:
+    istanbul-lib-coverage "^1.0.2"
+    mkdirp "^0.5.1"
+    path-parse "^1.0.5"
+    supports-color "^3.1.2"
+
+istanbul-lib-source-maps@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.1.1.tgz#f8c8c2e8f2160d1d91526d97e5bd63b2079af71c"
+  dependencies:
+    istanbul-lib-coverage "^1.0.2"
+    mkdirp "^0.5.1"
+    rimraf "^2.4.4"
+    source-map "^0.5.3"
+
+istanbul-reports@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.0.2.tgz#4e8366abe6fa746cc1cd6633f108de12cc6ac6fa"
+  dependencies:
+    handlebars "^4.0.3"
+
+jest-changed-files@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-19.0.2.tgz#16c54c84c3270be408e06d2e8af3f3e37a885824"
+
+jest-cli@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-19.0.2.tgz#cc3620b62acac5f2d93a548cb6ef697d4ec85443"
+  dependencies:
+    ansi-escapes "^1.4.0"
+    callsites "^2.0.0"
+    chalk "^1.1.1"
+    graceful-fs "^4.1.6"
+    is-ci "^1.0.9"
+    istanbul-api "^1.1.0-alpha.1"
+    istanbul-lib-coverage "^1.0.0"
+    istanbul-lib-instrument "^1.1.1"
+    jest-changed-files "^19.0.2"
+    jest-config "^19.0.2"
+    jest-environment-jsdom "^19.0.2"
+    jest-haste-map "^19.0.0"
+    jest-jasmine2 "^19.0.2"
+    jest-message-util "^19.0.0"
+    jest-regex-util "^19.0.0"
+    jest-resolve-dependencies "^19.0.0"
+    jest-runtime "^19.0.2"
+    jest-snapshot "^19.0.2"
+    jest-util "^19.0.2"
+    micromatch "^2.3.11"
+    node-notifier "^5.0.1"
+    slash "^1.0.0"
+    string-length "^1.0.1"
+    throat "^3.0.0"
+    which "^1.1.1"
+    worker-farm "^1.3.1"
+    yargs "^6.3.0"
+
+jest-config@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-19.0.2.tgz#1b9bd2db0ddd16df61c2b10a54009e1768da6411"
+  dependencies:
+    chalk "^1.1.1"
+    jest-environment-jsdom "^19.0.2"
+    jest-environment-node "^19.0.2"
+    jest-jasmine2 "^19.0.2"
+    jest-regex-util "^19.0.0"
+    jest-resolve "^19.0.2"
+    jest-validate "^19.0.2"
+    pretty-format "^19.0.0"
+
+jest-diff@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-19.0.0.tgz#d1563cfc56c8b60232988fbc05d4d16ed90f063c"
+  dependencies:
+    chalk "^1.1.3"
+    diff "^3.0.0"
+    jest-matcher-utils "^19.0.0"
+    pretty-format "^19.0.0"
+
+jest-environment-jsdom@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-19.0.2.tgz#ceda859c4a4b94ab35e4de7dab54b926f293e4a3"
+  dependencies:
+    jest-mock "^19.0.0"
+    jest-util "^19.0.2"
+    jsdom "^9.11.0"
+
+jest-environment-node@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-19.0.2.tgz#6e84079db87ed21d0c05e1f9669f207b116fe99b"
+  dependencies:
+    jest-mock "^19.0.0"
+    jest-util "^19.0.2"
+
+jest-file-exists@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-file-exists/-/jest-file-exists-19.0.0.tgz#cca2e587a11ec92e24cfeab3f8a94d657f3fceb8"
+
+jest-haste-map@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-19.0.0.tgz#adde00b62b1fe04432a104b3254fc5004514b55e"
+  dependencies:
+    fb-watchman "^2.0.0"
+    graceful-fs "^4.1.6"
+    micromatch "^2.3.11"
+    sane "~1.5.0"
+    worker-farm "^1.3.1"
+
+jest-jasmine2@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-19.0.2.tgz#167991ac825981fb1a800af126e83afcca832c73"
+  dependencies:
+    graceful-fs "^4.1.6"
+    jest-matcher-utils "^19.0.0"
+    jest-matchers "^19.0.0"
+    jest-message-util "^19.0.0"
+    jest-snapshot "^19.0.2"
+
+jest-matcher-utils@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-19.0.0.tgz#5ecd9b63565d2b001f61fbf7ec4c7f537964564d"
+  dependencies:
+    chalk "^1.1.3"
+    pretty-format "^19.0.0"
+
+jest-matchers@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-matchers/-/jest-matchers-19.0.0.tgz#c74ecc6ebfec06f384767ba4d6fa4a42d6755754"
+  dependencies:
+    jest-diff "^19.0.0"
+    jest-matcher-utils "^19.0.0"
+    jest-message-util "^19.0.0"
+    jest-regex-util "^19.0.0"
+
+jest-message-util@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-19.0.0.tgz#721796b89c0e4d761606f9ba8cb828a3b6246416"
+  dependencies:
+    chalk "^1.1.1"
+    micromatch "^2.3.11"
+
+jest-mock@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-19.0.0.tgz#67038641e9607ab2ce08ec4a8cb83aabbc899d01"
+
+jest-regex-util@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-19.0.0.tgz#b7754587112aede1456510bb1f6afe74ef598691"
+
+jest-resolve-dependencies@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-19.0.0.tgz#a741ad1fa094140e64ecf2642a504f834ece22ee"
+  dependencies:
+    jest-file-exists "^19.0.0"
+
+jest-resolve@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-19.0.2.tgz#5793575de4f07aec32f7d7ff0c6c181963eefb3c"
+  dependencies:
+    browser-resolve "^1.11.2"
+    jest-haste-map "^19.0.0"
+    resolve "^1.2.0"
+
+jest-runtime@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-19.0.2.tgz#d9a43e72de416d27d196fd9c7940d98fe6685407"
+  dependencies:
+    babel-core "^6.0.0"
+    babel-jest "^19.0.0"
+    babel-plugin-istanbul "^4.0.0"
+    chalk "^1.1.3"
+    graceful-fs "^4.1.6"
+    jest-config "^19.0.2"
+    jest-file-exists "^19.0.0"
+    jest-haste-map "^19.0.0"
+    jest-regex-util "^19.0.0"
+    jest-resolve "^19.0.2"
+    jest-util "^19.0.2"
+    json-stable-stringify "^1.0.1"
+    micromatch "^2.3.11"
+    strip-bom "3.0.0"
+    yargs "^6.3.0"
+
+jest-snapshot@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-19.0.2.tgz#9c1b216214f7187c38bfd5c70b1efab16b0ff50b"
+  dependencies:
+    chalk "^1.1.3"
+    jest-diff "^19.0.0"
+    jest-file-exists "^19.0.0"
+    jest-matcher-utils "^19.0.0"
+    jest-util "^19.0.2"
+    natural-compare "^1.4.0"
+    pretty-format "^19.0.0"
+
+jest-util@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-19.0.2.tgz#e0a0232a2ab9e6b2b53668bdb3534c2b5977ed41"
+  dependencies:
+    chalk "^1.1.1"
+    graceful-fs "^4.1.6"
+    jest-file-exists "^19.0.0"
+    jest-message-util "^19.0.0"
+    jest-mock "^19.0.0"
+    jest-validate "^19.0.2"
+    leven "^2.0.0"
+    mkdirp "^0.5.1"
+
+jest-validate@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-19.0.2.tgz#dc534df5f1278d5b63df32b14241d4dbf7244c0c"
+  dependencies:
+    chalk "^1.1.1"
+    jest-matcher-utils "^19.0.0"
+    leven "^2.0.0"
+    pretty-format "^19.0.0"
+
+jest@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest/-/jest-19.0.2.tgz#b794faaf8ff461e7388f28beef559a54f20b2c10"
+  dependencies:
+    jest-cli "^19.0.2"
+
+jodid25519@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967"
+  dependencies:
+    jsbn "~0.1.0"
+
+js-tokens@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7"
+
+js-yaml@^3.7.0:
+  version "3.8.3"
+  resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.3.tgz#33a05ec481c850c8875929166fe1beb61c728766"
+  dependencies:
+    argparse "^1.0.7"
+    esprima "^3.1.1"
+
+jsbn@~0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
+
+jsdom@^9.11.0:
+  version "9.12.0"
+  resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-9.12.0.tgz#e8c546fffcb06c00d4833ca84410fed7f8a097d4"
+  dependencies:
+    abab "^1.0.3"
+    acorn "^4.0.4"
+    acorn-globals "^3.1.0"
+    array-equal "^1.0.0"
+    content-type-parser "^1.0.1"
+    cssom ">= 0.3.2 < 0.4.0"
+    cssstyle ">= 0.2.37 < 0.3.0"
+    escodegen "^1.6.1"
+    html-encoding-sniffer "^1.0.1"
+    nwmatcher ">= 1.3.9 < 2.0.0"
+    parse5 "^1.5.1"
+    request "^2.79.0"
+    sax "^1.2.1"
+    symbol-tree "^3.2.1"
+    tough-cookie "^2.3.2"
+    webidl-conversions "^4.0.0"
+    whatwg-encoding "^1.0.1"
+    whatwg-url "^4.3.0"
+    xml-name-validator "^2.0.1"
+
+jsesc@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b"
+
+json-loader@^0.5.4:
+  version "0.5.4"
+  resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.4.tgz#8baa1365a632f58a3c46d20175fc6002c96e37de"
+
+json-schema@0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
+
+json-stable-stringify@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af"
+  dependencies:
+    jsonify "~0.0.0"
+
+json-stringify-safe@~5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
+
+json5@^0.5.0, json5@^0.5.1:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
+
+jsonify@~0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
+
+jsprim@^1.2.2:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.0.tgz#a3b87e40298d8c380552d8cc7628a0bb95a22918"
+  dependencies:
+    assert-plus "1.0.0"
+    extsprintf "1.0.2"
+    json-schema "0.2.3"
+    verror "1.3.6"
+
+kind-of@^3.0.2:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47"
+  dependencies:
+    is-buffer "^1.0.2"
+
+lazy-cache@^1.0.3:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
+
+lcid@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
+  dependencies:
+    invert-kv "^1.0.0"
+
+leven@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580"
+
+levn@~0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
+  dependencies:
+    prelude-ls "~1.1.2"
+    type-check "~0.3.2"
+
+load-json-file@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
+  dependencies:
+    graceful-fs "^4.1.2"
+    parse-json "^2.2.0"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+    strip-bom "^2.0.0"
+
+loader-runner@^2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2"
+
+loader-utils@^0.2.16:
+  version "0.2.17"
+  resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348"
+  dependencies:
+    big.js "^3.1.3"
+    emojis-list "^2.0.0"
+    json5 "^0.5.0"
+    object-assign "^4.0.1"
+
+locate-path@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
+  dependencies:
+    p-locate "^2.0.0"
+    path-exists "^3.0.0"
+
+lodash@^4.14.0, lodash@^4.2.0:
+  version "4.17.4"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
+
+longest@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
+
+loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1:
+  version "1.3.1"
+  resolved "https://artifacts.netflix.com/api/npm/npm-netflix/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
+  dependencies:
+    js-tokens "^3.0.0"
+
+makeerror@1.0.x:
+  version "1.0.11"
+  resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c"
+  dependencies:
+    tmpl "1.0.x"
+
+memory-fs@^0.4.0, memory-fs@~0.4.1:
+  version "0.4.1"
+  resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"
+  dependencies:
+    errno "^0.1.3"
+    readable-stream "^2.0.1"
+
+merge@^1.1.3:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da"
+
+micromatch@^2.1.5, micromatch@^2.3.11:
+  version "2.3.11"
+  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
+  dependencies:
+    arr-diff "^2.0.0"
+    array-unique "^0.2.1"
+    braces "^1.8.2"
+    expand-brackets "^0.1.4"
+    extglob "^0.3.1"
+    filename-regex "^2.0.0"
+    is-extglob "^1.0.0"
+    is-glob "^2.0.1"
+    kind-of "^3.0.2"
+    normalize-path "^2.0.1"
+    object.omit "^2.0.0"
+    parse-glob "^3.0.4"
+    regex-cache "^0.4.2"
+
+miller-rabin@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.0.tgz#4a62fb1d42933c05583982f4c716f6fb9e6c6d3d"
+  dependencies:
+    bn.js "^4.0.0"
+    brorand "^1.0.1"
+
+mime-db@~1.27.0:
+  version "1.27.0"
+  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1"
+
+mime-types@^2.1.12, mime-types@~2.1.7:
+  version "2.1.15"
+  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed"
+  dependencies:
+    mime-db "~1.27.0"
+
+minimalistic-assert@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3"
+
+minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
+
+minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774"
+  dependencies:
+    brace-expansion "^1.0.0"
+
+minimist@0.0.8, minimist@~0.0.1:
+  version "0.0.8"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
+
+minimist@^1.1.1, minimist@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
+
+"mkdirp@>=0.5 0", mkdirp@^0.5.1, mkdirp@~0.5.0:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
+  dependencies:
+    minimist "0.0.8"
+
+ms@0.7.2:
+  version "0.7.2"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765"
+
+nan@^2.3.0:
+  version "2.6.2"
+  resolved "https://registry.yarnpkg.com/nan/-/nan-2.6.2.tgz#e4ff34e6c95fdfb5aecc08de6596f43605a7db45"
+
+natural-compare@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
+
+node-fetch@^1.0.1:
+  version "1.6.3"
+  resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04"
+  dependencies:
+    encoding "^0.1.11"
+    is-stream "^1.0.1"
+
+node-int64@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
+
+node-libs-browser@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.0.0.tgz#a3a59ec97024985b46e958379646f96c4b616646"
+  dependencies:
+    assert "^1.1.1"
+    browserify-zlib "^0.1.4"
+    buffer "^4.3.0"
+    console-browserify "^1.1.0"
+    constants-browserify "^1.0.0"
+    crypto-browserify "^3.11.0"
+    domain-browser "^1.1.1"
+    events "^1.0.0"
+    https-browserify "0.0.1"
+    os-browserify "^0.2.0"
+    path-browserify "0.0.0"
+    process "^0.11.0"
+    punycode "^1.2.4"
+    querystring-es3 "^0.2.0"
+    readable-stream "^2.0.5"
+    stream-browserify "^2.0.1"
+    stream-http "^2.3.1"
+    string_decoder "^0.10.25"
+    timers-browserify "^2.0.2"
+    tty-browserify "0.0.0"
+    url "^0.11.0"
+    util "^0.10.3"
+    vm-browserify "0.0.4"
+
+node-notifier@^5.0.1:
+  version "5.1.2"
+  resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.1.2.tgz#2fa9e12605fa10009d44549d6fcd8a63dde0e4ff"
+  dependencies:
+    growly "^1.3.0"
+    semver "^5.3.0"
+    shellwords "^0.1.0"
+    which "^1.2.12"
+
+node-pre-gyp@^0.6.36:
+  version "0.6.36"
+  resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.36.tgz#db604112cb74e0d477554e9b505b17abddfab786"
+  dependencies:
+    mkdirp "^0.5.1"
+    nopt "^4.0.1"
+    npmlog "^4.0.2"
+    rc "^1.1.7"
+    request "^2.81.0"
+    rimraf "^2.6.1"
+    semver "^5.3.0"
+    tar "^2.2.1"
+    tar-pack "^3.4.0"
+
+nopt@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
+  dependencies:
+    abbrev "1"
+    osenv "^0.1.4"
+
+normalize-package-data@^2.3.2:
+  version "2.3.6"
+  resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.6.tgz#498fa420c96401f787402ba21e600def9f981fff"
+  dependencies:
+    hosted-git-info "^2.1.4"
+    is-builtin-module "^1.0.0"
+    semver "2 || 3 || 4 || 5"
+    validate-npm-package-license "^3.0.1"
+
+normalize-path@^2.0.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
+  dependencies:
+    remove-trailing-separator "^1.0.1"
+
+npmlog@^4.0.2:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.0.tgz#dc59bee85f64f00ed424efb2af0783df25d1c0b5"
+  dependencies:
+    are-we-there-yet "~1.1.2"
+    console-control-strings "~1.1.0"
+    gauge "~2.7.3"
+    set-blocking "~2.0.0"
+
+number-is-nan@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
+
+"nwmatcher@>= 1.3.9 < 2.0.0":
+  version "1.3.9"
+  resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.3.9.tgz#8bab486ff7fa3dfd086656bbe8b17116d3692d2a"
+
+oauth-sign@~0.8.1:
+  version "0.8.2"
+  resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
+
+object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+
+object.omit@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
+  dependencies:
+    for-own "^0.1.4"
+    is-extendable "^0.1.1"
+
+once@^1.3.0, once@^1.3.3, once@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+  dependencies:
+    wrappy "1"
+
+optimist@^0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
+  dependencies:
+    minimist "~0.0.1"
+    wordwrap "~0.0.2"
+
+optionator@^0.8.1:
+  version "0.8.2"
+  resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64"
+  dependencies:
+    deep-is "~0.1.3"
+    fast-levenshtein "~2.0.4"
+    levn "~0.3.0"
+    prelude-ls "~1.1.2"
+    type-check "~0.3.2"
+    wordwrap "~1.0.0"
+
+os-browserify@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.2.1.tgz#63fc4ccee5d2d7763d26bbf8601078e6c2e0044f"
+
+os-homedir@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
+
+os-locale@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9"
+  dependencies:
+    lcid "^1.0.0"
+
+os-tmpdir@^1.0.0, os-tmpdir@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
+
+osenv@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644"
+  dependencies:
+    os-homedir "^1.0.0"
+    os-tmpdir "^1.0.0"
+
+p-limit@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.1.0.tgz#b07ff2d9a5d88bec806035895a2bab66a27988bc"
+
+p-locate@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
+  dependencies:
+    p-limit "^1.1.0"
+
+pako@~0.2.0:
+  version "0.2.9"
+  resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
+
+parse-asn1@^5.0.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712"
+  dependencies:
+    asn1.js "^4.0.0"
+    browserify-aes "^1.0.0"
+    create-hash "^1.1.0"
+    evp_bytestokey "^1.0.0"
+    pbkdf2 "^3.0.3"
+
+parse-glob@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
+  dependencies:
+    glob-base "^0.3.0"
+    is-dotfile "^1.0.0"
+    is-extglob "^1.0.0"
+    is-glob "^2.0.0"
+
+parse-json@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
+  dependencies:
+    error-ex "^1.2.0"
+
+parse5@^1.5.1:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94"
+
+path-browserify@0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a"
+
+path-exists@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
+  dependencies:
+    pinkie-promise "^2.0.0"
+
+path-exists@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
+
+path-is-absolute@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+
+path-parse@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1"
+
+path-type@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
+  dependencies:
+    graceful-fs "^4.1.2"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+pbkdf2@^3.0.3:
+  version "3.0.12"
+  resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.12.tgz#be36785c5067ea48d806ff923288c5f750b6b8a2"
+  dependencies:
+    create-hash "^1.1.2"
+    create-hmac "^1.1.4"
+    ripemd160 "^2.0.1"
+    safe-buffer "^5.0.1"
+    sha.js "^2.4.8"
+
+performance-now@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5"
+
+pify@^2.0.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
+
+pinkie-promise@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
+  dependencies:
+    pinkie "^2.0.0"
+
+pinkie@^2.0.0:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
+
+prelude-ls@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
+
+preserve@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
+
+pretty-format@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-19.0.0.tgz#56530d32acb98a3fa4851c4e2b9d37b420684c84"
+  dependencies:
+    ansi-styles "^3.0.0"
+
+private@^0.1.6:
+  version "0.1.7"
+  resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1"
+
+process-nextick-args@~1.0.6:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
+
+process@^0.11.0:
+  version "0.11.10"
+  resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
+
+promise@^7.1.1:
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/promise/-/promise-7.1.1.tgz#489654c692616b8aa55b0724fa809bb7db49c5bf"
+  dependencies:
+    asap "~2.0.3"
+
+prop-types@^15.5.10, prop-types@^15.5.7, prop-types@~15.5.7:
+  version "15.5.10"
+  resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.10.tgz#2797dfc3126182e3a95e3dfbb2e893ddd7456154"
+  dependencies:
+    fbjs "^0.8.9"
+    loose-envify "^1.3.1"
+
+prr@~0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a"
+
+public-encrypt@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.0.tgz#39f699f3a46560dd5ebacbca693caf7c65c18cc6"
+  dependencies:
+    bn.js "^4.1.0"
+    browserify-rsa "^4.0.0"
+    create-hash "^1.1.0"
+    parse-asn1 "^5.0.0"
+    randombytes "^2.0.1"
+
+punycode@1.3.2:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
+
+punycode@^1.2.4, punycode@^1.4.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
+
+qs@~6.4.0:
+  version "6.4.0"
+  resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
+
+querystring-es3@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
+
+querystring@0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
+
+randomatic@^1.1.3:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb"
+  dependencies:
+    is-number "^2.0.2"
+    kind-of "^3.0.2"
+
+randombytes@^2.0.0, randombytes@^2.0.1:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.5.tgz#dc009a246b8d09a177b4b7a0ae77bc570f4b1b79"
+  dependencies:
+    safe-buffer "^5.1.0"
+
+rc@^1.1.7:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.1.tgz#2e03e8e42ee450b8cb3dce65be1bf8974e1dfd95"
+  dependencies:
+    deep-extend "~0.4.0"
+    ini "~1.3.0"
+    minimist "^1.2.0"
+    strip-json-comments "~2.0.1"
+
+react-dom@^15.5.4:
+  version "15.5.4"
+  resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.5.4.tgz#ba0c28786fd52ed7e4f2135fe0288d462aef93da"
+  dependencies:
+    fbjs "^0.8.9"
+    loose-envify "^1.1.0"
+    object-assign "^4.1.0"
+    prop-types "~15.5.7"
+
+react@^15.5.4:
+  version "15.5.4"
+  resolved "https://registry.yarnpkg.com/react/-/react-15.5.4.tgz#fa83eb01506ab237cdc1c8c3b1cea8de012bf047"
+  dependencies:
+    fbjs "^0.8.9"
+    loose-envify "^1.1.0"
+    object-assign "^4.1.0"
+    prop-types "^15.5.7"
+
+read-pkg-up@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
+  dependencies:
+    find-up "^1.0.0"
+    read-pkg "^1.0.0"
+
+read-pkg@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
+  dependencies:
+    load-json-file "^1.0.0"
+    normalize-package-data "^2.3.2"
+    path-type "^1.0.0"
+
+readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.2.6:
+  version "2.2.11"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.11.tgz#0796b31f8d7688007ff0b93a8088d34aa17c0f72"
+  dependencies:
+    core-util-is "~1.0.0"
+    inherits "~2.0.1"
+    isarray "~1.0.0"
+    process-nextick-args "~1.0.6"
+    safe-buffer "~5.0.1"
+    string_decoder "~1.0.0"
+    util-deprecate "~1.0.1"
+
+readdirp@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78"
+  dependencies:
+    graceful-fs "^4.1.2"
+    minimatch "^3.0.2"
+    readable-stream "^2.0.2"
+    set-immediate-shim "^1.0.1"
+
+regenerator-runtime@^0.10.0:
+  version "0.10.3"
+  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.3.tgz#8c4367a904b51ea62a908ac310bf99ff90a82a3e"
+
+regex-cache@^0.4.2:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145"
+  dependencies:
+    is-equal-shallow "^0.1.3"
+    is-primitive "^2.0.0"
+
+remove-trailing-separator@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.0.1.tgz#615ebb96af559552d4bf4057c8436d486ab63cc4"
+
+repeat-element@^1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a"
+
+repeat-string@^1.5.2:
+  version "1.6.1"
+  resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
+
+repeating@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda"
+  dependencies:
+    is-finite "^1.0.0"
+
+request@^2.79.0, request@^2.81.0:
+  version "2.81.0"
+  resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0"
+  dependencies:
+    aws-sign2 "~0.6.0"
+    aws4 "^1.2.1"
+    caseless "~0.12.0"
+    combined-stream "~1.0.5"
+    extend "~3.0.0"
+    forever-agent "~0.6.1"
+    form-data "~2.1.1"
+    har-validator "~4.2.1"
+    hawk "~3.1.3"
+    http-signature "~1.1.0"
+    is-typedarray "~1.0.0"
+    isstream "~0.1.2"
+    json-stringify-safe "~5.0.1"
+    mime-types "~2.1.7"
+    oauth-sign "~0.8.1"
+    performance-now "^0.2.0"
+    qs "~6.4.0"
+    safe-buffer "^5.0.1"
+    stringstream "~0.0.4"
+    tough-cookie "~2.3.0"
+    tunnel-agent "^0.6.0"
+    uuid "^3.0.0"
+
+require-directory@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
+
+require-main-filename@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
+
+resolve@1.1.7:
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
+
+resolve@^1.2.0:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.3.2.tgz#1f0442c9e0cbb8136e87b9305f932f46c7f28235"
+  dependencies:
+    path-parse "^1.0.5"
+
+right-align@^0.1.1:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef"
+  dependencies:
+    align-text "^0.1.1"
+
+rimraf@2, rimraf@^2.4.4, rimraf@^2.5.1, rimraf@^2.6.1:
+  version "2.6.1"
+  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d"
+  dependencies:
+    glob "^7.0.5"
+
+ripemd160@^2.0.0, ripemd160@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7"
+  dependencies:
+    hash-base "^2.0.0"
+    inherits "^2.0.1"
+
+safe-buffer@^5.0.1, safe-buffer@~5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7"
+
+safe-buffer@^5.1.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.0.tgz#fe4c8460397f9eaaaa58e73be46273408a45e223"
+
+sane@~1.5.0:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/sane/-/sane-1.5.0.tgz#a4adeae764d048621ecb27d5f9ecf513101939f3"
+  dependencies:
+    anymatch "^1.3.0"
+    exec-sh "^0.2.0"
+    fb-watchman "^1.8.0"
+    minimatch "^3.0.2"
+    minimist "^1.1.1"
+    walker "~1.0.5"
+    watch "~0.10.0"
+
+sax@^1.2.1:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.2.tgz#fd8631a23bc7826bef5d871bdb87378c95647828"
+
+"semver@2 || 3 || 4 || 5", semver@^5.3.0:
+  version "5.3.0"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
+
+set-blocking@^2.0.0, set-blocking@~2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
+
+set-immediate-shim@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61"
+
+setimmediate@^1.0.4, setimmediate@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
+
+sha.js@^2.4.0, sha.js@^2.4.8:
+  version "2.4.8"
+  resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.8.tgz#37068c2c476b6baf402d14a49c67f597921f634f"
+  dependencies:
+    inherits "^2.0.1"
+
+shellwords@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.0.tgz#66afd47b6a12932d9071cbfd98a52e785cd0ba14"
+
+signal-exit@^3.0.0:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
+
+slash@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
+
+sntp@1.x.x:
+  version "1.0.9"
+  resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198"
+  dependencies:
+    hoek "2.x.x"
+
+source-list-map@^1.1.1:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-1.1.2.tgz#9889019d1024cce55cdc069498337ef6186a11a1"
+
+source-map-support@^0.4.2:
+  version "0.4.14"
+  resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.14.tgz#9d4463772598b86271b4f523f6c1f4e02a7d6aef"
+  dependencies:
+    source-map "^0.5.6"
+
+source-map@^0.4.4:
+  version "0.4.4"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b"
+  dependencies:
+    amdefine ">=0.0.4"
+
+source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.3:
+  version "0.5.6"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
+
+source-map@~0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d"
+  dependencies:
+    amdefine ">=0.0.4"
+
+spdx-correct@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40"
+  dependencies:
+    spdx-license-ids "^1.0.2"
+
+spdx-expression-parse@~1.0.0:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c"
+
+spdx-license-ids@^1.0.2:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57"
+
+sprintf-js@~1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
+
+sshpk@^1.7.0:
+  version "1.11.0"
+  resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.11.0.tgz#2d8d5ebb4a6fab28ffba37fa62a90f4a3ea59d77"
+  dependencies:
+    asn1 "~0.2.3"
+    assert-plus "^1.0.0"
+    dashdash "^1.12.0"
+    getpass "^0.1.1"
+  optionalDependencies:
+    bcrypt-pbkdf "^1.0.0"
+    ecc-jsbn "~0.1.1"
+    jodid25519 "^1.0.0"
+    jsbn "~0.1.0"
+    tweetnacl "~0.14.0"
+
+stream-browserify@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db"
+  dependencies:
+    inherits "~2.0.1"
+    readable-stream "^2.0.2"
+
+stream-http@^2.3.1:
+  version "2.7.2"
+  resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.7.2.tgz#40a050ec8dc3b53b33d9909415c02c0bf1abfbad"
+  dependencies:
+    builtin-status-codes "^3.0.0"
+    inherits "^2.0.1"
+    readable-stream "^2.2.6"
+    to-arraybuffer "^1.0.0"
+    xtend "^4.0.0"
+
+string-length@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/string-length/-/string-length-1.0.1.tgz#56970fb1c38558e9e70b728bf3de269ac45adfac"
+  dependencies:
+    strip-ansi "^3.0.0"
+
+string-width@^1.0.1, string-width@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
+  dependencies:
+    code-point-at "^1.0.0"
+    is-fullwidth-code-point "^1.0.0"
+    strip-ansi "^3.0.0"
+
+string_decoder@^0.10.25:
+  version "0.10.31"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
+
+string_decoder@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.2.tgz#b29e1f4e1125fa97a10382b8a533737b7491e179"
+  dependencies:
+    safe-buffer "~5.0.1"
+
+stringstream@~0.0.4:
+  version "0.0.5"
+  resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878"
+
+strip-ansi@^3.0.0, strip-ansi@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
+  dependencies:
+    ansi-regex "^2.0.0"
+
+strip-bom@3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
+
+strip-bom@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
+  dependencies:
+    is-utf8 "^0.2.0"
+
+strip-json-comments@~2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
+
+supports-color@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
+
+supports-color@^3.1.0, supports-color@^3.1.2:
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
+  dependencies:
+    has-flag "^1.0.0"
+
+symbol-tree@^3.2.1:
+  version "3.2.2"
+  resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6"
+
+tapable@^0.2.5, tapable@~0.2.5:
+  version "0.2.6"
+  resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.6.tgz#206be8e188860b514425375e6f1ae89bfb01fd8d"
+
+tar-pack@^3.4.0:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.0.tgz#23be2d7f671a8339376cbdb0b8fe3fdebf317984"
+  dependencies:
+    debug "^2.2.0"
+    fstream "^1.0.10"
+    fstream-ignore "^1.0.5"
+    once "^1.3.3"
+    readable-stream "^2.1.4"
+    rimraf "^2.5.1"
+    tar "^2.2.1"
+    uid-number "^0.0.6"
+
+tar@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1"
+  dependencies:
+    block-stream "*"
+    fstream "^1.0.2"
+    inherits "2"
+
+test-exclude@^4.0.3:
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-4.0.3.tgz#86a13ce3effcc60e6c90403cf31a27a60ac6c4e7"
+  dependencies:
+    arrify "^1.0.1"
+    micromatch "^2.3.11"
+    object-assign "^4.1.0"
+    read-pkg-up "^1.0.1"
+    require-main-filename "^1.0.1"
+
+throat@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/throat/-/throat-3.0.0.tgz#e7c64c867cbb3845f10877642f7b60055b8ec0d6"
+
+timers-browserify@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.2.tgz#ab4883cf597dcd50af211349a00fbca56ac86b86"
+  dependencies:
+    setimmediate "^1.0.4"
+
+tmpl@1.0.x:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1"
+
+to-arraybuffer@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
+
+to-fast-properties@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320"
+
+tough-cookie@^2.3.2, tough-cookie@~2.3.0:
+  version "2.3.2"
+  resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a"
+  dependencies:
+    punycode "^1.4.1"
+
+tr46@~0.0.3:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
+
+trim-right@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
+
+tty-browserify@0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
+
+tunnel-agent@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
+  dependencies:
+    safe-buffer "^5.0.1"
+
+tweetnacl@^0.14.3, tweetnacl@~0.14.0:
+  version "0.14.5"
+  resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
+
+type-check@~0.3.2:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
+  dependencies:
+    prelude-ls "~1.1.2"
+
+ua-parser-js@^0.7.9:
+  version "0.7.12"
+  resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb"
+
+uglify-js@^2.6, uglify-js@^2.8.27:
+  version "2.8.28"
+  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.28.tgz#e335032df9bb20dcb918f164589d5af47f38834a"
+  dependencies:
+    source-map "~0.5.1"
+    yargs "~3.10.0"
+  optionalDependencies:
+    uglify-to-browserify "~1.0.0"
+
+uglify-to-browserify@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7"
+
+uid-number@^0.0.6:
+  version "0.0.6"
+  resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81"
+
+url@^0.11.0:
+  version "0.11.0"
+  resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
+  dependencies:
+    punycode "1.3.2"
+    querystring "0.2.0"
+
+util-deprecate@~1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+
+util@0.10.3, util@^0.10.3:
+  version "0.10.3"
+  resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9"
+  dependencies:
+    inherits "2.0.1"
+
+uuid@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1"
+
+validate-npm-package-license@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc"
+  dependencies:
+    spdx-correct "~1.0.0"
+    spdx-expression-parse "~1.0.0"
+
+verror@1.3.6:
+  version "1.3.6"
+  resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c"
+  dependencies:
+    extsprintf "1.0.2"
+
+vm-browserify@0.0.4:
+  version "0.0.4"
+  resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73"
+  dependencies:
+    indexof "0.0.1"
+
+walker@~1.0.5:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb"
+  dependencies:
+    makeerror "1.0.x"
+
+watch@~0.10.0:
+  version "0.10.0"
+  resolved "https://registry.yarnpkg.com/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc"
+
+watchpack@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.3.1.tgz#7d8693907b28ce6013e7f3610aa2a1acf07dad87"
+  dependencies:
+    async "^2.1.2"
+    chokidar "^1.4.3"
+    graceful-fs "^4.1.2"
+
+webidl-conversions@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
+
+webidl-conversions@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.1.tgz#8015a17ab83e7e1b311638486ace81da6ce206a0"
+
+webpack-sources@^0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-0.2.3.tgz#17c62bfaf13c707f9d02c479e0dcdde8380697fb"
+  dependencies:
+    source-list-map "^1.1.1"
+    source-map "~0.5.3"
+
+webpack@^2.6.1:
+  version "2.6.1"
+  resolved "https://registry.yarnpkg.com/webpack/-/webpack-2.6.1.tgz#2e0457f0abb1ac5df3ab106c69c672f236785f07"
+  dependencies:
+    acorn "^5.0.0"
+    acorn-dynamic-import "^2.0.0"
+    ajv "^4.7.0"
+    ajv-keywords "^1.1.1"
+    async "^2.1.2"
+    enhanced-resolve "^3.0.0"
+    interpret "^1.0.0"
+    json-loader "^0.5.4"
+    json5 "^0.5.1"
+    loader-runner "^2.3.0"
+    loader-utils "^0.2.16"
+    memory-fs "~0.4.1"
+    mkdirp "~0.5.0"
+    node-libs-browser "^2.0.0"
+    source-map "^0.5.3"
+    supports-color "^3.1.0"
+    tapable "~0.2.5"
+    uglify-js "^2.8.27"
+    watchpack "^1.3.1"
+    webpack-sources "^0.2.3"
+    yargs "^6.0.0"
+
+whatwg-encoding@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.1.tgz#3c6c451a198ee7aec55b1ec61d0920c67801a5f4"
+  dependencies:
+    iconv-lite "0.4.13"
+
+whatwg-fetch@>=0.10.0:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84"
+
+whatwg-url@^4.3.0:
+  version "4.7.0"
+  resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-4.7.0.tgz#202035ac1955b087cdd20fa8b58ded3ab1cd2af5"
+  dependencies:
+    tr46 "~0.0.3"
+    webidl-conversions "^3.0.0"
+
+which-module@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
+
+which@^1.1.1, which@^1.2.12:
+  version "1.2.14"
+  resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5"
+  dependencies:
+    isexe "^2.0.0"
+
+wide-align@^1.1.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710"
+  dependencies:
+    string-width "^1.0.2"
+
+window-size@0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
+
+wordwrap@0.0.2, wordwrap@~0.0.2:
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
+
+wordwrap@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
+
+worker-farm@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.3.1.tgz#4333112bb49b17aa050b87895ca6b2cacf40e5ff"
+  dependencies:
+    errno ">=0.1.1 <0.2.0-0"
+    xtend ">=4.0.0 <4.1.0-0"
+
+wrap-ansi@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
+  dependencies:
+    string-width "^1.0.1"
+    strip-ansi "^3.0.1"
+
+wrappy@1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+
+xml-name-validator@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635"
+
+"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
+
+y18n@^3.2.1:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
+
+yargs-parser@^4.2.0:
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c"
+  dependencies:
+    camelcase "^3.0.0"
+
+yargs@^6.0.0, yargs@^6.3.0:
+  version "6.6.0"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208"
+  dependencies:
+    camelcase "^3.0.0"
+    cliui "^3.2.0"
+    decamelize "^1.1.1"
+    get-caller-file "^1.0.1"
+    os-locale "^1.4.0"
+    read-pkg-up "^1.0.1"
+    require-directory "^2.1.1"
+    require-main-filename "^1.0.1"
+    set-blocking "^2.0.0"
+    string-width "^1.0.2"
+    which-module "^1.0.0"
+    y18n "^3.2.1"
+    yargs-parser "^4.2.0"
+
+yargs@~3.10.0:
+  version "3.10.0"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"
+  dependencies:
+    camelcase "^1.0.2"
+    cliui "^2.1.0"
+    decamelize "^1.0.0"
+    window-size "0.1.0"
diff --git a/addons/postbuild.js b/addons/postbuild.js
new file mode 100644
index 000000000000..7542ace0ed37
--- /dev/null
+++ b/addons/postbuild.js
@@ -0,0 +1,73 @@
+/**
+ * Copyright 2015-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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var fs = require('fs');
+var path = require('path');
+
+// This lets us import Webpack config without crashing
+process.env.NODE_ENV = 'development';
+
+// This script runs from the addon folder
+var exportName = require(path.resolve(process.cwd(), './webpack.config')).output
+  .library;
+var packageName = path.basename(process.cwd());
+
+if (packageName.indexOf('react-addons') !== 0) {
+  throw new Error(
+    'Only run this script for packages that used to be published as addons.'
+  );
+}
+
+// Inputs
+// DEV:  root["exportName"] = factory(root["React"])
+// PROD: e.exportName=t(e.React)
+var find = new RegExp(
+  '((?!exports)\\b\\w+)(\\["' +
+    exportName +
+    '"\\]|\\.' +
+    exportName +
+    ')\\s*=\\s*(\\w+)\\((.*)\\)'
+);
+// Outputs
+// DEV:  (root.React ? (root.React.addons = root.React.addons || {}) : /* throw */).exportName = factory(/* ... */);
+// PROD: (e.React ? (e.React.addons = e.React.addons || {}) : /* throw */).exportName = t(/* ... */)
+var throwIIFE = [
+  '(function(){',
+  'throw new Error("' +
+    packageName +
+    ' could not find the React object. If you are using script tags, make sure that React is being loaded before ' +
+    packageName +
+    '.")',
+  '})()'
+].join('');
+var replace =
+  '($1.React?($1.React.addons=$1.React.addons||{}):' +
+  throwIIFE +
+  ').' +
+  exportName +
+  '=$3($4)';
+
+console.log('Tweaking the development UMD...');
+var devUMD = fs.readFileSync('./' + packageName + '.js', 'utf8').toString();
+devUMD = devUMD.replace(find, replace);
+fs.writeFileSync('./' + packageName + '.js', devUMD);
+
+console.log('Tweaking the production UMD...');
+var prodUMD = fs
+  .readFileSync('./' + packageName + '.min.js', 'utf8')
+  .toString();
+prodUMD = prodUMD.replace(find, replace);
+fs.writeFileSync('./' + packageName + '.min.js', prodUMD);
+
+console.log('Done.');
+console.log('Note that you need to manually test the UMD builds.');
diff --git a/addons/react-addons-create-fragment/.gitignore b/addons/react-addons-create-fragment/.gitignore
new file mode 100644
index 000000000000..a37eb3b910a8
--- /dev/null
+++ b/addons/react-addons-create-fragment/.gitignore
@@ -0,0 +1,2 @@
+react-addons-create-fragment.js
+react-addons-create-fragment.min.js
diff --git a/addons/react-addons-create-fragment/LICENSE b/addons/react-addons-create-fragment/LICENSE
new file mode 100644
index 000000000000..91b8f6f76ff0
--- /dev/null
+++ b/addons/react-addons-create-fragment/LICENSE
@@ -0,0 +1,31 @@
+BSD License
+
+For React software
+
+Copyright (c) 2013-present, Facebook, Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+ * Neither the name Facebook nor the names of its contributors may be used to
+   endorse or promote products derived from this software without specific
+   prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/addons/react-addons-create-fragment/PATENTS b/addons/react-addons-create-fragment/PATENTS
new file mode 100644
index 000000000000..9c9f8e87a8f4
--- /dev/null
+++ b/addons/react-addons-create-fragment/PATENTS
@@ -0,0 +1,33 @@
+Additional Grant of Patent Rights Version 2
+
+"Software" means the React software distributed by Facebook, Inc.
+
+Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software
+("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable
+(subject to the termination provision below) license under any Necessary
+Claims, to make, have made, use, sell, offer to sell, import, and otherwise
+transfer the Software. For avoidance of doubt, no license is granted under
+Facebook's rights in any patent claims that are infringed by (i) modifications
+to the Software made by you or any third party or (ii) the Software in
+combination with any software or other technology.
+
+The license granted hereunder will terminate, automatically and without notice,
+if you (or any of your subsidiaries, corporate affiliates or agents) initiate
+directly or indirectly, or take a direct financial interest in, any Patent
+Assertion: (i) against Facebook or any of its subsidiaries or corporate
+affiliates, (ii) against any party if such Patent Assertion arises in whole or
+in part from any software, technology, product or service of Facebook or any of
+its subsidiaries or corporate affiliates, or (iii) against any party relating
+to the Software. Notwithstanding the foregoing, if Facebook or any of its
+subsidiaries or corporate affiliates files a lawsuit alleging patent
+infringement against you in the first instance, and you respond by filing a
+patent infringement counterclaim in that lawsuit against that party that is
+unrelated to the Software, the license granted hereunder will not terminate
+under section (i) of this paragraph due to such counterclaim.
+
+A "Necessary Claim" is a claim of a patent owned by Facebook that is
+necessarily infringed by the Software standing alone.
+
+A "Patent Assertion" is any lawsuit or other action alleging direct, indirect,
+or contributory infringement or inducement to infringe any patent, including a
+cross-claim or counterclaim.
diff --git a/addons/react-addons-create-fragment/README.md b/addons/react-addons-create-fragment/README.md
new file mode 100644
index 000000000000..24d3a64d6192
--- /dev/null
+++ b/addons/react-addons-create-fragment/README.md
@@ -0,0 +1,77 @@
+# react-addons-create-fragment
+
+
+>**Note:**
+>This is a legacy React addon, and is no longer maintained.
+>
+>We don't encourage using it in new code, but it exists for backwards compatibility.  
+>The recommended migration path is to use arrays with explicit keys on individual elements.
+
+**Importing**
+
+```javascript
+import createFragment from 'react-addons-create-fragment'; // ES6
+var createFragment = require('react-addons-create-fragment'); // ES5 with npm
+```
+
+If you prefer a `<script>` tag, you can get it from `React.addons.createFragment` with:
+
+```html
+<!-- development version -->
+<script src="https://unpkg.com/react-addons-create-fragment/react-addons-create-fragment.js"></script>
+
+<!-- production version -->
+<script src="https://unpkg.com/react-addons-create-fragment/react-addons-create-fragment.min.js"></script>
+```
+
+In this case, make sure to put the `<script>` tag after React.
+
+## Overview
+
+In most cases, you can use the `key` prop to specify keys on the elements you're returning from `render`. However, this breaks down in one situation: if you have two sets of children that you need to reorder, there's no way to put a key on each set without adding a wrapper element.
+
+That is, if you have a component such as:
+
+```js
+function Swapper(props) {
+  let children;
+  if (props.swapped) {
+    children = [props.rightChildren, props.leftChildren];
+  } else {
+    children = [props.leftChildren, props.rightChildren];
+  }
+  return <div>{children}</div>;
+}
+```
+
+The children will unmount and remount as you change the `swapped` prop because there aren't any keys marked on the two sets of children.
+
+To solve this problem, you can use the `createFragment` add-on to give keys to the sets of children.
+
+#### `Array<ReactNode> createFragment(object children)`
+
+Instead of creating arrays, we write:
+
+```javascript
+import createFragment from 'react-addons-create-fragment';
+
+function Swapper(props) {
+  let children;
+  if (props.swapped) {
+    children = createFragment({
+      right: props.rightChildren,
+      left: props.leftChildren
+    });
+  } else {
+    children = createFragment({
+      left: props.leftChildren,
+      right: props.rightChildren
+    });
+  }
+  return <div>{children}</div>;
+}
+```
+
+The keys of the passed object (that is, `left` and `right`) are used as keys for the entire set of children, and the order of the object's keys is used to determine the order of the rendered children. With this change, the two sets of children will be properly reordered in the DOM without unmounting.
+
+The return value of `createFragment` should be treated as an opaque object; you can use the [`React.Children`](https://facebook.github.io/react/docs/react-api.html#react.children) helpers to loop through a fragment but should not access it directly. Note also that we're relying on the JavaScript engine preserving object enumeration order here, which is not guaranteed by the spec but is implemented by all major browsers and VMs for objects with non-numeric keys.
diff --git a/addons/react-addons-create-fragment/index.js b/addons/react-addons-create-fragment/index.js
new file mode 100644
index 000000000000..725ce04e0317
--- /dev/null
+++ b/addons/react-addons-create-fragment/index.js
@@ -0,0 +1,348 @@
+/**
+ * Copyright 2015-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.
+ */
+
+'use strict';
+
+var React = require('react');
+
+var REACT_ELEMENT_TYPE =
+  (typeof Symbol === 'function' && Symbol.for && Symbol.for('react.element')) ||
+  0xeac7;
+
+var emptyFunction = require('fbjs/lib/emptyFunction');
+var invariant = require('fbjs/lib/invariant');
+var warning = require('fbjs/lib/warning');
+
+var SEPARATOR = '.';
+var SUBSEPARATOR = ':';
+
+var didWarnAboutMaps = false;
+
+var ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator;
+var FAUX_ITERATOR_SYMBOL = '@@iterator'; // Before Symbol spec.
+
+function getIteratorFn(maybeIterable) {
+  var iteratorFn =
+    maybeIterable &&
+    ((ITERATOR_SYMBOL && maybeIterable[ITERATOR_SYMBOL]) ||
+      maybeIterable[FAUX_ITERATOR_SYMBOL]);
+  if (typeof iteratorFn === 'function') {
+    return iteratorFn;
+  }
+}
+
+function escape(key) {
+  var escapeRegex = /[=:]/g;
+  var escaperLookup = {
+    '=': '=0',
+    ':': '=2'
+  };
+  var escapedString = ('' + key).replace(escapeRegex, function(match) {
+    return escaperLookup[match];
+  });
+
+  return '$' + escapedString;
+}
+
+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 escape(component.key);
+  }
+  // Implicit key determined by the index in the set
+  return index.toString(36);
+}
+
+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) {
+      if (process.env.NODE_ENV !== 'production') {
+        // Warn about using Maps as children
+        if (iteratorFn === children.entries) {
+          warning(
+            didWarnAboutMaps,
+            'Using Maps as children is unsupported and will likely yield ' +
+              'unexpected results. Convert it to a sequence/iterable of keyed ' +
+              'ReactElements instead.'
+          );
+          didWarnAboutMaps = true;
+        }
+      }
+
+      var iterator = iteratorFn.call(children);
+      var step;
+      var ii = 0;
+      while (!(step = iterator.next()).done) {
+        child = step.value;
+        nextName = nextNamePrefix + getComponentKey(child, ii++);
+        subtreeCount += traverseAllChildrenImpl(
+          child,
+          nextName,
+          callback,
+          traverseContext
+        );
+      }
+    } else if (type === 'object') {
+      var addendum = '';
+      if (process.env.NODE_ENV !== 'production') {
+        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.';
+      }
+      var childrenString = '' + children;
+      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
+      );
+    }
+  }
+
+  return subtreeCount;
+}
+
+function traverseAllChildren(children, callback, traverseContext) {
+  if (children == null) {
+    return 0;
+  }
+
+  return traverseAllChildrenImpl(children, '', callback, traverseContext);
+}
+
+var userProvidedKeyEscapeRegex = /\/+/g;
+function escapeUserProvidedKey(text) {
+  return ('' + text).replace(userProvidedKeyEscapeRegex, '$&/');
+}
+
+function cloneAndReplaceKey(oldElement, newKey) {
+  return React.cloneElement(
+    oldElement,
+    {key: newKey},
+    oldElement.props !== undefined ? oldElement.props.children : undefined
+  );
+}
+
+var DEFAULT_POOL_SIZE = 10;
+var DEFAULT_POOLER = oneArgumentPooler;
+
+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 addPoolingTo = function addPoolingTo(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 standardReleaser = function standardReleaser(instance) {
+  var Klass = this;
+  invariant(
+    instance instanceof Klass,
+    'Trying to release an instance into a pool of a different type.'
+  );
+  instance.destructor();
+  if (Klass.instancePool.length < Klass.poolSize) {
+    Klass.instancePool.push(instance);
+  }
+};
+
+var fourArgumentPooler = function fourArgumentPooler(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);
+  }
+};
+
+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;
+};
+addPoolingTo(MapBookKeeping, fourArgumentPooler);
+
+function mapSingleChildIntoContext(bookKeeping, child, childKey) {
+  var result = bookKeeping.result;
+  var keyPrefix = bookKeeping.keyPrefix;
+  var func = bookKeeping.func;
+  var 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 (React.isValidElement(mappedChild)) {
+      mappedChild = 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);
+}
+
+var numericPropertyRegex = /^\d+$/;
+
+var warnedAboutNumeric = false;
+
+function createReactFragment(object) {
+  if (typeof object !== 'object' || !object || Array.isArray(object)) {
+    warning(
+      false,
+      'React.addons.createFragment only accepts a single object. Got: %s',
+      object
+    );
+    return object;
+  }
+  if (React.isValidElement(object)) {
+    warning(
+      false,
+      'React.addons.createFragment does not accept a ReactElement ' +
+        'without a wrapper object.'
+    );
+    return object;
+  }
+
+  invariant(
+    object.nodeType !== 1,
+    'React.addons.createFragment(...): Encountered an invalid child; DOM ' +
+      'elements are not valid children of React components.'
+  );
+
+  var result = [];
+
+  for (var key in object) {
+    if (process.env.NODE_ENV !== 'production') {
+      if (!warnedAboutNumeric && numericPropertyRegex.test(key)) {
+        warning(
+          false,
+          'React.addons.createFragment(...): Child objects should have ' +
+            'non-numeric keys so ordering is preserved.'
+        );
+        warnedAboutNumeric = true;
+      }
+    }
+    mapIntoWithKeyPrefixInternal(
+      object[key],
+      result,
+      key,
+      emptyFunction.thatReturnsArgument
+    );
+  }
+
+  return result;
+}
+
+module.exports = createReactFragment;
diff --git a/addons/react-addons-create-fragment/package.json b/addons/react-addons-create-fragment/package.json
new file mode 100644
index 000000000000..5d55cb8e2ae1
--- /dev/null
+++ b/addons/react-addons-create-fragment/package.json
@@ -0,0 +1,42 @@
+{
+  "name": "react-addons-create-fragment",
+  "version": "15.6.0",
+  "main": "index.js",
+  "repository": "facebook/react",
+  "keywords": [
+    "react",
+    "react-addon"
+  ],
+  "license": "BSD-3-Clause",
+  "dependencies": {
+    "fbjs": "^0.8.4",
+    "loose-envify": "^1.3.1",
+    "object-assign": "^4.1.0"
+  },
+  "files": [
+    "LICENSE",
+    "PATENTS",
+    "README.md",
+    "index.js",
+    "react-addons-create-fragment.js",
+    "react-addons-create-fragment.min.js"
+  ],
+  "scripts": {
+    "test": "TEST_ENTRY=./index.js jest",
+    "build:dev": "NODE_ENV=development webpack && TEST_ENTRY=./react-addons-create-fragment.js jest",
+    "build:prod": "NODE_ENV=production webpack && NODE_ENV=production TEST_ENTRY=./react-addons-create-fragment.min.js jest",
+    "build": "npm run build:dev && npm run build:prod && node ../postbuild.js",
+    "prepublish": "npm test && npm run build"
+  },
+  "devDependencies": {
+    "jest": "^19.0.2",
+    "react": "^15.4.2",
+    "react-dom": "^15.4.2",
+    "webpack": "^2.6.1"
+  },
+  "browserify": {
+    "transform": [
+      "loose-envify"
+    ]
+  }
+}
diff --git a/addons/react-addons-create-fragment/test.js b/addons/react-addons-create-fragment/test.js
new file mode 100644
index 000000000000..97e928fe226a
--- /dev/null
+++ b/addons/react-addons-create-fragment/test.js
@@ -0,0 +1,133 @@
+/**
+ * Copyright 2015-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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var React;
+var createReactFragment;
+
+// Catch stray warnings
+var env = jasmine.getEnv();
+var callCount = 0;
+var oldError = console.error;
+var newError = function() {
+  callCount++;
+  oldError.apply(this, arguments);
+};
+console.error = newError;
+env.beforeEach(() => {
+  callCount = 0;
+  jasmine.addMatchers({
+    toBeReset() {
+      return {
+        compare(actual) {
+          if (actual !== newError && !jasmine.isSpy(actual)) {
+            return {
+              pass: false,
+              message: 'Test did not tear down console.error mock properly.'
+            };
+          }
+          return {pass: true};
+        }
+      };
+    },
+    toNotHaveBeenCalled() {
+      return {
+        compare(actual) {
+          return {
+            pass: callCount === 0,
+            message:
+              'Expected test not to warn. If the warning is expected, mock ' +
+                "it out using spyOn(console, 'error'); and test that the " +
+                'warning occurs.'
+          };
+        }
+      };
+    }
+  });
+});
+env.afterEach(() => {
+  expect(console.error).toBeReset();
+  expect(console.error).toNotHaveBeenCalled();
+});
+
+// Suppress warning expectations for prod builds
+function suppressDevMatcher(obj, name) {
+  const original = obj[name];
+  obj[name] = function devMatcher() {
+    try {
+      original.apply(this, arguments);
+    } catch (e) {
+      // skip
+    }
+  };
+}
+function expectDev(actual) {
+  const expectation = expect(actual);
+  if (process.env.NODE_ENV === 'production') {
+    Object.keys(expectation).forEach(name => {
+      suppressDevMatcher(expectation, name);
+      suppressDevMatcher(expectation.not, name);
+    });
+  }
+  return expectation;
+}
+
+describe('createReactFragment', () => {
+  beforeEach(() => {
+    jest.resetModules();
+
+    React = require('react');
+    createReactFragment = require(process.env.TEST_ENTRY);
+  });
+
+  it('warns for numeric keys on objects as children', () => {
+    spyOn(console, 'error');
+
+    createReactFragment({
+      1: React.createElement('span'),
+      2: React.createElement('span')
+    });
+
+    expectDev(console.error.calls.count()).toBe(1);
+    expectDev(console.error.calls.argsFor(0)[0]).toContain(
+      'Child objects should have non-numeric keys so ordering is preserved.'
+    );
+  });
+
+  it('should warn if passing null to createFragment', () => {
+    spyOn(console, 'error');
+    createReactFragment(null);
+    expectDev(console.error.calls.count()).toBe(1);
+    expectDev(console.error.calls.argsFor(0)[0]).toContain(
+      'React.addons.createFragment only accepts a single object.'
+    );
+  });
+
+  it('should warn if passing an array to createFragment', () => {
+    spyOn(console, 'error');
+    createReactFragment([]);
+    expectDev(console.error.calls.count()).toBe(1);
+    expectDev(console.error.calls.argsFor(0)[0]).toContain(
+      'React.addons.createFragment only accepts a single object.'
+    );
+  });
+
+  it('should warn if passing a ReactElement to createFragment', () => {
+    spyOn(console, 'error');
+    createReactFragment(React.createElement('div'));
+    expectDev(console.error.calls.count()).toBe(1);
+    expectDev(console.error.calls.argsFor(0)[0]).toContain(
+      'React.addons.createFragment does not accept a ReactElement without a ' +
+        'wrapper object.'
+    );
+  });
+});
diff --git a/addons/react-addons-create-fragment/webpack.config.js b/addons/react-addons-create-fragment/webpack.config.js
new file mode 100644
index 000000000000..bf3bf4064f5c
--- /dev/null
+++ b/addons/react-addons-create-fragment/webpack.config.js
@@ -0,0 +1,63 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+const webpack = require('webpack');
+
+let __DEV__;
+switch (process.env.NODE_ENV) {
+  case 'development':
+    __DEV__ = true;
+    break;
+  case 'production':
+    __DEV__ = false;
+    break;
+  default:
+    throw new Error('Unknown environment.');
+}
+
+module.exports = {
+  entry: './index',
+  output: {
+    library: 'createFragment',
+    libraryTarget: 'umd',
+    filename: __DEV__
+      ? 'react-addons-create-fragment.js'
+      : 'react-addons-create-fragment.min.js'
+  },
+  externals: {
+    react: {
+      root: 'React',
+      commonjs2: 'react',
+      commonjs: 'react',
+      amd: 'react'
+    }
+  },
+  plugins: [
+    new webpack.DefinePlugin({
+      'process.env.NODE_ENV': __DEV__ ? '"development"' : '"production"'
+    })
+  ].concat(
+    __DEV__
+      ? []
+      : [
+          new webpack.optimize.UglifyJsPlugin({
+            compress: {
+              warnings: false
+            },
+            output: {
+              comments: false
+            }
+          })
+        ]
+  )
+};
diff --git a/addons/react-addons-create-fragment/yarn.lock b/addons/react-addons-create-fragment/yarn.lock
new file mode 100644
index 000000000000..8d0c6421c555
--- /dev/null
+++ b/addons/react-addons-create-fragment/yarn.lock
@@ -0,0 +1,2827 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+abab@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.3.tgz#b81de5f7274ec4e756d797cd834f303642724e5d"
+
+abbrev@1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f"
+
+acorn-dynamic-import@^2.0.0:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz#c752bd210bef679501b6c6cb7fc84f8f47158cc4"
+  dependencies:
+    acorn "^4.0.3"
+
+acorn-globals@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-3.1.0.tgz#fd8270f71fbb4996b004fa880ee5d46573a731bf"
+  dependencies:
+    acorn "^4.0.4"
+
+acorn@^4.0.3, acorn@^4.0.4:
+  version "4.0.11"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.11.tgz#edcda3bd937e7556410d42ed5860f67399c794c0"
+
+acorn@^5.0.0:
+  version "5.0.3"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.0.3.tgz#c460df08491463f028ccb82eab3730bf01087b3d"
+
+ajv-keywords@^1.1.1:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c"
+
+ajv@^4.7.0, ajv@^4.9.1:
+  version "4.11.5"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.5.tgz#b6ee74657b993a01dce44b7944d56f485828d5bd"
+  dependencies:
+    co "^4.6.0"
+    json-stable-stringify "^1.0.1"
+
+align-text@^0.1.1, align-text@^0.1.3:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
+  dependencies:
+    kind-of "^3.0.2"
+    longest "^1.0.1"
+    repeat-string "^1.5.2"
+
+amdefine@>=0.0.4:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
+
+ansi-escapes@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
+
+ansi-regex@^2.0.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
+
+ansi-styles@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
+
+ansi-styles@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.0.0.tgz#5404e93a544c4fec7f048262977bebfe3155e0c1"
+  dependencies:
+    color-convert "^1.0.0"
+
+anymatch@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507"
+  dependencies:
+    arrify "^1.0.0"
+    micromatch "^2.1.5"
+
+append-transform@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-0.4.0.tgz#d76ebf8ca94d276e247a36bad44a4b74ab611991"
+  dependencies:
+    default-require-extensions "^1.0.0"
+
+aproba@^1.0.3:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.2.tgz#45c6629094de4e96f693ef7eab74ae079c240fc1"
+
+are-we-there-yet@~1.1.2:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d"
+  dependencies:
+    delegates "^1.0.0"
+    readable-stream "^2.0.6"
+
+argparse@^1.0.7:
+  version "1.0.9"
+  resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86"
+  dependencies:
+    sprintf-js "~1.0.2"
+
+arr-diff@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf"
+  dependencies:
+    arr-flatten "^1.0.1"
+
+arr-flatten@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b"
+
+array-equal@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93"
+
+array-unique@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
+
+arrify@^1.0.0, arrify@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
+
+asap@~2.0.3:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f"
+
+asn1.js@^4.0.0:
+  version "4.9.1"
+  resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.1.tgz#48ba240b45a9280e94748990ba597d216617fd40"
+  dependencies:
+    bn.js "^4.0.0"
+    inherits "^2.0.1"
+    minimalistic-assert "^1.0.0"
+
+asn1@~0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86"
+
+assert-plus@1.0.0, assert-plus@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
+
+assert-plus@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234"
+
+assert@^1.1.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91"
+  dependencies:
+    util "0.10.3"
+
+async-each@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
+
+async@^1.4.0:
+  version "1.5.2"
+  resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
+
+async@^2.1.2, async@^2.1.4:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/async/-/async-2.3.0.tgz#1013d1051047dd320fe24e494d5c66ecaf6147d9"
+  dependencies:
+    lodash "^4.14.0"
+
+asynckit@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+
+aws-sign2@~0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f"
+
+aws4@^1.2.1:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e"
+
+babel-code-frame@^6.22.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4"
+  dependencies:
+    chalk "^1.1.0"
+    esutils "^2.0.2"
+    js-tokens "^3.0.0"
+
+babel-core@^6.0.0, babel-core@^6.24.0:
+  version "6.24.0"
+  resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.24.0.tgz#8f36a0a77f5c155aed6f920b844d23ba56742a02"
+  dependencies:
+    babel-code-frame "^6.22.0"
+    babel-generator "^6.24.0"
+    babel-helpers "^6.23.0"
+    babel-messages "^6.23.0"
+    babel-register "^6.24.0"
+    babel-runtime "^6.22.0"
+    babel-template "^6.23.0"
+    babel-traverse "^6.23.1"
+    babel-types "^6.23.0"
+    babylon "^6.11.0"
+    convert-source-map "^1.1.0"
+    debug "^2.1.1"
+    json5 "^0.5.0"
+    lodash "^4.2.0"
+    minimatch "^3.0.2"
+    path-is-absolute "^1.0.0"
+    private "^0.1.6"
+    slash "^1.0.0"
+    source-map "^0.5.0"
+
+babel-generator@^6.18.0, babel-generator@^6.24.0:
+  version "6.24.0"
+  resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.24.0.tgz#eba270a8cc4ce6e09a61be43465d7c62c1f87c56"
+  dependencies:
+    babel-messages "^6.23.0"
+    babel-runtime "^6.22.0"
+    babel-types "^6.23.0"
+    detect-indent "^4.0.0"
+    jsesc "^1.3.0"
+    lodash "^4.2.0"
+    source-map "^0.5.0"
+    trim-right "^1.0.1"
+
+babel-helpers@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.23.0.tgz#4f8f2e092d0b6a8808a4bde79c27f1e2ecf0d992"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-template "^6.23.0"
+
+babel-jest@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-19.0.0.tgz#59323ced99a3a84d359da219ca881074ffc6ce3f"
+  dependencies:
+    babel-core "^6.0.0"
+    babel-plugin-istanbul "^4.0.0"
+    babel-preset-jest "^19.0.0"
+
+babel-messages@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e"
+  dependencies:
+    babel-runtime "^6.22.0"
+
+babel-plugin-istanbul@^4.0.0:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.1.tgz#c12de0fc6fe42adfb16be56f1ad11e4a9782eca9"
+  dependencies:
+    find-up "^2.1.0"
+    istanbul-lib-instrument "^1.6.2"
+    test-exclude "^4.0.3"
+
+babel-plugin-jest-hoist@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-19.0.0.tgz#4ae2a04ea612a6e73651f3fde52c178991304bea"
+
+babel-preset-jest@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-19.0.0.tgz#22d67201d02324a195811288eb38294bb3cac396"
+  dependencies:
+    babel-plugin-jest-hoist "^19.0.0"
+
+babel-register@^6.24.0:
+  version "6.24.0"
+  resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.24.0.tgz#5e89f8463ba9970356d02eb07dabe3308b080cfd"
+  dependencies:
+    babel-core "^6.24.0"
+    babel-runtime "^6.22.0"
+    core-js "^2.4.0"
+    home-or-tmp "^2.0.0"
+    lodash "^4.2.0"
+    mkdirp "^0.5.1"
+    source-map-support "^0.4.2"
+
+babel-runtime@^6.22.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b"
+  dependencies:
+    core-js "^2.4.0"
+    regenerator-runtime "^0.10.0"
+
+babel-template@^6.16.0, babel-template@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.23.0.tgz#04d4f270adbb3aa704a8143ae26faa529238e638"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-traverse "^6.23.0"
+    babel-types "^6.23.0"
+    babylon "^6.11.0"
+    lodash "^4.2.0"
+
+babel-traverse@^6.18.0, babel-traverse@^6.23.0, babel-traverse@^6.23.1:
+  version "6.23.1"
+  resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.23.1.tgz#d3cb59010ecd06a97d81310065f966b699e14f48"
+  dependencies:
+    babel-code-frame "^6.22.0"
+    babel-messages "^6.23.0"
+    babel-runtime "^6.22.0"
+    babel-types "^6.23.0"
+    babylon "^6.15.0"
+    debug "^2.2.0"
+    globals "^9.0.0"
+    invariant "^2.2.0"
+    lodash "^4.2.0"
+
+babel-types@^6.18.0, babel-types@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.23.0.tgz#bb17179d7538bad38cd0c9e115d340f77e7e9acf"
+  dependencies:
+    babel-runtime "^6.22.0"
+    esutils "^2.0.2"
+    lodash "^4.2.0"
+    to-fast-properties "^1.0.1"
+
+babylon@^6.11.0, babylon@^6.13.0, babylon@^6.15.0:
+  version "6.16.1"
+  resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.16.1.tgz#30c5a22f481978a9e7f8cdfdf496b11d94b404d3"
+
+balanced-match@^0.4.1:
+  version "0.4.2"
+  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
+
+base64-js@^1.0.2:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1"
+
+bcrypt-pbkdf@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d"
+  dependencies:
+    tweetnacl "^0.14.3"
+
+big.js@^3.1.3:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.1.3.tgz#4cada2193652eb3ca9ec8e55c9015669c9806978"
+
+binary-extensions@^1.0.0:
+  version "1.8.0"
+  resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.8.0.tgz#48ec8d16df4377eae5fa5884682480af4d95c774"
+
+block-stream@*:
+  version "0.0.9"
+  resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a"
+  dependencies:
+    inherits "~2.0.0"
+
+bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0:
+  version "4.11.6"
+  resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215"
+
+boom@2.x.x:
+  version "2.10.1"
+  resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f"
+  dependencies:
+    hoek "2.x.x"
+
+brace-expansion@^1.0.0:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9"
+  dependencies:
+    balanced-match "^0.4.1"
+    concat-map "0.0.1"
+
+braces@^1.8.2:
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7"
+  dependencies:
+    expand-range "^1.8.1"
+    preserve "^0.2.0"
+    repeat-element "^1.1.2"
+
+brorand@^1.0.1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
+
+browser-resolve@^1.11.2:
+  version "1.11.2"
+  resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.2.tgz#8ff09b0a2c421718a1051c260b32e48f442938ce"
+  dependencies:
+    resolve "1.1.7"
+
+browserify-aes@^1.0.0, browserify-aes@^1.0.4:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.0.6.tgz#5e7725dbdef1fd5930d4ebab48567ce451c48a0a"
+  dependencies:
+    buffer-xor "^1.0.2"
+    cipher-base "^1.0.0"
+    create-hash "^1.1.0"
+    evp_bytestokey "^1.0.0"
+    inherits "^2.0.1"
+
+browserify-cipher@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.0.tgz#9988244874bf5ed4e28da95666dcd66ac8fc363a"
+  dependencies:
+    browserify-aes "^1.0.4"
+    browserify-des "^1.0.0"
+    evp_bytestokey "^1.0.0"
+
+browserify-des@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.0.tgz#daa277717470922ed2fe18594118a175439721dd"
+  dependencies:
+    cipher-base "^1.0.1"
+    des.js "^1.0.0"
+    inherits "^2.0.1"
+
+browserify-rsa@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524"
+  dependencies:
+    bn.js "^4.1.0"
+    randombytes "^2.0.1"
+
+browserify-sign@^4.0.0:
+  version "4.0.4"
+  resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298"
+  dependencies:
+    bn.js "^4.1.1"
+    browserify-rsa "^4.0.0"
+    create-hash "^1.1.0"
+    create-hmac "^1.1.2"
+    elliptic "^6.0.0"
+    inherits "^2.0.1"
+    parse-asn1 "^5.0.0"
+
+browserify-zlib@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d"
+  dependencies:
+    pako "~0.2.0"
+
+bser@1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/bser/-/bser-1.0.2.tgz#381116970b2a6deea5646dd15dd7278444b56169"
+  dependencies:
+    node-int64 "^0.4.0"
+
+bser@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719"
+  dependencies:
+    node-int64 "^0.4.0"
+
+buffer-xor@^1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9"
+
+buffer@^4.3.0:
+  version "4.9.1"
+  resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298"
+  dependencies:
+    base64-js "^1.0.2"
+    ieee754 "^1.1.4"
+    isarray "^1.0.0"
+
+builtin-modules@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
+
+builtin-status-codes@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
+
+callsites@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50"
+
+camelcase@^1.0.2:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39"
+
+camelcase@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
+
+caseless@~0.12.0:
+  version "0.12.0"
+  resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
+
+center-align@^0.1.1:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad"
+  dependencies:
+    align-text "^0.1.3"
+    lazy-cache "^1.0.3"
+
+chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
+  dependencies:
+    ansi-styles "^2.2.1"
+    escape-string-regexp "^1.0.2"
+    has-ansi "^2.0.0"
+    strip-ansi "^3.0.0"
+    supports-color "^2.0.0"
+
+chokidar@^1.4.3:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
+  dependencies:
+    anymatch "^1.3.0"
+    async-each "^1.0.0"
+    glob-parent "^2.0.0"
+    inherits "^2.0.1"
+    is-binary-path "^1.0.0"
+    is-glob "^2.0.0"
+    path-is-absolute "^1.0.0"
+    readdirp "^2.0.0"
+  optionalDependencies:
+    fsevents "^1.0.0"
+
+ci-info@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.0.0.tgz#dc5285f2b4e251821683681c381c3388f46ec534"
+
+cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.3.tgz#eeabf194419ce900da3018c207d212f2a6df0a07"
+  dependencies:
+    inherits "^2.0.1"
+
+cliui@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1"
+  dependencies:
+    center-align "^0.1.1"
+    right-align "^0.1.1"
+    wordwrap "0.0.2"
+
+cliui@^3.2.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
+  dependencies:
+    string-width "^1.0.1"
+    strip-ansi "^3.0.1"
+    wrap-ansi "^2.0.0"
+
+co@^4.6.0:
+  version "4.6.0"
+  resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
+
+code-point-at@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
+
+color-convert@^1.0.0:
+  version "1.9.0"
+  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a"
+  dependencies:
+    color-name "^1.1.1"
+
+color-name@^1.1.1:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.2.tgz#5c8ab72b64bd2215d617ae9559ebb148475cf98d"
+
+combined-stream@^1.0.5, combined-stream@~1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009"
+  dependencies:
+    delayed-stream "~1.0.0"
+
+concat-map@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+
+console-browserify@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10"
+  dependencies:
+    date-now "^0.1.4"
+
+console-control-strings@^1.0.0, console-control-strings@~1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
+
+constants-browserify@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
+
+content-type-parser@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/content-type-parser/-/content-type-parser-1.0.1.tgz#c3e56988c53c65127fb46d4032a3a900246fdc94"
+
+convert-source-map@^1.1.0:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5"
+
+core-js@^1.0.0:
+  version "1.2.7"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
+
+core-js@^2.4.0:
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e"
+
+core-util-is@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
+
+create-ecdh@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.0.tgz#888c723596cdf7612f6498233eebd7a35301737d"
+  dependencies:
+    bn.js "^4.1.0"
+    elliptic "^6.0.0"
+
+create-hash@^1.1.0, create-hash@^1.1.1, create-hash@^1.1.2:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.3.tgz#606042ac8b9262750f483caddab0f5819172d8fd"
+  dependencies:
+    cipher-base "^1.0.1"
+    inherits "^2.0.1"
+    ripemd160 "^2.0.0"
+    sha.js "^2.4.0"
+
+create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.6.tgz#acb9e221a4e17bdb076e90657c42b93e3726cf06"
+  dependencies:
+    cipher-base "^1.0.3"
+    create-hash "^1.1.0"
+    inherits "^2.0.1"
+    ripemd160 "^2.0.0"
+    safe-buffer "^5.0.1"
+    sha.js "^2.4.8"
+
+cryptiles@2.x.x:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8"
+  dependencies:
+    boom "2.x.x"
+
+crypto-browserify@^3.11.0:
+  version "3.11.0"
+  resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.11.0.tgz#3652a0906ab9b2a7e0c3ce66a408e957a2485522"
+  dependencies:
+    browserify-cipher "^1.0.0"
+    browserify-sign "^4.0.0"
+    create-ecdh "^4.0.0"
+    create-hash "^1.1.0"
+    create-hmac "^1.1.0"
+    diffie-hellman "^5.0.0"
+    inherits "^2.0.1"
+    pbkdf2 "^3.0.3"
+    public-encrypt "^4.0.0"
+    randombytes "^2.0.0"
+
+cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0":
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.2.tgz#b8036170c79f07a90ff2f16e22284027a243848b"
+
+"cssstyle@>= 0.2.37 < 0.3.0":
+  version "0.2.37"
+  resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-0.2.37.tgz#541097234cb2513c83ceed3acddc27ff27987d54"
+  dependencies:
+    cssom "0.3.x"
+
+dashdash@^1.12.0:
+  version "1.14.1"
+  resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
+  dependencies:
+    assert-plus "^1.0.0"
+
+date-now@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
+
+debug@^2.1.1, debug@^2.2.0:
+  version "2.6.3"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.3.tgz#0f7eb8c30965ec08c72accfa0130c8b79984141d"
+  dependencies:
+    ms "0.7.2"
+
+decamelize@^1.0.0, decamelize@^1.1.1:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
+
+deep-extend@~0.4.0:
+  version "0.4.2"
+  resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f"
+
+deep-is@~0.1.3:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
+
+default-require-extensions@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8"
+  dependencies:
+    strip-bom "^2.0.0"
+
+delayed-stream@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+
+delegates@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
+
+des.js@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc"
+  dependencies:
+    inherits "^2.0.1"
+    minimalistic-assert "^1.0.0"
+
+detect-indent@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208"
+  dependencies:
+    repeating "^2.0.0"
+
+diff@^3.0.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9"
+
+diffie-hellman@^5.0.0:
+  version "5.0.2"
+  resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.2.tgz#b5835739270cfe26acf632099fded2a07f209e5e"
+  dependencies:
+    bn.js "^4.1.0"
+    miller-rabin "^4.0.0"
+    randombytes "^2.0.0"
+
+domain-browser@^1.1.1:
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc"
+
+ecc-jsbn@~0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505"
+  dependencies:
+    jsbn "~0.1.0"
+
+elliptic@^6.0.0:
+  version "6.4.0"
+  resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df"
+  dependencies:
+    bn.js "^4.4.0"
+    brorand "^1.0.1"
+    hash.js "^1.0.0"
+    hmac-drbg "^1.0.0"
+    inherits "^2.0.1"
+    minimalistic-assert "^1.0.0"
+    minimalistic-crypto-utils "^1.0.0"
+
+emojis-list@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
+
+encoding@^0.1.11:
+  version "0.1.12"
+  resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb"
+  dependencies:
+    iconv-lite "~0.4.13"
+
+enhanced-resolve@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.1.0.tgz#9f4b626f577245edcf4b2ad83d86e17f4f421dec"
+  dependencies:
+    graceful-fs "^4.1.2"
+    memory-fs "^0.4.0"
+    object-assign "^4.0.1"
+    tapable "^0.2.5"
+
+"errno@>=0.1.1 <0.2.0-0", errno@^0.1.3:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d"
+  dependencies:
+    prr "~0.0.0"
+
+error-ex@^1.2.0:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc"
+  dependencies:
+    is-arrayish "^0.2.1"
+
+escape-string-regexp@^1.0.2:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+
+escodegen@^1.6.1:
+  version "1.8.1"
+  resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018"
+  dependencies:
+    esprima "^2.7.1"
+    estraverse "^1.9.1"
+    esutils "^2.0.2"
+    optionator "^0.8.1"
+  optionalDependencies:
+    source-map "~0.2.0"
+
+esprima@^2.7.1:
+  version "2.7.3"
+  resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
+
+esprima@^3.1.1:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633"
+
+estraverse@^1.9.1:
+  version "1.9.3"
+  resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44"
+
+esutils@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
+
+events@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924"
+
+evp_bytestokey@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.0.tgz#497b66ad9fef65cd7c08a6180824ba1476b66e53"
+  dependencies:
+    create-hash "^1.1.1"
+
+exec-sh@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.0.tgz#14f75de3f20d286ef933099b2ce50a90359cef10"
+  dependencies:
+    merge "^1.1.3"
+
+expand-brackets@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
+  dependencies:
+    is-posix-bracket "^0.1.0"
+
+expand-range@^1.8.1:
+  version "1.8.2"
+  resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337"
+  dependencies:
+    fill-range "^2.1.0"
+
+extend@~3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4"
+
+extglob@^0.3.1:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1"
+  dependencies:
+    is-extglob "^1.0.0"
+
+extsprintf@1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550"
+
+fast-levenshtein@~2.0.4:
+  version "2.0.6"
+  resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
+
+fb-watchman@^1.8.0:
+  version "1.9.2"
+  resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-1.9.2.tgz#a24cf47827f82d38fb59a69ad70b76e3b6ae7383"
+  dependencies:
+    bser "1.0.2"
+
+fb-watchman@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58"
+  dependencies:
+    bser "^2.0.0"
+
+fbjs@^0.8.1, fbjs@^0.8.4:
+  version "0.8.12"
+  resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.12.tgz#10b5d92f76d45575fd63a217d4ea02bea2f8ed04"
+  dependencies:
+    core-js "^1.0.0"
+    isomorphic-fetch "^2.1.1"
+    loose-envify "^1.0.0"
+    object-assign "^4.1.0"
+    promise "^7.1.1"
+    setimmediate "^1.0.5"
+    ua-parser-js "^0.7.9"
+
+filename-regex@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775"
+
+fileset@^2.0.2:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/fileset/-/fileset-2.0.3.tgz#8e7548a96d3cc2327ee5e674168723a333bba2a0"
+  dependencies:
+    glob "^7.0.3"
+    minimatch "^3.0.3"
+
+fill-range@^2.1.0:
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723"
+  dependencies:
+    is-number "^2.1.0"
+    isobject "^2.0.0"
+    randomatic "^1.1.3"
+    repeat-element "^1.1.2"
+    repeat-string "^1.5.2"
+
+find-up@^1.0.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
+  dependencies:
+    path-exists "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+find-up@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
+  dependencies:
+    locate-path "^2.0.0"
+
+for-in@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
+
+for-own@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce"
+  dependencies:
+    for-in "^1.0.1"
+
+forever-agent@~0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
+
+form-data@~2.1.1:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4"
+  dependencies:
+    asynckit "^0.4.0"
+    combined-stream "^1.0.5"
+    mime-types "^2.1.12"
+
+fs.realpath@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+
+fsevents@^1.0.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.2.tgz#3282b713fb3ad80ede0e9fcf4611b5aa6fc033f4"
+  dependencies:
+    nan "^2.3.0"
+    node-pre-gyp "^0.6.36"
+
+fstream-ignore@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105"
+  dependencies:
+    fstream "^1.0.0"
+    inherits "2"
+    minimatch "^3.0.0"
+
+fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2:
+  version "1.0.11"
+  resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171"
+  dependencies:
+    graceful-fs "^4.1.2"
+    inherits "~2.0.0"
+    mkdirp ">=0.5 0"
+    rimraf "2"
+
+gauge@~2.7.3:
+  version "2.7.4"
+  resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
+  dependencies:
+    aproba "^1.0.3"
+    console-control-strings "^1.0.0"
+    has-unicode "^2.0.0"
+    object-assign "^4.1.0"
+    signal-exit "^3.0.0"
+    string-width "^1.0.1"
+    strip-ansi "^3.0.1"
+    wide-align "^1.1.0"
+
+get-caller-file@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5"
+
+getpass@^0.1.1:
+  version "0.1.6"
+  resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6"
+  dependencies:
+    assert-plus "^1.0.0"
+
+glob-base@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
+  dependencies:
+    glob-parent "^2.0.0"
+    is-glob "^2.0.0"
+
+glob-parent@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28"
+  dependencies:
+    is-glob "^2.0.0"
+
+glob@^7.0.3, glob@^7.0.5:
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
+  dependencies:
+    fs.realpath "^1.0.0"
+    inflight "^1.0.4"
+    inherits "2"
+    minimatch "^3.0.2"
+    once "^1.3.0"
+    path-is-absolute "^1.0.0"
+
+globals@^9.0.0:
+  version "9.17.0"
+  resolved "https://registry.yarnpkg.com/globals/-/globals-9.17.0.tgz#0c0ca696d9b9bb694d2e5470bd37777caad50286"
+
+graceful-fs@^4.1.2, graceful-fs@^4.1.6:
+  version "4.1.11"
+  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
+
+growly@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
+
+handlebars@^4.0.3:
+  version "4.0.6"
+  resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7"
+  dependencies:
+    async "^1.4.0"
+    optimist "^0.6.1"
+    source-map "^0.4.4"
+  optionalDependencies:
+    uglify-js "^2.6"
+
+har-schema@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e"
+
+har-validator@~4.2.1:
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a"
+  dependencies:
+    ajv "^4.9.1"
+    har-schema "^1.0.5"
+
+has-ansi@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
+  dependencies:
+    ansi-regex "^2.0.0"
+
+has-flag@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
+
+has-unicode@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
+
+hash-base@^2.0.0:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1"
+  dependencies:
+    inherits "^2.0.1"
+
+hash.js@^1.0.0, hash.js@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.0.3.tgz#1332ff00156c0a0ffdd8236013d07b77a0451573"
+  dependencies:
+    inherits "^2.0.1"
+
+hawk@~3.1.3:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4"
+  dependencies:
+    boom "2.x.x"
+    cryptiles "2.x.x"
+    hoek "2.x.x"
+    sntp "1.x.x"
+
+hmac-drbg@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
+  dependencies:
+    hash.js "^1.0.3"
+    minimalistic-assert "^1.0.0"
+    minimalistic-crypto-utils "^1.0.1"
+
+hoek@2.x.x:
+  version "2.16.3"
+  resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed"
+
+home-or-tmp@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8"
+  dependencies:
+    os-homedir "^1.0.0"
+    os-tmpdir "^1.0.1"
+
+hosted-git-info@^2.1.4:
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.4.1.tgz#4b0445e41c004a8bd1337773a4ff790ca40318c8"
+
+html-encoding-sniffer@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.1.tgz#79bf7a785ea495fe66165e734153f363ff5437da"
+  dependencies:
+    whatwg-encoding "^1.0.1"
+
+http-signature@~1.1.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf"
+  dependencies:
+    assert-plus "^0.2.0"
+    jsprim "^1.2.2"
+    sshpk "^1.7.0"
+
+https-browserify@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82"
+
+iconv-lite@0.4.13:
+  version "0.4.13"
+  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2"
+
+iconv-lite@~0.4.13:
+  version "0.4.15"
+  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb"
+
+ieee754@^1.1.4:
+  version "1.1.8"
+  resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4"
+
+indexof@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d"
+
+inflight@^1.0.4:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+  dependencies:
+    once "^1.3.0"
+    wrappy "1"
+
+inherits@2, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
+
+inherits@2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
+
+ini@~1.3.0:
+  version "1.3.4"
+  resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e"
+
+interpret@^1.0.0:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.3.tgz#cbc35c62eeee73f19ab7b10a801511401afc0f90"
+
+invariant@^2.2.0:
+  version "2.2.2"
+  resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360"
+  dependencies:
+    loose-envify "^1.0.0"
+
+invert-kv@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
+
+is-arrayish@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
+
+is-binary-path@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
+  dependencies:
+    binary-extensions "^1.0.0"
+
+is-buffer@^1.0.2:
+  version "1.1.5"
+  resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc"
+
+is-builtin-module@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe"
+  dependencies:
+    builtin-modules "^1.0.0"
+
+is-ci@^1.0.9:
+  version "1.0.10"
+  resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.0.10.tgz#f739336b2632365061a9d48270cd56ae3369318e"
+  dependencies:
+    ci-info "^1.0.0"
+
+is-dotfile@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d"
+
+is-equal-shallow@^0.1.3:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534"
+  dependencies:
+    is-primitive "^2.0.0"
+
+is-extendable@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
+
+is-extglob@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
+
+is-finite@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa"
+  dependencies:
+    number-is-nan "^1.0.0"
+
+is-fullwidth-code-point@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
+  dependencies:
+    number-is-nan "^1.0.0"
+
+is-glob@^2.0.0, is-glob@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
+  dependencies:
+    is-extglob "^1.0.0"
+
+is-number@^2.0.2, is-number@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
+  dependencies:
+    kind-of "^3.0.2"
+
+is-posix-bracket@^0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
+
+is-primitive@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
+
+is-stream@^1.0.1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
+
+is-typedarray@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
+
+is-utf8@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
+
+isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
+
+isexe@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+
+isobject@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
+  dependencies:
+    isarray "1.0.0"
+
+isomorphic-fetch@^2.1.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
+  dependencies:
+    node-fetch "^1.0.1"
+    whatwg-fetch ">=0.10.0"
+
+isstream@~0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
+
+istanbul-api@^1.1.0-alpha.1:
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-1.1.7.tgz#f6f37f09f8002b130f891c646b70ee4a8e7345ae"
+  dependencies:
+    async "^2.1.4"
+    fileset "^2.0.2"
+    istanbul-lib-coverage "^1.0.2"
+    istanbul-lib-hook "^1.0.5"
+    istanbul-lib-instrument "^1.7.0"
+    istanbul-lib-report "^1.0.0"
+    istanbul-lib-source-maps "^1.1.1"
+    istanbul-reports "^1.0.2"
+    js-yaml "^3.7.0"
+    mkdirp "^0.5.1"
+    once "^1.4.0"
+
+istanbul-lib-coverage@^1.0.0, istanbul-lib-coverage@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.0.2.tgz#87a0c015b6910651cb3b184814dfb339337e25e1"
+
+istanbul-lib-hook@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.0.5.tgz#6ca3d16d60c5f4082da39f7c5cd38ea8a772b88e"
+  dependencies:
+    append-transform "^0.4.0"
+
+istanbul-lib-instrument@^1.1.1, istanbul-lib-instrument@^1.6.2, istanbul-lib-instrument@^1.7.0:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.7.0.tgz#b8e0dc25709bb44e17336ab47b7bb5c97c23f659"
+  dependencies:
+    babel-generator "^6.18.0"
+    babel-template "^6.16.0"
+    babel-traverse "^6.18.0"
+    babel-types "^6.18.0"
+    babylon "^6.13.0"
+    istanbul-lib-coverage "^1.0.2"
+    semver "^5.3.0"
+
+istanbul-lib-report@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.0.0.tgz#d83dac7f26566b521585569367fe84ccfc7aaecb"
+  dependencies:
+    istanbul-lib-coverage "^1.0.2"
+    mkdirp "^0.5.1"
+    path-parse "^1.0.5"
+    supports-color "^3.1.2"
+
+istanbul-lib-source-maps@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.1.1.tgz#f8c8c2e8f2160d1d91526d97e5bd63b2079af71c"
+  dependencies:
+    istanbul-lib-coverage "^1.0.2"
+    mkdirp "^0.5.1"
+    rimraf "^2.4.4"
+    source-map "^0.5.3"
+
+istanbul-reports@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.0.2.tgz#4e8366abe6fa746cc1cd6633f108de12cc6ac6fa"
+  dependencies:
+    handlebars "^4.0.3"
+
+jest-changed-files@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-19.0.2.tgz#16c54c84c3270be408e06d2e8af3f3e37a885824"
+
+jest-cli@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-19.0.2.tgz#cc3620b62acac5f2d93a548cb6ef697d4ec85443"
+  dependencies:
+    ansi-escapes "^1.4.0"
+    callsites "^2.0.0"
+    chalk "^1.1.1"
+    graceful-fs "^4.1.6"
+    is-ci "^1.0.9"
+    istanbul-api "^1.1.0-alpha.1"
+    istanbul-lib-coverage "^1.0.0"
+    istanbul-lib-instrument "^1.1.1"
+    jest-changed-files "^19.0.2"
+    jest-config "^19.0.2"
+    jest-environment-jsdom "^19.0.2"
+    jest-haste-map "^19.0.0"
+    jest-jasmine2 "^19.0.2"
+    jest-message-util "^19.0.0"
+    jest-regex-util "^19.0.0"
+    jest-resolve-dependencies "^19.0.0"
+    jest-runtime "^19.0.2"
+    jest-snapshot "^19.0.2"
+    jest-util "^19.0.2"
+    micromatch "^2.3.11"
+    node-notifier "^5.0.1"
+    slash "^1.0.0"
+    string-length "^1.0.1"
+    throat "^3.0.0"
+    which "^1.1.1"
+    worker-farm "^1.3.1"
+    yargs "^6.3.0"
+
+jest-config@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-19.0.2.tgz#1b9bd2db0ddd16df61c2b10a54009e1768da6411"
+  dependencies:
+    chalk "^1.1.1"
+    jest-environment-jsdom "^19.0.2"
+    jest-environment-node "^19.0.2"
+    jest-jasmine2 "^19.0.2"
+    jest-regex-util "^19.0.0"
+    jest-resolve "^19.0.2"
+    jest-validate "^19.0.2"
+    pretty-format "^19.0.0"
+
+jest-diff@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-19.0.0.tgz#d1563cfc56c8b60232988fbc05d4d16ed90f063c"
+  dependencies:
+    chalk "^1.1.3"
+    diff "^3.0.0"
+    jest-matcher-utils "^19.0.0"
+    pretty-format "^19.0.0"
+
+jest-environment-jsdom@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-19.0.2.tgz#ceda859c4a4b94ab35e4de7dab54b926f293e4a3"
+  dependencies:
+    jest-mock "^19.0.0"
+    jest-util "^19.0.2"
+    jsdom "^9.11.0"
+
+jest-environment-node@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-19.0.2.tgz#6e84079db87ed21d0c05e1f9669f207b116fe99b"
+  dependencies:
+    jest-mock "^19.0.0"
+    jest-util "^19.0.2"
+
+jest-file-exists@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-file-exists/-/jest-file-exists-19.0.0.tgz#cca2e587a11ec92e24cfeab3f8a94d657f3fceb8"
+
+jest-haste-map@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-19.0.0.tgz#adde00b62b1fe04432a104b3254fc5004514b55e"
+  dependencies:
+    fb-watchman "^2.0.0"
+    graceful-fs "^4.1.6"
+    micromatch "^2.3.11"
+    sane "~1.5.0"
+    worker-farm "^1.3.1"
+
+jest-jasmine2@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-19.0.2.tgz#167991ac825981fb1a800af126e83afcca832c73"
+  dependencies:
+    graceful-fs "^4.1.6"
+    jest-matcher-utils "^19.0.0"
+    jest-matchers "^19.0.0"
+    jest-message-util "^19.0.0"
+    jest-snapshot "^19.0.2"
+
+jest-matcher-utils@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-19.0.0.tgz#5ecd9b63565d2b001f61fbf7ec4c7f537964564d"
+  dependencies:
+    chalk "^1.1.3"
+    pretty-format "^19.0.0"
+
+jest-matchers@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-matchers/-/jest-matchers-19.0.0.tgz#c74ecc6ebfec06f384767ba4d6fa4a42d6755754"
+  dependencies:
+    jest-diff "^19.0.0"
+    jest-matcher-utils "^19.0.0"
+    jest-message-util "^19.0.0"
+    jest-regex-util "^19.0.0"
+
+jest-message-util@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-19.0.0.tgz#721796b89c0e4d761606f9ba8cb828a3b6246416"
+  dependencies:
+    chalk "^1.1.1"
+    micromatch "^2.3.11"
+
+jest-mock@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-19.0.0.tgz#67038641e9607ab2ce08ec4a8cb83aabbc899d01"
+
+jest-regex-util@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-19.0.0.tgz#b7754587112aede1456510bb1f6afe74ef598691"
+
+jest-resolve-dependencies@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-19.0.0.tgz#a741ad1fa094140e64ecf2642a504f834ece22ee"
+  dependencies:
+    jest-file-exists "^19.0.0"
+
+jest-resolve@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-19.0.2.tgz#5793575de4f07aec32f7d7ff0c6c181963eefb3c"
+  dependencies:
+    browser-resolve "^1.11.2"
+    jest-haste-map "^19.0.0"
+    resolve "^1.2.0"
+
+jest-runtime@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-19.0.2.tgz#d9a43e72de416d27d196fd9c7940d98fe6685407"
+  dependencies:
+    babel-core "^6.0.0"
+    babel-jest "^19.0.0"
+    babel-plugin-istanbul "^4.0.0"
+    chalk "^1.1.3"
+    graceful-fs "^4.1.6"
+    jest-config "^19.0.2"
+    jest-file-exists "^19.0.0"
+    jest-haste-map "^19.0.0"
+    jest-regex-util "^19.0.0"
+    jest-resolve "^19.0.2"
+    jest-util "^19.0.2"
+    json-stable-stringify "^1.0.1"
+    micromatch "^2.3.11"
+    strip-bom "3.0.0"
+    yargs "^6.3.0"
+
+jest-snapshot@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-19.0.2.tgz#9c1b216214f7187c38bfd5c70b1efab16b0ff50b"
+  dependencies:
+    chalk "^1.1.3"
+    jest-diff "^19.0.0"
+    jest-file-exists "^19.0.0"
+    jest-matcher-utils "^19.0.0"
+    jest-util "^19.0.2"
+    natural-compare "^1.4.0"
+    pretty-format "^19.0.0"
+
+jest-util@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-19.0.2.tgz#e0a0232a2ab9e6b2b53668bdb3534c2b5977ed41"
+  dependencies:
+    chalk "^1.1.1"
+    graceful-fs "^4.1.6"
+    jest-file-exists "^19.0.0"
+    jest-message-util "^19.0.0"
+    jest-mock "^19.0.0"
+    jest-validate "^19.0.2"
+    leven "^2.0.0"
+    mkdirp "^0.5.1"
+
+jest-validate@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-19.0.2.tgz#dc534df5f1278d5b63df32b14241d4dbf7244c0c"
+  dependencies:
+    chalk "^1.1.1"
+    jest-matcher-utils "^19.0.0"
+    leven "^2.0.0"
+    pretty-format "^19.0.0"
+
+jest@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest/-/jest-19.0.2.tgz#b794faaf8ff461e7388f28beef559a54f20b2c10"
+  dependencies:
+    jest-cli "^19.0.2"
+
+jodid25519@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967"
+  dependencies:
+    jsbn "~0.1.0"
+
+js-tokens@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7"
+
+js-yaml@^3.7.0:
+  version "3.8.3"
+  resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.3.tgz#33a05ec481c850c8875929166fe1beb61c728766"
+  dependencies:
+    argparse "^1.0.7"
+    esprima "^3.1.1"
+
+jsbn@~0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
+
+jsdom@^9.11.0:
+  version "9.12.0"
+  resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-9.12.0.tgz#e8c546fffcb06c00d4833ca84410fed7f8a097d4"
+  dependencies:
+    abab "^1.0.3"
+    acorn "^4.0.4"
+    acorn-globals "^3.1.0"
+    array-equal "^1.0.0"
+    content-type-parser "^1.0.1"
+    cssom ">= 0.3.2 < 0.4.0"
+    cssstyle ">= 0.2.37 < 0.3.0"
+    escodegen "^1.6.1"
+    html-encoding-sniffer "^1.0.1"
+    nwmatcher ">= 1.3.9 < 2.0.0"
+    parse5 "^1.5.1"
+    request "^2.79.0"
+    sax "^1.2.1"
+    symbol-tree "^3.2.1"
+    tough-cookie "^2.3.2"
+    webidl-conversions "^4.0.0"
+    whatwg-encoding "^1.0.1"
+    whatwg-url "^4.3.0"
+    xml-name-validator "^2.0.1"
+
+jsesc@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b"
+
+json-loader@^0.5.4:
+  version "0.5.4"
+  resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.4.tgz#8baa1365a632f58a3c46d20175fc6002c96e37de"
+
+json-schema@0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
+
+json-stable-stringify@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af"
+  dependencies:
+    jsonify "~0.0.0"
+
+json-stringify-safe@~5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
+
+json5@^0.5.0, json5@^0.5.1:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
+
+jsonify@~0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
+
+jsprim@^1.2.2:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.0.tgz#a3b87e40298d8c380552d8cc7628a0bb95a22918"
+  dependencies:
+    assert-plus "1.0.0"
+    extsprintf "1.0.2"
+    json-schema "0.2.3"
+    verror "1.3.6"
+
+kind-of@^3.0.2:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47"
+  dependencies:
+    is-buffer "^1.0.2"
+
+lazy-cache@^1.0.3:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
+
+lcid@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
+  dependencies:
+    invert-kv "^1.0.0"
+
+leven@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580"
+
+levn@~0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
+  dependencies:
+    prelude-ls "~1.1.2"
+    type-check "~0.3.2"
+
+load-json-file@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
+  dependencies:
+    graceful-fs "^4.1.2"
+    parse-json "^2.2.0"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+    strip-bom "^2.0.0"
+
+loader-runner@^2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2"
+
+loader-utils@^0.2.16:
+  version "0.2.17"
+  resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348"
+  dependencies:
+    big.js "^3.1.3"
+    emojis-list "^2.0.0"
+    json5 "^0.5.0"
+    object-assign "^4.0.1"
+
+locate-path@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
+  dependencies:
+    p-locate "^2.0.0"
+    path-exists "^3.0.0"
+
+lodash@^4.14.0, lodash@^4.2.0:
+  version "4.17.4"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
+
+longest@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
+
+loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1:
+  version "1.3.1"
+  resolved "https://artifacts.netflix.com/api/npm/npm-netflix/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
+  dependencies:
+    js-tokens "^3.0.0"
+
+makeerror@1.0.x:
+  version "1.0.11"
+  resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c"
+  dependencies:
+    tmpl "1.0.x"
+
+memory-fs@^0.4.0, memory-fs@~0.4.1:
+  version "0.4.1"
+  resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"
+  dependencies:
+    errno "^0.1.3"
+    readable-stream "^2.0.1"
+
+merge@^1.1.3:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da"
+
+micromatch@^2.1.5, micromatch@^2.3.11:
+  version "2.3.11"
+  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
+  dependencies:
+    arr-diff "^2.0.0"
+    array-unique "^0.2.1"
+    braces "^1.8.2"
+    expand-brackets "^0.1.4"
+    extglob "^0.3.1"
+    filename-regex "^2.0.0"
+    is-extglob "^1.0.0"
+    is-glob "^2.0.1"
+    kind-of "^3.0.2"
+    normalize-path "^2.0.1"
+    object.omit "^2.0.0"
+    parse-glob "^3.0.4"
+    regex-cache "^0.4.2"
+
+miller-rabin@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.0.tgz#4a62fb1d42933c05583982f4c716f6fb9e6c6d3d"
+  dependencies:
+    bn.js "^4.0.0"
+    brorand "^1.0.1"
+
+mime-db@~1.27.0:
+  version "1.27.0"
+  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1"
+
+mime-types@^2.1.12, mime-types@~2.1.7:
+  version "2.1.15"
+  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed"
+  dependencies:
+    mime-db "~1.27.0"
+
+minimalistic-assert@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3"
+
+minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
+
+minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774"
+  dependencies:
+    brace-expansion "^1.0.0"
+
+minimist@0.0.8, minimist@~0.0.1:
+  version "0.0.8"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
+
+minimist@^1.1.1, minimist@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
+
+"mkdirp@>=0.5 0", mkdirp@^0.5.1, mkdirp@~0.5.0:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
+  dependencies:
+    minimist "0.0.8"
+
+ms@0.7.2:
+  version "0.7.2"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765"
+
+nan@^2.3.0:
+  version "2.6.2"
+  resolved "https://registry.yarnpkg.com/nan/-/nan-2.6.2.tgz#e4ff34e6c95fdfb5aecc08de6596f43605a7db45"
+
+natural-compare@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
+
+node-fetch@^1.0.1:
+  version "1.6.3"
+  resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04"
+  dependencies:
+    encoding "^0.1.11"
+    is-stream "^1.0.1"
+
+node-int64@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
+
+node-libs-browser@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.0.0.tgz#a3a59ec97024985b46e958379646f96c4b616646"
+  dependencies:
+    assert "^1.1.1"
+    browserify-zlib "^0.1.4"
+    buffer "^4.3.0"
+    console-browserify "^1.1.0"
+    constants-browserify "^1.0.0"
+    crypto-browserify "^3.11.0"
+    domain-browser "^1.1.1"
+    events "^1.0.0"
+    https-browserify "0.0.1"
+    os-browserify "^0.2.0"
+    path-browserify "0.0.0"
+    process "^0.11.0"
+    punycode "^1.2.4"
+    querystring-es3 "^0.2.0"
+    readable-stream "^2.0.5"
+    stream-browserify "^2.0.1"
+    stream-http "^2.3.1"
+    string_decoder "^0.10.25"
+    timers-browserify "^2.0.2"
+    tty-browserify "0.0.0"
+    url "^0.11.0"
+    util "^0.10.3"
+    vm-browserify "0.0.4"
+
+node-notifier@^5.0.1:
+  version "5.1.2"
+  resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.1.2.tgz#2fa9e12605fa10009d44549d6fcd8a63dde0e4ff"
+  dependencies:
+    growly "^1.3.0"
+    semver "^5.3.0"
+    shellwords "^0.1.0"
+    which "^1.2.12"
+
+node-pre-gyp@^0.6.36:
+  version "0.6.36"
+  resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.36.tgz#db604112cb74e0d477554e9b505b17abddfab786"
+  dependencies:
+    mkdirp "^0.5.1"
+    nopt "^4.0.1"
+    npmlog "^4.0.2"
+    rc "^1.1.7"
+    request "^2.81.0"
+    rimraf "^2.6.1"
+    semver "^5.3.0"
+    tar "^2.2.1"
+    tar-pack "^3.4.0"
+
+nopt@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
+  dependencies:
+    abbrev "1"
+    osenv "^0.1.4"
+
+normalize-package-data@^2.3.2:
+  version "2.3.6"
+  resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.6.tgz#498fa420c96401f787402ba21e600def9f981fff"
+  dependencies:
+    hosted-git-info "^2.1.4"
+    is-builtin-module "^1.0.0"
+    semver "2 || 3 || 4 || 5"
+    validate-npm-package-license "^3.0.1"
+
+normalize-path@^2.0.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
+  dependencies:
+    remove-trailing-separator "^1.0.1"
+
+npmlog@^4.0.2:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.0.tgz#dc59bee85f64f00ed424efb2af0783df25d1c0b5"
+  dependencies:
+    are-we-there-yet "~1.1.2"
+    console-control-strings "~1.1.0"
+    gauge "~2.7.3"
+    set-blocking "~2.0.0"
+
+number-is-nan@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
+
+"nwmatcher@>= 1.3.9 < 2.0.0":
+  version "1.3.9"
+  resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.3.9.tgz#8bab486ff7fa3dfd086656bbe8b17116d3692d2a"
+
+oauth-sign@~0.8.1:
+  version "0.8.2"
+  resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
+
+object-assign@^4.0.1, object-assign@^4.1.0:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+
+object.omit@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
+  dependencies:
+    for-own "^0.1.4"
+    is-extendable "^0.1.1"
+
+once@^1.3.0, once@^1.3.3, once@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+  dependencies:
+    wrappy "1"
+
+optimist@^0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
+  dependencies:
+    minimist "~0.0.1"
+    wordwrap "~0.0.2"
+
+optionator@^0.8.1:
+  version "0.8.2"
+  resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64"
+  dependencies:
+    deep-is "~0.1.3"
+    fast-levenshtein "~2.0.4"
+    levn "~0.3.0"
+    prelude-ls "~1.1.2"
+    type-check "~0.3.2"
+    wordwrap "~1.0.0"
+
+os-browserify@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.2.1.tgz#63fc4ccee5d2d7763d26bbf8601078e6c2e0044f"
+
+os-homedir@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
+
+os-locale@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9"
+  dependencies:
+    lcid "^1.0.0"
+
+os-tmpdir@^1.0.0, os-tmpdir@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
+
+osenv@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644"
+  dependencies:
+    os-homedir "^1.0.0"
+    os-tmpdir "^1.0.0"
+
+p-limit@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.1.0.tgz#b07ff2d9a5d88bec806035895a2bab66a27988bc"
+
+p-locate@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
+  dependencies:
+    p-limit "^1.1.0"
+
+pako@~0.2.0:
+  version "0.2.9"
+  resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
+
+parse-asn1@^5.0.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712"
+  dependencies:
+    asn1.js "^4.0.0"
+    browserify-aes "^1.0.0"
+    create-hash "^1.1.0"
+    evp_bytestokey "^1.0.0"
+    pbkdf2 "^3.0.3"
+
+parse-glob@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
+  dependencies:
+    glob-base "^0.3.0"
+    is-dotfile "^1.0.0"
+    is-extglob "^1.0.0"
+    is-glob "^2.0.0"
+
+parse-json@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
+  dependencies:
+    error-ex "^1.2.0"
+
+parse5@^1.5.1:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94"
+
+path-browserify@0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a"
+
+path-exists@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
+  dependencies:
+    pinkie-promise "^2.0.0"
+
+path-exists@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
+
+path-is-absolute@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+
+path-parse@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1"
+
+path-type@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
+  dependencies:
+    graceful-fs "^4.1.2"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+pbkdf2@^3.0.3:
+  version "3.0.12"
+  resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.12.tgz#be36785c5067ea48d806ff923288c5f750b6b8a2"
+  dependencies:
+    create-hash "^1.1.2"
+    create-hmac "^1.1.4"
+    ripemd160 "^2.0.1"
+    safe-buffer "^5.0.1"
+    sha.js "^2.4.8"
+
+performance-now@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5"
+
+pify@^2.0.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
+
+pinkie-promise@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
+  dependencies:
+    pinkie "^2.0.0"
+
+pinkie@^2.0.0:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
+
+prelude-ls@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
+
+preserve@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
+
+pretty-format@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-19.0.0.tgz#56530d32acb98a3fa4851c4e2b9d37b420684c84"
+  dependencies:
+    ansi-styles "^3.0.0"
+
+private@^0.1.6:
+  version "0.1.7"
+  resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1"
+
+process-nextick-args@~1.0.6:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
+
+process@^0.11.0:
+  version "0.11.10"
+  resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
+
+promise@^7.1.1:
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/promise/-/promise-7.1.1.tgz#489654c692616b8aa55b0724fa809bb7db49c5bf"
+  dependencies:
+    asap "~2.0.3"
+
+prr@~0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a"
+
+public-encrypt@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.0.tgz#39f699f3a46560dd5ebacbca693caf7c65c18cc6"
+  dependencies:
+    bn.js "^4.1.0"
+    browserify-rsa "^4.0.0"
+    create-hash "^1.1.0"
+    parse-asn1 "^5.0.0"
+    randombytes "^2.0.1"
+
+punycode@1.3.2:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
+
+punycode@^1.2.4, punycode@^1.4.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
+
+qs@~6.4.0:
+  version "6.4.0"
+  resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
+
+querystring-es3@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
+
+querystring@0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
+
+randomatic@^1.1.3:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb"
+  dependencies:
+    is-number "^2.0.2"
+    kind-of "^3.0.2"
+
+randombytes@^2.0.0, randombytes@^2.0.1:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.5.tgz#dc009a246b8d09a177b4b7a0ae77bc570f4b1b79"
+  dependencies:
+    safe-buffer "^5.1.0"
+
+rc@^1.1.7:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.1.tgz#2e03e8e42ee450b8cb3dce65be1bf8974e1dfd95"
+  dependencies:
+    deep-extend "~0.4.0"
+    ini "~1.3.0"
+    minimist "^1.2.0"
+    strip-json-comments "~2.0.1"
+
+react-dom@^15.4.2:
+  version "15.4.2"
+  resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.4.2.tgz#015363f05b0a1fd52ae9efdd3a0060d90695208f"
+  dependencies:
+    fbjs "^0.8.1"
+    loose-envify "^1.1.0"
+    object-assign "^4.1.0"
+
+react@^15.4.2:
+  version "15.4.2"
+  resolved "https://registry.yarnpkg.com/react/-/react-15.4.2.tgz#41f7991b26185392ba9bae96c8889e7e018397ef"
+  dependencies:
+    fbjs "^0.8.4"
+    loose-envify "^1.1.0"
+    object-assign "^4.1.0"
+
+read-pkg-up@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
+  dependencies:
+    find-up "^1.0.0"
+    read-pkg "^1.0.0"
+
+read-pkg@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
+  dependencies:
+    load-json-file "^1.0.0"
+    normalize-package-data "^2.3.2"
+    path-type "^1.0.0"
+
+readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.2.6:
+  version "2.2.11"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.11.tgz#0796b31f8d7688007ff0b93a8088d34aa17c0f72"
+  dependencies:
+    core-util-is "~1.0.0"
+    inherits "~2.0.1"
+    isarray "~1.0.0"
+    process-nextick-args "~1.0.6"
+    safe-buffer "~5.0.1"
+    string_decoder "~1.0.0"
+    util-deprecate "~1.0.1"
+
+readdirp@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78"
+  dependencies:
+    graceful-fs "^4.1.2"
+    minimatch "^3.0.2"
+    readable-stream "^2.0.2"
+    set-immediate-shim "^1.0.1"
+
+regenerator-runtime@^0.10.0:
+  version "0.10.3"
+  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.3.tgz#8c4367a904b51ea62a908ac310bf99ff90a82a3e"
+
+regex-cache@^0.4.2:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145"
+  dependencies:
+    is-equal-shallow "^0.1.3"
+    is-primitive "^2.0.0"
+
+remove-trailing-separator@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.0.1.tgz#615ebb96af559552d4bf4057c8436d486ab63cc4"
+
+repeat-element@^1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a"
+
+repeat-string@^1.5.2:
+  version "1.6.1"
+  resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
+
+repeating@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda"
+  dependencies:
+    is-finite "^1.0.0"
+
+request@^2.79.0, request@^2.81.0:
+  version "2.81.0"
+  resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0"
+  dependencies:
+    aws-sign2 "~0.6.0"
+    aws4 "^1.2.1"
+    caseless "~0.12.0"
+    combined-stream "~1.0.5"
+    extend "~3.0.0"
+    forever-agent "~0.6.1"
+    form-data "~2.1.1"
+    har-validator "~4.2.1"
+    hawk "~3.1.3"
+    http-signature "~1.1.0"
+    is-typedarray "~1.0.0"
+    isstream "~0.1.2"
+    json-stringify-safe "~5.0.1"
+    mime-types "~2.1.7"
+    oauth-sign "~0.8.1"
+    performance-now "^0.2.0"
+    qs "~6.4.0"
+    safe-buffer "^5.0.1"
+    stringstream "~0.0.4"
+    tough-cookie "~2.3.0"
+    tunnel-agent "^0.6.0"
+    uuid "^3.0.0"
+
+require-directory@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
+
+require-main-filename@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
+
+resolve@1.1.7:
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
+
+resolve@^1.2.0:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.3.2.tgz#1f0442c9e0cbb8136e87b9305f932f46c7f28235"
+  dependencies:
+    path-parse "^1.0.5"
+
+right-align@^0.1.1:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef"
+  dependencies:
+    align-text "^0.1.1"
+
+rimraf@2, rimraf@^2.4.4, rimraf@^2.5.1, rimraf@^2.6.1:
+  version "2.6.1"
+  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d"
+  dependencies:
+    glob "^7.0.5"
+
+ripemd160@^2.0.0, ripemd160@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7"
+  dependencies:
+    hash-base "^2.0.0"
+    inherits "^2.0.1"
+
+safe-buffer@^5.0.1, safe-buffer@~5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7"
+
+safe-buffer@^5.1.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.0.tgz#fe4c8460397f9eaaaa58e73be46273408a45e223"
+
+sane@~1.5.0:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/sane/-/sane-1.5.0.tgz#a4adeae764d048621ecb27d5f9ecf513101939f3"
+  dependencies:
+    anymatch "^1.3.0"
+    exec-sh "^0.2.0"
+    fb-watchman "^1.8.0"
+    minimatch "^3.0.2"
+    minimist "^1.1.1"
+    walker "~1.0.5"
+    watch "~0.10.0"
+
+sax@^1.2.1:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.2.tgz#fd8631a23bc7826bef5d871bdb87378c95647828"
+
+"semver@2 || 3 || 4 || 5", semver@^5.3.0:
+  version "5.3.0"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
+
+set-blocking@^2.0.0, set-blocking@~2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
+
+set-immediate-shim@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61"
+
+setimmediate@^1.0.4, setimmediate@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
+
+sha.js@^2.4.0, sha.js@^2.4.8:
+  version "2.4.8"
+  resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.8.tgz#37068c2c476b6baf402d14a49c67f597921f634f"
+  dependencies:
+    inherits "^2.0.1"
+
+shellwords@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.0.tgz#66afd47b6a12932d9071cbfd98a52e785cd0ba14"
+
+signal-exit@^3.0.0:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
+
+slash@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
+
+sntp@1.x.x:
+  version "1.0.9"
+  resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198"
+  dependencies:
+    hoek "2.x.x"
+
+source-list-map@^1.1.1:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-1.1.2.tgz#9889019d1024cce55cdc069498337ef6186a11a1"
+
+source-map-support@^0.4.2:
+  version "0.4.14"
+  resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.14.tgz#9d4463772598b86271b4f523f6c1f4e02a7d6aef"
+  dependencies:
+    source-map "^0.5.6"
+
+source-map@^0.4.4:
+  version "0.4.4"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b"
+  dependencies:
+    amdefine ">=0.0.4"
+
+source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.3:
+  version "0.5.6"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
+
+source-map@~0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d"
+  dependencies:
+    amdefine ">=0.0.4"
+
+spdx-correct@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40"
+  dependencies:
+    spdx-license-ids "^1.0.2"
+
+spdx-expression-parse@~1.0.0:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c"
+
+spdx-license-ids@^1.0.2:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57"
+
+sprintf-js@~1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
+
+sshpk@^1.7.0:
+  version "1.11.0"
+  resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.11.0.tgz#2d8d5ebb4a6fab28ffba37fa62a90f4a3ea59d77"
+  dependencies:
+    asn1 "~0.2.3"
+    assert-plus "^1.0.0"
+    dashdash "^1.12.0"
+    getpass "^0.1.1"
+  optionalDependencies:
+    bcrypt-pbkdf "^1.0.0"
+    ecc-jsbn "~0.1.1"
+    jodid25519 "^1.0.0"
+    jsbn "~0.1.0"
+    tweetnacl "~0.14.0"
+
+stream-browserify@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db"
+  dependencies:
+    inherits "~2.0.1"
+    readable-stream "^2.0.2"
+
+stream-http@^2.3.1:
+  version "2.7.2"
+  resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.7.2.tgz#40a050ec8dc3b53b33d9909415c02c0bf1abfbad"
+  dependencies:
+    builtin-status-codes "^3.0.0"
+    inherits "^2.0.1"
+    readable-stream "^2.2.6"
+    to-arraybuffer "^1.0.0"
+    xtend "^4.0.0"
+
+string-length@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/string-length/-/string-length-1.0.1.tgz#56970fb1c38558e9e70b728bf3de269ac45adfac"
+  dependencies:
+    strip-ansi "^3.0.0"
+
+string-width@^1.0.1, string-width@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
+  dependencies:
+    code-point-at "^1.0.0"
+    is-fullwidth-code-point "^1.0.0"
+    strip-ansi "^3.0.0"
+
+string_decoder@^0.10.25:
+  version "0.10.31"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
+
+string_decoder@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.2.tgz#b29e1f4e1125fa97a10382b8a533737b7491e179"
+  dependencies:
+    safe-buffer "~5.0.1"
+
+stringstream@~0.0.4:
+  version "0.0.5"
+  resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878"
+
+strip-ansi@^3.0.0, strip-ansi@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
+  dependencies:
+    ansi-regex "^2.0.0"
+
+strip-bom@3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
+
+strip-bom@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
+  dependencies:
+    is-utf8 "^0.2.0"
+
+strip-json-comments@~2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
+
+supports-color@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
+
+supports-color@^3.1.0, supports-color@^3.1.2:
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
+  dependencies:
+    has-flag "^1.0.0"
+
+symbol-tree@^3.2.1:
+  version "3.2.2"
+  resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6"
+
+tapable@^0.2.5, tapable@~0.2.5:
+  version "0.2.6"
+  resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.6.tgz#206be8e188860b514425375e6f1ae89bfb01fd8d"
+
+tar-pack@^3.4.0:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.0.tgz#23be2d7f671a8339376cbdb0b8fe3fdebf317984"
+  dependencies:
+    debug "^2.2.0"
+    fstream "^1.0.10"
+    fstream-ignore "^1.0.5"
+    once "^1.3.3"
+    readable-stream "^2.1.4"
+    rimraf "^2.5.1"
+    tar "^2.2.1"
+    uid-number "^0.0.6"
+
+tar@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1"
+  dependencies:
+    block-stream "*"
+    fstream "^1.0.2"
+    inherits "2"
+
+test-exclude@^4.0.3:
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-4.0.3.tgz#86a13ce3effcc60e6c90403cf31a27a60ac6c4e7"
+  dependencies:
+    arrify "^1.0.1"
+    micromatch "^2.3.11"
+    object-assign "^4.1.0"
+    read-pkg-up "^1.0.1"
+    require-main-filename "^1.0.1"
+
+throat@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/throat/-/throat-3.0.0.tgz#e7c64c867cbb3845f10877642f7b60055b8ec0d6"
+
+timers-browserify@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.2.tgz#ab4883cf597dcd50af211349a00fbca56ac86b86"
+  dependencies:
+    setimmediate "^1.0.4"
+
+tmpl@1.0.x:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1"
+
+to-arraybuffer@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
+
+to-fast-properties@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320"
+
+tough-cookie@^2.3.2, tough-cookie@~2.3.0:
+  version "2.3.2"
+  resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a"
+  dependencies:
+    punycode "^1.4.1"
+
+tr46@~0.0.3:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
+
+trim-right@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
+
+tty-browserify@0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
+
+tunnel-agent@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
+  dependencies:
+    safe-buffer "^5.0.1"
+
+tweetnacl@^0.14.3, tweetnacl@~0.14.0:
+  version "0.14.5"
+  resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
+
+type-check@~0.3.2:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
+  dependencies:
+    prelude-ls "~1.1.2"
+
+ua-parser-js@^0.7.9:
+  version "0.7.12"
+  resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb"
+
+uglify-js@^2.6:
+  version "2.8.21"
+  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.21.tgz#1733f669ae6f82fc90c7b25ec0f5c783ee375314"
+  dependencies:
+    source-map "~0.5.1"
+    yargs "~3.10.0"
+  optionalDependencies:
+    uglify-to-browserify "~1.0.0"
+
+uglify-js@^2.8.27:
+  version "2.8.28"
+  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.28.tgz#e335032df9bb20dcb918f164589d5af47f38834a"
+  dependencies:
+    source-map "~0.5.1"
+    yargs "~3.10.0"
+  optionalDependencies:
+    uglify-to-browserify "~1.0.0"
+
+uglify-to-browserify@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7"
+
+uid-number@^0.0.6:
+  version "0.0.6"
+  resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81"
+
+url@^0.11.0:
+  version "0.11.0"
+  resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
+  dependencies:
+    punycode "1.3.2"
+    querystring "0.2.0"
+
+util-deprecate@~1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+
+util@0.10.3, util@^0.10.3:
+  version "0.10.3"
+  resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9"
+  dependencies:
+    inherits "2.0.1"
+
+uuid@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1"
+
+validate-npm-package-license@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc"
+  dependencies:
+    spdx-correct "~1.0.0"
+    spdx-expression-parse "~1.0.0"
+
+verror@1.3.6:
+  version "1.3.6"
+  resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c"
+  dependencies:
+    extsprintf "1.0.2"
+
+vm-browserify@0.0.4:
+  version "0.0.4"
+  resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73"
+  dependencies:
+    indexof "0.0.1"
+
+walker@~1.0.5:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb"
+  dependencies:
+    makeerror "1.0.x"
+
+watch@~0.10.0:
+  version "0.10.0"
+  resolved "https://registry.yarnpkg.com/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc"
+
+watchpack@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.3.1.tgz#7d8693907b28ce6013e7f3610aa2a1acf07dad87"
+  dependencies:
+    async "^2.1.2"
+    chokidar "^1.4.3"
+    graceful-fs "^4.1.2"
+
+webidl-conversions@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
+
+webidl-conversions@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.1.tgz#8015a17ab83e7e1b311638486ace81da6ce206a0"
+
+webpack-sources@^0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-0.2.3.tgz#17c62bfaf13c707f9d02c479e0dcdde8380697fb"
+  dependencies:
+    source-list-map "^1.1.1"
+    source-map "~0.5.3"
+
+webpack@^2.6.1:
+  version "2.6.1"
+  resolved "https://registry.yarnpkg.com/webpack/-/webpack-2.6.1.tgz#2e0457f0abb1ac5df3ab106c69c672f236785f07"
+  dependencies:
+    acorn "^5.0.0"
+    acorn-dynamic-import "^2.0.0"
+    ajv "^4.7.0"
+    ajv-keywords "^1.1.1"
+    async "^2.1.2"
+    enhanced-resolve "^3.0.0"
+    interpret "^1.0.0"
+    json-loader "^0.5.4"
+    json5 "^0.5.1"
+    loader-runner "^2.3.0"
+    loader-utils "^0.2.16"
+    memory-fs "~0.4.1"
+    mkdirp "~0.5.0"
+    node-libs-browser "^2.0.0"
+    source-map "^0.5.3"
+    supports-color "^3.1.0"
+    tapable "~0.2.5"
+    uglify-js "^2.8.27"
+    watchpack "^1.3.1"
+    webpack-sources "^0.2.3"
+    yargs "^6.0.0"
+
+whatwg-encoding@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.1.tgz#3c6c451a198ee7aec55b1ec61d0920c67801a5f4"
+  dependencies:
+    iconv-lite "0.4.13"
+
+whatwg-fetch@>=0.10.0:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84"
+
+whatwg-url@^4.3.0:
+  version "4.7.0"
+  resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-4.7.0.tgz#202035ac1955b087cdd20fa8b58ded3ab1cd2af5"
+  dependencies:
+    tr46 "~0.0.3"
+    webidl-conversions "^3.0.0"
+
+which-module@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
+
+which@^1.1.1, which@^1.2.12:
+  version "1.2.14"
+  resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5"
+  dependencies:
+    isexe "^2.0.0"
+
+wide-align@^1.1.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710"
+  dependencies:
+    string-width "^1.0.2"
+
+window-size@0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
+
+wordwrap@0.0.2:
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
+
+wordwrap@~0.0.2:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
+
+wordwrap@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
+
+worker-farm@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.3.1.tgz#4333112bb49b17aa050b87895ca6b2cacf40e5ff"
+  dependencies:
+    errno ">=0.1.1 <0.2.0-0"
+    xtend ">=4.0.0 <4.1.0-0"
+
+wrap-ansi@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
+  dependencies:
+    string-width "^1.0.1"
+    strip-ansi "^3.0.1"
+
+wrappy@1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+
+xml-name-validator@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635"
+
+"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
+
+y18n@^3.2.1:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
+
+yargs-parser@^4.2.0:
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c"
+  dependencies:
+    camelcase "^3.0.0"
+
+yargs@^6.0.0, yargs@^6.3.0:
+  version "6.6.0"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208"
+  dependencies:
+    camelcase "^3.0.0"
+    cliui "^3.2.0"
+    decamelize "^1.1.1"
+    get-caller-file "^1.0.1"
+    os-locale "^1.4.0"
+    read-pkg-up "^1.0.1"
+    require-directory "^2.1.1"
+    require-main-filename "^1.0.1"
+    set-blocking "^2.0.0"
+    string-width "^1.0.2"
+    which-module "^1.0.0"
+    y18n "^3.2.1"
+    yargs-parser "^4.2.0"
+
+yargs@~3.10.0:
+  version "3.10.0"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"
+  dependencies:
+    camelcase "^1.0.2"
+    cliui "^2.1.0"
+    decamelize "^1.0.0"
+    window-size "0.1.0"
diff --git a/addons/react-addons-css-transition-group/LICENSE b/addons/react-addons-css-transition-group/LICENSE
new file mode 100644
index 000000000000..91b8f6f76ff0
--- /dev/null
+++ b/addons/react-addons-css-transition-group/LICENSE
@@ -0,0 +1,31 @@
+BSD License
+
+For React software
+
+Copyright (c) 2013-present, Facebook, Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+ * Neither the name Facebook nor the names of its contributors may be used to
+   endorse or promote products derived from this software without specific
+   prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/addons/react-addons-css-transition-group/PATENTS b/addons/react-addons-css-transition-group/PATENTS
new file mode 100644
index 000000000000..9c9f8e87a8f4
--- /dev/null
+++ b/addons/react-addons-css-transition-group/PATENTS
@@ -0,0 +1,33 @@
+Additional Grant of Patent Rights Version 2
+
+"Software" means the React software distributed by Facebook, Inc.
+
+Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software
+("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable
+(subject to the termination provision below) license under any Necessary
+Claims, to make, have made, use, sell, offer to sell, import, and otherwise
+transfer the Software. For avoidance of doubt, no license is granted under
+Facebook's rights in any patent claims that are infringed by (i) modifications
+to the Software made by you or any third party or (ii) the Software in
+combination with any software or other technology.
+
+The license granted hereunder will terminate, automatically and without notice,
+if you (or any of your subsidiaries, corporate affiliates or agents) initiate
+directly or indirectly, or take a direct financial interest in, any Patent
+Assertion: (i) against Facebook or any of its subsidiaries or corporate
+affiliates, (ii) against any party if such Patent Assertion arises in whole or
+in part from any software, technology, product or service of Facebook or any of
+its subsidiaries or corporate affiliates, or (iii) against any party relating
+to the Software. Notwithstanding the foregoing, if Facebook or any of its
+subsidiaries or corporate affiliates files a lawsuit alleging patent
+infringement against you in the first instance, and you respond by filing a
+patent infringement counterclaim in that lawsuit against that party that is
+unrelated to the Software, the license granted hereunder will not terminate
+under section (i) of this paragraph due to such counterclaim.
+
+A "Necessary Claim" is a claim of a patent owned by Facebook that is
+necessarily infringed by the Software standing alone.
+
+A "Patent Assertion" is any lawsuit or other action alleging direct, indirect,
+or contributory infringement or inducement to infringe any patent, including a
+cross-claim or counterclaim.
diff --git a/addons/react-addons-css-transition-group/README.md b/addons/react-addons-css-transition-group/README.md
new file mode 100644
index 000000000000..a84f8296dc5e
--- /dev/null
+++ b/addons/react-addons-css-transition-group/README.md
@@ -0,0 +1,17 @@
+# react-addons-css-transition-group
+
+The code in this package has moved. We recommend you to use `CSSTransitionGroup` from [`react-transition-group`](https://github.com/reactjs/react-transition-group) instead.
+
+In particular, its version `1.x` is a drop-in replacement for the last released version of `react-addons-css-transition-group`.
+
+Run `npm install --save react-transition-group@1.x`, and replace the imports in your code:
+
+```js
+// Old
+import CSSTransitionGroup from 'react-addons-css-transition-group';
+
+// New
+import CSSTransitionGroup from 'react-transition-group/CSSTransitionGroup';
+```
+
+The documentation branch for `react-transition-group@1.x` [can be found here](https://github.com/reactjs/react-transition-group/tree/v1-stable#high-level-api-csstransitiongroup).
diff --git a/addons/react-addons-css-transition-group/index.js b/addons/react-addons-css-transition-group/index.js
new file mode 100644
index 000000000000..e0524e44e7c4
--- /dev/null
+++ b/addons/react-addons-css-transition-group/index.js
@@ -0,0 +1,12 @@
+/**
+ * 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.
+ */
+
+'use strict';
+
+module.exports = require('react-transition-group/CSSTransitionGroup');
diff --git a/addons/react-addons-css-transition-group/package.json b/addons/react-addons-css-transition-group/package.json
new file mode 100644
index 000000000000..80e1dd9b2722
--- /dev/null
+++ b/addons/react-addons-css-transition-group/package.json
@@ -0,0 +1,26 @@
+{
+  "name": "react-addons-css-transition-group",
+  "version": "15.6.0",
+  "main": "index.js",
+  "repository": "facebook/react",
+  "keywords": [
+    "react",
+    "react-addon"
+  ],
+  "license": "BSD-3-Clause",
+  "scripts": {
+    "prepublish": ":"
+  },
+  "dependencies": {
+    "react-transition-group": "^1.2.0"
+  },
+  "files": [
+    "LICENSE",
+    "PATENTS",
+    "README.md",
+    "index.js"
+  ],
+  "peerDependencies": {
+    "react": "^15.4.2"
+  }
+}
diff --git a/addons/react-addons-css-transition-group/yarn.lock b/addons/react-addons-css-transition-group/yarn.lock
new file mode 100644
index 000000000000..a451c1bc8bbd
--- /dev/null
+++ b/addons/react-addons-css-transition-group/yarn.lock
@@ -0,0 +1,114 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+asap@~2.0.3:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f"
+
+chain-function@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/chain-function/-/chain-function-1.0.0.tgz#0d4ab37e7e18ead0bdc47b920764118ce58733dc"
+
+core-js@^1.0.0:
+  version "1.2.7"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
+
+dom-helpers@^3.2.0:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.2.1.tgz#3203e07fed217bd1f424b019735582fc37b2825a"
+
+encoding@^0.1.11:
+  version "0.1.12"
+  resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb"
+  dependencies:
+    iconv-lite "~0.4.13"
+
+fbjs@^0.8.9:
+  version "0.8.12"
+  resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.12.tgz#10b5d92f76d45575fd63a217d4ea02bea2f8ed04"
+  dependencies:
+    core-js "^1.0.0"
+    isomorphic-fetch "^2.1.1"
+    loose-envify "^1.0.0"
+    object-assign "^4.1.0"
+    promise "^7.1.1"
+    setimmediate "^1.0.5"
+    ua-parser-js "^0.7.9"
+
+iconv-lite@~0.4.13:
+  version "0.4.17"
+  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.17.tgz#4fdaa3b38acbc2c031b045d0edcdfe1ecab18c8d"
+
+is-stream@^1.0.1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
+
+isomorphic-fetch@^2.1.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
+  dependencies:
+    node-fetch "^1.0.1"
+    whatwg-fetch ">=0.10.0"
+
+js-tokens@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7"
+
+loose-envify@^1.0.0, loose-envify@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
+  dependencies:
+    js-tokens "^3.0.0"
+
+node-fetch@^1.0.1:
+  version "1.7.1"
+  resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.1.tgz#899cb3d0a3c92f952c47f1b876f4c8aeabd400d5"
+  dependencies:
+    encoding "^0.1.11"
+    is-stream "^1.0.1"
+
+object-assign@^4.1.0:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+
+promise@^7.1.1:
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/promise/-/promise-7.1.1.tgz#489654c692616b8aa55b0724fa809bb7db49c5bf"
+  dependencies:
+    asap "~2.0.3"
+
+prop-types@^15.5.6:
+  version "15.5.10"
+  resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.10.tgz#2797dfc3126182e3a95e3dfbb2e893ddd7456154"
+  dependencies:
+    fbjs "^0.8.9"
+    loose-envify "^1.3.1"
+
+react-transition-group@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-1.2.0.tgz#b51fc921b0c3835a7ef7c571c79fc82c73e9204f"
+  dependencies:
+    chain-function "^1.0.0"
+    dom-helpers "^3.2.0"
+    loose-envify "^1.3.1"
+    prop-types "^15.5.6"
+    warning "^3.0.0"
+
+setimmediate@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
+
+ua-parser-js@^0.7.9:
+  version "0.7.12"
+  resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb"
+
+warning@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c"
+  dependencies:
+    loose-envify "^1.0.0"
+
+whatwg-fetch@>=0.10.0:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84"
diff --git a/addons/react-addons-linked-state-mixin/.gitignore b/addons/react-addons-linked-state-mixin/.gitignore
new file mode 100644
index 000000000000..07acb4248396
--- /dev/null
+++ b/addons/react-addons-linked-state-mixin/.gitignore
@@ -0,0 +1,2 @@
+react-addons-linked-state-mixin.js
+react-addons-linked-state-mixin.min.js
diff --git a/addons/react-addons-linked-state-mixin/LICENSE b/addons/react-addons-linked-state-mixin/LICENSE
new file mode 100644
index 000000000000..91b8f6f76ff0
--- /dev/null
+++ b/addons/react-addons-linked-state-mixin/LICENSE
@@ -0,0 +1,31 @@
+BSD License
+
+For React software
+
+Copyright (c) 2013-present, Facebook, Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+ * Neither the name Facebook nor the names of its contributors may be used to
+   endorse or promote products derived from this software without specific
+   prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/addons/react-addons-linked-state-mixin/PATENTS b/addons/react-addons-linked-state-mixin/PATENTS
new file mode 100644
index 000000000000..9c9f8e87a8f4
--- /dev/null
+++ b/addons/react-addons-linked-state-mixin/PATENTS
@@ -0,0 +1,33 @@
+Additional Grant of Patent Rights Version 2
+
+"Software" means the React software distributed by Facebook, Inc.
+
+Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software
+("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable
+(subject to the termination provision below) license under any Necessary
+Claims, to make, have made, use, sell, offer to sell, import, and otherwise
+transfer the Software. For avoidance of doubt, no license is granted under
+Facebook's rights in any patent claims that are infringed by (i) modifications
+to the Software made by you or any third party or (ii) the Software in
+combination with any software or other technology.
+
+The license granted hereunder will terminate, automatically and without notice,
+if you (or any of your subsidiaries, corporate affiliates or agents) initiate
+directly or indirectly, or take a direct financial interest in, any Patent
+Assertion: (i) against Facebook or any of its subsidiaries or corporate
+affiliates, (ii) against any party if such Patent Assertion arises in whole or
+in part from any software, technology, product or service of Facebook or any of
+its subsidiaries or corporate affiliates, or (iii) against any party relating
+to the Software. Notwithstanding the foregoing, if Facebook or any of its
+subsidiaries or corporate affiliates files a lawsuit alleging patent
+infringement against you in the first instance, and you respond by filing a
+patent infringement counterclaim in that lawsuit against that party that is
+unrelated to the Software, the license granted hereunder will not terminate
+under section (i) of this paragraph due to such counterclaim.
+
+A "Necessary Claim" is a claim of a patent owned by Facebook that is
+necessarily infringed by the Software standing alone.
+
+A "Patent Assertion" is any lawsuit or other action alleging direct, indirect,
+or contributory infringement or inducement to infringe any patent, including a
+cross-claim or counterclaim.
diff --git a/addons/react-addons-linked-state-mixin/README.md b/addons/react-addons-linked-state-mixin/README.md
new file mode 100644
index 000000000000..2510196fd7fd
--- /dev/null
+++ b/addons/react-addons-linked-state-mixin/README.md
@@ -0,0 +1,109 @@
+# react-addons-linked-state-mixin
+
+>**Note:**
+>This is a legacy React addon, and is no longer maintained.
+>
+>We don't encourage using it in new code, but it exists for backwards compatibility.  
+>The recommended migration path is to explicitly set `value` and the `onChange` handler instead of using `LinkedStateMixin`.
+
+**Importing `LinkedStateMixin`**
+
+```javascript
+import LinkedStateMixin from 'react-addons-linked-state-mixin'; // ES6
+var LinkedStateMixin = require('react-addons-linked-state-mixin'); // ES5 with npm
+```
+
+If you prefer a `<script>` tag, you can get it from `React.addons.LinkedStateMixin` with:
+
+```html
+<!-- development version -->
+<script src="https://unpkg.com/react-addons-linked-state-mixin/react-addons-linked-state-mixin.js"></script>
+
+<!-- production version -->
+<script src="https://unpkg.com/react-addons-linked-state-mixin/react-addons-linked-state-mixin.min.js"></script>
+```
+
+In this case, make sure to put the `<script>` tag after React.
+
+**Importing `LinkedInput`**
+
+After React 16, you will also need `LinkedInput` component if you want to keep using this pattern. You can import it like this:
+
+```javascript
+import LinkedInput from 'react-linked-input'; // ES6
+var LinkedInput = require('react-linked-input'); // ES5 with npm
+```
+
+If you prefer a `<script>` tag, you can get it from `LinkedInput` global with:
+
+```html
+<!-- development version -->
+<script src="https://unpkg.com/react-linked-input/react-linked-input.js"></script>
+
+<!-- production version -->
+<script src="https://unpkg.com/react-linked-input/react-linked-input.min.js"></script>
+```
+
+## Overview
+
+`LinkedStateMixin` is an easy way to express two-way binding with React.
+
+In React, data flows one way: from owner to child. We think that this makes your app's code easier to understand. You can think of it as "one-way data binding."
+
+However, there are lots of applications that require you to read some data and flow it back into your program. For example, when developing forms, you'll often want to update some React `state` when you receive user input. Or perhaps you want to perform layout in JavaScript and react to changes in some DOM element size.
+
+In React, you would implement this by listening to a "change" event, read from your data source (usually the DOM) and call `setState()` on one of your components. "Closing the data flow loop" explicitly leads to more understandable and easier-to-maintain programs. See [our forms documentation](https://facebook.github.io/react/docs/forms.html) for more information.
+
+Two-way binding -- implicitly enforcing that some value in the DOM is always consistent with some React `state` -- is concise and supports a wide variety of applications. We've provided `LinkedStateMixin`: syntactic sugar for setting up the common data flow loop pattern described above, or "linking" some data source to React `state`.
+
+> Note:
+>
+> `LinkedStateMixin` is just a thin wrapper and convention around the `onChange`/`setState()` pattern. It doesn't fundamentally change how data flows in your React application.
+
+## LinkedStateMixin: Before and After
+
+Here's a simple form example without using `LinkedStateMixin`:
+
+```javascript
+var createReactClass = require('create-react-class');
+
+var NoLink = createReactClass({
+  getInitialState: function() {
+    return {message: 'Hello!'};
+  },
+  handleChange: function(event) {
+    this.setState({message: event.target.value});
+  },
+  render: function() {
+    var message = this.state.message;
+    return <input type="text" value={message} onChange={this.handleChange} />;
+  }
+});
+```
+
+This works really well and it's very clear how data is flowing, however, with a lot of form fields it could get a bit verbose. Let's use `LinkedStateMixin` to save us some typing:
+
+```javascript
+var createReactClass = require('create-react-class');
+var LinkedInput = require('react-linked-input');
+
+var WithLink = createReactClass({
+  mixins: [LinkedStateMixin],
+  getInitialState: function() {
+    return {message: 'Hello!'};
+  },
+  render: function() {
+    return <LinkedInput type="text" valueLink={this.linkState('message')} />;
+  }
+});
+```
+
+`LinkedStateMixin` adds a method to your React component called `linkState()`. `linkState()` returns a `valueLink` object which contains the current value of the React state and a callback to change it. The `LinkInput` component passes those properties to the input it renders.
+
+`valueLink` objects can be passed up and down the tree as props, so it's easy (and explicit) to set up two-way binding between a component deep in the hierarchy and state that lives higher in the hierarchy.
+
+Note that checkboxes have a special behavior regarding their `value` attribute, which is the value that will be sent on form submit if the checkbox is checked (defaults to `on`). The `value` attribute is not updated when the checkbox is checked or unchecked. For checkboxes, you should use `checkedLink` instead of `valueLink`:
+
+```
+<LinkedInput type="checkbox" checkedLink={this.linkState('booleanValue')} />
+```
diff --git a/addons/react-addons-linked-state-mixin/index.js b/addons/react-addons-linked-state-mixin/index.js
new file mode 100644
index 000000000000..a174a4fc0eaf
--- /dev/null
+++ b/addons/react-addons-linked-state-mixin/index.js
@@ -0,0 +1,158 @@
+/**
+ * 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.
+ */
+
+'use strict';
+
+/**
+ * ReactLink encapsulates a common pattern in which a component wants to modify
+ * a prop received from its parent. ReactLink allows the parent to pass down a
+ * value coupled with a callback that, when invoked, expresses an intent to
+ * modify that value. For example:
+ *
+ * React.createClass({
+ *   getInitialState: function() {
+ *     return {value: ''};
+ *   },
+ *   render: function() {
+ *     var valueLink = new ReactLink(this.state.value, this._handleValueChange);
+ *     return <input valueLink={valueLink} />;
+ *   },
+ *   _handleValueChange: function(newValue) {
+ *     this.setState({value: newValue});
+ *   }
+ * });
+ *
+ * We have provided some sugary mixins to make the creation and
+ * consumption of ReactLink easier; see LinkedValueUtils and LinkedStateMixin.
+ */
+
+/**
+ * Deprecated: An an easy way to express two-way binding with React.
+ * See https://facebook.github.io/react/docs/two-way-binding-helpers.html
+ *
+ * @param {*} value current value of the link
+ * @param {function} requestChange callback to request a change
+ */
+function ReactLink(value, requestChange) {
+  this.value = value;
+  this.requestChange = requestChange;
+}
+
+var ReactStateSetters = {
+  /**
+   * Returns a function that calls the provided function, and uses the result
+   * of that to set the component's state.
+   *
+   * @param {ReactCompositeComponent} component
+   * @param {function} funcReturningState Returned callback uses this to
+   *                                      determine how to update state.
+   * @return {function} callback that when invoked uses funcReturningState to
+   *                    determined the object literal to setState.
+   */
+  createStateSetter: function(component, funcReturningState) {
+    return function(a, b, c, d, e, f) {
+      var partialState = funcReturningState.call(component, a, b, c, d, e, f);
+      if (partialState) {
+        component.setState(partialState);
+      }
+    };
+  },
+
+  /**
+   * Returns a single-argument callback that can be used to update a single
+   * key in the component's state.
+   *
+   * Note: this is memoized function, which makes it inexpensive to call.
+   *
+   * @param {ReactCompositeComponent} component
+   * @param {string} key The key in the state that you should update.
+   * @return {function} callback of 1 argument which calls setState() with
+   *                    the provided keyName and callback argument.
+   */
+  createStateKeySetter: function(component, key) {
+    // Memoize the setters.
+    var cache = component.__keySetters || (component.__keySetters = {});
+    return cache[key] || (cache[key] = createStateKeySetter(component, key));
+  }
+};
+
+function createStateKeySetter(component, key) {
+  // Partial state is allocated outside of the function closure so it can be
+  // reused with every call, avoiding memory allocation when this function
+  // is called.
+  var partialState = {};
+  return function stateKeySetter(value) {
+    partialState[key] = value;
+    component.setState(partialState);
+  };
+}
+
+ReactStateSetters.Mixin = {
+  /**
+   * Returns a function that calls the provided function, and uses the result
+   * of that to set the component's state.
+   *
+   * For example, these statements are equivalent:
+   *
+   *   this.setState({x: 1});
+   *   this.createStateSetter(function(xValue) {
+   *     return {x: xValue};
+   *   })(1);
+   *
+   * @param {function} funcReturningState Returned callback uses this to
+   *                                      determine how to update state.
+   * @return {function} callback that when invoked uses funcReturningState to
+   *                    determined the object literal to setState.
+   */
+  createStateSetter: function(funcReturningState) {
+    return ReactStateSetters.createStateSetter(this, funcReturningState);
+  },
+
+  /**
+   * Returns a single-argument callback that can be used to update a single
+   * key in the component's state.
+   *
+   * For example, these statements are equivalent:
+   *
+   *   this.setState({x: 1});
+   *   this.createStateKeySetter('x')(1);
+   *
+   * Note: this is memoized function, which makes it inexpensive to call.
+   *
+   * @param {string} key The key in the state that you should update.
+   * @return {function} callback of 1 argument which calls setState() with
+   *                    the provided keyName and callback argument.
+   */
+  createStateKeySetter: function(key) {
+    return ReactStateSetters.createStateKeySetter(this, key);
+  }
+};
+
+/**
+ * A simple mixin around ReactLink.forState().
+ * See https://facebook.github.io/react/docs/two-way-binding-helpers.html
+ */
+var LinkedStateMixin = {
+  /**
+   * Create a ReactLink that's linked to part of this component's state. The
+   * ReactLink will have the current value of this.state[key] and will call
+   * setState() when a change is requested.
+   *
+   * @param {string} key state key to update.
+   * @return {ReactLink} ReactLink instance linking to the state.
+   */
+  linkState: function(key) {
+    return new ReactLink(
+      this.state[key],
+      ReactStateSetters.createStateKeySetter(this, key)
+    );
+  }
+};
+
+module.exports = LinkedStateMixin;
diff --git a/addons/react-addons-linked-state-mixin/package.json b/addons/react-addons-linked-state-mixin/package.json
new file mode 100644
index 000000000000..c48f6c542f2c
--- /dev/null
+++ b/addons/react-addons-linked-state-mixin/package.json
@@ -0,0 +1,37 @@
+{
+  "name": "react-addons-linked-state-mixin",
+  "version": "15.6.0",
+  "main": "index.js",
+  "repository": "facebook/react",
+  "keywords": [
+    "react",
+    "react-addon"
+  ],
+  "license": "BSD-3-Clause",
+  "dependencies": {
+    "fbjs": "^0.8.4",
+    "object-assign": "^4.1.0"
+  },
+  "scripts": {
+    "test": "TEST_ENTRY=./index.js jest",
+    "build:dev": "NODE_ENV=development webpack && TEST_ENTRY=./react-addons-linked-state-mixin.js jest",
+    "build:prod": "NODE_ENV=production webpack && NODE_ENV=production TEST_ENTRY=./react-addons-linked-state-mixin.min.js jest",
+    "build": "npm run build:dev && npm run build:prod && node ../postbuild.js",
+    "prepublish": "npm test && npm run build"
+  },
+  "files": [
+    "LICENSE",
+    "PATENTS",
+    "README.md",
+    "index.js",
+    "react-addons-linked-state-mixin.js",
+    "react-addons-linked-state-mixin.min.js"
+  ],
+  "devDependencies": {
+    "create-react-class": "^15.5.4",
+    "jest": "^19.0.2",
+    "react": "^15.5.4",
+    "react-dom": "^15.5.4",
+    "webpack": "^2.6.1"
+  }
+}
diff --git a/addons/react-addons-linked-state-mixin/test.js b/addons/react-addons-linked-state-mixin/test.js
new file mode 100644
index 000000000000..e8527fd87d32
--- /dev/null
+++ b/addons/react-addons-linked-state-mixin/test.js
@@ -0,0 +1,133 @@
+/**
+ * Copyright 2015-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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+let LinkedStateMixin;
+let createReactClass;
+let React;
+let ReactDOM;
+let ReactTestUtils;
+
+// Catch stray warnings
+var env = jasmine.getEnv();
+var callCount = 0;
+var oldError = console.error;
+var newError = function() {
+  callCount++;
+  oldError.apply(this, arguments);
+};
+console.error = newError;
+env.beforeEach(() => {
+  callCount = 0;
+  jasmine.addMatchers({
+    toBeReset() {
+      return {
+        compare(actual) {
+          if (actual !== newError && !jasmine.isSpy(actual)) {
+            return {
+              pass: false,
+              message: 'Test did not tear down console.error mock properly.'
+            };
+          }
+          return {pass: true};
+        }
+      };
+    },
+    toNotHaveBeenCalled() {
+      return {
+        compare(actual) {
+          return {
+            pass: callCount === 0,
+            message:
+              'Expected test not to warn. If the warning is expected, mock ' +
+                "it out using spyOn(console, 'error'); and test that the " +
+                'warning occurs.'
+          };
+        }
+      };
+    }
+  });
+});
+env.afterEach(() => {
+  expect(console.error).toBeReset();
+  expect(console.error).toNotHaveBeenCalled();
+});
+
+describe('LinkedStateMixin', () => {
+  beforeEach(() => {
+    jest.resetModules();
+
+    createReactClass = require('create-react-class');
+    React = require('react');
+    ReactDOM = require('react-dom');
+    ReactTestUtils = require('react-dom/test-utils');
+    LinkedStateMixin = require(process.env.TEST_ENTRY);
+  });
+
+  // https://facebook.github.io/react/docs/two-way-binding-helpers.html#linkedstatemixin-before-and-after
+  it('should work with valueLink', () => {
+    spyOn(console, 'error'); // Ignore deprecated valueLink message for now
+
+    const WithLink = createReactClass({
+      mixins: [LinkedStateMixin],
+      getInitialState: function() {
+        return {message: 'Hello!'};
+      },
+      render: function() {
+        return <input type="text" valueLink={this.linkState('message')} />;
+      }
+    });
+
+    const instance = ReactTestUtils.renderIntoDocument(
+      React.createElement(WithLink)
+    );
+
+    expect(instance.state.message).toBe('Hello!');
+
+    const node = ReactDOM.findDOMNode(instance);
+    node.value = 'Goodbye!';
+    ReactTestUtils.Simulate.change(node);
+
+    expect(instance.state.message).toBe('Goodbye!');
+  });
+
+  // https://facebook.github.io/react/docs/two-way-binding-helpers.html#linkedstatemixin-without-valuelink
+  it('should work without valueLink', () => {
+    const WithoutLink = createReactClass({
+      mixins: [LinkedStateMixin],
+      getInitialState: function() {
+        return {message: 'Hello!'};
+      },
+      render: function() {
+        var valueLink = this.linkState('message');
+        var handleChange = function(e) {
+          valueLink.requestChange(e.target.value);
+        };
+        return (
+          <input type="text" value={valueLink.value} onChange={handleChange} />
+        );
+      }
+    });
+
+    const instance = ReactTestUtils.renderIntoDocument(
+      React.createElement(WithoutLink)
+    );
+
+    expect(instance.state.message).toBe('Hello!');
+
+    const node = ReactDOM.findDOMNode(instance);
+    node.value = 'Goodbye!';
+    ReactTestUtils.Simulate.change(node);
+
+    expect(instance.state.message).toBe('Goodbye!');
+  });
+});
diff --git a/addons/react-addons-linked-state-mixin/webpack.config.js b/addons/react-addons-linked-state-mixin/webpack.config.js
new file mode 100644
index 000000000000..5058312b2d8d
--- /dev/null
+++ b/addons/react-addons-linked-state-mixin/webpack.config.js
@@ -0,0 +1,55 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+const webpack = require('webpack');
+
+let __DEV__;
+switch (process.env.NODE_ENV) {
+  case 'development':
+    __DEV__ = true;
+    break;
+  case 'production':
+    __DEV__ = false;
+    break;
+  default:
+    throw new Error('Unknown environment.');
+}
+
+module.exports = {
+  entry: './index',
+  output: {
+    library: 'LinkedStateMixin',
+    libraryTarget: 'umd',
+    filename: __DEV__
+      ? 'react-addons-linked-state-mixin.js'
+      : 'react-addons-linked-state-mixin.min.js'
+  },
+  plugins: [
+    new webpack.DefinePlugin({
+      'process.env.NODE_ENV': __DEV__ ? '"development"' : '"production"'
+    })
+  ].concat(
+    __DEV__
+      ? []
+      : [
+          new webpack.optimize.UglifyJsPlugin({
+            compress: {
+              warnings: false
+            },
+            output: {
+              comments: false
+            }
+          })
+        ]
+  )
+};
diff --git a/addons/react-addons-linked-state-mixin/yarn.lock b/addons/react-addons-linked-state-mixin/yarn.lock
new file mode 100644
index 000000000000..9f8f5d3e4db2
--- /dev/null
+++ b/addons/react-addons-linked-state-mixin/yarn.lock
@@ -0,0 +1,2831 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+abab@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.3.tgz#b81de5f7274ec4e756d797cd834f303642724e5d"
+
+abbrev@1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f"
+
+acorn-dynamic-import@^2.0.0:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz#c752bd210bef679501b6c6cb7fc84f8f47158cc4"
+  dependencies:
+    acorn "^4.0.3"
+
+acorn-globals@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-3.1.0.tgz#fd8270f71fbb4996b004fa880ee5d46573a731bf"
+  dependencies:
+    acorn "^4.0.4"
+
+acorn@^4.0.3, acorn@^4.0.4:
+  version "4.0.11"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.11.tgz#edcda3bd937e7556410d42ed5860f67399c794c0"
+
+acorn@^5.0.0:
+  version "5.0.3"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.0.3.tgz#c460df08491463f028ccb82eab3730bf01087b3d"
+
+ajv-keywords@^1.1.1:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c"
+
+ajv@^4.7.0, ajv@^4.9.1:
+  version "4.11.5"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.5.tgz#b6ee74657b993a01dce44b7944d56f485828d5bd"
+  dependencies:
+    co "^4.6.0"
+    json-stable-stringify "^1.0.1"
+
+align-text@^0.1.1, align-text@^0.1.3:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
+  dependencies:
+    kind-of "^3.0.2"
+    longest "^1.0.1"
+    repeat-string "^1.5.2"
+
+amdefine@>=0.0.4:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
+
+ansi-escapes@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
+
+ansi-regex@^2.0.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
+
+ansi-styles@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
+
+ansi-styles@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.0.0.tgz#5404e93a544c4fec7f048262977bebfe3155e0c1"
+  dependencies:
+    color-convert "^1.0.0"
+
+anymatch@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507"
+  dependencies:
+    arrify "^1.0.0"
+    micromatch "^2.1.5"
+
+append-transform@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-0.4.0.tgz#d76ebf8ca94d276e247a36bad44a4b74ab611991"
+  dependencies:
+    default-require-extensions "^1.0.0"
+
+aproba@^1.0.3:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.2.tgz#45c6629094de4e96f693ef7eab74ae079c240fc1"
+
+are-we-there-yet@~1.1.2:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d"
+  dependencies:
+    delegates "^1.0.0"
+    readable-stream "^2.0.6"
+
+argparse@^1.0.7:
+  version "1.0.9"
+  resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86"
+  dependencies:
+    sprintf-js "~1.0.2"
+
+arr-diff@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf"
+  dependencies:
+    arr-flatten "^1.0.1"
+
+arr-flatten@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b"
+
+array-equal@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93"
+
+array-unique@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
+
+arrify@^1.0.0, arrify@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
+
+asap@~2.0.3:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f"
+
+asn1.js@^4.0.0:
+  version "4.9.1"
+  resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.1.tgz#48ba240b45a9280e94748990ba597d216617fd40"
+  dependencies:
+    bn.js "^4.0.0"
+    inherits "^2.0.1"
+    minimalistic-assert "^1.0.0"
+
+asn1@~0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86"
+
+assert-plus@1.0.0, assert-plus@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
+
+assert-plus@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234"
+
+assert@^1.1.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91"
+  dependencies:
+    util "0.10.3"
+
+async-each@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
+
+async@^1.4.0:
+  version "1.5.2"
+  resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
+
+async@^2.1.2, async@^2.1.4:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/async/-/async-2.3.0.tgz#1013d1051047dd320fe24e494d5c66ecaf6147d9"
+  dependencies:
+    lodash "^4.14.0"
+
+asynckit@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+
+aws-sign2@~0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f"
+
+aws4@^1.2.1:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e"
+
+babel-code-frame@^6.22.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4"
+  dependencies:
+    chalk "^1.1.0"
+    esutils "^2.0.2"
+    js-tokens "^3.0.0"
+
+babel-core@^6.0.0, babel-core@^6.24.0:
+  version "6.24.0"
+  resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.24.0.tgz#8f36a0a77f5c155aed6f920b844d23ba56742a02"
+  dependencies:
+    babel-code-frame "^6.22.0"
+    babel-generator "^6.24.0"
+    babel-helpers "^6.23.0"
+    babel-messages "^6.23.0"
+    babel-register "^6.24.0"
+    babel-runtime "^6.22.0"
+    babel-template "^6.23.0"
+    babel-traverse "^6.23.1"
+    babel-types "^6.23.0"
+    babylon "^6.11.0"
+    convert-source-map "^1.1.0"
+    debug "^2.1.1"
+    json5 "^0.5.0"
+    lodash "^4.2.0"
+    minimatch "^3.0.2"
+    path-is-absolute "^1.0.0"
+    private "^0.1.6"
+    slash "^1.0.0"
+    source-map "^0.5.0"
+
+babel-generator@^6.18.0, babel-generator@^6.24.0:
+  version "6.24.0"
+  resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.24.0.tgz#eba270a8cc4ce6e09a61be43465d7c62c1f87c56"
+  dependencies:
+    babel-messages "^6.23.0"
+    babel-runtime "^6.22.0"
+    babel-types "^6.23.0"
+    detect-indent "^4.0.0"
+    jsesc "^1.3.0"
+    lodash "^4.2.0"
+    source-map "^0.5.0"
+    trim-right "^1.0.1"
+
+babel-helpers@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.23.0.tgz#4f8f2e092d0b6a8808a4bde79c27f1e2ecf0d992"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-template "^6.23.0"
+
+babel-jest@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-19.0.0.tgz#59323ced99a3a84d359da219ca881074ffc6ce3f"
+  dependencies:
+    babel-core "^6.0.0"
+    babel-plugin-istanbul "^4.0.0"
+    babel-preset-jest "^19.0.0"
+
+babel-messages@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e"
+  dependencies:
+    babel-runtime "^6.22.0"
+
+babel-plugin-istanbul@^4.0.0:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.1.tgz#c12de0fc6fe42adfb16be56f1ad11e4a9782eca9"
+  dependencies:
+    find-up "^2.1.0"
+    istanbul-lib-instrument "^1.6.2"
+    test-exclude "^4.0.3"
+
+babel-plugin-jest-hoist@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-19.0.0.tgz#4ae2a04ea612a6e73651f3fde52c178991304bea"
+
+babel-preset-jest@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-19.0.0.tgz#22d67201d02324a195811288eb38294bb3cac396"
+  dependencies:
+    babel-plugin-jest-hoist "^19.0.0"
+
+babel-register@^6.24.0:
+  version "6.24.0"
+  resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.24.0.tgz#5e89f8463ba9970356d02eb07dabe3308b080cfd"
+  dependencies:
+    babel-core "^6.24.0"
+    babel-runtime "^6.22.0"
+    core-js "^2.4.0"
+    home-or-tmp "^2.0.0"
+    lodash "^4.2.0"
+    mkdirp "^0.5.1"
+    source-map-support "^0.4.2"
+
+babel-runtime@^6.22.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b"
+  dependencies:
+    core-js "^2.4.0"
+    regenerator-runtime "^0.10.0"
+
+babel-template@^6.16.0, babel-template@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.23.0.tgz#04d4f270adbb3aa704a8143ae26faa529238e638"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-traverse "^6.23.0"
+    babel-types "^6.23.0"
+    babylon "^6.11.0"
+    lodash "^4.2.0"
+
+babel-traverse@^6.18.0, babel-traverse@^6.23.0, babel-traverse@^6.23.1:
+  version "6.23.1"
+  resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.23.1.tgz#d3cb59010ecd06a97d81310065f966b699e14f48"
+  dependencies:
+    babel-code-frame "^6.22.0"
+    babel-messages "^6.23.0"
+    babel-runtime "^6.22.0"
+    babel-types "^6.23.0"
+    babylon "^6.15.0"
+    debug "^2.2.0"
+    globals "^9.0.0"
+    invariant "^2.2.0"
+    lodash "^4.2.0"
+
+babel-types@^6.18.0, babel-types@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.23.0.tgz#bb17179d7538bad38cd0c9e115d340f77e7e9acf"
+  dependencies:
+    babel-runtime "^6.22.0"
+    esutils "^2.0.2"
+    lodash "^4.2.0"
+    to-fast-properties "^1.0.1"
+
+babylon@^6.11.0, babylon@^6.13.0, babylon@^6.15.0:
+  version "6.16.1"
+  resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.16.1.tgz#30c5a22f481978a9e7f8cdfdf496b11d94b404d3"
+
+balanced-match@^0.4.1:
+  version "0.4.2"
+  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
+
+base64-js@^1.0.2:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1"
+
+bcrypt-pbkdf@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d"
+  dependencies:
+    tweetnacl "^0.14.3"
+
+big.js@^3.1.3:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.1.3.tgz#4cada2193652eb3ca9ec8e55c9015669c9806978"
+
+binary-extensions@^1.0.0:
+  version "1.8.0"
+  resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.8.0.tgz#48ec8d16df4377eae5fa5884682480af4d95c774"
+
+block-stream@*:
+  version "0.0.9"
+  resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a"
+  dependencies:
+    inherits "~2.0.0"
+
+bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0:
+  version "4.11.6"
+  resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215"
+
+boom@2.x.x:
+  version "2.10.1"
+  resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f"
+  dependencies:
+    hoek "2.x.x"
+
+brace-expansion@^1.0.0:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9"
+  dependencies:
+    balanced-match "^0.4.1"
+    concat-map "0.0.1"
+
+braces@^1.8.2:
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7"
+  dependencies:
+    expand-range "^1.8.1"
+    preserve "^0.2.0"
+    repeat-element "^1.1.2"
+
+brorand@^1.0.1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
+
+browser-resolve@^1.11.2:
+  version "1.11.2"
+  resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.2.tgz#8ff09b0a2c421718a1051c260b32e48f442938ce"
+  dependencies:
+    resolve "1.1.7"
+
+browserify-aes@^1.0.0, browserify-aes@^1.0.4:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.0.6.tgz#5e7725dbdef1fd5930d4ebab48567ce451c48a0a"
+  dependencies:
+    buffer-xor "^1.0.2"
+    cipher-base "^1.0.0"
+    create-hash "^1.1.0"
+    evp_bytestokey "^1.0.0"
+    inherits "^2.0.1"
+
+browserify-cipher@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.0.tgz#9988244874bf5ed4e28da95666dcd66ac8fc363a"
+  dependencies:
+    browserify-aes "^1.0.4"
+    browserify-des "^1.0.0"
+    evp_bytestokey "^1.0.0"
+
+browserify-des@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.0.tgz#daa277717470922ed2fe18594118a175439721dd"
+  dependencies:
+    cipher-base "^1.0.1"
+    des.js "^1.0.0"
+    inherits "^2.0.1"
+
+browserify-rsa@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524"
+  dependencies:
+    bn.js "^4.1.0"
+    randombytes "^2.0.1"
+
+browserify-sign@^4.0.0:
+  version "4.0.4"
+  resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298"
+  dependencies:
+    bn.js "^4.1.1"
+    browserify-rsa "^4.0.0"
+    create-hash "^1.1.0"
+    create-hmac "^1.1.2"
+    elliptic "^6.0.0"
+    inherits "^2.0.1"
+    parse-asn1 "^5.0.0"
+
+browserify-zlib@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d"
+  dependencies:
+    pako "~0.2.0"
+
+bser@1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/bser/-/bser-1.0.2.tgz#381116970b2a6deea5646dd15dd7278444b56169"
+  dependencies:
+    node-int64 "^0.4.0"
+
+bser@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719"
+  dependencies:
+    node-int64 "^0.4.0"
+
+buffer-xor@^1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9"
+
+buffer@^4.3.0:
+  version "4.9.1"
+  resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298"
+  dependencies:
+    base64-js "^1.0.2"
+    ieee754 "^1.1.4"
+    isarray "^1.0.0"
+
+builtin-modules@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
+
+builtin-status-codes@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
+
+callsites@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50"
+
+camelcase@^1.0.2:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39"
+
+camelcase@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
+
+caseless@~0.12.0:
+  version "0.12.0"
+  resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
+
+center-align@^0.1.1:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad"
+  dependencies:
+    align-text "^0.1.3"
+    lazy-cache "^1.0.3"
+
+chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
+  dependencies:
+    ansi-styles "^2.2.1"
+    escape-string-regexp "^1.0.2"
+    has-ansi "^2.0.0"
+    strip-ansi "^3.0.0"
+    supports-color "^2.0.0"
+
+chokidar@^1.4.3:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
+  dependencies:
+    anymatch "^1.3.0"
+    async-each "^1.0.0"
+    glob-parent "^2.0.0"
+    inherits "^2.0.1"
+    is-binary-path "^1.0.0"
+    is-glob "^2.0.0"
+    path-is-absolute "^1.0.0"
+    readdirp "^2.0.0"
+  optionalDependencies:
+    fsevents "^1.0.0"
+
+ci-info@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.0.0.tgz#dc5285f2b4e251821683681c381c3388f46ec534"
+
+cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.3.tgz#eeabf194419ce900da3018c207d212f2a6df0a07"
+  dependencies:
+    inherits "^2.0.1"
+
+cliui@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1"
+  dependencies:
+    center-align "^0.1.1"
+    right-align "^0.1.1"
+    wordwrap "0.0.2"
+
+cliui@^3.2.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
+  dependencies:
+    string-width "^1.0.1"
+    strip-ansi "^3.0.1"
+    wrap-ansi "^2.0.0"
+
+co@^4.6.0:
+  version "4.6.0"
+  resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
+
+code-point-at@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
+
+color-convert@^1.0.0:
+  version "1.9.0"
+  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a"
+  dependencies:
+    color-name "^1.1.1"
+
+color-name@^1.1.1:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.2.tgz#5c8ab72b64bd2215d617ae9559ebb148475cf98d"
+
+combined-stream@^1.0.5, combined-stream@~1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009"
+  dependencies:
+    delayed-stream "~1.0.0"
+
+concat-map@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+
+console-browserify@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10"
+  dependencies:
+    date-now "^0.1.4"
+
+console-control-strings@^1.0.0, console-control-strings@~1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
+
+constants-browserify@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
+
+content-type-parser@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/content-type-parser/-/content-type-parser-1.0.1.tgz#c3e56988c53c65127fb46d4032a3a900246fdc94"
+
+convert-source-map@^1.1.0:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5"
+
+core-js@^1.0.0:
+  version "1.2.7"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
+
+core-js@^2.4.0:
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e"
+
+core-util-is@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
+
+create-ecdh@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.0.tgz#888c723596cdf7612f6498233eebd7a35301737d"
+  dependencies:
+    bn.js "^4.1.0"
+    elliptic "^6.0.0"
+
+create-hash@^1.1.0, create-hash@^1.1.1, create-hash@^1.1.2:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.3.tgz#606042ac8b9262750f483caddab0f5819172d8fd"
+  dependencies:
+    cipher-base "^1.0.1"
+    inherits "^2.0.1"
+    ripemd160 "^2.0.0"
+    sha.js "^2.4.0"
+
+create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.6.tgz#acb9e221a4e17bdb076e90657c42b93e3726cf06"
+  dependencies:
+    cipher-base "^1.0.3"
+    create-hash "^1.1.0"
+    inherits "^2.0.1"
+    ripemd160 "^2.0.0"
+    safe-buffer "^5.0.1"
+    sha.js "^2.4.8"
+
+create-react-class@^15.5.4:
+  version "15.5.4"
+  resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.5.4.tgz#188875cb15e2fbe4ca595b6f43eb0e4a1f00fe50"
+  dependencies:
+    fbjs "^0.8.9"
+    loose-envify "^1.3.1"
+    object-assign "^4.1.1"
+
+cryptiles@2.x.x:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8"
+  dependencies:
+    boom "2.x.x"
+
+crypto-browserify@^3.11.0:
+  version "3.11.0"
+  resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.11.0.tgz#3652a0906ab9b2a7e0c3ce66a408e957a2485522"
+  dependencies:
+    browserify-cipher "^1.0.0"
+    browserify-sign "^4.0.0"
+    create-ecdh "^4.0.0"
+    create-hash "^1.1.0"
+    create-hmac "^1.1.0"
+    diffie-hellman "^5.0.0"
+    inherits "^2.0.1"
+    pbkdf2 "^3.0.3"
+    public-encrypt "^4.0.0"
+    randombytes "^2.0.0"
+
+cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0":
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.2.tgz#b8036170c79f07a90ff2f16e22284027a243848b"
+
+"cssstyle@>= 0.2.37 < 0.3.0":
+  version "0.2.37"
+  resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-0.2.37.tgz#541097234cb2513c83ceed3acddc27ff27987d54"
+  dependencies:
+    cssom "0.3.x"
+
+dashdash@^1.12.0:
+  version "1.14.1"
+  resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
+  dependencies:
+    assert-plus "^1.0.0"
+
+date-now@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
+
+debug@^2.1.1, debug@^2.2.0:
+  version "2.6.3"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.3.tgz#0f7eb8c30965ec08c72accfa0130c8b79984141d"
+  dependencies:
+    ms "0.7.2"
+
+decamelize@^1.0.0, decamelize@^1.1.1:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
+
+deep-extend@~0.4.0:
+  version "0.4.2"
+  resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f"
+
+deep-is@~0.1.3:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
+
+default-require-extensions@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8"
+  dependencies:
+    strip-bom "^2.0.0"
+
+delayed-stream@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+
+delegates@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
+
+des.js@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc"
+  dependencies:
+    inherits "^2.0.1"
+    minimalistic-assert "^1.0.0"
+
+detect-indent@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208"
+  dependencies:
+    repeating "^2.0.0"
+
+diff@^3.0.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9"
+
+diffie-hellman@^5.0.0:
+  version "5.0.2"
+  resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.2.tgz#b5835739270cfe26acf632099fded2a07f209e5e"
+  dependencies:
+    bn.js "^4.1.0"
+    miller-rabin "^4.0.0"
+    randombytes "^2.0.0"
+
+domain-browser@^1.1.1:
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc"
+
+ecc-jsbn@~0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505"
+  dependencies:
+    jsbn "~0.1.0"
+
+elliptic@^6.0.0:
+  version "6.4.0"
+  resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df"
+  dependencies:
+    bn.js "^4.4.0"
+    brorand "^1.0.1"
+    hash.js "^1.0.0"
+    hmac-drbg "^1.0.0"
+    inherits "^2.0.1"
+    minimalistic-assert "^1.0.0"
+    minimalistic-crypto-utils "^1.0.0"
+
+emojis-list@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
+
+encoding@^0.1.11:
+  version "0.1.12"
+  resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb"
+  dependencies:
+    iconv-lite "~0.4.13"
+
+enhanced-resolve@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.1.0.tgz#9f4b626f577245edcf4b2ad83d86e17f4f421dec"
+  dependencies:
+    graceful-fs "^4.1.2"
+    memory-fs "^0.4.0"
+    object-assign "^4.0.1"
+    tapable "^0.2.5"
+
+"errno@>=0.1.1 <0.2.0-0", errno@^0.1.3:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d"
+  dependencies:
+    prr "~0.0.0"
+
+error-ex@^1.2.0:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc"
+  dependencies:
+    is-arrayish "^0.2.1"
+
+escape-string-regexp@^1.0.2:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+
+escodegen@^1.6.1:
+  version "1.8.1"
+  resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018"
+  dependencies:
+    esprima "^2.7.1"
+    estraverse "^1.9.1"
+    esutils "^2.0.2"
+    optionator "^0.8.1"
+  optionalDependencies:
+    source-map "~0.2.0"
+
+esprima@^2.7.1:
+  version "2.7.3"
+  resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
+
+esprima@^3.1.1:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633"
+
+estraverse@^1.9.1:
+  version "1.9.3"
+  resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44"
+
+esutils@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
+
+events@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924"
+
+evp_bytestokey@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.0.tgz#497b66ad9fef65cd7c08a6180824ba1476b66e53"
+  dependencies:
+    create-hash "^1.1.1"
+
+exec-sh@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.0.tgz#14f75de3f20d286ef933099b2ce50a90359cef10"
+  dependencies:
+    merge "^1.1.3"
+
+expand-brackets@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
+  dependencies:
+    is-posix-bracket "^0.1.0"
+
+expand-range@^1.8.1:
+  version "1.8.2"
+  resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337"
+  dependencies:
+    fill-range "^2.1.0"
+
+extend@~3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4"
+
+extglob@^0.3.1:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1"
+  dependencies:
+    is-extglob "^1.0.0"
+
+extsprintf@1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550"
+
+fast-levenshtein@~2.0.4:
+  version "2.0.6"
+  resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
+
+fb-watchman@^1.8.0:
+  version "1.9.2"
+  resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-1.9.2.tgz#a24cf47827f82d38fb59a69ad70b76e3b6ae7383"
+  dependencies:
+    bser "1.0.2"
+
+fb-watchman@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58"
+  dependencies:
+    bser "^2.0.0"
+
+fbjs@^0.8.4, fbjs@^0.8.9:
+  version "0.8.12"
+  resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.12.tgz#10b5d92f76d45575fd63a217d4ea02bea2f8ed04"
+  dependencies:
+    core-js "^1.0.0"
+    isomorphic-fetch "^2.1.1"
+    loose-envify "^1.0.0"
+    object-assign "^4.1.0"
+    promise "^7.1.1"
+    setimmediate "^1.0.5"
+    ua-parser-js "^0.7.9"
+
+filename-regex@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775"
+
+fileset@^2.0.2:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/fileset/-/fileset-2.0.3.tgz#8e7548a96d3cc2327ee5e674168723a333bba2a0"
+  dependencies:
+    glob "^7.0.3"
+    minimatch "^3.0.3"
+
+fill-range@^2.1.0:
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723"
+  dependencies:
+    is-number "^2.1.0"
+    isobject "^2.0.0"
+    randomatic "^1.1.3"
+    repeat-element "^1.1.2"
+    repeat-string "^1.5.2"
+
+find-up@^1.0.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
+  dependencies:
+    path-exists "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+find-up@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
+  dependencies:
+    locate-path "^2.0.0"
+
+for-in@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
+
+for-own@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce"
+  dependencies:
+    for-in "^1.0.1"
+
+forever-agent@~0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
+
+form-data@~2.1.1:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4"
+  dependencies:
+    asynckit "^0.4.0"
+    combined-stream "^1.0.5"
+    mime-types "^2.1.12"
+
+fs.realpath@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+
+fsevents@^1.0.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.2.tgz#3282b713fb3ad80ede0e9fcf4611b5aa6fc033f4"
+  dependencies:
+    nan "^2.3.0"
+    node-pre-gyp "^0.6.36"
+
+fstream-ignore@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105"
+  dependencies:
+    fstream "^1.0.0"
+    inherits "2"
+    minimatch "^3.0.0"
+
+fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2:
+  version "1.0.11"
+  resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171"
+  dependencies:
+    graceful-fs "^4.1.2"
+    inherits "~2.0.0"
+    mkdirp ">=0.5 0"
+    rimraf "2"
+
+gauge@~2.7.3:
+  version "2.7.4"
+  resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
+  dependencies:
+    aproba "^1.0.3"
+    console-control-strings "^1.0.0"
+    has-unicode "^2.0.0"
+    object-assign "^4.1.0"
+    signal-exit "^3.0.0"
+    string-width "^1.0.1"
+    strip-ansi "^3.0.1"
+    wide-align "^1.1.0"
+
+get-caller-file@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5"
+
+getpass@^0.1.1:
+  version "0.1.6"
+  resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6"
+  dependencies:
+    assert-plus "^1.0.0"
+
+glob-base@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
+  dependencies:
+    glob-parent "^2.0.0"
+    is-glob "^2.0.0"
+
+glob-parent@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28"
+  dependencies:
+    is-glob "^2.0.0"
+
+glob@^7.0.3, glob@^7.0.5:
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
+  dependencies:
+    fs.realpath "^1.0.0"
+    inflight "^1.0.4"
+    inherits "2"
+    minimatch "^3.0.2"
+    once "^1.3.0"
+    path-is-absolute "^1.0.0"
+
+globals@^9.0.0:
+  version "9.17.0"
+  resolved "https://registry.yarnpkg.com/globals/-/globals-9.17.0.tgz#0c0ca696d9b9bb694d2e5470bd37777caad50286"
+
+graceful-fs@^4.1.2, graceful-fs@^4.1.6:
+  version "4.1.11"
+  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
+
+growly@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
+
+handlebars@^4.0.3:
+  version "4.0.6"
+  resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7"
+  dependencies:
+    async "^1.4.0"
+    optimist "^0.6.1"
+    source-map "^0.4.4"
+  optionalDependencies:
+    uglify-js "^2.6"
+
+har-schema@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e"
+
+har-validator@~4.2.1:
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a"
+  dependencies:
+    ajv "^4.9.1"
+    har-schema "^1.0.5"
+
+has-ansi@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
+  dependencies:
+    ansi-regex "^2.0.0"
+
+has-flag@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
+
+has-unicode@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
+
+hash-base@^2.0.0:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1"
+  dependencies:
+    inherits "^2.0.1"
+
+hash.js@^1.0.0, hash.js@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.0.3.tgz#1332ff00156c0a0ffdd8236013d07b77a0451573"
+  dependencies:
+    inherits "^2.0.1"
+
+hawk@~3.1.3:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4"
+  dependencies:
+    boom "2.x.x"
+    cryptiles "2.x.x"
+    hoek "2.x.x"
+    sntp "1.x.x"
+
+hmac-drbg@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
+  dependencies:
+    hash.js "^1.0.3"
+    minimalistic-assert "^1.0.0"
+    minimalistic-crypto-utils "^1.0.1"
+
+hoek@2.x.x:
+  version "2.16.3"
+  resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed"
+
+home-or-tmp@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8"
+  dependencies:
+    os-homedir "^1.0.0"
+    os-tmpdir "^1.0.1"
+
+hosted-git-info@^2.1.4:
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.4.1.tgz#4b0445e41c004a8bd1337773a4ff790ca40318c8"
+
+html-encoding-sniffer@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.1.tgz#79bf7a785ea495fe66165e734153f363ff5437da"
+  dependencies:
+    whatwg-encoding "^1.0.1"
+
+http-signature@~1.1.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf"
+  dependencies:
+    assert-plus "^0.2.0"
+    jsprim "^1.2.2"
+    sshpk "^1.7.0"
+
+https-browserify@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82"
+
+iconv-lite@0.4.13:
+  version "0.4.13"
+  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2"
+
+iconv-lite@~0.4.13:
+  version "0.4.15"
+  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb"
+
+ieee754@^1.1.4:
+  version "1.1.8"
+  resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4"
+
+indexof@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d"
+
+inflight@^1.0.4:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+  dependencies:
+    once "^1.3.0"
+    wrappy "1"
+
+inherits@2, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
+
+inherits@2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
+
+ini@~1.3.0:
+  version "1.3.4"
+  resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e"
+
+interpret@^1.0.0:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.3.tgz#cbc35c62eeee73f19ab7b10a801511401afc0f90"
+
+invariant@^2.2.0:
+  version "2.2.2"
+  resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360"
+  dependencies:
+    loose-envify "^1.0.0"
+
+invert-kv@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
+
+is-arrayish@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
+
+is-binary-path@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
+  dependencies:
+    binary-extensions "^1.0.0"
+
+is-buffer@^1.0.2:
+  version "1.1.5"
+  resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc"
+
+is-builtin-module@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe"
+  dependencies:
+    builtin-modules "^1.0.0"
+
+is-ci@^1.0.9:
+  version "1.0.10"
+  resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.0.10.tgz#f739336b2632365061a9d48270cd56ae3369318e"
+  dependencies:
+    ci-info "^1.0.0"
+
+is-dotfile@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d"
+
+is-equal-shallow@^0.1.3:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534"
+  dependencies:
+    is-primitive "^2.0.0"
+
+is-extendable@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
+
+is-extglob@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
+
+is-finite@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa"
+  dependencies:
+    number-is-nan "^1.0.0"
+
+is-fullwidth-code-point@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
+  dependencies:
+    number-is-nan "^1.0.0"
+
+is-glob@^2.0.0, is-glob@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
+  dependencies:
+    is-extglob "^1.0.0"
+
+is-number@^2.0.2, is-number@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
+  dependencies:
+    kind-of "^3.0.2"
+
+is-posix-bracket@^0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
+
+is-primitive@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
+
+is-stream@^1.0.1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
+
+is-typedarray@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
+
+is-utf8@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
+
+isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
+
+isexe@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+
+isobject@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
+  dependencies:
+    isarray "1.0.0"
+
+isomorphic-fetch@^2.1.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
+  dependencies:
+    node-fetch "^1.0.1"
+    whatwg-fetch ">=0.10.0"
+
+isstream@~0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
+
+istanbul-api@^1.1.0-alpha.1:
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-1.1.7.tgz#f6f37f09f8002b130f891c646b70ee4a8e7345ae"
+  dependencies:
+    async "^2.1.4"
+    fileset "^2.0.2"
+    istanbul-lib-coverage "^1.0.2"
+    istanbul-lib-hook "^1.0.5"
+    istanbul-lib-instrument "^1.7.0"
+    istanbul-lib-report "^1.0.0"
+    istanbul-lib-source-maps "^1.1.1"
+    istanbul-reports "^1.0.2"
+    js-yaml "^3.7.0"
+    mkdirp "^0.5.1"
+    once "^1.4.0"
+
+istanbul-lib-coverage@^1.0.0, istanbul-lib-coverage@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.0.2.tgz#87a0c015b6910651cb3b184814dfb339337e25e1"
+
+istanbul-lib-hook@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.0.5.tgz#6ca3d16d60c5f4082da39f7c5cd38ea8a772b88e"
+  dependencies:
+    append-transform "^0.4.0"
+
+istanbul-lib-instrument@^1.1.1, istanbul-lib-instrument@^1.6.2, istanbul-lib-instrument@^1.7.0:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.7.0.tgz#b8e0dc25709bb44e17336ab47b7bb5c97c23f659"
+  dependencies:
+    babel-generator "^6.18.0"
+    babel-template "^6.16.0"
+    babel-traverse "^6.18.0"
+    babel-types "^6.18.0"
+    babylon "^6.13.0"
+    istanbul-lib-coverage "^1.0.2"
+    semver "^5.3.0"
+
+istanbul-lib-report@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.0.0.tgz#d83dac7f26566b521585569367fe84ccfc7aaecb"
+  dependencies:
+    istanbul-lib-coverage "^1.0.2"
+    mkdirp "^0.5.1"
+    path-parse "^1.0.5"
+    supports-color "^3.1.2"
+
+istanbul-lib-source-maps@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.1.1.tgz#f8c8c2e8f2160d1d91526d97e5bd63b2079af71c"
+  dependencies:
+    istanbul-lib-coverage "^1.0.2"
+    mkdirp "^0.5.1"
+    rimraf "^2.4.4"
+    source-map "^0.5.3"
+
+istanbul-reports@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.0.2.tgz#4e8366abe6fa746cc1cd6633f108de12cc6ac6fa"
+  dependencies:
+    handlebars "^4.0.3"
+
+jest-changed-files@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-19.0.2.tgz#16c54c84c3270be408e06d2e8af3f3e37a885824"
+
+jest-cli@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-19.0.2.tgz#cc3620b62acac5f2d93a548cb6ef697d4ec85443"
+  dependencies:
+    ansi-escapes "^1.4.0"
+    callsites "^2.0.0"
+    chalk "^1.1.1"
+    graceful-fs "^4.1.6"
+    is-ci "^1.0.9"
+    istanbul-api "^1.1.0-alpha.1"
+    istanbul-lib-coverage "^1.0.0"
+    istanbul-lib-instrument "^1.1.1"
+    jest-changed-files "^19.0.2"
+    jest-config "^19.0.2"
+    jest-environment-jsdom "^19.0.2"
+    jest-haste-map "^19.0.0"
+    jest-jasmine2 "^19.0.2"
+    jest-message-util "^19.0.0"
+    jest-regex-util "^19.0.0"
+    jest-resolve-dependencies "^19.0.0"
+    jest-runtime "^19.0.2"
+    jest-snapshot "^19.0.2"
+    jest-util "^19.0.2"
+    micromatch "^2.3.11"
+    node-notifier "^5.0.1"
+    slash "^1.0.0"
+    string-length "^1.0.1"
+    throat "^3.0.0"
+    which "^1.1.1"
+    worker-farm "^1.3.1"
+    yargs "^6.3.0"
+
+jest-config@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-19.0.2.tgz#1b9bd2db0ddd16df61c2b10a54009e1768da6411"
+  dependencies:
+    chalk "^1.1.1"
+    jest-environment-jsdom "^19.0.2"
+    jest-environment-node "^19.0.2"
+    jest-jasmine2 "^19.0.2"
+    jest-regex-util "^19.0.0"
+    jest-resolve "^19.0.2"
+    jest-validate "^19.0.2"
+    pretty-format "^19.0.0"
+
+jest-diff@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-19.0.0.tgz#d1563cfc56c8b60232988fbc05d4d16ed90f063c"
+  dependencies:
+    chalk "^1.1.3"
+    diff "^3.0.0"
+    jest-matcher-utils "^19.0.0"
+    pretty-format "^19.0.0"
+
+jest-environment-jsdom@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-19.0.2.tgz#ceda859c4a4b94ab35e4de7dab54b926f293e4a3"
+  dependencies:
+    jest-mock "^19.0.0"
+    jest-util "^19.0.2"
+    jsdom "^9.11.0"
+
+jest-environment-node@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-19.0.2.tgz#6e84079db87ed21d0c05e1f9669f207b116fe99b"
+  dependencies:
+    jest-mock "^19.0.0"
+    jest-util "^19.0.2"
+
+jest-file-exists@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-file-exists/-/jest-file-exists-19.0.0.tgz#cca2e587a11ec92e24cfeab3f8a94d657f3fceb8"
+
+jest-haste-map@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-19.0.0.tgz#adde00b62b1fe04432a104b3254fc5004514b55e"
+  dependencies:
+    fb-watchman "^2.0.0"
+    graceful-fs "^4.1.6"
+    micromatch "^2.3.11"
+    sane "~1.5.0"
+    worker-farm "^1.3.1"
+
+jest-jasmine2@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-19.0.2.tgz#167991ac825981fb1a800af126e83afcca832c73"
+  dependencies:
+    graceful-fs "^4.1.6"
+    jest-matcher-utils "^19.0.0"
+    jest-matchers "^19.0.0"
+    jest-message-util "^19.0.0"
+    jest-snapshot "^19.0.2"
+
+jest-matcher-utils@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-19.0.0.tgz#5ecd9b63565d2b001f61fbf7ec4c7f537964564d"
+  dependencies:
+    chalk "^1.1.3"
+    pretty-format "^19.0.0"
+
+jest-matchers@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-matchers/-/jest-matchers-19.0.0.tgz#c74ecc6ebfec06f384767ba4d6fa4a42d6755754"
+  dependencies:
+    jest-diff "^19.0.0"
+    jest-matcher-utils "^19.0.0"
+    jest-message-util "^19.0.0"
+    jest-regex-util "^19.0.0"
+
+jest-message-util@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-19.0.0.tgz#721796b89c0e4d761606f9ba8cb828a3b6246416"
+  dependencies:
+    chalk "^1.1.1"
+    micromatch "^2.3.11"
+
+jest-mock@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-19.0.0.tgz#67038641e9607ab2ce08ec4a8cb83aabbc899d01"
+
+jest-regex-util@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-19.0.0.tgz#b7754587112aede1456510bb1f6afe74ef598691"
+
+jest-resolve-dependencies@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-19.0.0.tgz#a741ad1fa094140e64ecf2642a504f834ece22ee"
+  dependencies:
+    jest-file-exists "^19.0.0"
+
+jest-resolve@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-19.0.2.tgz#5793575de4f07aec32f7d7ff0c6c181963eefb3c"
+  dependencies:
+    browser-resolve "^1.11.2"
+    jest-haste-map "^19.0.0"
+    resolve "^1.2.0"
+
+jest-runtime@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-19.0.2.tgz#d9a43e72de416d27d196fd9c7940d98fe6685407"
+  dependencies:
+    babel-core "^6.0.0"
+    babel-jest "^19.0.0"
+    babel-plugin-istanbul "^4.0.0"
+    chalk "^1.1.3"
+    graceful-fs "^4.1.6"
+    jest-config "^19.0.2"
+    jest-file-exists "^19.0.0"
+    jest-haste-map "^19.0.0"
+    jest-regex-util "^19.0.0"
+    jest-resolve "^19.0.2"
+    jest-util "^19.0.2"
+    json-stable-stringify "^1.0.1"
+    micromatch "^2.3.11"
+    strip-bom "3.0.0"
+    yargs "^6.3.0"
+
+jest-snapshot@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-19.0.2.tgz#9c1b216214f7187c38bfd5c70b1efab16b0ff50b"
+  dependencies:
+    chalk "^1.1.3"
+    jest-diff "^19.0.0"
+    jest-file-exists "^19.0.0"
+    jest-matcher-utils "^19.0.0"
+    jest-util "^19.0.2"
+    natural-compare "^1.4.0"
+    pretty-format "^19.0.0"
+
+jest-util@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-19.0.2.tgz#e0a0232a2ab9e6b2b53668bdb3534c2b5977ed41"
+  dependencies:
+    chalk "^1.1.1"
+    graceful-fs "^4.1.6"
+    jest-file-exists "^19.0.0"
+    jest-message-util "^19.0.0"
+    jest-mock "^19.0.0"
+    jest-validate "^19.0.2"
+    leven "^2.0.0"
+    mkdirp "^0.5.1"
+
+jest-validate@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-19.0.2.tgz#dc534df5f1278d5b63df32b14241d4dbf7244c0c"
+  dependencies:
+    chalk "^1.1.1"
+    jest-matcher-utils "^19.0.0"
+    leven "^2.0.0"
+    pretty-format "^19.0.0"
+
+jest@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest/-/jest-19.0.2.tgz#b794faaf8ff461e7388f28beef559a54f20b2c10"
+  dependencies:
+    jest-cli "^19.0.2"
+
+jodid25519@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967"
+  dependencies:
+    jsbn "~0.1.0"
+
+js-tokens@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7"
+
+js-yaml@^3.7.0:
+  version "3.8.3"
+  resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.3.tgz#33a05ec481c850c8875929166fe1beb61c728766"
+  dependencies:
+    argparse "^1.0.7"
+    esprima "^3.1.1"
+
+jsbn@~0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
+
+jsdom@^9.11.0:
+  version "9.12.0"
+  resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-9.12.0.tgz#e8c546fffcb06c00d4833ca84410fed7f8a097d4"
+  dependencies:
+    abab "^1.0.3"
+    acorn "^4.0.4"
+    acorn-globals "^3.1.0"
+    array-equal "^1.0.0"
+    content-type-parser "^1.0.1"
+    cssom ">= 0.3.2 < 0.4.0"
+    cssstyle ">= 0.2.37 < 0.3.0"
+    escodegen "^1.6.1"
+    html-encoding-sniffer "^1.0.1"
+    nwmatcher ">= 1.3.9 < 2.0.0"
+    parse5 "^1.5.1"
+    request "^2.79.0"
+    sax "^1.2.1"
+    symbol-tree "^3.2.1"
+    tough-cookie "^2.3.2"
+    webidl-conversions "^4.0.0"
+    whatwg-encoding "^1.0.1"
+    whatwg-url "^4.3.0"
+    xml-name-validator "^2.0.1"
+
+jsesc@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b"
+
+json-loader@^0.5.4:
+  version "0.5.4"
+  resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.4.tgz#8baa1365a632f58a3c46d20175fc6002c96e37de"
+
+json-schema@0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
+
+json-stable-stringify@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af"
+  dependencies:
+    jsonify "~0.0.0"
+
+json-stringify-safe@~5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
+
+json5@^0.5.0, json5@^0.5.1:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
+
+jsonify@~0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
+
+jsprim@^1.2.2:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.0.tgz#a3b87e40298d8c380552d8cc7628a0bb95a22918"
+  dependencies:
+    assert-plus "1.0.0"
+    extsprintf "1.0.2"
+    json-schema "0.2.3"
+    verror "1.3.6"
+
+kind-of@^3.0.2:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47"
+  dependencies:
+    is-buffer "^1.0.2"
+
+lazy-cache@^1.0.3:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
+
+lcid@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
+  dependencies:
+    invert-kv "^1.0.0"
+
+leven@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580"
+
+levn@~0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
+  dependencies:
+    prelude-ls "~1.1.2"
+    type-check "~0.3.2"
+
+load-json-file@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
+  dependencies:
+    graceful-fs "^4.1.2"
+    parse-json "^2.2.0"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+    strip-bom "^2.0.0"
+
+loader-runner@^2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2"
+
+loader-utils@^0.2.16:
+  version "0.2.17"
+  resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348"
+  dependencies:
+    big.js "^3.1.3"
+    emojis-list "^2.0.0"
+    json5 "^0.5.0"
+    object-assign "^4.0.1"
+
+locate-path@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
+  dependencies:
+    p-locate "^2.0.0"
+    path-exists "^3.0.0"
+
+lodash@^4.14.0, lodash@^4.2.0:
+  version "4.17.4"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
+
+longest@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
+
+loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
+  dependencies:
+    js-tokens "^3.0.0"
+
+makeerror@1.0.x:
+  version "1.0.11"
+  resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c"
+  dependencies:
+    tmpl "1.0.x"
+
+memory-fs@^0.4.0, memory-fs@~0.4.1:
+  version "0.4.1"
+  resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"
+  dependencies:
+    errno "^0.1.3"
+    readable-stream "^2.0.1"
+
+merge@^1.1.3:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da"
+
+micromatch@^2.1.5, micromatch@^2.3.11:
+  version "2.3.11"
+  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
+  dependencies:
+    arr-diff "^2.0.0"
+    array-unique "^0.2.1"
+    braces "^1.8.2"
+    expand-brackets "^0.1.4"
+    extglob "^0.3.1"
+    filename-regex "^2.0.0"
+    is-extglob "^1.0.0"
+    is-glob "^2.0.1"
+    kind-of "^3.0.2"
+    normalize-path "^2.0.1"
+    object.omit "^2.0.0"
+    parse-glob "^3.0.4"
+    regex-cache "^0.4.2"
+
+miller-rabin@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.0.tgz#4a62fb1d42933c05583982f4c716f6fb9e6c6d3d"
+  dependencies:
+    bn.js "^4.0.0"
+    brorand "^1.0.1"
+
+mime-db@~1.27.0:
+  version "1.27.0"
+  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1"
+
+mime-types@^2.1.12, mime-types@~2.1.7:
+  version "2.1.15"
+  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed"
+  dependencies:
+    mime-db "~1.27.0"
+
+minimalistic-assert@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3"
+
+minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
+
+minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774"
+  dependencies:
+    brace-expansion "^1.0.0"
+
+minimist@0.0.8, minimist@~0.0.1:
+  version "0.0.8"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
+
+minimist@^1.1.1, minimist@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
+
+"mkdirp@>=0.5 0", mkdirp@^0.5.1, mkdirp@~0.5.0:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
+  dependencies:
+    minimist "0.0.8"
+
+ms@0.7.2:
+  version "0.7.2"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765"
+
+nan@^2.3.0:
+  version "2.6.2"
+  resolved "https://registry.yarnpkg.com/nan/-/nan-2.6.2.tgz#e4ff34e6c95fdfb5aecc08de6596f43605a7db45"
+
+natural-compare@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
+
+node-fetch@^1.0.1:
+  version "1.6.3"
+  resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04"
+  dependencies:
+    encoding "^0.1.11"
+    is-stream "^1.0.1"
+
+node-int64@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
+
+node-libs-browser@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.0.0.tgz#a3a59ec97024985b46e958379646f96c4b616646"
+  dependencies:
+    assert "^1.1.1"
+    browserify-zlib "^0.1.4"
+    buffer "^4.3.0"
+    console-browserify "^1.1.0"
+    constants-browserify "^1.0.0"
+    crypto-browserify "^3.11.0"
+    domain-browser "^1.1.1"
+    events "^1.0.0"
+    https-browserify "0.0.1"
+    os-browserify "^0.2.0"
+    path-browserify "0.0.0"
+    process "^0.11.0"
+    punycode "^1.2.4"
+    querystring-es3 "^0.2.0"
+    readable-stream "^2.0.5"
+    stream-browserify "^2.0.1"
+    stream-http "^2.3.1"
+    string_decoder "^0.10.25"
+    timers-browserify "^2.0.2"
+    tty-browserify "0.0.0"
+    url "^0.11.0"
+    util "^0.10.3"
+    vm-browserify "0.0.4"
+
+node-notifier@^5.0.1:
+  version "5.1.2"
+  resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.1.2.tgz#2fa9e12605fa10009d44549d6fcd8a63dde0e4ff"
+  dependencies:
+    growly "^1.3.0"
+    semver "^5.3.0"
+    shellwords "^0.1.0"
+    which "^1.2.12"
+
+node-pre-gyp@^0.6.36:
+  version "0.6.36"
+  resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.36.tgz#db604112cb74e0d477554e9b505b17abddfab786"
+  dependencies:
+    mkdirp "^0.5.1"
+    nopt "^4.0.1"
+    npmlog "^4.0.2"
+    rc "^1.1.7"
+    request "^2.81.0"
+    rimraf "^2.6.1"
+    semver "^5.3.0"
+    tar "^2.2.1"
+    tar-pack "^3.4.0"
+
+nopt@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
+  dependencies:
+    abbrev "1"
+    osenv "^0.1.4"
+
+normalize-package-data@^2.3.2:
+  version "2.3.6"
+  resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.6.tgz#498fa420c96401f787402ba21e600def9f981fff"
+  dependencies:
+    hosted-git-info "^2.1.4"
+    is-builtin-module "^1.0.0"
+    semver "2 || 3 || 4 || 5"
+    validate-npm-package-license "^3.0.1"
+
+normalize-path@^2.0.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
+  dependencies:
+    remove-trailing-separator "^1.0.1"
+
+npmlog@^4.0.2:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.0.tgz#dc59bee85f64f00ed424efb2af0783df25d1c0b5"
+  dependencies:
+    are-we-there-yet "~1.1.2"
+    console-control-strings "~1.1.0"
+    gauge "~2.7.3"
+    set-blocking "~2.0.0"
+
+number-is-nan@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
+
+"nwmatcher@>= 1.3.9 < 2.0.0":
+  version "1.3.9"
+  resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.3.9.tgz#8bab486ff7fa3dfd086656bbe8b17116d3692d2a"
+
+oauth-sign@~0.8.1:
+  version "0.8.2"
+  resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
+
+object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+
+object.omit@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
+  dependencies:
+    for-own "^0.1.4"
+    is-extendable "^0.1.1"
+
+once@^1.3.0, once@^1.3.3, once@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+  dependencies:
+    wrappy "1"
+
+optimist@^0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
+  dependencies:
+    minimist "~0.0.1"
+    wordwrap "~0.0.2"
+
+optionator@^0.8.1:
+  version "0.8.2"
+  resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64"
+  dependencies:
+    deep-is "~0.1.3"
+    fast-levenshtein "~2.0.4"
+    levn "~0.3.0"
+    prelude-ls "~1.1.2"
+    type-check "~0.3.2"
+    wordwrap "~1.0.0"
+
+os-browserify@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.2.1.tgz#63fc4ccee5d2d7763d26bbf8601078e6c2e0044f"
+
+os-homedir@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
+
+os-locale@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9"
+  dependencies:
+    lcid "^1.0.0"
+
+os-tmpdir@^1.0.0, os-tmpdir@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
+
+osenv@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644"
+  dependencies:
+    os-homedir "^1.0.0"
+    os-tmpdir "^1.0.0"
+
+p-limit@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.1.0.tgz#b07ff2d9a5d88bec806035895a2bab66a27988bc"
+
+p-locate@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
+  dependencies:
+    p-limit "^1.1.0"
+
+pako@~0.2.0:
+  version "0.2.9"
+  resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
+
+parse-asn1@^5.0.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712"
+  dependencies:
+    asn1.js "^4.0.0"
+    browserify-aes "^1.0.0"
+    create-hash "^1.1.0"
+    evp_bytestokey "^1.0.0"
+    pbkdf2 "^3.0.3"
+
+parse-glob@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
+  dependencies:
+    glob-base "^0.3.0"
+    is-dotfile "^1.0.0"
+    is-extglob "^1.0.0"
+    is-glob "^2.0.0"
+
+parse-json@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
+  dependencies:
+    error-ex "^1.2.0"
+
+parse5@^1.5.1:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94"
+
+path-browserify@0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a"
+
+path-exists@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
+  dependencies:
+    pinkie-promise "^2.0.0"
+
+path-exists@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
+
+path-is-absolute@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+
+path-parse@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1"
+
+path-type@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
+  dependencies:
+    graceful-fs "^4.1.2"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+pbkdf2@^3.0.3:
+  version "3.0.12"
+  resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.12.tgz#be36785c5067ea48d806ff923288c5f750b6b8a2"
+  dependencies:
+    create-hash "^1.1.2"
+    create-hmac "^1.1.4"
+    ripemd160 "^2.0.1"
+    safe-buffer "^5.0.1"
+    sha.js "^2.4.8"
+
+performance-now@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5"
+
+pify@^2.0.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
+
+pinkie-promise@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
+  dependencies:
+    pinkie "^2.0.0"
+
+pinkie@^2.0.0:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
+
+prelude-ls@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
+
+preserve@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
+
+pretty-format@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-19.0.0.tgz#56530d32acb98a3fa4851c4e2b9d37b420684c84"
+  dependencies:
+    ansi-styles "^3.0.0"
+
+private@^0.1.6:
+  version "0.1.7"
+  resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1"
+
+process-nextick-args@~1.0.6:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
+
+process@^0.11.0:
+  version "0.11.10"
+  resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
+
+promise@^7.1.1:
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/promise/-/promise-7.1.1.tgz#489654c692616b8aa55b0724fa809bb7db49c5bf"
+  dependencies:
+    asap "~2.0.3"
+
+prop-types@^15.5.7, prop-types@~15.5.7:
+  version "15.5.10"
+  resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.10.tgz#2797dfc3126182e3a95e3dfbb2e893ddd7456154"
+  dependencies:
+    fbjs "^0.8.9"
+    loose-envify "^1.3.1"
+
+prr@~0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a"
+
+public-encrypt@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.0.tgz#39f699f3a46560dd5ebacbca693caf7c65c18cc6"
+  dependencies:
+    bn.js "^4.1.0"
+    browserify-rsa "^4.0.0"
+    create-hash "^1.1.0"
+    parse-asn1 "^5.0.0"
+    randombytes "^2.0.1"
+
+punycode@1.3.2:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
+
+punycode@^1.2.4, punycode@^1.4.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
+
+qs@~6.4.0:
+  version "6.4.0"
+  resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
+
+querystring-es3@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
+
+querystring@0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
+
+randomatic@^1.1.3:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb"
+  dependencies:
+    is-number "^2.0.2"
+    kind-of "^3.0.2"
+
+randombytes@^2.0.0, randombytes@^2.0.1:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.5.tgz#dc009a246b8d09a177b4b7a0ae77bc570f4b1b79"
+  dependencies:
+    safe-buffer "^5.1.0"
+
+rc@^1.1.7:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.1.tgz#2e03e8e42ee450b8cb3dce65be1bf8974e1dfd95"
+  dependencies:
+    deep-extend "~0.4.0"
+    ini "~1.3.0"
+    minimist "^1.2.0"
+    strip-json-comments "~2.0.1"
+
+react-dom@^15.5.4:
+  version "15.5.4"
+  resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.5.4.tgz#ba0c28786fd52ed7e4f2135fe0288d462aef93da"
+  dependencies:
+    fbjs "^0.8.9"
+    loose-envify "^1.1.0"
+    object-assign "^4.1.0"
+    prop-types "~15.5.7"
+
+react@^15.5.4:
+  version "15.5.4"
+  resolved "https://registry.yarnpkg.com/react/-/react-15.5.4.tgz#fa83eb01506ab237cdc1c8c3b1cea8de012bf047"
+  dependencies:
+    fbjs "^0.8.9"
+    loose-envify "^1.1.0"
+    object-assign "^4.1.0"
+    prop-types "^15.5.7"
+
+read-pkg-up@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
+  dependencies:
+    find-up "^1.0.0"
+    read-pkg "^1.0.0"
+
+read-pkg@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
+  dependencies:
+    load-json-file "^1.0.0"
+    normalize-package-data "^2.3.2"
+    path-type "^1.0.0"
+
+readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.2.6:
+  version "2.2.11"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.11.tgz#0796b31f8d7688007ff0b93a8088d34aa17c0f72"
+  dependencies:
+    core-util-is "~1.0.0"
+    inherits "~2.0.1"
+    isarray "~1.0.0"
+    process-nextick-args "~1.0.6"
+    safe-buffer "~5.0.1"
+    string_decoder "~1.0.0"
+    util-deprecate "~1.0.1"
+
+readdirp@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78"
+  dependencies:
+    graceful-fs "^4.1.2"
+    minimatch "^3.0.2"
+    readable-stream "^2.0.2"
+    set-immediate-shim "^1.0.1"
+
+regenerator-runtime@^0.10.0:
+  version "0.10.3"
+  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.3.tgz#8c4367a904b51ea62a908ac310bf99ff90a82a3e"
+
+regex-cache@^0.4.2:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145"
+  dependencies:
+    is-equal-shallow "^0.1.3"
+    is-primitive "^2.0.0"
+
+remove-trailing-separator@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.0.1.tgz#615ebb96af559552d4bf4057c8436d486ab63cc4"
+
+repeat-element@^1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a"
+
+repeat-string@^1.5.2:
+  version "1.6.1"
+  resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
+
+repeating@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda"
+  dependencies:
+    is-finite "^1.0.0"
+
+request@^2.79.0, request@^2.81.0:
+  version "2.81.0"
+  resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0"
+  dependencies:
+    aws-sign2 "~0.6.0"
+    aws4 "^1.2.1"
+    caseless "~0.12.0"
+    combined-stream "~1.0.5"
+    extend "~3.0.0"
+    forever-agent "~0.6.1"
+    form-data "~2.1.1"
+    har-validator "~4.2.1"
+    hawk "~3.1.3"
+    http-signature "~1.1.0"
+    is-typedarray "~1.0.0"
+    isstream "~0.1.2"
+    json-stringify-safe "~5.0.1"
+    mime-types "~2.1.7"
+    oauth-sign "~0.8.1"
+    performance-now "^0.2.0"
+    qs "~6.4.0"
+    safe-buffer "^5.0.1"
+    stringstream "~0.0.4"
+    tough-cookie "~2.3.0"
+    tunnel-agent "^0.6.0"
+    uuid "^3.0.0"
+
+require-directory@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
+
+require-main-filename@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
+
+resolve@1.1.7:
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
+
+resolve@^1.2.0:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.3.2.tgz#1f0442c9e0cbb8136e87b9305f932f46c7f28235"
+  dependencies:
+    path-parse "^1.0.5"
+
+right-align@^0.1.1:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef"
+  dependencies:
+    align-text "^0.1.1"
+
+rimraf@2, rimraf@^2.4.4, rimraf@^2.5.1, rimraf@^2.6.1:
+  version "2.6.1"
+  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d"
+  dependencies:
+    glob "^7.0.5"
+
+ripemd160@^2.0.0, ripemd160@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7"
+  dependencies:
+    hash-base "^2.0.0"
+    inherits "^2.0.1"
+
+safe-buffer@^5.0.1, safe-buffer@~5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7"
+
+safe-buffer@^5.1.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.0.tgz#fe4c8460397f9eaaaa58e73be46273408a45e223"
+
+sane@~1.5.0:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/sane/-/sane-1.5.0.tgz#a4adeae764d048621ecb27d5f9ecf513101939f3"
+  dependencies:
+    anymatch "^1.3.0"
+    exec-sh "^0.2.0"
+    fb-watchman "^1.8.0"
+    minimatch "^3.0.2"
+    minimist "^1.1.1"
+    walker "~1.0.5"
+    watch "~0.10.0"
+
+sax@^1.2.1:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.2.tgz#fd8631a23bc7826bef5d871bdb87378c95647828"
+
+"semver@2 || 3 || 4 || 5", semver@^5.3.0:
+  version "5.3.0"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
+
+set-blocking@^2.0.0, set-blocking@~2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
+
+set-immediate-shim@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61"
+
+setimmediate@^1.0.4, setimmediate@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
+
+sha.js@^2.4.0, sha.js@^2.4.8:
+  version "2.4.8"
+  resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.8.tgz#37068c2c476b6baf402d14a49c67f597921f634f"
+  dependencies:
+    inherits "^2.0.1"
+
+shellwords@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.0.tgz#66afd47b6a12932d9071cbfd98a52e785cd0ba14"
+
+signal-exit@^3.0.0:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
+
+slash@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
+
+sntp@1.x.x:
+  version "1.0.9"
+  resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198"
+  dependencies:
+    hoek "2.x.x"
+
+source-list-map@^1.1.1:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-1.1.2.tgz#9889019d1024cce55cdc069498337ef6186a11a1"
+
+source-map-support@^0.4.2:
+  version "0.4.14"
+  resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.14.tgz#9d4463772598b86271b4f523f6c1f4e02a7d6aef"
+  dependencies:
+    source-map "^0.5.6"
+
+source-map@^0.4.4:
+  version "0.4.4"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b"
+  dependencies:
+    amdefine ">=0.0.4"
+
+source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.3:
+  version "0.5.6"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
+
+source-map@~0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d"
+  dependencies:
+    amdefine ">=0.0.4"
+
+spdx-correct@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40"
+  dependencies:
+    spdx-license-ids "^1.0.2"
+
+spdx-expression-parse@~1.0.0:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c"
+
+spdx-license-ids@^1.0.2:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57"
+
+sprintf-js@~1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
+
+sshpk@^1.7.0:
+  version "1.11.0"
+  resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.11.0.tgz#2d8d5ebb4a6fab28ffba37fa62a90f4a3ea59d77"
+  dependencies:
+    asn1 "~0.2.3"
+    assert-plus "^1.0.0"
+    dashdash "^1.12.0"
+    getpass "^0.1.1"
+  optionalDependencies:
+    bcrypt-pbkdf "^1.0.0"
+    ecc-jsbn "~0.1.1"
+    jodid25519 "^1.0.0"
+    jsbn "~0.1.0"
+    tweetnacl "~0.14.0"
+
+stream-browserify@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db"
+  dependencies:
+    inherits "~2.0.1"
+    readable-stream "^2.0.2"
+
+stream-http@^2.3.1:
+  version "2.7.2"
+  resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.7.2.tgz#40a050ec8dc3b53b33d9909415c02c0bf1abfbad"
+  dependencies:
+    builtin-status-codes "^3.0.0"
+    inherits "^2.0.1"
+    readable-stream "^2.2.6"
+    to-arraybuffer "^1.0.0"
+    xtend "^4.0.0"
+
+string-length@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/string-length/-/string-length-1.0.1.tgz#56970fb1c38558e9e70b728bf3de269ac45adfac"
+  dependencies:
+    strip-ansi "^3.0.0"
+
+string-width@^1.0.1, string-width@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
+  dependencies:
+    code-point-at "^1.0.0"
+    is-fullwidth-code-point "^1.0.0"
+    strip-ansi "^3.0.0"
+
+string_decoder@^0.10.25:
+  version "0.10.31"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
+
+string_decoder@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.2.tgz#b29e1f4e1125fa97a10382b8a533737b7491e179"
+  dependencies:
+    safe-buffer "~5.0.1"
+
+stringstream@~0.0.4:
+  version "0.0.5"
+  resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878"
+
+strip-ansi@^3.0.0, strip-ansi@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
+  dependencies:
+    ansi-regex "^2.0.0"
+
+strip-bom@3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
+
+strip-bom@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
+  dependencies:
+    is-utf8 "^0.2.0"
+
+strip-json-comments@~2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
+
+supports-color@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
+
+supports-color@^3.1.0, supports-color@^3.1.2:
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
+  dependencies:
+    has-flag "^1.0.0"
+
+symbol-tree@^3.2.1:
+  version "3.2.2"
+  resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6"
+
+tapable@^0.2.5, tapable@~0.2.5:
+  version "0.2.6"
+  resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.6.tgz#206be8e188860b514425375e6f1ae89bfb01fd8d"
+
+tar-pack@^3.4.0:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.0.tgz#23be2d7f671a8339376cbdb0b8fe3fdebf317984"
+  dependencies:
+    debug "^2.2.0"
+    fstream "^1.0.10"
+    fstream-ignore "^1.0.5"
+    once "^1.3.3"
+    readable-stream "^2.1.4"
+    rimraf "^2.5.1"
+    tar "^2.2.1"
+    uid-number "^0.0.6"
+
+tar@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1"
+  dependencies:
+    block-stream "*"
+    fstream "^1.0.2"
+    inherits "2"
+
+test-exclude@^4.0.3:
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-4.0.3.tgz#86a13ce3effcc60e6c90403cf31a27a60ac6c4e7"
+  dependencies:
+    arrify "^1.0.1"
+    micromatch "^2.3.11"
+    object-assign "^4.1.0"
+    read-pkg-up "^1.0.1"
+    require-main-filename "^1.0.1"
+
+throat@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/throat/-/throat-3.0.0.tgz#e7c64c867cbb3845f10877642f7b60055b8ec0d6"
+
+timers-browserify@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.2.tgz#ab4883cf597dcd50af211349a00fbca56ac86b86"
+  dependencies:
+    setimmediate "^1.0.4"
+
+tmpl@1.0.x:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1"
+
+to-arraybuffer@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
+
+to-fast-properties@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320"
+
+tough-cookie@^2.3.2, tough-cookie@~2.3.0:
+  version "2.3.2"
+  resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a"
+  dependencies:
+    punycode "^1.4.1"
+
+tr46@~0.0.3:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
+
+trim-right@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
+
+tty-browserify@0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
+
+tunnel-agent@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
+  dependencies:
+    safe-buffer "^5.0.1"
+
+tweetnacl@^0.14.3, tweetnacl@~0.14.0:
+  version "0.14.5"
+  resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
+
+type-check@~0.3.2:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
+  dependencies:
+    prelude-ls "~1.1.2"
+
+ua-parser-js@^0.7.9:
+  version "0.7.12"
+  resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb"
+
+uglify-js@^2.6, uglify-js@^2.8.27:
+  version "2.8.28"
+  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.28.tgz#e335032df9bb20dcb918f164589d5af47f38834a"
+  dependencies:
+    source-map "~0.5.1"
+    yargs "~3.10.0"
+  optionalDependencies:
+    uglify-to-browserify "~1.0.0"
+
+uglify-to-browserify@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7"
+
+uid-number@^0.0.6:
+  version "0.0.6"
+  resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81"
+
+url@^0.11.0:
+  version "0.11.0"
+  resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
+  dependencies:
+    punycode "1.3.2"
+    querystring "0.2.0"
+
+util-deprecate@~1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+
+util@0.10.3, util@^0.10.3:
+  version "0.10.3"
+  resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9"
+  dependencies:
+    inherits "2.0.1"
+
+uuid@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1"
+
+validate-npm-package-license@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc"
+  dependencies:
+    spdx-correct "~1.0.0"
+    spdx-expression-parse "~1.0.0"
+
+verror@1.3.6:
+  version "1.3.6"
+  resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c"
+  dependencies:
+    extsprintf "1.0.2"
+
+vm-browserify@0.0.4:
+  version "0.0.4"
+  resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73"
+  dependencies:
+    indexof "0.0.1"
+
+walker@~1.0.5:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb"
+  dependencies:
+    makeerror "1.0.x"
+
+watch@~0.10.0:
+  version "0.10.0"
+  resolved "https://registry.yarnpkg.com/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc"
+
+watchpack@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.3.1.tgz#7d8693907b28ce6013e7f3610aa2a1acf07dad87"
+  dependencies:
+    async "^2.1.2"
+    chokidar "^1.4.3"
+    graceful-fs "^4.1.2"
+
+webidl-conversions@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
+
+webidl-conversions@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.1.tgz#8015a17ab83e7e1b311638486ace81da6ce206a0"
+
+webpack-sources@^0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-0.2.3.tgz#17c62bfaf13c707f9d02c479e0dcdde8380697fb"
+  dependencies:
+    source-list-map "^1.1.1"
+    source-map "~0.5.3"
+
+webpack@^2.6.1:
+  version "2.6.1"
+  resolved "https://registry.yarnpkg.com/webpack/-/webpack-2.6.1.tgz#2e0457f0abb1ac5df3ab106c69c672f236785f07"
+  dependencies:
+    acorn "^5.0.0"
+    acorn-dynamic-import "^2.0.0"
+    ajv "^4.7.0"
+    ajv-keywords "^1.1.1"
+    async "^2.1.2"
+    enhanced-resolve "^3.0.0"
+    interpret "^1.0.0"
+    json-loader "^0.5.4"
+    json5 "^0.5.1"
+    loader-runner "^2.3.0"
+    loader-utils "^0.2.16"
+    memory-fs "~0.4.1"
+    mkdirp "~0.5.0"
+    node-libs-browser "^2.0.0"
+    source-map "^0.5.3"
+    supports-color "^3.1.0"
+    tapable "~0.2.5"
+    uglify-js "^2.8.27"
+    watchpack "^1.3.1"
+    webpack-sources "^0.2.3"
+    yargs "^6.0.0"
+
+whatwg-encoding@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.1.tgz#3c6c451a198ee7aec55b1ec61d0920c67801a5f4"
+  dependencies:
+    iconv-lite "0.4.13"
+
+whatwg-fetch@>=0.10.0:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84"
+
+whatwg-url@^4.3.0:
+  version "4.7.0"
+  resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-4.7.0.tgz#202035ac1955b087cdd20fa8b58ded3ab1cd2af5"
+  dependencies:
+    tr46 "~0.0.3"
+    webidl-conversions "^3.0.0"
+
+which-module@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
+
+which@^1.1.1, which@^1.2.12:
+  version "1.2.14"
+  resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5"
+  dependencies:
+    isexe "^2.0.0"
+
+wide-align@^1.1.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710"
+  dependencies:
+    string-width "^1.0.2"
+
+window-size@0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
+
+wordwrap@0.0.2, wordwrap@~0.0.2:
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
+
+wordwrap@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
+
+worker-farm@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.3.1.tgz#4333112bb49b17aa050b87895ca6b2cacf40e5ff"
+  dependencies:
+    errno ">=0.1.1 <0.2.0-0"
+    xtend ">=4.0.0 <4.1.0-0"
+
+wrap-ansi@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
+  dependencies:
+    string-width "^1.0.1"
+    strip-ansi "^3.0.1"
+
+wrappy@1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+
+xml-name-validator@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635"
+
+"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
+
+y18n@^3.2.1:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
+
+yargs-parser@^4.2.0:
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c"
+  dependencies:
+    camelcase "^3.0.0"
+
+yargs@^6.0.0, yargs@^6.3.0:
+  version "6.6.0"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208"
+  dependencies:
+    camelcase "^3.0.0"
+    cliui "^3.2.0"
+    decamelize "^1.1.1"
+    get-caller-file "^1.0.1"
+    os-locale "^1.4.0"
+    read-pkg-up "^1.0.1"
+    require-directory "^2.1.1"
+    require-main-filename "^1.0.1"
+    set-blocking "^2.0.0"
+    string-width "^1.0.2"
+    which-module "^1.0.0"
+    y18n "^3.2.1"
+    yargs-parser "^4.2.0"
+
+yargs@~3.10.0:
+  version "3.10.0"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"
+  dependencies:
+    camelcase "^1.0.2"
+    cliui "^2.1.0"
+    decamelize "^1.0.0"
+    window-size "0.1.0"
diff --git a/addons/react-addons-pure-render-mixin/.gitignore b/addons/react-addons-pure-render-mixin/.gitignore
new file mode 100644
index 000000000000..d6faf7dda567
--- /dev/null
+++ b/addons/react-addons-pure-render-mixin/.gitignore
@@ -0,0 +1,2 @@
+react-addons-pure-render-mixin.js
+react-addons-pure-render-mixin.min.js
diff --git a/addons/react-addons-pure-render-mixin/LICENSE b/addons/react-addons-pure-render-mixin/LICENSE
new file mode 100644
index 000000000000..91b8f6f76ff0
--- /dev/null
+++ b/addons/react-addons-pure-render-mixin/LICENSE
@@ -0,0 +1,31 @@
+BSD License
+
+For React software
+
+Copyright (c) 2013-present, Facebook, Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+ * Neither the name Facebook nor the names of its contributors may be used to
+   endorse or promote products derived from this software without specific
+   prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/addons/react-addons-pure-render-mixin/PATENTS b/addons/react-addons-pure-render-mixin/PATENTS
new file mode 100644
index 000000000000..9c9f8e87a8f4
--- /dev/null
+++ b/addons/react-addons-pure-render-mixin/PATENTS
@@ -0,0 +1,33 @@
+Additional Grant of Patent Rights Version 2
+
+"Software" means the React software distributed by Facebook, Inc.
+
+Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software
+("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable
+(subject to the termination provision below) license under any Necessary
+Claims, to make, have made, use, sell, offer to sell, import, and otherwise
+transfer the Software. For avoidance of doubt, no license is granted under
+Facebook's rights in any patent claims that are infringed by (i) modifications
+to the Software made by you or any third party or (ii) the Software in
+combination with any software or other technology.
+
+The license granted hereunder will terminate, automatically and without notice,
+if you (or any of your subsidiaries, corporate affiliates or agents) initiate
+directly or indirectly, or take a direct financial interest in, any Patent
+Assertion: (i) against Facebook or any of its subsidiaries or corporate
+affiliates, (ii) against any party if such Patent Assertion arises in whole or
+in part from any software, technology, product or service of Facebook or any of
+its subsidiaries or corporate affiliates, or (iii) against any party relating
+to the Software. Notwithstanding the foregoing, if Facebook or any of its
+subsidiaries or corporate affiliates files a lawsuit alleging patent
+infringement against you in the first instance, and you respond by filing a
+patent infringement counterclaim in that lawsuit against that party that is
+unrelated to the Software, the license granted hereunder will not terminate
+under section (i) of this paragraph due to such counterclaim.
+
+A "Necessary Claim" is a claim of a patent owned by Facebook that is
+necessarily infringed by the Software standing alone.
+
+A "Patent Assertion" is any lawsuit or other action alleging direct, indirect,
+or contributory infringement or inducement to infringe any patent, including a
+cross-claim or counterclaim.
diff --git a/addons/react-addons-pure-render-mixin/README.md b/addons/react-addons-pure-render-mixin/README.md
new file mode 100644
index 000000000000..821370aef7fc
--- /dev/null
+++ b/addons/react-addons-pure-render-mixin/README.md
@@ -0,0 +1,52 @@
+# react-addons-pure-render-mixin
+
+>**Note:**
+>This is a legacy React addon, and is no longer maintained.
+>
+>We don't encourage using it in new code, but it exists for backwards compatibility.  
+>The recommended migration path is to use [`React.PureComponent`](https://facebook.github.io/react/docs/react-api.html#react.purecomponent) instead.
+
+**Importing**
+
+```javascript
+import PureRenderMixin from 'react-addons-pure-render-mixin'; // ES6
+var PureRenderMixin = require('react-addons-pure-render-mixin'); // ES5 with npm
+```
+
+If you prefer a `<script>` tag, you can get it from `React.addons.PureRenderMixin` with:
+
+```html
+<!-- development version -->
+<script src="https://unpkg.com/react-addons-pure-render-mixin/react-addons-pure-render-mixin.js"></script>
+
+<!-- production version -->
+<script src="https://unpkg.com/react-addons-pure-render-mixin/react-addons-pure-render-mixin.min.js"></script>
+```
+
+In this case, make sure to put the `<script>` tag after React.
+
+## Overview
+
+If your React component's render function renders the same result given the same props and state, you can use this mixin for a performance boost in some cases.
+
+Example:
+
+```js
+const createReactClass = require('create-react-class');
+
+createReactClass({
+  mixins: [PureRenderMixin],
+
+  render: function() {
+    return <div className={this.props.className}>foo</div>;
+  }
+});
+```
+
+Under the hood, the mixin implements [shouldComponentUpdate](https://facebook.github.io/react/docs/component-specs.html#updating-shouldcomponentupdate), in which it compares the current props and state with the next ones and returns `false` if the equalities pass.
+
+> Note:
+>
+> This only shallowly compares the objects. If these contain complex data structures, it may produce false-negatives for deeper differences. Only mix into components which have simple props and state, or use `forceUpdate()` when you know deep data structures have changed. Or, consider using [immutable objects](https://facebook.github.io/immutable-js/) to facilitate fast comparisons of nested data.
+>
+> Furthermore, `shouldComponentUpdate` skips updates for the whole component subtree. Make sure all the children components are also "pure".
diff --git a/addons/react-addons-pure-render-mixin/index.js b/addons/react-addons-pure-render-mixin/index.js
new file mode 100644
index 000000000000..80774e022b33
--- /dev/null
+++ b/addons/react-addons-pure-render-mixin/index.js
@@ -0,0 +1,22 @@
+/**
+ * Copyright 2015-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.
+ *
+ */
+
+'use strict';
+
+var shallowEqual = require('fbjs/lib/shallowEqual');
+
+module.exports = {
+  shouldComponentUpdate: function(nextProps, nextState) {
+    return (
+      !shallowEqual(this.props, nextProps) ||
+      !shallowEqual(this.state, nextState)
+    );
+  }
+};
diff --git a/addons/react-addons-pure-render-mixin/package.json b/addons/react-addons-pure-render-mixin/package.json
new file mode 100644
index 000000000000..d26263d19476
--- /dev/null
+++ b/addons/react-addons-pure-render-mixin/package.json
@@ -0,0 +1,36 @@
+{
+  "name": "react-addons-pure-render-mixin",
+  "version": "15.6.0",
+  "main": "index.js",
+  "repository": "facebook/react",
+  "keywords": [
+    "react",
+    "react-addon"
+  ],
+  "license": "BSD-3-Clause",
+  "dependencies": {
+    "fbjs": "^0.8.4",
+    "object-assign": "^4.1.0"
+  },
+  "files": [
+    "LICENSE",
+    "PATENTS",
+    "README.md",
+    "index.js",
+    "react-addons-pure-render-mixin.js",
+    "react-addons-pure-render-mixin.min.js"
+  ],
+  "scripts": {
+    "test": "TEST_ENTRY=./index.js jest",
+    "build:dev": "NODE_ENV=development webpack && TEST_ENTRY=./react-addons-pure-render-mixin.js jest",
+    "build:prod": "NODE_ENV=production webpack && NODE_ENV=production TEST_ENTRY=./react-addons-pure-render-mixin.min.js jest",
+    "build": "npm run build:dev && npm run build:prod && node ../postbuild.js",
+    "prepublish": "npm test && npm run build"
+  },
+  "devDependencies": {
+    "jest": "^19.0.2",
+    "react": "^15.4.2",
+    "react-dom": "^15.4.2",
+    "webpack": "^2.6.1"
+  }
+}
diff --git a/addons/react-addons-pure-render-mixin/test.js b/addons/react-addons-pure-render-mixin/test.js
new file mode 100644
index 000000000000..0cf696048b5e
--- /dev/null
+++ b/addons/react-addons-pure-render-mixin/test.js
@@ -0,0 +1,190 @@
+/**
+ * Copyright 2015-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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var React;
+var ReactDOM;
+var ReactComponentWithPureRenderMixin;
+
+// Catch stray warnings
+var env = jasmine.getEnv();
+var callCount = 0;
+var oldError = console.error;
+var newError = function() {
+  callCount++;
+  oldError.apply(this, arguments);
+};
+console.error = newError;
+env.beforeEach(() => {
+  callCount = 0;
+  jasmine.addMatchers({
+    toBeReset() {
+      return {
+        compare(actual) {
+          if (actual !== newError && !jasmine.isSpy(actual)) {
+            return {
+              pass: false,
+              message: 'Test did not tear down console.error mock properly.'
+            };
+          }
+          return {pass: true};
+        }
+      };
+    },
+    toNotHaveBeenCalled() {
+      return {
+        compare(actual) {
+          return {
+            pass: callCount === 0,
+            message:
+              'Expected test not to warn. If the warning is expected, mock ' +
+                "it out using spyOn(console, 'error'); and test that the " +
+                'warning occurs.'
+          };
+        }
+      };
+    }
+  });
+});
+env.afterEach(() => {
+  expect(console.error).toBeReset();
+  expect(console.error).toNotHaveBeenCalled();
+});
+
+function renderIntoDocument(element) {
+  var node = document.createElement('div');
+  return ReactDOM.render(element, node);
+}
+
+describe('PureRenderMixin', () => {
+  beforeEach(() => {
+    React = require('react');
+    ReactDOM = require('react-dom');
+    ReactComponentWithPureRenderMixin = require(process.env.TEST_ENTRY);
+  });
+
+  it('provides a default shouldComponentUpdate implementation', () => {
+    var renderCalls = 0;
+    class PlasticWrap extends React.Component {
+      constructor(props, context) {
+        super(props, context);
+        this.state = {
+          color: 'green'
+        };
+      }
+
+      render() {
+        return React.createElement(Apple, {
+          color: this.state.color,
+          ref: 'apple'
+        });
+      }
+    }
+
+    var Apple = React.createClass({
+      mixins: [ReactComponentWithPureRenderMixin],
+
+      getInitialState: function() {
+        return {
+          cut: false,
+          slices: 1
+        };
+      },
+
+      cut: function() {
+        this.setState({
+          cut: true,
+          slices: 10
+        });
+      },
+
+      eatSlice: function() {
+        this.setState({
+          slices: this.state.slices - 1
+        });
+      },
+
+      render: function() {
+        renderCalls++;
+        return React.createElement('div');
+      }
+    });
+
+    var instance = renderIntoDocument(React.createElement(PlasticWrap));
+    expect(renderCalls).toBe(1);
+
+    // Do not re-render based on props
+    instance.setState({color: 'green'});
+    expect(renderCalls).toBe(1);
+
+    // Re-render based on props
+    instance.setState({color: 'red'});
+    expect(renderCalls).toBe(2);
+
+    // Re-render base on state
+    instance.refs.apple.cut();
+    expect(renderCalls).toBe(3);
+
+    // No re-render based on state
+    instance.refs.apple.cut();
+    expect(renderCalls).toBe(3);
+
+    // Re-render based on state again
+    instance.refs.apple.eatSlice();
+    expect(renderCalls).toBe(4);
+  });
+
+  it('does not do a deep comparison', () => {
+    function getInitialState() {
+      return {
+        foo: [1, 2, 3],
+        bar: {a: 4, b: 5, c: 6}
+      };
+    }
+
+    var renderCalls = 0;
+    var initialSettings = getInitialState();
+
+    var Component = React.createClass({
+      mixins: [ReactComponentWithPureRenderMixin],
+
+      getInitialState: function() {
+        return initialSettings;
+      },
+
+      render: function() {
+        renderCalls++;
+        return React.createElement('div');
+      }
+    });
+
+    var instance = renderIntoDocument(React.createElement(Component));
+    expect(renderCalls).toBe(1);
+
+    // Do not re-render if state is equal
+    var settings = {
+      foo: initialSettings.foo,
+      bar: initialSettings.bar
+    };
+    instance.setState(settings);
+    expect(renderCalls).toBe(1);
+
+    // Re-render because one field changed
+    initialSettings.foo = [1, 2, 3];
+    instance.setState(initialSettings);
+    expect(renderCalls).toBe(2);
+
+    // Re-render because the object changed
+    instance.setState(getInitialState());
+    expect(renderCalls).toBe(3);
+  });
+});
diff --git a/addons/react-addons-pure-render-mixin/webpack.config.js b/addons/react-addons-pure-render-mixin/webpack.config.js
new file mode 100644
index 000000000000..94bde0071123
--- /dev/null
+++ b/addons/react-addons-pure-render-mixin/webpack.config.js
@@ -0,0 +1,55 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+const webpack = require('webpack');
+
+let __DEV__;
+switch (process.env.NODE_ENV) {
+  case 'development':
+    __DEV__ = true;
+    break;
+  case 'production':
+    __DEV__ = false;
+    break;
+  default:
+    throw new Error('Unknown environment.');
+}
+
+module.exports = {
+  entry: './index',
+  output: {
+    library: 'PureRenderMixin',
+    libraryTarget: 'umd',
+    filename: __DEV__
+      ? 'react-addons-pure-render-mixin.js'
+      : 'react-addons-pure-render-mixin.min.js'
+  },
+  plugins: [
+    new webpack.DefinePlugin({
+      'process.env.NODE_ENV': __DEV__ ? '"development"' : '"production"'
+    })
+  ].concat(
+    __DEV__
+      ? []
+      : [
+          new webpack.optimize.UglifyJsPlugin({
+            compress: {
+              warnings: false
+            },
+            output: {
+              comments: false
+            }
+          })
+        ]
+  )
+};
diff --git a/addons/react-addons-pure-render-mixin/yarn.lock b/addons/react-addons-pure-render-mixin/yarn.lock
new file mode 100644
index 000000000000..2423b18a05ab
--- /dev/null
+++ b/addons/react-addons-pure-render-mixin/yarn.lock
@@ -0,0 +1,2814 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+abab@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.3.tgz#b81de5f7274ec4e756d797cd834f303642724e5d"
+
+abbrev@1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f"
+
+acorn-dynamic-import@^2.0.0:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz#c752bd210bef679501b6c6cb7fc84f8f47158cc4"
+  dependencies:
+    acorn "^4.0.3"
+
+acorn-globals@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-3.1.0.tgz#fd8270f71fbb4996b004fa880ee5d46573a731bf"
+  dependencies:
+    acorn "^4.0.4"
+
+acorn@^4.0.3, acorn@^4.0.4:
+  version "4.0.11"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.11.tgz#edcda3bd937e7556410d42ed5860f67399c794c0"
+
+acorn@^5.0.0:
+  version "5.0.3"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.0.3.tgz#c460df08491463f028ccb82eab3730bf01087b3d"
+
+ajv-keywords@^1.1.1:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c"
+
+ajv@^4.7.0, ajv@^4.9.1:
+  version "4.11.5"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.5.tgz#b6ee74657b993a01dce44b7944d56f485828d5bd"
+  dependencies:
+    co "^4.6.0"
+    json-stable-stringify "^1.0.1"
+
+align-text@^0.1.1, align-text@^0.1.3:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
+  dependencies:
+    kind-of "^3.0.2"
+    longest "^1.0.1"
+    repeat-string "^1.5.2"
+
+amdefine@>=0.0.4:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
+
+ansi-escapes@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
+
+ansi-regex@^2.0.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
+
+ansi-styles@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
+
+ansi-styles@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.0.0.tgz#5404e93a544c4fec7f048262977bebfe3155e0c1"
+  dependencies:
+    color-convert "^1.0.0"
+
+anymatch@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507"
+  dependencies:
+    arrify "^1.0.0"
+    micromatch "^2.1.5"
+
+append-transform@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-0.4.0.tgz#d76ebf8ca94d276e247a36bad44a4b74ab611991"
+  dependencies:
+    default-require-extensions "^1.0.0"
+
+aproba@^1.0.3:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.2.tgz#45c6629094de4e96f693ef7eab74ae079c240fc1"
+
+are-we-there-yet@~1.1.2:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d"
+  dependencies:
+    delegates "^1.0.0"
+    readable-stream "^2.0.6"
+
+argparse@^1.0.7:
+  version "1.0.9"
+  resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86"
+  dependencies:
+    sprintf-js "~1.0.2"
+
+arr-diff@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf"
+  dependencies:
+    arr-flatten "^1.0.1"
+
+arr-flatten@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b"
+
+array-equal@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93"
+
+array-unique@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
+
+arrify@^1.0.0, arrify@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
+
+asap@~2.0.3:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f"
+
+asn1.js@^4.0.0:
+  version "4.9.1"
+  resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.1.tgz#48ba240b45a9280e94748990ba597d216617fd40"
+  dependencies:
+    bn.js "^4.0.0"
+    inherits "^2.0.1"
+    minimalistic-assert "^1.0.0"
+
+asn1@~0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86"
+
+assert-plus@1.0.0, assert-plus@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
+
+assert-plus@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234"
+
+assert@^1.1.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91"
+  dependencies:
+    util "0.10.3"
+
+async-each@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
+
+async@^1.4.0:
+  version "1.5.2"
+  resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
+
+async@^2.1.2, async@^2.1.4:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/async/-/async-2.3.0.tgz#1013d1051047dd320fe24e494d5c66ecaf6147d9"
+  dependencies:
+    lodash "^4.14.0"
+
+asynckit@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+
+aws-sign2@~0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f"
+
+aws4@^1.2.1:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e"
+
+babel-code-frame@^6.22.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4"
+  dependencies:
+    chalk "^1.1.0"
+    esutils "^2.0.2"
+    js-tokens "^3.0.0"
+
+babel-core@^6.0.0, babel-core@^6.24.0:
+  version "6.24.0"
+  resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.24.0.tgz#8f36a0a77f5c155aed6f920b844d23ba56742a02"
+  dependencies:
+    babel-code-frame "^6.22.0"
+    babel-generator "^6.24.0"
+    babel-helpers "^6.23.0"
+    babel-messages "^6.23.0"
+    babel-register "^6.24.0"
+    babel-runtime "^6.22.0"
+    babel-template "^6.23.0"
+    babel-traverse "^6.23.1"
+    babel-types "^6.23.0"
+    babylon "^6.11.0"
+    convert-source-map "^1.1.0"
+    debug "^2.1.1"
+    json5 "^0.5.0"
+    lodash "^4.2.0"
+    minimatch "^3.0.2"
+    path-is-absolute "^1.0.0"
+    private "^0.1.6"
+    slash "^1.0.0"
+    source-map "^0.5.0"
+
+babel-generator@^6.18.0, babel-generator@^6.24.0:
+  version "6.24.0"
+  resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.24.0.tgz#eba270a8cc4ce6e09a61be43465d7c62c1f87c56"
+  dependencies:
+    babel-messages "^6.23.0"
+    babel-runtime "^6.22.0"
+    babel-types "^6.23.0"
+    detect-indent "^4.0.0"
+    jsesc "^1.3.0"
+    lodash "^4.2.0"
+    source-map "^0.5.0"
+    trim-right "^1.0.1"
+
+babel-helpers@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.23.0.tgz#4f8f2e092d0b6a8808a4bde79c27f1e2ecf0d992"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-template "^6.23.0"
+
+babel-jest@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-19.0.0.tgz#59323ced99a3a84d359da219ca881074ffc6ce3f"
+  dependencies:
+    babel-core "^6.0.0"
+    babel-plugin-istanbul "^4.0.0"
+    babel-preset-jest "^19.0.0"
+
+babel-messages@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e"
+  dependencies:
+    babel-runtime "^6.22.0"
+
+babel-plugin-istanbul@^4.0.0:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.1.tgz#c12de0fc6fe42adfb16be56f1ad11e4a9782eca9"
+  dependencies:
+    find-up "^2.1.0"
+    istanbul-lib-instrument "^1.6.2"
+    test-exclude "^4.0.3"
+
+babel-plugin-jest-hoist@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-19.0.0.tgz#4ae2a04ea612a6e73651f3fde52c178991304bea"
+
+babel-preset-jest@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-19.0.0.tgz#22d67201d02324a195811288eb38294bb3cac396"
+  dependencies:
+    babel-plugin-jest-hoist "^19.0.0"
+
+babel-register@^6.24.0:
+  version "6.24.0"
+  resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.24.0.tgz#5e89f8463ba9970356d02eb07dabe3308b080cfd"
+  dependencies:
+    babel-core "^6.24.0"
+    babel-runtime "^6.22.0"
+    core-js "^2.4.0"
+    home-or-tmp "^2.0.0"
+    lodash "^4.2.0"
+    mkdirp "^0.5.1"
+    source-map-support "^0.4.2"
+
+babel-runtime@^6.22.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b"
+  dependencies:
+    core-js "^2.4.0"
+    regenerator-runtime "^0.10.0"
+
+babel-template@^6.16.0, babel-template@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.23.0.tgz#04d4f270adbb3aa704a8143ae26faa529238e638"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-traverse "^6.23.0"
+    babel-types "^6.23.0"
+    babylon "^6.11.0"
+    lodash "^4.2.0"
+
+babel-traverse@^6.18.0, babel-traverse@^6.23.0, babel-traverse@^6.23.1:
+  version "6.23.1"
+  resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.23.1.tgz#d3cb59010ecd06a97d81310065f966b699e14f48"
+  dependencies:
+    babel-code-frame "^6.22.0"
+    babel-messages "^6.23.0"
+    babel-runtime "^6.22.0"
+    babel-types "^6.23.0"
+    babylon "^6.15.0"
+    debug "^2.2.0"
+    globals "^9.0.0"
+    invariant "^2.2.0"
+    lodash "^4.2.0"
+
+babel-types@^6.18.0, babel-types@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.23.0.tgz#bb17179d7538bad38cd0c9e115d340f77e7e9acf"
+  dependencies:
+    babel-runtime "^6.22.0"
+    esutils "^2.0.2"
+    lodash "^4.2.0"
+    to-fast-properties "^1.0.1"
+
+babylon@^6.11.0, babylon@^6.13.0, babylon@^6.15.0:
+  version "6.16.1"
+  resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.16.1.tgz#30c5a22f481978a9e7f8cdfdf496b11d94b404d3"
+
+balanced-match@^0.4.1:
+  version "0.4.2"
+  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
+
+base64-js@^1.0.2:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1"
+
+bcrypt-pbkdf@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d"
+  dependencies:
+    tweetnacl "^0.14.3"
+
+big.js@^3.1.3:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.1.3.tgz#4cada2193652eb3ca9ec8e55c9015669c9806978"
+
+binary-extensions@^1.0.0:
+  version "1.8.0"
+  resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.8.0.tgz#48ec8d16df4377eae5fa5884682480af4d95c774"
+
+block-stream@*:
+  version "0.0.9"
+  resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a"
+  dependencies:
+    inherits "~2.0.0"
+
+bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0:
+  version "4.11.6"
+  resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215"
+
+boom@2.x.x:
+  version "2.10.1"
+  resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f"
+  dependencies:
+    hoek "2.x.x"
+
+brace-expansion@^1.0.0:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9"
+  dependencies:
+    balanced-match "^0.4.1"
+    concat-map "0.0.1"
+
+braces@^1.8.2:
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7"
+  dependencies:
+    expand-range "^1.8.1"
+    preserve "^0.2.0"
+    repeat-element "^1.1.2"
+
+brorand@^1.0.1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
+
+browser-resolve@^1.11.2:
+  version "1.11.2"
+  resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.2.tgz#8ff09b0a2c421718a1051c260b32e48f442938ce"
+  dependencies:
+    resolve "1.1.7"
+
+browserify-aes@^1.0.0, browserify-aes@^1.0.4:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.0.6.tgz#5e7725dbdef1fd5930d4ebab48567ce451c48a0a"
+  dependencies:
+    buffer-xor "^1.0.2"
+    cipher-base "^1.0.0"
+    create-hash "^1.1.0"
+    evp_bytestokey "^1.0.0"
+    inherits "^2.0.1"
+
+browserify-cipher@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.0.tgz#9988244874bf5ed4e28da95666dcd66ac8fc363a"
+  dependencies:
+    browserify-aes "^1.0.4"
+    browserify-des "^1.0.0"
+    evp_bytestokey "^1.0.0"
+
+browserify-des@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.0.tgz#daa277717470922ed2fe18594118a175439721dd"
+  dependencies:
+    cipher-base "^1.0.1"
+    des.js "^1.0.0"
+    inherits "^2.0.1"
+
+browserify-rsa@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524"
+  dependencies:
+    bn.js "^4.1.0"
+    randombytes "^2.0.1"
+
+browserify-sign@^4.0.0:
+  version "4.0.4"
+  resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298"
+  dependencies:
+    bn.js "^4.1.1"
+    browserify-rsa "^4.0.0"
+    create-hash "^1.1.0"
+    create-hmac "^1.1.2"
+    elliptic "^6.0.0"
+    inherits "^2.0.1"
+    parse-asn1 "^5.0.0"
+
+browserify-zlib@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d"
+  dependencies:
+    pako "~0.2.0"
+
+bser@1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/bser/-/bser-1.0.2.tgz#381116970b2a6deea5646dd15dd7278444b56169"
+  dependencies:
+    node-int64 "^0.4.0"
+
+bser@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719"
+  dependencies:
+    node-int64 "^0.4.0"
+
+buffer-xor@^1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9"
+
+buffer@^4.3.0:
+  version "4.9.1"
+  resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298"
+  dependencies:
+    base64-js "^1.0.2"
+    ieee754 "^1.1.4"
+    isarray "^1.0.0"
+
+builtin-modules@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
+
+builtin-status-codes@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
+
+callsites@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50"
+
+camelcase@^1.0.2:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39"
+
+camelcase@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
+
+caseless@~0.12.0:
+  version "0.12.0"
+  resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
+
+center-align@^0.1.1:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad"
+  dependencies:
+    align-text "^0.1.3"
+    lazy-cache "^1.0.3"
+
+chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
+  dependencies:
+    ansi-styles "^2.2.1"
+    escape-string-regexp "^1.0.2"
+    has-ansi "^2.0.0"
+    strip-ansi "^3.0.0"
+    supports-color "^2.0.0"
+
+chokidar@^1.4.3:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
+  dependencies:
+    anymatch "^1.3.0"
+    async-each "^1.0.0"
+    glob-parent "^2.0.0"
+    inherits "^2.0.1"
+    is-binary-path "^1.0.0"
+    is-glob "^2.0.0"
+    path-is-absolute "^1.0.0"
+    readdirp "^2.0.0"
+  optionalDependencies:
+    fsevents "^1.0.0"
+
+ci-info@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.0.0.tgz#dc5285f2b4e251821683681c381c3388f46ec534"
+
+cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.3.tgz#eeabf194419ce900da3018c207d212f2a6df0a07"
+  dependencies:
+    inherits "^2.0.1"
+
+cliui@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1"
+  dependencies:
+    center-align "^0.1.1"
+    right-align "^0.1.1"
+    wordwrap "0.0.2"
+
+cliui@^3.2.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
+  dependencies:
+    string-width "^1.0.1"
+    strip-ansi "^3.0.1"
+    wrap-ansi "^2.0.0"
+
+co@^4.6.0:
+  version "4.6.0"
+  resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
+
+code-point-at@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
+
+color-convert@^1.0.0:
+  version "1.9.0"
+  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a"
+  dependencies:
+    color-name "^1.1.1"
+
+color-name@^1.1.1:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.2.tgz#5c8ab72b64bd2215d617ae9559ebb148475cf98d"
+
+combined-stream@^1.0.5, combined-stream@~1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009"
+  dependencies:
+    delayed-stream "~1.0.0"
+
+concat-map@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+
+console-browserify@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10"
+  dependencies:
+    date-now "^0.1.4"
+
+console-control-strings@^1.0.0, console-control-strings@~1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
+
+constants-browserify@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
+
+content-type-parser@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/content-type-parser/-/content-type-parser-1.0.1.tgz#c3e56988c53c65127fb46d4032a3a900246fdc94"
+
+convert-source-map@^1.1.0:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5"
+
+core-js@^1.0.0:
+  version "1.2.7"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
+
+core-js@^2.4.0:
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e"
+
+core-util-is@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
+
+create-ecdh@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.0.tgz#888c723596cdf7612f6498233eebd7a35301737d"
+  dependencies:
+    bn.js "^4.1.0"
+    elliptic "^6.0.0"
+
+create-hash@^1.1.0, create-hash@^1.1.1, create-hash@^1.1.2:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.3.tgz#606042ac8b9262750f483caddab0f5819172d8fd"
+  dependencies:
+    cipher-base "^1.0.1"
+    inherits "^2.0.1"
+    ripemd160 "^2.0.0"
+    sha.js "^2.4.0"
+
+create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.6.tgz#acb9e221a4e17bdb076e90657c42b93e3726cf06"
+  dependencies:
+    cipher-base "^1.0.3"
+    create-hash "^1.1.0"
+    inherits "^2.0.1"
+    ripemd160 "^2.0.0"
+    safe-buffer "^5.0.1"
+    sha.js "^2.4.8"
+
+cryptiles@2.x.x:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8"
+  dependencies:
+    boom "2.x.x"
+
+crypto-browserify@^3.11.0:
+  version "3.11.0"
+  resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.11.0.tgz#3652a0906ab9b2a7e0c3ce66a408e957a2485522"
+  dependencies:
+    browserify-cipher "^1.0.0"
+    browserify-sign "^4.0.0"
+    create-ecdh "^4.0.0"
+    create-hash "^1.1.0"
+    create-hmac "^1.1.0"
+    diffie-hellman "^5.0.0"
+    inherits "^2.0.1"
+    pbkdf2 "^3.0.3"
+    public-encrypt "^4.0.0"
+    randombytes "^2.0.0"
+
+cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0":
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.2.tgz#b8036170c79f07a90ff2f16e22284027a243848b"
+
+"cssstyle@>= 0.2.37 < 0.3.0":
+  version "0.2.37"
+  resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-0.2.37.tgz#541097234cb2513c83ceed3acddc27ff27987d54"
+  dependencies:
+    cssom "0.3.x"
+
+dashdash@^1.12.0:
+  version "1.14.1"
+  resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
+  dependencies:
+    assert-plus "^1.0.0"
+
+date-now@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
+
+debug@^2.1.1, debug@^2.2.0:
+  version "2.6.3"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.3.tgz#0f7eb8c30965ec08c72accfa0130c8b79984141d"
+  dependencies:
+    ms "0.7.2"
+
+decamelize@^1.0.0, decamelize@^1.1.1:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
+
+deep-extend@~0.4.0:
+  version "0.4.2"
+  resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f"
+
+deep-is@~0.1.3:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
+
+default-require-extensions@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8"
+  dependencies:
+    strip-bom "^2.0.0"
+
+delayed-stream@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+
+delegates@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
+
+des.js@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc"
+  dependencies:
+    inherits "^2.0.1"
+    minimalistic-assert "^1.0.0"
+
+detect-indent@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208"
+  dependencies:
+    repeating "^2.0.0"
+
+diff@^3.0.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9"
+
+diffie-hellman@^5.0.0:
+  version "5.0.2"
+  resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.2.tgz#b5835739270cfe26acf632099fded2a07f209e5e"
+  dependencies:
+    bn.js "^4.1.0"
+    miller-rabin "^4.0.0"
+    randombytes "^2.0.0"
+
+domain-browser@^1.1.1:
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc"
+
+ecc-jsbn@~0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505"
+  dependencies:
+    jsbn "~0.1.0"
+
+elliptic@^6.0.0:
+  version "6.4.0"
+  resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df"
+  dependencies:
+    bn.js "^4.4.0"
+    brorand "^1.0.1"
+    hash.js "^1.0.0"
+    hmac-drbg "^1.0.0"
+    inherits "^2.0.1"
+    minimalistic-assert "^1.0.0"
+    minimalistic-crypto-utils "^1.0.0"
+
+emojis-list@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
+
+encoding@^0.1.11:
+  version "0.1.12"
+  resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb"
+  dependencies:
+    iconv-lite "~0.4.13"
+
+enhanced-resolve@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.1.0.tgz#9f4b626f577245edcf4b2ad83d86e17f4f421dec"
+  dependencies:
+    graceful-fs "^4.1.2"
+    memory-fs "^0.4.0"
+    object-assign "^4.0.1"
+    tapable "^0.2.5"
+
+"errno@>=0.1.1 <0.2.0-0", errno@^0.1.3:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d"
+  dependencies:
+    prr "~0.0.0"
+
+error-ex@^1.2.0:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc"
+  dependencies:
+    is-arrayish "^0.2.1"
+
+escape-string-regexp@^1.0.2:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+
+escodegen@^1.6.1:
+  version "1.8.1"
+  resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018"
+  dependencies:
+    esprima "^2.7.1"
+    estraverse "^1.9.1"
+    esutils "^2.0.2"
+    optionator "^0.8.1"
+  optionalDependencies:
+    source-map "~0.2.0"
+
+esprima@^2.7.1:
+  version "2.7.3"
+  resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
+
+esprima@^3.1.1:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633"
+
+estraverse@^1.9.1:
+  version "1.9.3"
+  resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44"
+
+esutils@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
+
+events@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924"
+
+evp_bytestokey@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.0.tgz#497b66ad9fef65cd7c08a6180824ba1476b66e53"
+  dependencies:
+    create-hash "^1.1.1"
+
+exec-sh@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.0.tgz#14f75de3f20d286ef933099b2ce50a90359cef10"
+  dependencies:
+    merge "^1.1.3"
+
+expand-brackets@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
+  dependencies:
+    is-posix-bracket "^0.1.0"
+
+expand-range@^1.8.1:
+  version "1.8.2"
+  resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337"
+  dependencies:
+    fill-range "^2.1.0"
+
+extend@~3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4"
+
+extglob@^0.3.1:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1"
+  dependencies:
+    is-extglob "^1.0.0"
+
+extsprintf@1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550"
+
+fast-levenshtein@~2.0.4:
+  version "2.0.6"
+  resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
+
+fb-watchman@^1.8.0:
+  version "1.9.2"
+  resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-1.9.2.tgz#a24cf47827f82d38fb59a69ad70b76e3b6ae7383"
+  dependencies:
+    bser "1.0.2"
+
+fb-watchman@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58"
+  dependencies:
+    bser "^2.0.0"
+
+fbjs@^0.8.1, fbjs@^0.8.4:
+  version "0.8.12"
+  resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.12.tgz#10b5d92f76d45575fd63a217d4ea02bea2f8ed04"
+  dependencies:
+    core-js "^1.0.0"
+    isomorphic-fetch "^2.1.1"
+    loose-envify "^1.0.0"
+    object-assign "^4.1.0"
+    promise "^7.1.1"
+    setimmediate "^1.0.5"
+    ua-parser-js "^0.7.9"
+
+filename-regex@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775"
+
+fileset@^2.0.2:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/fileset/-/fileset-2.0.3.tgz#8e7548a96d3cc2327ee5e674168723a333bba2a0"
+  dependencies:
+    glob "^7.0.3"
+    minimatch "^3.0.3"
+
+fill-range@^2.1.0:
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723"
+  dependencies:
+    is-number "^2.1.0"
+    isobject "^2.0.0"
+    randomatic "^1.1.3"
+    repeat-element "^1.1.2"
+    repeat-string "^1.5.2"
+
+find-up@^1.0.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
+  dependencies:
+    path-exists "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+find-up@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
+  dependencies:
+    locate-path "^2.0.0"
+
+for-in@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
+
+for-own@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce"
+  dependencies:
+    for-in "^1.0.1"
+
+forever-agent@~0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
+
+form-data@~2.1.1:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4"
+  dependencies:
+    asynckit "^0.4.0"
+    combined-stream "^1.0.5"
+    mime-types "^2.1.12"
+
+fs.realpath@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+
+fsevents@^1.0.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.2.tgz#3282b713fb3ad80ede0e9fcf4611b5aa6fc033f4"
+  dependencies:
+    nan "^2.3.0"
+    node-pre-gyp "^0.6.36"
+
+fstream-ignore@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105"
+  dependencies:
+    fstream "^1.0.0"
+    inherits "2"
+    minimatch "^3.0.0"
+
+fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2:
+  version "1.0.11"
+  resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171"
+  dependencies:
+    graceful-fs "^4.1.2"
+    inherits "~2.0.0"
+    mkdirp ">=0.5 0"
+    rimraf "2"
+
+gauge@~2.7.3:
+  version "2.7.4"
+  resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
+  dependencies:
+    aproba "^1.0.3"
+    console-control-strings "^1.0.0"
+    has-unicode "^2.0.0"
+    object-assign "^4.1.0"
+    signal-exit "^3.0.0"
+    string-width "^1.0.1"
+    strip-ansi "^3.0.1"
+    wide-align "^1.1.0"
+
+get-caller-file@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5"
+
+getpass@^0.1.1:
+  version "0.1.6"
+  resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6"
+  dependencies:
+    assert-plus "^1.0.0"
+
+glob-base@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
+  dependencies:
+    glob-parent "^2.0.0"
+    is-glob "^2.0.0"
+
+glob-parent@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28"
+  dependencies:
+    is-glob "^2.0.0"
+
+glob@^7.0.3, glob@^7.0.5:
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
+  dependencies:
+    fs.realpath "^1.0.0"
+    inflight "^1.0.4"
+    inherits "2"
+    minimatch "^3.0.2"
+    once "^1.3.0"
+    path-is-absolute "^1.0.0"
+
+globals@^9.0.0:
+  version "9.17.0"
+  resolved "https://registry.yarnpkg.com/globals/-/globals-9.17.0.tgz#0c0ca696d9b9bb694d2e5470bd37777caad50286"
+
+graceful-fs@^4.1.2, graceful-fs@^4.1.6:
+  version "4.1.11"
+  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
+
+growly@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
+
+handlebars@^4.0.3:
+  version "4.0.6"
+  resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7"
+  dependencies:
+    async "^1.4.0"
+    optimist "^0.6.1"
+    source-map "^0.4.4"
+  optionalDependencies:
+    uglify-js "^2.6"
+
+har-schema@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e"
+
+har-validator@~4.2.1:
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a"
+  dependencies:
+    ajv "^4.9.1"
+    har-schema "^1.0.5"
+
+has-ansi@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
+  dependencies:
+    ansi-regex "^2.0.0"
+
+has-flag@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
+
+has-unicode@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
+
+hash-base@^2.0.0:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1"
+  dependencies:
+    inherits "^2.0.1"
+
+hash.js@^1.0.0, hash.js@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.0.3.tgz#1332ff00156c0a0ffdd8236013d07b77a0451573"
+  dependencies:
+    inherits "^2.0.1"
+
+hawk@~3.1.3:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4"
+  dependencies:
+    boom "2.x.x"
+    cryptiles "2.x.x"
+    hoek "2.x.x"
+    sntp "1.x.x"
+
+hmac-drbg@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
+  dependencies:
+    hash.js "^1.0.3"
+    minimalistic-assert "^1.0.0"
+    minimalistic-crypto-utils "^1.0.1"
+
+hoek@2.x.x:
+  version "2.16.3"
+  resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed"
+
+home-or-tmp@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8"
+  dependencies:
+    os-homedir "^1.0.0"
+    os-tmpdir "^1.0.1"
+
+hosted-git-info@^2.1.4:
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.4.1.tgz#4b0445e41c004a8bd1337773a4ff790ca40318c8"
+
+html-encoding-sniffer@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.1.tgz#79bf7a785ea495fe66165e734153f363ff5437da"
+  dependencies:
+    whatwg-encoding "^1.0.1"
+
+http-signature@~1.1.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf"
+  dependencies:
+    assert-plus "^0.2.0"
+    jsprim "^1.2.2"
+    sshpk "^1.7.0"
+
+https-browserify@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82"
+
+iconv-lite@0.4.13:
+  version "0.4.13"
+  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2"
+
+iconv-lite@~0.4.13:
+  version "0.4.15"
+  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb"
+
+ieee754@^1.1.4:
+  version "1.1.8"
+  resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4"
+
+indexof@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d"
+
+inflight@^1.0.4:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+  dependencies:
+    once "^1.3.0"
+    wrappy "1"
+
+inherits@2, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
+
+inherits@2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
+
+ini@~1.3.0:
+  version "1.3.4"
+  resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e"
+
+interpret@^1.0.0:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.3.tgz#cbc35c62eeee73f19ab7b10a801511401afc0f90"
+
+invariant@^2.2.0:
+  version "2.2.2"
+  resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360"
+  dependencies:
+    loose-envify "^1.0.0"
+
+invert-kv@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
+
+is-arrayish@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
+
+is-binary-path@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
+  dependencies:
+    binary-extensions "^1.0.0"
+
+is-buffer@^1.0.2:
+  version "1.1.5"
+  resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc"
+
+is-builtin-module@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe"
+  dependencies:
+    builtin-modules "^1.0.0"
+
+is-ci@^1.0.9:
+  version "1.0.10"
+  resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.0.10.tgz#f739336b2632365061a9d48270cd56ae3369318e"
+  dependencies:
+    ci-info "^1.0.0"
+
+is-dotfile@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d"
+
+is-equal-shallow@^0.1.3:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534"
+  dependencies:
+    is-primitive "^2.0.0"
+
+is-extendable@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
+
+is-extglob@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
+
+is-finite@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa"
+  dependencies:
+    number-is-nan "^1.0.0"
+
+is-fullwidth-code-point@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
+  dependencies:
+    number-is-nan "^1.0.0"
+
+is-glob@^2.0.0, is-glob@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
+  dependencies:
+    is-extglob "^1.0.0"
+
+is-number@^2.0.2, is-number@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
+  dependencies:
+    kind-of "^3.0.2"
+
+is-posix-bracket@^0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
+
+is-primitive@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
+
+is-stream@^1.0.1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
+
+is-typedarray@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
+
+is-utf8@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
+
+isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
+
+isexe@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+
+isobject@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
+  dependencies:
+    isarray "1.0.0"
+
+isomorphic-fetch@^2.1.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
+  dependencies:
+    node-fetch "^1.0.1"
+    whatwg-fetch ">=0.10.0"
+
+isstream@~0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
+
+istanbul-api@^1.1.0-alpha.1:
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-1.1.7.tgz#f6f37f09f8002b130f891c646b70ee4a8e7345ae"
+  dependencies:
+    async "^2.1.4"
+    fileset "^2.0.2"
+    istanbul-lib-coverage "^1.0.2"
+    istanbul-lib-hook "^1.0.5"
+    istanbul-lib-instrument "^1.7.0"
+    istanbul-lib-report "^1.0.0"
+    istanbul-lib-source-maps "^1.1.1"
+    istanbul-reports "^1.0.2"
+    js-yaml "^3.7.0"
+    mkdirp "^0.5.1"
+    once "^1.4.0"
+
+istanbul-lib-coverage@^1.0.0, istanbul-lib-coverage@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.0.2.tgz#87a0c015b6910651cb3b184814dfb339337e25e1"
+
+istanbul-lib-hook@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.0.5.tgz#6ca3d16d60c5f4082da39f7c5cd38ea8a772b88e"
+  dependencies:
+    append-transform "^0.4.0"
+
+istanbul-lib-instrument@^1.1.1, istanbul-lib-instrument@^1.6.2, istanbul-lib-instrument@^1.7.0:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.7.0.tgz#b8e0dc25709bb44e17336ab47b7bb5c97c23f659"
+  dependencies:
+    babel-generator "^6.18.0"
+    babel-template "^6.16.0"
+    babel-traverse "^6.18.0"
+    babel-types "^6.18.0"
+    babylon "^6.13.0"
+    istanbul-lib-coverage "^1.0.2"
+    semver "^5.3.0"
+
+istanbul-lib-report@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.0.0.tgz#d83dac7f26566b521585569367fe84ccfc7aaecb"
+  dependencies:
+    istanbul-lib-coverage "^1.0.2"
+    mkdirp "^0.5.1"
+    path-parse "^1.0.5"
+    supports-color "^3.1.2"
+
+istanbul-lib-source-maps@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.1.1.tgz#f8c8c2e8f2160d1d91526d97e5bd63b2079af71c"
+  dependencies:
+    istanbul-lib-coverage "^1.0.2"
+    mkdirp "^0.5.1"
+    rimraf "^2.4.4"
+    source-map "^0.5.3"
+
+istanbul-reports@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.0.2.tgz#4e8366abe6fa746cc1cd6633f108de12cc6ac6fa"
+  dependencies:
+    handlebars "^4.0.3"
+
+jest-changed-files@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-19.0.2.tgz#16c54c84c3270be408e06d2e8af3f3e37a885824"
+
+jest-cli@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-19.0.2.tgz#cc3620b62acac5f2d93a548cb6ef697d4ec85443"
+  dependencies:
+    ansi-escapes "^1.4.0"
+    callsites "^2.0.0"
+    chalk "^1.1.1"
+    graceful-fs "^4.1.6"
+    is-ci "^1.0.9"
+    istanbul-api "^1.1.0-alpha.1"
+    istanbul-lib-coverage "^1.0.0"
+    istanbul-lib-instrument "^1.1.1"
+    jest-changed-files "^19.0.2"
+    jest-config "^19.0.2"
+    jest-environment-jsdom "^19.0.2"
+    jest-haste-map "^19.0.0"
+    jest-jasmine2 "^19.0.2"
+    jest-message-util "^19.0.0"
+    jest-regex-util "^19.0.0"
+    jest-resolve-dependencies "^19.0.0"
+    jest-runtime "^19.0.2"
+    jest-snapshot "^19.0.2"
+    jest-util "^19.0.2"
+    micromatch "^2.3.11"
+    node-notifier "^5.0.1"
+    slash "^1.0.0"
+    string-length "^1.0.1"
+    throat "^3.0.0"
+    which "^1.1.1"
+    worker-farm "^1.3.1"
+    yargs "^6.3.0"
+
+jest-config@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-19.0.2.tgz#1b9bd2db0ddd16df61c2b10a54009e1768da6411"
+  dependencies:
+    chalk "^1.1.1"
+    jest-environment-jsdom "^19.0.2"
+    jest-environment-node "^19.0.2"
+    jest-jasmine2 "^19.0.2"
+    jest-regex-util "^19.0.0"
+    jest-resolve "^19.0.2"
+    jest-validate "^19.0.2"
+    pretty-format "^19.0.0"
+
+jest-diff@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-19.0.0.tgz#d1563cfc56c8b60232988fbc05d4d16ed90f063c"
+  dependencies:
+    chalk "^1.1.3"
+    diff "^3.0.0"
+    jest-matcher-utils "^19.0.0"
+    pretty-format "^19.0.0"
+
+jest-environment-jsdom@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-19.0.2.tgz#ceda859c4a4b94ab35e4de7dab54b926f293e4a3"
+  dependencies:
+    jest-mock "^19.0.0"
+    jest-util "^19.0.2"
+    jsdom "^9.11.0"
+
+jest-environment-node@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-19.0.2.tgz#6e84079db87ed21d0c05e1f9669f207b116fe99b"
+  dependencies:
+    jest-mock "^19.0.0"
+    jest-util "^19.0.2"
+
+jest-file-exists@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-file-exists/-/jest-file-exists-19.0.0.tgz#cca2e587a11ec92e24cfeab3f8a94d657f3fceb8"
+
+jest-haste-map@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-19.0.0.tgz#adde00b62b1fe04432a104b3254fc5004514b55e"
+  dependencies:
+    fb-watchman "^2.0.0"
+    graceful-fs "^4.1.6"
+    micromatch "^2.3.11"
+    sane "~1.5.0"
+    worker-farm "^1.3.1"
+
+jest-jasmine2@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-19.0.2.tgz#167991ac825981fb1a800af126e83afcca832c73"
+  dependencies:
+    graceful-fs "^4.1.6"
+    jest-matcher-utils "^19.0.0"
+    jest-matchers "^19.0.0"
+    jest-message-util "^19.0.0"
+    jest-snapshot "^19.0.2"
+
+jest-matcher-utils@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-19.0.0.tgz#5ecd9b63565d2b001f61fbf7ec4c7f537964564d"
+  dependencies:
+    chalk "^1.1.3"
+    pretty-format "^19.0.0"
+
+jest-matchers@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-matchers/-/jest-matchers-19.0.0.tgz#c74ecc6ebfec06f384767ba4d6fa4a42d6755754"
+  dependencies:
+    jest-diff "^19.0.0"
+    jest-matcher-utils "^19.0.0"
+    jest-message-util "^19.0.0"
+    jest-regex-util "^19.0.0"
+
+jest-message-util@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-19.0.0.tgz#721796b89c0e4d761606f9ba8cb828a3b6246416"
+  dependencies:
+    chalk "^1.1.1"
+    micromatch "^2.3.11"
+
+jest-mock@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-19.0.0.tgz#67038641e9607ab2ce08ec4a8cb83aabbc899d01"
+
+jest-regex-util@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-19.0.0.tgz#b7754587112aede1456510bb1f6afe74ef598691"
+
+jest-resolve-dependencies@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-19.0.0.tgz#a741ad1fa094140e64ecf2642a504f834ece22ee"
+  dependencies:
+    jest-file-exists "^19.0.0"
+
+jest-resolve@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-19.0.2.tgz#5793575de4f07aec32f7d7ff0c6c181963eefb3c"
+  dependencies:
+    browser-resolve "^1.11.2"
+    jest-haste-map "^19.0.0"
+    resolve "^1.2.0"
+
+jest-runtime@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-19.0.2.tgz#d9a43e72de416d27d196fd9c7940d98fe6685407"
+  dependencies:
+    babel-core "^6.0.0"
+    babel-jest "^19.0.0"
+    babel-plugin-istanbul "^4.0.0"
+    chalk "^1.1.3"
+    graceful-fs "^4.1.6"
+    jest-config "^19.0.2"
+    jest-file-exists "^19.0.0"
+    jest-haste-map "^19.0.0"
+    jest-regex-util "^19.0.0"
+    jest-resolve "^19.0.2"
+    jest-util "^19.0.2"
+    json-stable-stringify "^1.0.1"
+    micromatch "^2.3.11"
+    strip-bom "3.0.0"
+    yargs "^6.3.0"
+
+jest-snapshot@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-19.0.2.tgz#9c1b216214f7187c38bfd5c70b1efab16b0ff50b"
+  dependencies:
+    chalk "^1.1.3"
+    jest-diff "^19.0.0"
+    jest-file-exists "^19.0.0"
+    jest-matcher-utils "^19.0.0"
+    jest-util "^19.0.2"
+    natural-compare "^1.4.0"
+    pretty-format "^19.0.0"
+
+jest-util@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-19.0.2.tgz#e0a0232a2ab9e6b2b53668bdb3534c2b5977ed41"
+  dependencies:
+    chalk "^1.1.1"
+    graceful-fs "^4.1.6"
+    jest-file-exists "^19.0.0"
+    jest-message-util "^19.0.0"
+    jest-mock "^19.0.0"
+    jest-validate "^19.0.2"
+    leven "^2.0.0"
+    mkdirp "^0.5.1"
+
+jest-validate@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-19.0.2.tgz#dc534df5f1278d5b63df32b14241d4dbf7244c0c"
+  dependencies:
+    chalk "^1.1.1"
+    jest-matcher-utils "^19.0.0"
+    leven "^2.0.0"
+    pretty-format "^19.0.0"
+
+jest@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest/-/jest-19.0.2.tgz#b794faaf8ff461e7388f28beef559a54f20b2c10"
+  dependencies:
+    jest-cli "^19.0.2"
+
+jodid25519@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967"
+  dependencies:
+    jsbn "~0.1.0"
+
+js-tokens@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7"
+
+js-yaml@^3.7.0:
+  version "3.8.3"
+  resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.3.tgz#33a05ec481c850c8875929166fe1beb61c728766"
+  dependencies:
+    argparse "^1.0.7"
+    esprima "^3.1.1"
+
+jsbn@~0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
+
+jsdom@^9.11.0:
+  version "9.12.0"
+  resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-9.12.0.tgz#e8c546fffcb06c00d4833ca84410fed7f8a097d4"
+  dependencies:
+    abab "^1.0.3"
+    acorn "^4.0.4"
+    acorn-globals "^3.1.0"
+    array-equal "^1.0.0"
+    content-type-parser "^1.0.1"
+    cssom ">= 0.3.2 < 0.4.0"
+    cssstyle ">= 0.2.37 < 0.3.0"
+    escodegen "^1.6.1"
+    html-encoding-sniffer "^1.0.1"
+    nwmatcher ">= 1.3.9 < 2.0.0"
+    parse5 "^1.5.1"
+    request "^2.79.0"
+    sax "^1.2.1"
+    symbol-tree "^3.2.1"
+    tough-cookie "^2.3.2"
+    webidl-conversions "^4.0.0"
+    whatwg-encoding "^1.0.1"
+    whatwg-url "^4.3.0"
+    xml-name-validator "^2.0.1"
+
+jsesc@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b"
+
+json-loader@^0.5.4:
+  version "0.5.4"
+  resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.4.tgz#8baa1365a632f58a3c46d20175fc6002c96e37de"
+
+json-schema@0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
+
+json-stable-stringify@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af"
+  dependencies:
+    jsonify "~0.0.0"
+
+json-stringify-safe@~5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
+
+json5@^0.5.0, json5@^0.5.1:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
+
+jsonify@~0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
+
+jsprim@^1.2.2:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.0.tgz#a3b87e40298d8c380552d8cc7628a0bb95a22918"
+  dependencies:
+    assert-plus "1.0.0"
+    extsprintf "1.0.2"
+    json-schema "0.2.3"
+    verror "1.3.6"
+
+kind-of@^3.0.2:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47"
+  dependencies:
+    is-buffer "^1.0.2"
+
+lazy-cache@^1.0.3:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
+
+lcid@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
+  dependencies:
+    invert-kv "^1.0.0"
+
+leven@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580"
+
+levn@~0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
+  dependencies:
+    prelude-ls "~1.1.2"
+    type-check "~0.3.2"
+
+load-json-file@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
+  dependencies:
+    graceful-fs "^4.1.2"
+    parse-json "^2.2.0"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+    strip-bom "^2.0.0"
+
+loader-runner@^2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2"
+
+loader-utils@^0.2.16:
+  version "0.2.17"
+  resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348"
+  dependencies:
+    big.js "^3.1.3"
+    emojis-list "^2.0.0"
+    json5 "^0.5.0"
+    object-assign "^4.0.1"
+
+locate-path@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
+  dependencies:
+    p-locate "^2.0.0"
+    path-exists "^3.0.0"
+
+lodash@^4.14.0, lodash@^4.2.0:
+  version "4.17.4"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
+
+longest@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
+
+loose-envify@^1.0.0, loose-envify@^1.1.0:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
+  dependencies:
+    js-tokens "^3.0.0"
+
+makeerror@1.0.x:
+  version "1.0.11"
+  resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c"
+  dependencies:
+    tmpl "1.0.x"
+
+memory-fs@^0.4.0, memory-fs@~0.4.1:
+  version "0.4.1"
+  resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"
+  dependencies:
+    errno "^0.1.3"
+    readable-stream "^2.0.1"
+
+merge@^1.1.3:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da"
+
+micromatch@^2.1.5, micromatch@^2.3.11:
+  version "2.3.11"
+  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
+  dependencies:
+    arr-diff "^2.0.0"
+    array-unique "^0.2.1"
+    braces "^1.8.2"
+    expand-brackets "^0.1.4"
+    extglob "^0.3.1"
+    filename-regex "^2.0.0"
+    is-extglob "^1.0.0"
+    is-glob "^2.0.1"
+    kind-of "^3.0.2"
+    normalize-path "^2.0.1"
+    object.omit "^2.0.0"
+    parse-glob "^3.0.4"
+    regex-cache "^0.4.2"
+
+miller-rabin@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.0.tgz#4a62fb1d42933c05583982f4c716f6fb9e6c6d3d"
+  dependencies:
+    bn.js "^4.0.0"
+    brorand "^1.0.1"
+
+mime-db@~1.27.0:
+  version "1.27.0"
+  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1"
+
+mime-types@^2.1.12, mime-types@~2.1.7:
+  version "2.1.15"
+  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed"
+  dependencies:
+    mime-db "~1.27.0"
+
+minimalistic-assert@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3"
+
+minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
+
+minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774"
+  dependencies:
+    brace-expansion "^1.0.0"
+
+minimist@0.0.8, minimist@~0.0.1:
+  version "0.0.8"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
+
+minimist@^1.1.1, minimist@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
+
+"mkdirp@>=0.5 0", mkdirp@^0.5.1, mkdirp@~0.5.0:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
+  dependencies:
+    minimist "0.0.8"
+
+ms@0.7.2:
+  version "0.7.2"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765"
+
+nan@^2.3.0:
+  version "2.6.2"
+  resolved "https://registry.yarnpkg.com/nan/-/nan-2.6.2.tgz#e4ff34e6c95fdfb5aecc08de6596f43605a7db45"
+
+natural-compare@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
+
+node-fetch@^1.0.1:
+  version "1.6.3"
+  resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04"
+  dependencies:
+    encoding "^0.1.11"
+    is-stream "^1.0.1"
+
+node-int64@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
+
+node-libs-browser@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.0.0.tgz#a3a59ec97024985b46e958379646f96c4b616646"
+  dependencies:
+    assert "^1.1.1"
+    browserify-zlib "^0.1.4"
+    buffer "^4.3.0"
+    console-browserify "^1.1.0"
+    constants-browserify "^1.0.0"
+    crypto-browserify "^3.11.0"
+    domain-browser "^1.1.1"
+    events "^1.0.0"
+    https-browserify "0.0.1"
+    os-browserify "^0.2.0"
+    path-browserify "0.0.0"
+    process "^0.11.0"
+    punycode "^1.2.4"
+    querystring-es3 "^0.2.0"
+    readable-stream "^2.0.5"
+    stream-browserify "^2.0.1"
+    stream-http "^2.3.1"
+    string_decoder "^0.10.25"
+    timers-browserify "^2.0.2"
+    tty-browserify "0.0.0"
+    url "^0.11.0"
+    util "^0.10.3"
+    vm-browserify "0.0.4"
+
+node-notifier@^5.0.1:
+  version "5.1.2"
+  resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.1.2.tgz#2fa9e12605fa10009d44549d6fcd8a63dde0e4ff"
+  dependencies:
+    growly "^1.3.0"
+    semver "^5.3.0"
+    shellwords "^0.1.0"
+    which "^1.2.12"
+
+node-pre-gyp@^0.6.36:
+  version "0.6.36"
+  resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.36.tgz#db604112cb74e0d477554e9b505b17abddfab786"
+  dependencies:
+    mkdirp "^0.5.1"
+    nopt "^4.0.1"
+    npmlog "^4.0.2"
+    rc "^1.1.7"
+    request "^2.81.0"
+    rimraf "^2.6.1"
+    semver "^5.3.0"
+    tar "^2.2.1"
+    tar-pack "^3.4.0"
+
+nopt@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
+  dependencies:
+    abbrev "1"
+    osenv "^0.1.4"
+
+normalize-package-data@^2.3.2:
+  version "2.3.6"
+  resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.6.tgz#498fa420c96401f787402ba21e600def9f981fff"
+  dependencies:
+    hosted-git-info "^2.1.4"
+    is-builtin-module "^1.0.0"
+    semver "2 || 3 || 4 || 5"
+    validate-npm-package-license "^3.0.1"
+
+normalize-path@^2.0.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
+  dependencies:
+    remove-trailing-separator "^1.0.1"
+
+npmlog@^4.0.2:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.0.tgz#dc59bee85f64f00ed424efb2af0783df25d1c0b5"
+  dependencies:
+    are-we-there-yet "~1.1.2"
+    console-control-strings "~1.1.0"
+    gauge "~2.7.3"
+    set-blocking "~2.0.0"
+
+number-is-nan@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
+
+"nwmatcher@>= 1.3.9 < 2.0.0":
+  version "1.3.9"
+  resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.3.9.tgz#8bab486ff7fa3dfd086656bbe8b17116d3692d2a"
+
+oauth-sign@~0.8.1:
+  version "0.8.2"
+  resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
+
+object-assign@^4.0.1, object-assign@^4.1.0:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+
+object.omit@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
+  dependencies:
+    for-own "^0.1.4"
+    is-extendable "^0.1.1"
+
+once@^1.3.0, once@^1.3.3, once@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+  dependencies:
+    wrappy "1"
+
+optimist@^0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
+  dependencies:
+    minimist "~0.0.1"
+    wordwrap "~0.0.2"
+
+optionator@^0.8.1:
+  version "0.8.2"
+  resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64"
+  dependencies:
+    deep-is "~0.1.3"
+    fast-levenshtein "~2.0.4"
+    levn "~0.3.0"
+    prelude-ls "~1.1.2"
+    type-check "~0.3.2"
+    wordwrap "~1.0.0"
+
+os-browserify@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.2.1.tgz#63fc4ccee5d2d7763d26bbf8601078e6c2e0044f"
+
+os-homedir@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
+
+os-locale@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9"
+  dependencies:
+    lcid "^1.0.0"
+
+os-tmpdir@^1.0.0, os-tmpdir@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
+
+osenv@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644"
+  dependencies:
+    os-homedir "^1.0.0"
+    os-tmpdir "^1.0.0"
+
+p-limit@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.1.0.tgz#b07ff2d9a5d88bec806035895a2bab66a27988bc"
+
+p-locate@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
+  dependencies:
+    p-limit "^1.1.0"
+
+pako@~0.2.0:
+  version "0.2.9"
+  resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
+
+parse-asn1@^5.0.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712"
+  dependencies:
+    asn1.js "^4.0.0"
+    browserify-aes "^1.0.0"
+    create-hash "^1.1.0"
+    evp_bytestokey "^1.0.0"
+    pbkdf2 "^3.0.3"
+
+parse-glob@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
+  dependencies:
+    glob-base "^0.3.0"
+    is-dotfile "^1.0.0"
+    is-extglob "^1.0.0"
+    is-glob "^2.0.0"
+
+parse-json@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
+  dependencies:
+    error-ex "^1.2.0"
+
+parse5@^1.5.1:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94"
+
+path-browserify@0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a"
+
+path-exists@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
+  dependencies:
+    pinkie-promise "^2.0.0"
+
+path-exists@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
+
+path-is-absolute@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+
+path-parse@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1"
+
+path-type@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
+  dependencies:
+    graceful-fs "^4.1.2"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+pbkdf2@^3.0.3:
+  version "3.0.12"
+  resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.12.tgz#be36785c5067ea48d806ff923288c5f750b6b8a2"
+  dependencies:
+    create-hash "^1.1.2"
+    create-hmac "^1.1.4"
+    ripemd160 "^2.0.1"
+    safe-buffer "^5.0.1"
+    sha.js "^2.4.8"
+
+performance-now@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5"
+
+pify@^2.0.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
+
+pinkie-promise@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
+  dependencies:
+    pinkie "^2.0.0"
+
+pinkie@^2.0.0:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
+
+prelude-ls@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
+
+preserve@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
+
+pretty-format@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-19.0.0.tgz#56530d32acb98a3fa4851c4e2b9d37b420684c84"
+  dependencies:
+    ansi-styles "^3.0.0"
+
+private@^0.1.6:
+  version "0.1.7"
+  resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1"
+
+process-nextick-args@~1.0.6:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
+
+process@^0.11.0:
+  version "0.11.10"
+  resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
+
+promise@^7.1.1:
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/promise/-/promise-7.1.1.tgz#489654c692616b8aa55b0724fa809bb7db49c5bf"
+  dependencies:
+    asap "~2.0.3"
+
+prr@~0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a"
+
+public-encrypt@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.0.tgz#39f699f3a46560dd5ebacbca693caf7c65c18cc6"
+  dependencies:
+    bn.js "^4.1.0"
+    browserify-rsa "^4.0.0"
+    create-hash "^1.1.0"
+    parse-asn1 "^5.0.0"
+    randombytes "^2.0.1"
+
+punycode@1.3.2:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
+
+punycode@^1.2.4, punycode@^1.4.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
+
+qs@~6.4.0:
+  version "6.4.0"
+  resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
+
+querystring-es3@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
+
+querystring@0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
+
+randomatic@^1.1.3:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb"
+  dependencies:
+    is-number "^2.0.2"
+    kind-of "^3.0.2"
+
+randombytes@^2.0.0, randombytes@^2.0.1:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.5.tgz#dc009a246b8d09a177b4b7a0ae77bc570f4b1b79"
+  dependencies:
+    safe-buffer "^5.1.0"
+
+rc@^1.1.7:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.1.tgz#2e03e8e42ee450b8cb3dce65be1bf8974e1dfd95"
+  dependencies:
+    deep-extend "~0.4.0"
+    ini "~1.3.0"
+    minimist "^1.2.0"
+    strip-json-comments "~2.0.1"
+
+react-dom@^15.4.2:
+  version "15.4.2"
+  resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.4.2.tgz#015363f05b0a1fd52ae9efdd3a0060d90695208f"
+  dependencies:
+    fbjs "^0.8.1"
+    loose-envify "^1.1.0"
+    object-assign "^4.1.0"
+
+react@^15.4.2:
+  version "15.4.2"
+  resolved "https://registry.yarnpkg.com/react/-/react-15.4.2.tgz#41f7991b26185392ba9bae96c8889e7e018397ef"
+  dependencies:
+    fbjs "^0.8.4"
+    loose-envify "^1.1.0"
+    object-assign "^4.1.0"
+
+read-pkg-up@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
+  dependencies:
+    find-up "^1.0.0"
+    read-pkg "^1.0.0"
+
+read-pkg@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
+  dependencies:
+    load-json-file "^1.0.0"
+    normalize-package-data "^2.3.2"
+    path-type "^1.0.0"
+
+readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.2.6:
+  version "2.2.11"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.11.tgz#0796b31f8d7688007ff0b93a8088d34aa17c0f72"
+  dependencies:
+    core-util-is "~1.0.0"
+    inherits "~2.0.1"
+    isarray "~1.0.0"
+    process-nextick-args "~1.0.6"
+    safe-buffer "~5.0.1"
+    string_decoder "~1.0.0"
+    util-deprecate "~1.0.1"
+
+readdirp@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78"
+  dependencies:
+    graceful-fs "^4.1.2"
+    minimatch "^3.0.2"
+    readable-stream "^2.0.2"
+    set-immediate-shim "^1.0.1"
+
+regenerator-runtime@^0.10.0:
+  version "0.10.3"
+  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.3.tgz#8c4367a904b51ea62a908ac310bf99ff90a82a3e"
+
+regex-cache@^0.4.2:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145"
+  dependencies:
+    is-equal-shallow "^0.1.3"
+    is-primitive "^2.0.0"
+
+remove-trailing-separator@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.0.1.tgz#615ebb96af559552d4bf4057c8436d486ab63cc4"
+
+repeat-element@^1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a"
+
+repeat-string@^1.5.2:
+  version "1.6.1"
+  resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
+
+repeating@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda"
+  dependencies:
+    is-finite "^1.0.0"
+
+request@^2.79.0, request@^2.81.0:
+  version "2.81.0"
+  resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0"
+  dependencies:
+    aws-sign2 "~0.6.0"
+    aws4 "^1.2.1"
+    caseless "~0.12.0"
+    combined-stream "~1.0.5"
+    extend "~3.0.0"
+    forever-agent "~0.6.1"
+    form-data "~2.1.1"
+    har-validator "~4.2.1"
+    hawk "~3.1.3"
+    http-signature "~1.1.0"
+    is-typedarray "~1.0.0"
+    isstream "~0.1.2"
+    json-stringify-safe "~5.0.1"
+    mime-types "~2.1.7"
+    oauth-sign "~0.8.1"
+    performance-now "^0.2.0"
+    qs "~6.4.0"
+    safe-buffer "^5.0.1"
+    stringstream "~0.0.4"
+    tough-cookie "~2.3.0"
+    tunnel-agent "^0.6.0"
+    uuid "^3.0.0"
+
+require-directory@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
+
+require-main-filename@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
+
+resolve@1.1.7:
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
+
+resolve@^1.2.0:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.3.2.tgz#1f0442c9e0cbb8136e87b9305f932f46c7f28235"
+  dependencies:
+    path-parse "^1.0.5"
+
+right-align@^0.1.1:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef"
+  dependencies:
+    align-text "^0.1.1"
+
+rimraf@2, rimraf@^2.4.4, rimraf@^2.5.1, rimraf@^2.6.1:
+  version "2.6.1"
+  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d"
+  dependencies:
+    glob "^7.0.5"
+
+ripemd160@^2.0.0, ripemd160@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7"
+  dependencies:
+    hash-base "^2.0.0"
+    inherits "^2.0.1"
+
+safe-buffer@^5.0.1, safe-buffer@~5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7"
+
+safe-buffer@^5.1.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.0.tgz#fe4c8460397f9eaaaa58e73be46273408a45e223"
+
+sane@~1.5.0:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/sane/-/sane-1.5.0.tgz#a4adeae764d048621ecb27d5f9ecf513101939f3"
+  dependencies:
+    anymatch "^1.3.0"
+    exec-sh "^0.2.0"
+    fb-watchman "^1.8.0"
+    minimatch "^3.0.2"
+    minimist "^1.1.1"
+    walker "~1.0.5"
+    watch "~0.10.0"
+
+sax@^1.2.1:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.2.tgz#fd8631a23bc7826bef5d871bdb87378c95647828"
+
+"semver@2 || 3 || 4 || 5", semver@^5.3.0:
+  version "5.3.0"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
+
+set-blocking@^2.0.0, set-blocking@~2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
+
+set-immediate-shim@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61"
+
+setimmediate@^1.0.4, setimmediate@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
+
+sha.js@^2.4.0, sha.js@^2.4.8:
+  version "2.4.8"
+  resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.8.tgz#37068c2c476b6baf402d14a49c67f597921f634f"
+  dependencies:
+    inherits "^2.0.1"
+
+shellwords@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.0.tgz#66afd47b6a12932d9071cbfd98a52e785cd0ba14"
+
+signal-exit@^3.0.0:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
+
+slash@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
+
+sntp@1.x.x:
+  version "1.0.9"
+  resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198"
+  dependencies:
+    hoek "2.x.x"
+
+source-list-map@^1.1.1:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-1.1.2.tgz#9889019d1024cce55cdc069498337ef6186a11a1"
+
+source-map-support@^0.4.2:
+  version "0.4.14"
+  resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.14.tgz#9d4463772598b86271b4f523f6c1f4e02a7d6aef"
+  dependencies:
+    source-map "^0.5.6"
+
+source-map@^0.4.4:
+  version "0.4.4"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b"
+  dependencies:
+    amdefine ">=0.0.4"
+
+source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.3:
+  version "0.5.6"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
+
+source-map@~0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d"
+  dependencies:
+    amdefine ">=0.0.4"
+
+spdx-correct@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40"
+  dependencies:
+    spdx-license-ids "^1.0.2"
+
+spdx-expression-parse@~1.0.0:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c"
+
+spdx-license-ids@^1.0.2:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57"
+
+sprintf-js@~1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
+
+sshpk@^1.7.0:
+  version "1.11.0"
+  resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.11.0.tgz#2d8d5ebb4a6fab28ffba37fa62a90f4a3ea59d77"
+  dependencies:
+    asn1 "~0.2.3"
+    assert-plus "^1.0.0"
+    dashdash "^1.12.0"
+    getpass "^0.1.1"
+  optionalDependencies:
+    bcrypt-pbkdf "^1.0.0"
+    ecc-jsbn "~0.1.1"
+    jodid25519 "^1.0.0"
+    jsbn "~0.1.0"
+    tweetnacl "~0.14.0"
+
+stream-browserify@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db"
+  dependencies:
+    inherits "~2.0.1"
+    readable-stream "^2.0.2"
+
+stream-http@^2.3.1:
+  version "2.7.2"
+  resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.7.2.tgz#40a050ec8dc3b53b33d9909415c02c0bf1abfbad"
+  dependencies:
+    builtin-status-codes "^3.0.0"
+    inherits "^2.0.1"
+    readable-stream "^2.2.6"
+    to-arraybuffer "^1.0.0"
+    xtend "^4.0.0"
+
+string-length@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/string-length/-/string-length-1.0.1.tgz#56970fb1c38558e9e70b728bf3de269ac45adfac"
+  dependencies:
+    strip-ansi "^3.0.0"
+
+string-width@^1.0.1, string-width@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
+  dependencies:
+    code-point-at "^1.0.0"
+    is-fullwidth-code-point "^1.0.0"
+    strip-ansi "^3.0.0"
+
+string_decoder@^0.10.25:
+  version "0.10.31"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
+
+string_decoder@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.2.tgz#b29e1f4e1125fa97a10382b8a533737b7491e179"
+  dependencies:
+    safe-buffer "~5.0.1"
+
+stringstream@~0.0.4:
+  version "0.0.5"
+  resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878"
+
+strip-ansi@^3.0.0, strip-ansi@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
+  dependencies:
+    ansi-regex "^2.0.0"
+
+strip-bom@3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
+
+strip-bom@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
+  dependencies:
+    is-utf8 "^0.2.0"
+
+strip-json-comments@~2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
+
+supports-color@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
+
+supports-color@^3.1.0, supports-color@^3.1.2:
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
+  dependencies:
+    has-flag "^1.0.0"
+
+symbol-tree@^3.2.1:
+  version "3.2.2"
+  resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6"
+
+tapable@^0.2.5, tapable@~0.2.5:
+  version "0.2.6"
+  resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.6.tgz#206be8e188860b514425375e6f1ae89bfb01fd8d"
+
+tar-pack@^3.4.0:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.0.tgz#23be2d7f671a8339376cbdb0b8fe3fdebf317984"
+  dependencies:
+    debug "^2.2.0"
+    fstream "^1.0.10"
+    fstream-ignore "^1.0.5"
+    once "^1.3.3"
+    readable-stream "^2.1.4"
+    rimraf "^2.5.1"
+    tar "^2.2.1"
+    uid-number "^0.0.6"
+
+tar@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1"
+  dependencies:
+    block-stream "*"
+    fstream "^1.0.2"
+    inherits "2"
+
+test-exclude@^4.0.3:
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-4.0.3.tgz#86a13ce3effcc60e6c90403cf31a27a60ac6c4e7"
+  dependencies:
+    arrify "^1.0.1"
+    micromatch "^2.3.11"
+    object-assign "^4.1.0"
+    read-pkg-up "^1.0.1"
+    require-main-filename "^1.0.1"
+
+throat@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/throat/-/throat-3.0.0.tgz#e7c64c867cbb3845f10877642f7b60055b8ec0d6"
+
+timers-browserify@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.2.tgz#ab4883cf597dcd50af211349a00fbca56ac86b86"
+  dependencies:
+    setimmediate "^1.0.4"
+
+tmpl@1.0.x:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1"
+
+to-arraybuffer@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
+
+to-fast-properties@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320"
+
+tough-cookie@^2.3.2, tough-cookie@~2.3.0:
+  version "2.3.2"
+  resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a"
+  dependencies:
+    punycode "^1.4.1"
+
+tr46@~0.0.3:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
+
+trim-right@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
+
+tty-browserify@0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
+
+tunnel-agent@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
+  dependencies:
+    safe-buffer "^5.0.1"
+
+tweetnacl@^0.14.3, tweetnacl@~0.14.0:
+  version "0.14.5"
+  resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
+
+type-check@~0.3.2:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
+  dependencies:
+    prelude-ls "~1.1.2"
+
+ua-parser-js@^0.7.9:
+  version "0.7.12"
+  resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb"
+
+uglify-js@^2.6, uglify-js@^2.8.27:
+  version "2.8.28"
+  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.28.tgz#e335032df9bb20dcb918f164589d5af47f38834a"
+  dependencies:
+    source-map "~0.5.1"
+    yargs "~3.10.0"
+  optionalDependencies:
+    uglify-to-browserify "~1.0.0"
+
+uglify-to-browserify@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7"
+
+uid-number@^0.0.6:
+  version "0.0.6"
+  resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81"
+
+url@^0.11.0:
+  version "0.11.0"
+  resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
+  dependencies:
+    punycode "1.3.2"
+    querystring "0.2.0"
+
+util-deprecate@~1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+
+util@0.10.3, util@^0.10.3:
+  version "0.10.3"
+  resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9"
+  dependencies:
+    inherits "2.0.1"
+
+uuid@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1"
+
+validate-npm-package-license@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc"
+  dependencies:
+    spdx-correct "~1.0.0"
+    spdx-expression-parse "~1.0.0"
+
+verror@1.3.6:
+  version "1.3.6"
+  resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c"
+  dependencies:
+    extsprintf "1.0.2"
+
+vm-browserify@0.0.4:
+  version "0.0.4"
+  resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73"
+  dependencies:
+    indexof "0.0.1"
+
+walker@~1.0.5:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb"
+  dependencies:
+    makeerror "1.0.x"
+
+watch@~0.10.0:
+  version "0.10.0"
+  resolved "https://registry.yarnpkg.com/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc"
+
+watchpack@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.3.1.tgz#7d8693907b28ce6013e7f3610aa2a1acf07dad87"
+  dependencies:
+    async "^2.1.2"
+    chokidar "^1.4.3"
+    graceful-fs "^4.1.2"
+
+webidl-conversions@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
+
+webidl-conversions@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.1.tgz#8015a17ab83e7e1b311638486ace81da6ce206a0"
+
+webpack-sources@^0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-0.2.3.tgz#17c62bfaf13c707f9d02c479e0dcdde8380697fb"
+  dependencies:
+    source-list-map "^1.1.1"
+    source-map "~0.5.3"
+
+webpack@^2.6.1:
+  version "2.6.1"
+  resolved "https://registry.yarnpkg.com/webpack/-/webpack-2.6.1.tgz#2e0457f0abb1ac5df3ab106c69c672f236785f07"
+  dependencies:
+    acorn "^5.0.0"
+    acorn-dynamic-import "^2.0.0"
+    ajv "^4.7.0"
+    ajv-keywords "^1.1.1"
+    async "^2.1.2"
+    enhanced-resolve "^3.0.0"
+    interpret "^1.0.0"
+    json-loader "^0.5.4"
+    json5 "^0.5.1"
+    loader-runner "^2.3.0"
+    loader-utils "^0.2.16"
+    memory-fs "~0.4.1"
+    mkdirp "~0.5.0"
+    node-libs-browser "^2.0.0"
+    source-map "^0.5.3"
+    supports-color "^3.1.0"
+    tapable "~0.2.5"
+    uglify-js "^2.8.27"
+    watchpack "^1.3.1"
+    webpack-sources "^0.2.3"
+    yargs "^6.0.0"
+
+whatwg-encoding@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.1.tgz#3c6c451a198ee7aec55b1ec61d0920c67801a5f4"
+  dependencies:
+    iconv-lite "0.4.13"
+
+whatwg-fetch@>=0.10.0:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84"
+
+whatwg-url@^4.3.0:
+  version "4.7.0"
+  resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-4.7.0.tgz#202035ac1955b087cdd20fa8b58ded3ab1cd2af5"
+  dependencies:
+    tr46 "~0.0.3"
+    webidl-conversions "^3.0.0"
+
+which-module@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
+
+which@^1.1.1, which@^1.2.12:
+  version "1.2.14"
+  resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5"
+  dependencies:
+    isexe "^2.0.0"
+
+wide-align@^1.1.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710"
+  dependencies:
+    string-width "^1.0.2"
+
+window-size@0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
+
+wordwrap@0.0.2, wordwrap@~0.0.2:
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
+
+wordwrap@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
+
+worker-farm@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.3.1.tgz#4333112bb49b17aa050b87895ca6b2cacf40e5ff"
+  dependencies:
+    errno ">=0.1.1 <0.2.0-0"
+    xtend ">=4.0.0 <4.1.0-0"
+
+wrap-ansi@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
+  dependencies:
+    string-width "^1.0.1"
+    strip-ansi "^3.0.1"
+
+wrappy@1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+
+xml-name-validator@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635"
+
+"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
+
+y18n@^3.2.1:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
+
+yargs-parser@^4.2.0:
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c"
+  dependencies:
+    camelcase "^3.0.0"
+
+yargs@^6.0.0, yargs@^6.3.0:
+  version "6.6.0"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208"
+  dependencies:
+    camelcase "^3.0.0"
+    cliui "^3.2.0"
+    decamelize "^1.1.1"
+    get-caller-file "^1.0.1"
+    os-locale "^1.4.0"
+    read-pkg-up "^1.0.1"
+    require-directory "^2.1.1"
+    require-main-filename "^1.0.1"
+    set-blocking "^2.0.0"
+    string-width "^1.0.2"
+    which-module "^1.0.0"
+    y18n "^3.2.1"
+    yargs-parser "^4.2.0"
+
+yargs@~3.10.0:
+  version "3.10.0"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"
+  dependencies:
+    camelcase "^1.0.2"
+    cliui "^2.1.0"
+    decamelize "^1.0.0"
+    window-size "0.1.0"
diff --git a/addons/react-addons-shallow-compare/.gitignore b/addons/react-addons-shallow-compare/.gitignore
new file mode 100644
index 000000000000..ddf487440267
--- /dev/null
+++ b/addons/react-addons-shallow-compare/.gitignore
@@ -0,0 +1,2 @@
+react-addons-shallow-compare.js
+react-addons-shallow-compare.min.js
diff --git a/addons/react-addons-shallow-compare/LICENSE b/addons/react-addons-shallow-compare/LICENSE
new file mode 100644
index 000000000000..edbd6d9b04f1
--- /dev/null
+++ b/addons/react-addons-shallow-compare/LICENSE
@@ -0,0 +1,31 @@
+BSD License
+
+For React software
+
+Copyright (c) 2013-present, Facebook, Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+ * Neither the name Facebook nor the names of its contributors may be used to
+   endorse or promote products derived from this software without specific
+   prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/addons/react-addons-shallow-compare/PATENTS b/addons/react-addons-shallow-compare/PATENTS
new file mode 100644
index 000000000000..9c9f8e87a8f4
--- /dev/null
+++ b/addons/react-addons-shallow-compare/PATENTS
@@ -0,0 +1,33 @@
+Additional Grant of Patent Rights Version 2
+
+"Software" means the React software distributed by Facebook, Inc.
+
+Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software
+("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable
+(subject to the termination provision below) license under any Necessary
+Claims, to make, have made, use, sell, offer to sell, import, and otherwise
+transfer the Software. For avoidance of doubt, no license is granted under
+Facebook's rights in any patent claims that are infringed by (i) modifications
+to the Software made by you or any third party or (ii) the Software in
+combination with any software or other technology.
+
+The license granted hereunder will terminate, automatically and without notice,
+if you (or any of your subsidiaries, corporate affiliates or agents) initiate
+directly or indirectly, or take a direct financial interest in, any Patent
+Assertion: (i) against Facebook or any of its subsidiaries or corporate
+affiliates, (ii) against any party if such Patent Assertion arises in whole or
+in part from any software, technology, product or service of Facebook or any of
+its subsidiaries or corporate affiliates, or (iii) against any party relating
+to the Software. Notwithstanding the foregoing, if Facebook or any of its
+subsidiaries or corporate affiliates files a lawsuit alleging patent
+infringement against you in the first instance, and you respond by filing a
+patent infringement counterclaim in that lawsuit against that party that is
+unrelated to the Software, the license granted hereunder will not terminate
+under section (i) of this paragraph due to such counterclaim.
+
+A "Necessary Claim" is a claim of a patent owned by Facebook that is
+necessarily infringed by the Software standing alone.
+
+A "Patent Assertion" is any lawsuit or other action alleging direct, indirect,
+or contributory infringement or inducement to infringe any patent, including a
+cross-claim or counterclaim.
diff --git a/addons/react-addons-shallow-compare/README.md b/addons/react-addons-shallow-compare/README.md
new file mode 100644
index 000000000000..791e8c5c5ba7
--- /dev/null
+++ b/addons/react-addons-shallow-compare/README.md
@@ -0,0 +1,53 @@
+# react-addons-shallow-compare
+
+>**Note:**
+>This is a legacy React addon, and is no longer maintained.
+>
+>We don't encourage using it in new code, but it exists for backwards compatibility.  
+>The recommended migration path is to use [`React.PureComponent`](https://facebook.github.io/react/docs/react-api.html#react.purecomponent) instead.
+
+**Importing**
+
+```javascript
+import shallowCompare from 'react-addons-shallow-compare'; // ES6
+var shallowCompare = require('react-addons-shallow-compare'); // ES5 with npm
+```
+
+If you prefer a `<script>` tag, you can get it from `React.addons.shallowCompare` with:
+
+```html
+<!-- development version -->
+<script src="https://unpkg.com/react-addons-shallow-compare/react-addons-shallow-compare.js"></script>
+
+<!-- production version -->
+<script src="https://unpkg.com/react-addons-shallow-compare/react-addons-shallow-compare.min.js"></script>
+```
+
+In this case, make sure to put the `<script>` tag after React.
+
+
+## Overview
+
+Before [`React.PureComponent`](https://facebook.github.io/react/docs/react-api.html#react.purecomponent) was introduced, `shallowCompare` was commonly used to achieve the same functionality as [`PureRenderMixin`](https://www.npmjs.com/package/react-addons-pure-render-mixin) while using ES6 classes with React.
+
+If your React component's render function is "pure" (in other words, it renders the same result given the same props and state), you can use this helper function for a performance boost in some cases.
+
+Example:
+
+```js
+export class SampleComponent extends React.Component {
+  shouldComponentUpdate(nextProps, nextState) {
+    return shallowCompare(this, nextProps, nextState);
+  }
+
+  render() {
+    return <div className={this.props.className}>foo</div>;
+  }
+}
+```
+
+`shallowCompare` performs a shallow equality check on the current `props` and `nextProps` objects as well as the current `state` and `nextState` objects.  
+It does this by iterating on the keys of the objects being compared and returning true when the values of a key in each object are not strictly equal.
+
+`shallowCompare` returns `true` if the shallow comparison for props or state fails and therefore the component should update.  
+`shallowCompare` returns `false` if the shallow comparison for props and state both pass and therefore the component does not need to update.
diff --git a/addons/react-addons-shallow-compare/index.js b/addons/react-addons-shallow-compare/index.js
new file mode 100644
index 000000000000..f06b8a6e547d
--- /dev/null
+++ b/addons/react-addons-shallow-compare/index.js
@@ -0,0 +1,28 @@
+/**
+ * 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 shallowCompare
+ */
+
+'use strict';
+
+var shallowEqual = require('fbjs/lib/shallowEqual');
+
+/**
+ * Does a shallow comparison for props and state.
+ * See ReactComponentWithPureRenderMixin
+ * See also https://facebook.github.io/react/docs/shallow-compare.html
+ */
+function shallowCompare(instance, nextProps, nextState) {
+  return (
+    !shallowEqual(instance.props, nextProps) ||
+    !shallowEqual(instance.state, nextState)
+  );
+}
+
+module.exports = shallowCompare;
diff --git a/addons/react-addons-shallow-compare/package.json b/addons/react-addons-shallow-compare/package.json
new file mode 100644
index 000000000000..882b382f9d50
--- /dev/null
+++ b/addons/react-addons-shallow-compare/package.json
@@ -0,0 +1,36 @@
+{
+  "name": "react-addons-shallow-compare",
+  "version": "15.6.0",
+  "main": "index.js",
+  "repository": "facebook/react",
+  "keywords": [
+    "react",
+    "react-addon"
+  ],
+  "license": "BSD-3-Clause",
+  "dependencies": {
+    "fbjs": "^0.8.4",
+    "object-assign": "^4.1.0"
+  },
+  "files": [
+    "LICENSE",
+    "PATENTS",
+    "README.md",
+    "index.js",
+    "react-addons-shallow-compare.js",
+    "react-addons-shallow-compare.min.js"
+  ],
+  "scripts": {
+    "test": "TEST_ENTRY=./index.js jest",
+    "build:dev": "NODE_ENV=development webpack && TEST_ENTRY=./react-addons-shallow-compare.js jest",
+    "build:prod": "NODE_ENV=production webpack && NODE_ENV=production TEST_ENTRY=./react-addons-shallow-compare.min.js jest",
+    "build": "npm run build:dev && npm run build:prod && node ../postbuild.js",
+    "prepublish": "npm test && npm run build"
+  },
+  "devDependencies": {
+    "jest": "^19.0.2",
+    "react": "^15.4.2",
+    "react-dom": "^15.4.2",
+    "webpack": "^2.6.1"
+  }
+}
diff --git a/addons/react-addons-shallow-compare/test.js b/addons/react-addons-shallow-compare/test.js
new file mode 100644
index 000000000000..2609f58fd68f
--- /dev/null
+++ b/addons/react-addons-shallow-compare/test.js
@@ -0,0 +1,271 @@
+/**
+ * Copyright 2015-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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var React;
+var ReactDOM;
+var shallowCompare;
+
+// Catch stray warnings
+var env = jasmine.getEnv();
+var callCount = 0;
+var oldError = console.error;
+var newError = function() {
+  callCount++;
+  oldError.apply(this, arguments);
+};
+console.error = newError;
+env.beforeEach(() => {
+  callCount = 0;
+  jasmine.addMatchers({
+    toBeReset() {
+      return {
+        compare(actual) {
+          if (actual !== newError && !jasmine.isSpy(actual)) {
+            return {
+              pass: false,
+              message: 'Test did not tear down console.error mock properly.'
+            };
+          }
+          return {pass: true};
+        }
+      };
+    },
+    toNotHaveBeenCalled() {
+      return {
+        compare(actual) {
+          return {
+            pass: callCount === 0,
+            message:
+              'Expected test not to warn. If the warning is expected, mock ' +
+                "it out using spyOn(console, 'error'); and test that the " +
+                'warning occurs.'
+          };
+        }
+      };
+    }
+  });
+});
+env.afterEach(() => {
+  expect(console.error).toBeReset();
+  expect(console.error).toNotHaveBeenCalled();
+});
+
+function renderIntoDocument(element) {
+  var node = document.createElement('div');
+  return ReactDOM.render(element, node);
+}
+
+// Tests adapted from ReactComponentWithPureRendererMixin and ReactPureComponent tests
+describe('shallowCompare', () => {
+  beforeEach(() => {
+    React = require('react');
+    ReactDOM = require('react-dom');
+    shallowCompare = require(process.env.TEST_ENTRY);
+  });
+
+  it('should render', () => {
+    var renders = 0;
+    class Component extends React.Component {
+      constructor() {
+        super();
+        this.state = {type: 'mushrooms'};
+      }
+      render() {
+        renders++;
+        return React.createElement('div', null, this.props.text[0]);
+      }
+      shouldComponentUpdate(nextProps, nextState) {
+        return shallowCompare(this, nextProps, nextState);
+      }
+    }
+
+    var container = document.createElement('div');
+    var text;
+    var component;
+
+    text = ['porcini'];
+    component = ReactDOM.render(
+      React.createElement(Component, {text}),
+      container
+    );
+    expect(container.textContent).toBe('porcini');
+    expect(renders).toBe(1);
+
+    text = ['morel'];
+    component = ReactDOM.render(
+      React.createElement(Component, {text}),
+      container
+    );
+    expect(container.textContent).toBe('morel');
+    expect(renders).toBe(2);
+
+    text[0] = 'portobello';
+    component = ReactDOM.render(
+      React.createElement(Component, {text}),
+      container
+    );
+    expect(container.textContent).toBe('morel');
+    expect(renders).toBe(2);
+
+    // Setting state without changing it doesn't cause a rerender.
+    component.setState({type: 'mushrooms'});
+    expect(container.textContent).toBe('morel');
+    expect(renders).toBe(2);
+
+    // But changing state does.
+    component.setState({type: 'portobello mushrooms'});
+    expect(container.textContent).toBe('portobello');
+    expect(renders).toBe(3);
+  });
+
+  it('can override shouldComponentUpdate', () => {
+    var renders = 0;
+    class Component extends React.PureComponent {
+      render() {
+        renders++;
+        return React.createElement('div');
+      }
+      shouldComponentUpdate() {
+        return true;
+      }
+    }
+    var container = document.createElement('div');
+    ReactDOM.render(React.createElement(Component), container);
+    ReactDOM.render(React.createElement(Component), container);
+    expect(renders).toBe(2);
+  });
+
+  it('provides a default shouldComponentUpdate implementation', () => {
+    var renderCalls = 0;
+    class PlasticWrap extends React.Component {
+      constructor(props, context) {
+        super(props, context);
+        this.state = {
+          color: 'green'
+        };
+      }
+
+      shouldComponentUpdate(nextProps, nextState) {
+        return shallowCompare(this, nextProps, nextState);
+      }
+
+      render() {
+        return React.createElement(Apple, {
+          color: this.state.color,
+          ref: 'apple'
+        });
+      }
+    }
+
+    var Apple = React.createClass({
+      getInitialState: function() {
+        return {
+          cut: false,
+          slices: 1
+        };
+      },
+
+      cut: function() {
+        this.setState({
+          cut: true,
+          slices: 10
+        });
+      },
+
+      eatSlice: function() {
+        this.setState({
+          slices: this.state.slices - 1
+        });
+      },
+
+      shouldComponentUpdate(nextProps, nextState) {
+        return shallowCompare(this, nextProps, nextState);
+      },
+
+      render: function() {
+        renderCalls++;
+        return React.createElement('div');
+      }
+    });
+
+    var instance = renderIntoDocument(React.createElement(PlasticWrap));
+    expect(renderCalls).toBe(1);
+
+    // Do not re-render based on props
+    instance.setState({color: 'green'});
+    expect(renderCalls).toBe(1);
+
+    // Re-render based on props
+    instance.setState({color: 'red'});
+    expect(renderCalls).toBe(2);
+
+    // Re-render base on state
+    instance.refs.apple.cut();
+    expect(renderCalls).toBe(3);
+
+    // No re-render based on state
+    instance.refs.apple.cut();
+    expect(renderCalls).toBe(3);
+
+    // Re-render based on state again
+    instance.refs.apple.eatSlice();
+    expect(renderCalls).toBe(4);
+  });
+
+  it('does not do a deep comparison', () => {
+    function getInitialState() {
+      return {
+        foo: [1, 2, 3],
+        bar: {a: 4, b: 5, c: 6}
+      };
+    }
+
+    var renderCalls = 0;
+    var initialSettings = getInitialState();
+
+    var Component = React.createClass({
+      shouldComponentUpdate(nextProps, nextState) {
+        return shallowCompare(this, nextProps, nextState);
+      },
+
+      getInitialState: function() {
+        return initialSettings;
+      },
+
+      render: function() {
+        renderCalls++;
+        return React.createElement('div');
+      }
+    });
+
+    var instance = renderIntoDocument(React.createElement(Component));
+    expect(renderCalls).toBe(1);
+
+    // Do not re-render if state is equal
+    var settings = {
+      foo: initialSettings.foo,
+      bar: initialSettings.bar
+    };
+    instance.setState(settings);
+    expect(renderCalls).toBe(1);
+
+    // Re-render because one field changed
+    initialSettings.foo = [1, 2, 3];
+    instance.setState(initialSettings);
+    expect(renderCalls).toBe(2);
+
+    // Re-render because the object changed
+    instance.setState(getInitialState());
+    expect(renderCalls).toBe(3);
+  });
+});
diff --git a/addons/react-addons-shallow-compare/webpack.config.js b/addons/react-addons-shallow-compare/webpack.config.js
new file mode 100644
index 000000000000..7c2e3d2f0584
--- /dev/null
+++ b/addons/react-addons-shallow-compare/webpack.config.js
@@ -0,0 +1,55 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+const webpack = require('webpack');
+
+let __DEV__;
+switch (process.env.NODE_ENV) {
+  case 'development':
+    __DEV__ = true;
+    break;
+  case 'production':
+    __DEV__ = false;
+    break;
+  default:
+    throw new Error('Unknown environment.');
+}
+
+module.exports = {
+  entry: './index',
+  output: {
+    library: 'shallowCompare',
+    libraryTarget: 'umd',
+    filename: __DEV__
+      ? 'react-addons-shallow-compare.js'
+      : 'react-addons-shallow-compare.min.js'
+  },
+  plugins: [
+    new webpack.DefinePlugin({
+      'process.env.NODE_ENV': __DEV__ ? '"development"' : '"production"'
+    })
+  ].concat(
+    __DEV__
+      ? []
+      : [
+          new webpack.optimize.UglifyJsPlugin({
+            compress: {
+              warnings: false
+            },
+            output: {
+              comments: false
+            }
+          })
+        ]
+  )
+};
diff --git a/addons/react-addons-shallow-compare/yarn.lock b/addons/react-addons-shallow-compare/yarn.lock
new file mode 100644
index 000000000000..2423b18a05ab
--- /dev/null
+++ b/addons/react-addons-shallow-compare/yarn.lock
@@ -0,0 +1,2814 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+abab@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.3.tgz#b81de5f7274ec4e756d797cd834f303642724e5d"
+
+abbrev@1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f"
+
+acorn-dynamic-import@^2.0.0:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz#c752bd210bef679501b6c6cb7fc84f8f47158cc4"
+  dependencies:
+    acorn "^4.0.3"
+
+acorn-globals@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-3.1.0.tgz#fd8270f71fbb4996b004fa880ee5d46573a731bf"
+  dependencies:
+    acorn "^4.0.4"
+
+acorn@^4.0.3, acorn@^4.0.4:
+  version "4.0.11"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.11.tgz#edcda3bd937e7556410d42ed5860f67399c794c0"
+
+acorn@^5.0.0:
+  version "5.0.3"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.0.3.tgz#c460df08491463f028ccb82eab3730bf01087b3d"
+
+ajv-keywords@^1.1.1:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c"
+
+ajv@^4.7.0, ajv@^4.9.1:
+  version "4.11.5"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.5.tgz#b6ee74657b993a01dce44b7944d56f485828d5bd"
+  dependencies:
+    co "^4.6.0"
+    json-stable-stringify "^1.0.1"
+
+align-text@^0.1.1, align-text@^0.1.3:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
+  dependencies:
+    kind-of "^3.0.2"
+    longest "^1.0.1"
+    repeat-string "^1.5.2"
+
+amdefine@>=0.0.4:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
+
+ansi-escapes@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
+
+ansi-regex@^2.0.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
+
+ansi-styles@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
+
+ansi-styles@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.0.0.tgz#5404e93a544c4fec7f048262977bebfe3155e0c1"
+  dependencies:
+    color-convert "^1.0.0"
+
+anymatch@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507"
+  dependencies:
+    arrify "^1.0.0"
+    micromatch "^2.1.5"
+
+append-transform@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-0.4.0.tgz#d76ebf8ca94d276e247a36bad44a4b74ab611991"
+  dependencies:
+    default-require-extensions "^1.0.0"
+
+aproba@^1.0.3:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.2.tgz#45c6629094de4e96f693ef7eab74ae079c240fc1"
+
+are-we-there-yet@~1.1.2:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d"
+  dependencies:
+    delegates "^1.0.0"
+    readable-stream "^2.0.6"
+
+argparse@^1.0.7:
+  version "1.0.9"
+  resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86"
+  dependencies:
+    sprintf-js "~1.0.2"
+
+arr-diff@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf"
+  dependencies:
+    arr-flatten "^1.0.1"
+
+arr-flatten@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b"
+
+array-equal@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93"
+
+array-unique@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
+
+arrify@^1.0.0, arrify@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
+
+asap@~2.0.3:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f"
+
+asn1.js@^4.0.0:
+  version "4.9.1"
+  resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.1.tgz#48ba240b45a9280e94748990ba597d216617fd40"
+  dependencies:
+    bn.js "^4.0.0"
+    inherits "^2.0.1"
+    minimalistic-assert "^1.0.0"
+
+asn1@~0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86"
+
+assert-plus@1.0.0, assert-plus@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
+
+assert-plus@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234"
+
+assert@^1.1.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91"
+  dependencies:
+    util "0.10.3"
+
+async-each@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
+
+async@^1.4.0:
+  version "1.5.2"
+  resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
+
+async@^2.1.2, async@^2.1.4:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/async/-/async-2.3.0.tgz#1013d1051047dd320fe24e494d5c66ecaf6147d9"
+  dependencies:
+    lodash "^4.14.0"
+
+asynckit@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+
+aws-sign2@~0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f"
+
+aws4@^1.2.1:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e"
+
+babel-code-frame@^6.22.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4"
+  dependencies:
+    chalk "^1.1.0"
+    esutils "^2.0.2"
+    js-tokens "^3.0.0"
+
+babel-core@^6.0.0, babel-core@^6.24.0:
+  version "6.24.0"
+  resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.24.0.tgz#8f36a0a77f5c155aed6f920b844d23ba56742a02"
+  dependencies:
+    babel-code-frame "^6.22.0"
+    babel-generator "^6.24.0"
+    babel-helpers "^6.23.0"
+    babel-messages "^6.23.0"
+    babel-register "^6.24.0"
+    babel-runtime "^6.22.0"
+    babel-template "^6.23.0"
+    babel-traverse "^6.23.1"
+    babel-types "^6.23.0"
+    babylon "^6.11.0"
+    convert-source-map "^1.1.0"
+    debug "^2.1.1"
+    json5 "^0.5.0"
+    lodash "^4.2.0"
+    minimatch "^3.0.2"
+    path-is-absolute "^1.0.0"
+    private "^0.1.6"
+    slash "^1.0.0"
+    source-map "^0.5.0"
+
+babel-generator@^6.18.0, babel-generator@^6.24.0:
+  version "6.24.0"
+  resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.24.0.tgz#eba270a8cc4ce6e09a61be43465d7c62c1f87c56"
+  dependencies:
+    babel-messages "^6.23.0"
+    babel-runtime "^6.22.0"
+    babel-types "^6.23.0"
+    detect-indent "^4.0.0"
+    jsesc "^1.3.0"
+    lodash "^4.2.0"
+    source-map "^0.5.0"
+    trim-right "^1.0.1"
+
+babel-helpers@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.23.0.tgz#4f8f2e092d0b6a8808a4bde79c27f1e2ecf0d992"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-template "^6.23.0"
+
+babel-jest@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-19.0.0.tgz#59323ced99a3a84d359da219ca881074ffc6ce3f"
+  dependencies:
+    babel-core "^6.0.0"
+    babel-plugin-istanbul "^4.0.0"
+    babel-preset-jest "^19.0.0"
+
+babel-messages@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e"
+  dependencies:
+    babel-runtime "^6.22.0"
+
+babel-plugin-istanbul@^4.0.0:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.1.tgz#c12de0fc6fe42adfb16be56f1ad11e4a9782eca9"
+  dependencies:
+    find-up "^2.1.0"
+    istanbul-lib-instrument "^1.6.2"
+    test-exclude "^4.0.3"
+
+babel-plugin-jest-hoist@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-19.0.0.tgz#4ae2a04ea612a6e73651f3fde52c178991304bea"
+
+babel-preset-jest@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-19.0.0.tgz#22d67201d02324a195811288eb38294bb3cac396"
+  dependencies:
+    babel-plugin-jest-hoist "^19.0.0"
+
+babel-register@^6.24.0:
+  version "6.24.0"
+  resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.24.0.tgz#5e89f8463ba9970356d02eb07dabe3308b080cfd"
+  dependencies:
+    babel-core "^6.24.0"
+    babel-runtime "^6.22.0"
+    core-js "^2.4.0"
+    home-or-tmp "^2.0.0"
+    lodash "^4.2.0"
+    mkdirp "^0.5.1"
+    source-map-support "^0.4.2"
+
+babel-runtime@^6.22.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b"
+  dependencies:
+    core-js "^2.4.0"
+    regenerator-runtime "^0.10.0"
+
+babel-template@^6.16.0, babel-template@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.23.0.tgz#04d4f270adbb3aa704a8143ae26faa529238e638"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-traverse "^6.23.0"
+    babel-types "^6.23.0"
+    babylon "^6.11.0"
+    lodash "^4.2.0"
+
+babel-traverse@^6.18.0, babel-traverse@^6.23.0, babel-traverse@^6.23.1:
+  version "6.23.1"
+  resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.23.1.tgz#d3cb59010ecd06a97d81310065f966b699e14f48"
+  dependencies:
+    babel-code-frame "^6.22.0"
+    babel-messages "^6.23.0"
+    babel-runtime "^6.22.0"
+    babel-types "^6.23.0"
+    babylon "^6.15.0"
+    debug "^2.2.0"
+    globals "^9.0.0"
+    invariant "^2.2.0"
+    lodash "^4.2.0"
+
+babel-types@^6.18.0, babel-types@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.23.0.tgz#bb17179d7538bad38cd0c9e115d340f77e7e9acf"
+  dependencies:
+    babel-runtime "^6.22.0"
+    esutils "^2.0.2"
+    lodash "^4.2.0"
+    to-fast-properties "^1.0.1"
+
+babylon@^6.11.0, babylon@^6.13.0, babylon@^6.15.0:
+  version "6.16.1"
+  resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.16.1.tgz#30c5a22f481978a9e7f8cdfdf496b11d94b404d3"
+
+balanced-match@^0.4.1:
+  version "0.4.2"
+  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
+
+base64-js@^1.0.2:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1"
+
+bcrypt-pbkdf@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d"
+  dependencies:
+    tweetnacl "^0.14.3"
+
+big.js@^3.1.3:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.1.3.tgz#4cada2193652eb3ca9ec8e55c9015669c9806978"
+
+binary-extensions@^1.0.0:
+  version "1.8.0"
+  resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.8.0.tgz#48ec8d16df4377eae5fa5884682480af4d95c774"
+
+block-stream@*:
+  version "0.0.9"
+  resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a"
+  dependencies:
+    inherits "~2.0.0"
+
+bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0:
+  version "4.11.6"
+  resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215"
+
+boom@2.x.x:
+  version "2.10.1"
+  resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f"
+  dependencies:
+    hoek "2.x.x"
+
+brace-expansion@^1.0.0:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9"
+  dependencies:
+    balanced-match "^0.4.1"
+    concat-map "0.0.1"
+
+braces@^1.8.2:
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7"
+  dependencies:
+    expand-range "^1.8.1"
+    preserve "^0.2.0"
+    repeat-element "^1.1.2"
+
+brorand@^1.0.1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
+
+browser-resolve@^1.11.2:
+  version "1.11.2"
+  resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.2.tgz#8ff09b0a2c421718a1051c260b32e48f442938ce"
+  dependencies:
+    resolve "1.1.7"
+
+browserify-aes@^1.0.0, browserify-aes@^1.0.4:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.0.6.tgz#5e7725dbdef1fd5930d4ebab48567ce451c48a0a"
+  dependencies:
+    buffer-xor "^1.0.2"
+    cipher-base "^1.0.0"
+    create-hash "^1.1.0"
+    evp_bytestokey "^1.0.0"
+    inherits "^2.0.1"
+
+browserify-cipher@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.0.tgz#9988244874bf5ed4e28da95666dcd66ac8fc363a"
+  dependencies:
+    browserify-aes "^1.0.4"
+    browserify-des "^1.0.0"
+    evp_bytestokey "^1.0.0"
+
+browserify-des@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.0.tgz#daa277717470922ed2fe18594118a175439721dd"
+  dependencies:
+    cipher-base "^1.0.1"
+    des.js "^1.0.0"
+    inherits "^2.0.1"
+
+browserify-rsa@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524"
+  dependencies:
+    bn.js "^4.1.0"
+    randombytes "^2.0.1"
+
+browserify-sign@^4.0.0:
+  version "4.0.4"
+  resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298"
+  dependencies:
+    bn.js "^4.1.1"
+    browserify-rsa "^4.0.0"
+    create-hash "^1.1.0"
+    create-hmac "^1.1.2"
+    elliptic "^6.0.0"
+    inherits "^2.0.1"
+    parse-asn1 "^5.0.0"
+
+browserify-zlib@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d"
+  dependencies:
+    pako "~0.2.0"
+
+bser@1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/bser/-/bser-1.0.2.tgz#381116970b2a6deea5646dd15dd7278444b56169"
+  dependencies:
+    node-int64 "^0.4.0"
+
+bser@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719"
+  dependencies:
+    node-int64 "^0.4.0"
+
+buffer-xor@^1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9"
+
+buffer@^4.3.0:
+  version "4.9.1"
+  resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298"
+  dependencies:
+    base64-js "^1.0.2"
+    ieee754 "^1.1.4"
+    isarray "^1.0.0"
+
+builtin-modules@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
+
+builtin-status-codes@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
+
+callsites@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50"
+
+camelcase@^1.0.2:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39"
+
+camelcase@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
+
+caseless@~0.12.0:
+  version "0.12.0"
+  resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
+
+center-align@^0.1.1:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad"
+  dependencies:
+    align-text "^0.1.3"
+    lazy-cache "^1.0.3"
+
+chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
+  dependencies:
+    ansi-styles "^2.2.1"
+    escape-string-regexp "^1.0.2"
+    has-ansi "^2.0.0"
+    strip-ansi "^3.0.0"
+    supports-color "^2.0.0"
+
+chokidar@^1.4.3:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
+  dependencies:
+    anymatch "^1.3.0"
+    async-each "^1.0.0"
+    glob-parent "^2.0.0"
+    inherits "^2.0.1"
+    is-binary-path "^1.0.0"
+    is-glob "^2.0.0"
+    path-is-absolute "^1.0.0"
+    readdirp "^2.0.0"
+  optionalDependencies:
+    fsevents "^1.0.0"
+
+ci-info@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.0.0.tgz#dc5285f2b4e251821683681c381c3388f46ec534"
+
+cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.3.tgz#eeabf194419ce900da3018c207d212f2a6df0a07"
+  dependencies:
+    inherits "^2.0.1"
+
+cliui@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1"
+  dependencies:
+    center-align "^0.1.1"
+    right-align "^0.1.1"
+    wordwrap "0.0.2"
+
+cliui@^3.2.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
+  dependencies:
+    string-width "^1.0.1"
+    strip-ansi "^3.0.1"
+    wrap-ansi "^2.0.0"
+
+co@^4.6.0:
+  version "4.6.0"
+  resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
+
+code-point-at@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
+
+color-convert@^1.0.0:
+  version "1.9.0"
+  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a"
+  dependencies:
+    color-name "^1.1.1"
+
+color-name@^1.1.1:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.2.tgz#5c8ab72b64bd2215d617ae9559ebb148475cf98d"
+
+combined-stream@^1.0.5, combined-stream@~1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009"
+  dependencies:
+    delayed-stream "~1.0.0"
+
+concat-map@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+
+console-browserify@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10"
+  dependencies:
+    date-now "^0.1.4"
+
+console-control-strings@^1.0.0, console-control-strings@~1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
+
+constants-browserify@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
+
+content-type-parser@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/content-type-parser/-/content-type-parser-1.0.1.tgz#c3e56988c53c65127fb46d4032a3a900246fdc94"
+
+convert-source-map@^1.1.0:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5"
+
+core-js@^1.0.0:
+  version "1.2.7"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
+
+core-js@^2.4.0:
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e"
+
+core-util-is@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
+
+create-ecdh@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.0.tgz#888c723596cdf7612f6498233eebd7a35301737d"
+  dependencies:
+    bn.js "^4.1.0"
+    elliptic "^6.0.0"
+
+create-hash@^1.1.0, create-hash@^1.1.1, create-hash@^1.1.2:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.3.tgz#606042ac8b9262750f483caddab0f5819172d8fd"
+  dependencies:
+    cipher-base "^1.0.1"
+    inherits "^2.0.1"
+    ripemd160 "^2.0.0"
+    sha.js "^2.4.0"
+
+create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.6.tgz#acb9e221a4e17bdb076e90657c42b93e3726cf06"
+  dependencies:
+    cipher-base "^1.0.3"
+    create-hash "^1.1.0"
+    inherits "^2.0.1"
+    ripemd160 "^2.0.0"
+    safe-buffer "^5.0.1"
+    sha.js "^2.4.8"
+
+cryptiles@2.x.x:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8"
+  dependencies:
+    boom "2.x.x"
+
+crypto-browserify@^3.11.0:
+  version "3.11.0"
+  resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.11.0.tgz#3652a0906ab9b2a7e0c3ce66a408e957a2485522"
+  dependencies:
+    browserify-cipher "^1.0.0"
+    browserify-sign "^4.0.0"
+    create-ecdh "^4.0.0"
+    create-hash "^1.1.0"
+    create-hmac "^1.1.0"
+    diffie-hellman "^5.0.0"
+    inherits "^2.0.1"
+    pbkdf2 "^3.0.3"
+    public-encrypt "^4.0.0"
+    randombytes "^2.0.0"
+
+cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0":
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.2.tgz#b8036170c79f07a90ff2f16e22284027a243848b"
+
+"cssstyle@>= 0.2.37 < 0.3.0":
+  version "0.2.37"
+  resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-0.2.37.tgz#541097234cb2513c83ceed3acddc27ff27987d54"
+  dependencies:
+    cssom "0.3.x"
+
+dashdash@^1.12.0:
+  version "1.14.1"
+  resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
+  dependencies:
+    assert-plus "^1.0.0"
+
+date-now@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
+
+debug@^2.1.1, debug@^2.2.0:
+  version "2.6.3"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.3.tgz#0f7eb8c30965ec08c72accfa0130c8b79984141d"
+  dependencies:
+    ms "0.7.2"
+
+decamelize@^1.0.0, decamelize@^1.1.1:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
+
+deep-extend@~0.4.0:
+  version "0.4.2"
+  resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f"
+
+deep-is@~0.1.3:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
+
+default-require-extensions@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8"
+  dependencies:
+    strip-bom "^2.0.0"
+
+delayed-stream@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+
+delegates@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
+
+des.js@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc"
+  dependencies:
+    inherits "^2.0.1"
+    minimalistic-assert "^1.0.0"
+
+detect-indent@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208"
+  dependencies:
+    repeating "^2.0.0"
+
+diff@^3.0.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9"
+
+diffie-hellman@^5.0.0:
+  version "5.0.2"
+  resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.2.tgz#b5835739270cfe26acf632099fded2a07f209e5e"
+  dependencies:
+    bn.js "^4.1.0"
+    miller-rabin "^4.0.0"
+    randombytes "^2.0.0"
+
+domain-browser@^1.1.1:
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc"
+
+ecc-jsbn@~0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505"
+  dependencies:
+    jsbn "~0.1.0"
+
+elliptic@^6.0.0:
+  version "6.4.0"
+  resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df"
+  dependencies:
+    bn.js "^4.4.0"
+    brorand "^1.0.1"
+    hash.js "^1.0.0"
+    hmac-drbg "^1.0.0"
+    inherits "^2.0.1"
+    minimalistic-assert "^1.0.0"
+    minimalistic-crypto-utils "^1.0.0"
+
+emojis-list@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
+
+encoding@^0.1.11:
+  version "0.1.12"
+  resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb"
+  dependencies:
+    iconv-lite "~0.4.13"
+
+enhanced-resolve@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.1.0.tgz#9f4b626f577245edcf4b2ad83d86e17f4f421dec"
+  dependencies:
+    graceful-fs "^4.1.2"
+    memory-fs "^0.4.0"
+    object-assign "^4.0.1"
+    tapable "^0.2.5"
+
+"errno@>=0.1.1 <0.2.0-0", errno@^0.1.3:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d"
+  dependencies:
+    prr "~0.0.0"
+
+error-ex@^1.2.0:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc"
+  dependencies:
+    is-arrayish "^0.2.1"
+
+escape-string-regexp@^1.0.2:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+
+escodegen@^1.6.1:
+  version "1.8.1"
+  resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018"
+  dependencies:
+    esprima "^2.7.1"
+    estraverse "^1.9.1"
+    esutils "^2.0.2"
+    optionator "^0.8.1"
+  optionalDependencies:
+    source-map "~0.2.0"
+
+esprima@^2.7.1:
+  version "2.7.3"
+  resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
+
+esprima@^3.1.1:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633"
+
+estraverse@^1.9.1:
+  version "1.9.3"
+  resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44"
+
+esutils@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
+
+events@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924"
+
+evp_bytestokey@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.0.tgz#497b66ad9fef65cd7c08a6180824ba1476b66e53"
+  dependencies:
+    create-hash "^1.1.1"
+
+exec-sh@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.0.tgz#14f75de3f20d286ef933099b2ce50a90359cef10"
+  dependencies:
+    merge "^1.1.3"
+
+expand-brackets@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
+  dependencies:
+    is-posix-bracket "^0.1.0"
+
+expand-range@^1.8.1:
+  version "1.8.2"
+  resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337"
+  dependencies:
+    fill-range "^2.1.0"
+
+extend@~3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4"
+
+extglob@^0.3.1:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1"
+  dependencies:
+    is-extglob "^1.0.0"
+
+extsprintf@1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550"
+
+fast-levenshtein@~2.0.4:
+  version "2.0.6"
+  resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
+
+fb-watchman@^1.8.0:
+  version "1.9.2"
+  resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-1.9.2.tgz#a24cf47827f82d38fb59a69ad70b76e3b6ae7383"
+  dependencies:
+    bser "1.0.2"
+
+fb-watchman@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58"
+  dependencies:
+    bser "^2.0.0"
+
+fbjs@^0.8.1, fbjs@^0.8.4:
+  version "0.8.12"
+  resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.12.tgz#10b5d92f76d45575fd63a217d4ea02bea2f8ed04"
+  dependencies:
+    core-js "^1.0.0"
+    isomorphic-fetch "^2.1.1"
+    loose-envify "^1.0.0"
+    object-assign "^4.1.0"
+    promise "^7.1.1"
+    setimmediate "^1.0.5"
+    ua-parser-js "^0.7.9"
+
+filename-regex@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775"
+
+fileset@^2.0.2:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/fileset/-/fileset-2.0.3.tgz#8e7548a96d3cc2327ee5e674168723a333bba2a0"
+  dependencies:
+    glob "^7.0.3"
+    minimatch "^3.0.3"
+
+fill-range@^2.1.0:
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723"
+  dependencies:
+    is-number "^2.1.0"
+    isobject "^2.0.0"
+    randomatic "^1.1.3"
+    repeat-element "^1.1.2"
+    repeat-string "^1.5.2"
+
+find-up@^1.0.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
+  dependencies:
+    path-exists "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+find-up@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
+  dependencies:
+    locate-path "^2.0.0"
+
+for-in@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
+
+for-own@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce"
+  dependencies:
+    for-in "^1.0.1"
+
+forever-agent@~0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
+
+form-data@~2.1.1:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4"
+  dependencies:
+    asynckit "^0.4.0"
+    combined-stream "^1.0.5"
+    mime-types "^2.1.12"
+
+fs.realpath@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+
+fsevents@^1.0.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.2.tgz#3282b713fb3ad80ede0e9fcf4611b5aa6fc033f4"
+  dependencies:
+    nan "^2.3.0"
+    node-pre-gyp "^0.6.36"
+
+fstream-ignore@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105"
+  dependencies:
+    fstream "^1.0.0"
+    inherits "2"
+    minimatch "^3.0.0"
+
+fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2:
+  version "1.0.11"
+  resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171"
+  dependencies:
+    graceful-fs "^4.1.2"
+    inherits "~2.0.0"
+    mkdirp ">=0.5 0"
+    rimraf "2"
+
+gauge@~2.7.3:
+  version "2.7.4"
+  resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
+  dependencies:
+    aproba "^1.0.3"
+    console-control-strings "^1.0.0"
+    has-unicode "^2.0.0"
+    object-assign "^4.1.0"
+    signal-exit "^3.0.0"
+    string-width "^1.0.1"
+    strip-ansi "^3.0.1"
+    wide-align "^1.1.0"
+
+get-caller-file@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5"
+
+getpass@^0.1.1:
+  version "0.1.6"
+  resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6"
+  dependencies:
+    assert-plus "^1.0.0"
+
+glob-base@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
+  dependencies:
+    glob-parent "^2.0.0"
+    is-glob "^2.0.0"
+
+glob-parent@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28"
+  dependencies:
+    is-glob "^2.0.0"
+
+glob@^7.0.3, glob@^7.0.5:
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
+  dependencies:
+    fs.realpath "^1.0.0"
+    inflight "^1.0.4"
+    inherits "2"
+    minimatch "^3.0.2"
+    once "^1.3.0"
+    path-is-absolute "^1.0.0"
+
+globals@^9.0.0:
+  version "9.17.0"
+  resolved "https://registry.yarnpkg.com/globals/-/globals-9.17.0.tgz#0c0ca696d9b9bb694d2e5470bd37777caad50286"
+
+graceful-fs@^4.1.2, graceful-fs@^4.1.6:
+  version "4.1.11"
+  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
+
+growly@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
+
+handlebars@^4.0.3:
+  version "4.0.6"
+  resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7"
+  dependencies:
+    async "^1.4.0"
+    optimist "^0.6.1"
+    source-map "^0.4.4"
+  optionalDependencies:
+    uglify-js "^2.6"
+
+har-schema@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e"
+
+har-validator@~4.2.1:
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a"
+  dependencies:
+    ajv "^4.9.1"
+    har-schema "^1.0.5"
+
+has-ansi@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
+  dependencies:
+    ansi-regex "^2.0.0"
+
+has-flag@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
+
+has-unicode@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
+
+hash-base@^2.0.0:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1"
+  dependencies:
+    inherits "^2.0.1"
+
+hash.js@^1.0.0, hash.js@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.0.3.tgz#1332ff00156c0a0ffdd8236013d07b77a0451573"
+  dependencies:
+    inherits "^2.0.1"
+
+hawk@~3.1.3:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4"
+  dependencies:
+    boom "2.x.x"
+    cryptiles "2.x.x"
+    hoek "2.x.x"
+    sntp "1.x.x"
+
+hmac-drbg@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
+  dependencies:
+    hash.js "^1.0.3"
+    minimalistic-assert "^1.0.0"
+    minimalistic-crypto-utils "^1.0.1"
+
+hoek@2.x.x:
+  version "2.16.3"
+  resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed"
+
+home-or-tmp@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8"
+  dependencies:
+    os-homedir "^1.0.0"
+    os-tmpdir "^1.0.1"
+
+hosted-git-info@^2.1.4:
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.4.1.tgz#4b0445e41c004a8bd1337773a4ff790ca40318c8"
+
+html-encoding-sniffer@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.1.tgz#79bf7a785ea495fe66165e734153f363ff5437da"
+  dependencies:
+    whatwg-encoding "^1.0.1"
+
+http-signature@~1.1.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf"
+  dependencies:
+    assert-plus "^0.2.0"
+    jsprim "^1.2.2"
+    sshpk "^1.7.0"
+
+https-browserify@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82"
+
+iconv-lite@0.4.13:
+  version "0.4.13"
+  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2"
+
+iconv-lite@~0.4.13:
+  version "0.4.15"
+  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb"
+
+ieee754@^1.1.4:
+  version "1.1.8"
+  resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4"
+
+indexof@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d"
+
+inflight@^1.0.4:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+  dependencies:
+    once "^1.3.0"
+    wrappy "1"
+
+inherits@2, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
+
+inherits@2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
+
+ini@~1.3.0:
+  version "1.3.4"
+  resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e"
+
+interpret@^1.0.0:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.3.tgz#cbc35c62eeee73f19ab7b10a801511401afc0f90"
+
+invariant@^2.2.0:
+  version "2.2.2"
+  resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360"
+  dependencies:
+    loose-envify "^1.0.0"
+
+invert-kv@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
+
+is-arrayish@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
+
+is-binary-path@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
+  dependencies:
+    binary-extensions "^1.0.0"
+
+is-buffer@^1.0.2:
+  version "1.1.5"
+  resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc"
+
+is-builtin-module@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe"
+  dependencies:
+    builtin-modules "^1.0.0"
+
+is-ci@^1.0.9:
+  version "1.0.10"
+  resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.0.10.tgz#f739336b2632365061a9d48270cd56ae3369318e"
+  dependencies:
+    ci-info "^1.0.0"
+
+is-dotfile@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d"
+
+is-equal-shallow@^0.1.3:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534"
+  dependencies:
+    is-primitive "^2.0.0"
+
+is-extendable@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
+
+is-extglob@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
+
+is-finite@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa"
+  dependencies:
+    number-is-nan "^1.0.0"
+
+is-fullwidth-code-point@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
+  dependencies:
+    number-is-nan "^1.0.0"
+
+is-glob@^2.0.0, is-glob@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
+  dependencies:
+    is-extglob "^1.0.0"
+
+is-number@^2.0.2, is-number@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
+  dependencies:
+    kind-of "^3.0.2"
+
+is-posix-bracket@^0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
+
+is-primitive@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
+
+is-stream@^1.0.1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
+
+is-typedarray@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
+
+is-utf8@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
+
+isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
+
+isexe@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+
+isobject@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
+  dependencies:
+    isarray "1.0.0"
+
+isomorphic-fetch@^2.1.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
+  dependencies:
+    node-fetch "^1.0.1"
+    whatwg-fetch ">=0.10.0"
+
+isstream@~0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
+
+istanbul-api@^1.1.0-alpha.1:
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-1.1.7.tgz#f6f37f09f8002b130f891c646b70ee4a8e7345ae"
+  dependencies:
+    async "^2.1.4"
+    fileset "^2.0.2"
+    istanbul-lib-coverage "^1.0.2"
+    istanbul-lib-hook "^1.0.5"
+    istanbul-lib-instrument "^1.7.0"
+    istanbul-lib-report "^1.0.0"
+    istanbul-lib-source-maps "^1.1.1"
+    istanbul-reports "^1.0.2"
+    js-yaml "^3.7.0"
+    mkdirp "^0.5.1"
+    once "^1.4.0"
+
+istanbul-lib-coverage@^1.0.0, istanbul-lib-coverage@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.0.2.tgz#87a0c015b6910651cb3b184814dfb339337e25e1"
+
+istanbul-lib-hook@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.0.5.tgz#6ca3d16d60c5f4082da39f7c5cd38ea8a772b88e"
+  dependencies:
+    append-transform "^0.4.0"
+
+istanbul-lib-instrument@^1.1.1, istanbul-lib-instrument@^1.6.2, istanbul-lib-instrument@^1.7.0:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.7.0.tgz#b8e0dc25709bb44e17336ab47b7bb5c97c23f659"
+  dependencies:
+    babel-generator "^6.18.0"
+    babel-template "^6.16.0"
+    babel-traverse "^6.18.0"
+    babel-types "^6.18.0"
+    babylon "^6.13.0"
+    istanbul-lib-coverage "^1.0.2"
+    semver "^5.3.0"
+
+istanbul-lib-report@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.0.0.tgz#d83dac7f26566b521585569367fe84ccfc7aaecb"
+  dependencies:
+    istanbul-lib-coverage "^1.0.2"
+    mkdirp "^0.5.1"
+    path-parse "^1.0.5"
+    supports-color "^3.1.2"
+
+istanbul-lib-source-maps@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.1.1.tgz#f8c8c2e8f2160d1d91526d97e5bd63b2079af71c"
+  dependencies:
+    istanbul-lib-coverage "^1.0.2"
+    mkdirp "^0.5.1"
+    rimraf "^2.4.4"
+    source-map "^0.5.3"
+
+istanbul-reports@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.0.2.tgz#4e8366abe6fa746cc1cd6633f108de12cc6ac6fa"
+  dependencies:
+    handlebars "^4.0.3"
+
+jest-changed-files@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-19.0.2.tgz#16c54c84c3270be408e06d2e8af3f3e37a885824"
+
+jest-cli@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-19.0.2.tgz#cc3620b62acac5f2d93a548cb6ef697d4ec85443"
+  dependencies:
+    ansi-escapes "^1.4.0"
+    callsites "^2.0.0"
+    chalk "^1.1.1"
+    graceful-fs "^4.1.6"
+    is-ci "^1.0.9"
+    istanbul-api "^1.1.0-alpha.1"
+    istanbul-lib-coverage "^1.0.0"
+    istanbul-lib-instrument "^1.1.1"
+    jest-changed-files "^19.0.2"
+    jest-config "^19.0.2"
+    jest-environment-jsdom "^19.0.2"
+    jest-haste-map "^19.0.0"
+    jest-jasmine2 "^19.0.2"
+    jest-message-util "^19.0.0"
+    jest-regex-util "^19.0.0"
+    jest-resolve-dependencies "^19.0.0"
+    jest-runtime "^19.0.2"
+    jest-snapshot "^19.0.2"
+    jest-util "^19.0.2"
+    micromatch "^2.3.11"
+    node-notifier "^5.0.1"
+    slash "^1.0.0"
+    string-length "^1.0.1"
+    throat "^3.0.0"
+    which "^1.1.1"
+    worker-farm "^1.3.1"
+    yargs "^6.3.0"
+
+jest-config@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-19.0.2.tgz#1b9bd2db0ddd16df61c2b10a54009e1768da6411"
+  dependencies:
+    chalk "^1.1.1"
+    jest-environment-jsdom "^19.0.2"
+    jest-environment-node "^19.0.2"
+    jest-jasmine2 "^19.0.2"
+    jest-regex-util "^19.0.0"
+    jest-resolve "^19.0.2"
+    jest-validate "^19.0.2"
+    pretty-format "^19.0.0"
+
+jest-diff@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-19.0.0.tgz#d1563cfc56c8b60232988fbc05d4d16ed90f063c"
+  dependencies:
+    chalk "^1.1.3"
+    diff "^3.0.0"
+    jest-matcher-utils "^19.0.0"
+    pretty-format "^19.0.0"
+
+jest-environment-jsdom@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-19.0.2.tgz#ceda859c4a4b94ab35e4de7dab54b926f293e4a3"
+  dependencies:
+    jest-mock "^19.0.0"
+    jest-util "^19.0.2"
+    jsdom "^9.11.0"
+
+jest-environment-node@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-19.0.2.tgz#6e84079db87ed21d0c05e1f9669f207b116fe99b"
+  dependencies:
+    jest-mock "^19.0.0"
+    jest-util "^19.0.2"
+
+jest-file-exists@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-file-exists/-/jest-file-exists-19.0.0.tgz#cca2e587a11ec92e24cfeab3f8a94d657f3fceb8"
+
+jest-haste-map@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-19.0.0.tgz#adde00b62b1fe04432a104b3254fc5004514b55e"
+  dependencies:
+    fb-watchman "^2.0.0"
+    graceful-fs "^4.1.6"
+    micromatch "^2.3.11"
+    sane "~1.5.0"
+    worker-farm "^1.3.1"
+
+jest-jasmine2@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-19.0.2.tgz#167991ac825981fb1a800af126e83afcca832c73"
+  dependencies:
+    graceful-fs "^4.1.6"
+    jest-matcher-utils "^19.0.0"
+    jest-matchers "^19.0.0"
+    jest-message-util "^19.0.0"
+    jest-snapshot "^19.0.2"
+
+jest-matcher-utils@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-19.0.0.tgz#5ecd9b63565d2b001f61fbf7ec4c7f537964564d"
+  dependencies:
+    chalk "^1.1.3"
+    pretty-format "^19.0.0"
+
+jest-matchers@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-matchers/-/jest-matchers-19.0.0.tgz#c74ecc6ebfec06f384767ba4d6fa4a42d6755754"
+  dependencies:
+    jest-diff "^19.0.0"
+    jest-matcher-utils "^19.0.0"
+    jest-message-util "^19.0.0"
+    jest-regex-util "^19.0.0"
+
+jest-message-util@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-19.0.0.tgz#721796b89c0e4d761606f9ba8cb828a3b6246416"
+  dependencies:
+    chalk "^1.1.1"
+    micromatch "^2.3.11"
+
+jest-mock@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-19.0.0.tgz#67038641e9607ab2ce08ec4a8cb83aabbc899d01"
+
+jest-regex-util@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-19.0.0.tgz#b7754587112aede1456510bb1f6afe74ef598691"
+
+jest-resolve-dependencies@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-19.0.0.tgz#a741ad1fa094140e64ecf2642a504f834ece22ee"
+  dependencies:
+    jest-file-exists "^19.0.0"
+
+jest-resolve@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-19.0.2.tgz#5793575de4f07aec32f7d7ff0c6c181963eefb3c"
+  dependencies:
+    browser-resolve "^1.11.2"
+    jest-haste-map "^19.0.0"
+    resolve "^1.2.0"
+
+jest-runtime@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-19.0.2.tgz#d9a43e72de416d27d196fd9c7940d98fe6685407"
+  dependencies:
+    babel-core "^6.0.0"
+    babel-jest "^19.0.0"
+    babel-plugin-istanbul "^4.0.0"
+    chalk "^1.1.3"
+    graceful-fs "^4.1.6"
+    jest-config "^19.0.2"
+    jest-file-exists "^19.0.0"
+    jest-haste-map "^19.0.0"
+    jest-regex-util "^19.0.0"
+    jest-resolve "^19.0.2"
+    jest-util "^19.0.2"
+    json-stable-stringify "^1.0.1"
+    micromatch "^2.3.11"
+    strip-bom "3.0.0"
+    yargs "^6.3.0"
+
+jest-snapshot@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-19.0.2.tgz#9c1b216214f7187c38bfd5c70b1efab16b0ff50b"
+  dependencies:
+    chalk "^1.1.3"
+    jest-diff "^19.0.0"
+    jest-file-exists "^19.0.0"
+    jest-matcher-utils "^19.0.0"
+    jest-util "^19.0.2"
+    natural-compare "^1.4.0"
+    pretty-format "^19.0.0"
+
+jest-util@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-19.0.2.tgz#e0a0232a2ab9e6b2b53668bdb3534c2b5977ed41"
+  dependencies:
+    chalk "^1.1.1"
+    graceful-fs "^4.1.6"
+    jest-file-exists "^19.0.0"
+    jest-message-util "^19.0.0"
+    jest-mock "^19.0.0"
+    jest-validate "^19.0.2"
+    leven "^2.0.0"
+    mkdirp "^0.5.1"
+
+jest-validate@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-19.0.2.tgz#dc534df5f1278d5b63df32b14241d4dbf7244c0c"
+  dependencies:
+    chalk "^1.1.1"
+    jest-matcher-utils "^19.0.0"
+    leven "^2.0.0"
+    pretty-format "^19.0.0"
+
+jest@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest/-/jest-19.0.2.tgz#b794faaf8ff461e7388f28beef559a54f20b2c10"
+  dependencies:
+    jest-cli "^19.0.2"
+
+jodid25519@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967"
+  dependencies:
+    jsbn "~0.1.0"
+
+js-tokens@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7"
+
+js-yaml@^3.7.0:
+  version "3.8.3"
+  resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.3.tgz#33a05ec481c850c8875929166fe1beb61c728766"
+  dependencies:
+    argparse "^1.0.7"
+    esprima "^3.1.1"
+
+jsbn@~0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
+
+jsdom@^9.11.0:
+  version "9.12.0"
+  resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-9.12.0.tgz#e8c546fffcb06c00d4833ca84410fed7f8a097d4"
+  dependencies:
+    abab "^1.0.3"
+    acorn "^4.0.4"
+    acorn-globals "^3.1.0"
+    array-equal "^1.0.0"
+    content-type-parser "^1.0.1"
+    cssom ">= 0.3.2 < 0.4.0"
+    cssstyle ">= 0.2.37 < 0.3.0"
+    escodegen "^1.6.1"
+    html-encoding-sniffer "^1.0.1"
+    nwmatcher ">= 1.3.9 < 2.0.0"
+    parse5 "^1.5.1"
+    request "^2.79.0"
+    sax "^1.2.1"
+    symbol-tree "^3.2.1"
+    tough-cookie "^2.3.2"
+    webidl-conversions "^4.0.0"
+    whatwg-encoding "^1.0.1"
+    whatwg-url "^4.3.0"
+    xml-name-validator "^2.0.1"
+
+jsesc@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b"
+
+json-loader@^0.5.4:
+  version "0.5.4"
+  resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.4.tgz#8baa1365a632f58a3c46d20175fc6002c96e37de"
+
+json-schema@0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
+
+json-stable-stringify@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af"
+  dependencies:
+    jsonify "~0.0.0"
+
+json-stringify-safe@~5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
+
+json5@^0.5.0, json5@^0.5.1:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
+
+jsonify@~0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
+
+jsprim@^1.2.2:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.0.tgz#a3b87e40298d8c380552d8cc7628a0bb95a22918"
+  dependencies:
+    assert-plus "1.0.0"
+    extsprintf "1.0.2"
+    json-schema "0.2.3"
+    verror "1.3.6"
+
+kind-of@^3.0.2:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47"
+  dependencies:
+    is-buffer "^1.0.2"
+
+lazy-cache@^1.0.3:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
+
+lcid@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
+  dependencies:
+    invert-kv "^1.0.0"
+
+leven@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580"
+
+levn@~0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
+  dependencies:
+    prelude-ls "~1.1.2"
+    type-check "~0.3.2"
+
+load-json-file@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
+  dependencies:
+    graceful-fs "^4.1.2"
+    parse-json "^2.2.0"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+    strip-bom "^2.0.0"
+
+loader-runner@^2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2"
+
+loader-utils@^0.2.16:
+  version "0.2.17"
+  resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348"
+  dependencies:
+    big.js "^3.1.3"
+    emojis-list "^2.0.0"
+    json5 "^0.5.0"
+    object-assign "^4.0.1"
+
+locate-path@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
+  dependencies:
+    p-locate "^2.0.0"
+    path-exists "^3.0.0"
+
+lodash@^4.14.0, lodash@^4.2.0:
+  version "4.17.4"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
+
+longest@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
+
+loose-envify@^1.0.0, loose-envify@^1.1.0:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
+  dependencies:
+    js-tokens "^3.0.0"
+
+makeerror@1.0.x:
+  version "1.0.11"
+  resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c"
+  dependencies:
+    tmpl "1.0.x"
+
+memory-fs@^0.4.0, memory-fs@~0.4.1:
+  version "0.4.1"
+  resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"
+  dependencies:
+    errno "^0.1.3"
+    readable-stream "^2.0.1"
+
+merge@^1.1.3:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da"
+
+micromatch@^2.1.5, micromatch@^2.3.11:
+  version "2.3.11"
+  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
+  dependencies:
+    arr-diff "^2.0.0"
+    array-unique "^0.2.1"
+    braces "^1.8.2"
+    expand-brackets "^0.1.4"
+    extglob "^0.3.1"
+    filename-regex "^2.0.0"
+    is-extglob "^1.0.0"
+    is-glob "^2.0.1"
+    kind-of "^3.0.2"
+    normalize-path "^2.0.1"
+    object.omit "^2.0.0"
+    parse-glob "^3.0.4"
+    regex-cache "^0.4.2"
+
+miller-rabin@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.0.tgz#4a62fb1d42933c05583982f4c716f6fb9e6c6d3d"
+  dependencies:
+    bn.js "^4.0.0"
+    brorand "^1.0.1"
+
+mime-db@~1.27.0:
+  version "1.27.0"
+  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1"
+
+mime-types@^2.1.12, mime-types@~2.1.7:
+  version "2.1.15"
+  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed"
+  dependencies:
+    mime-db "~1.27.0"
+
+minimalistic-assert@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3"
+
+minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
+
+minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774"
+  dependencies:
+    brace-expansion "^1.0.0"
+
+minimist@0.0.8, minimist@~0.0.1:
+  version "0.0.8"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
+
+minimist@^1.1.1, minimist@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
+
+"mkdirp@>=0.5 0", mkdirp@^0.5.1, mkdirp@~0.5.0:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
+  dependencies:
+    minimist "0.0.8"
+
+ms@0.7.2:
+  version "0.7.2"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765"
+
+nan@^2.3.0:
+  version "2.6.2"
+  resolved "https://registry.yarnpkg.com/nan/-/nan-2.6.2.tgz#e4ff34e6c95fdfb5aecc08de6596f43605a7db45"
+
+natural-compare@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
+
+node-fetch@^1.0.1:
+  version "1.6.3"
+  resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04"
+  dependencies:
+    encoding "^0.1.11"
+    is-stream "^1.0.1"
+
+node-int64@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
+
+node-libs-browser@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.0.0.tgz#a3a59ec97024985b46e958379646f96c4b616646"
+  dependencies:
+    assert "^1.1.1"
+    browserify-zlib "^0.1.4"
+    buffer "^4.3.0"
+    console-browserify "^1.1.0"
+    constants-browserify "^1.0.0"
+    crypto-browserify "^3.11.0"
+    domain-browser "^1.1.1"
+    events "^1.0.0"
+    https-browserify "0.0.1"
+    os-browserify "^0.2.0"
+    path-browserify "0.0.0"
+    process "^0.11.0"
+    punycode "^1.2.4"
+    querystring-es3 "^0.2.0"
+    readable-stream "^2.0.5"
+    stream-browserify "^2.0.1"
+    stream-http "^2.3.1"
+    string_decoder "^0.10.25"
+    timers-browserify "^2.0.2"
+    tty-browserify "0.0.0"
+    url "^0.11.0"
+    util "^0.10.3"
+    vm-browserify "0.0.4"
+
+node-notifier@^5.0.1:
+  version "5.1.2"
+  resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.1.2.tgz#2fa9e12605fa10009d44549d6fcd8a63dde0e4ff"
+  dependencies:
+    growly "^1.3.0"
+    semver "^5.3.0"
+    shellwords "^0.1.0"
+    which "^1.2.12"
+
+node-pre-gyp@^0.6.36:
+  version "0.6.36"
+  resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.36.tgz#db604112cb74e0d477554e9b505b17abddfab786"
+  dependencies:
+    mkdirp "^0.5.1"
+    nopt "^4.0.1"
+    npmlog "^4.0.2"
+    rc "^1.1.7"
+    request "^2.81.0"
+    rimraf "^2.6.1"
+    semver "^5.3.0"
+    tar "^2.2.1"
+    tar-pack "^3.4.0"
+
+nopt@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
+  dependencies:
+    abbrev "1"
+    osenv "^0.1.4"
+
+normalize-package-data@^2.3.2:
+  version "2.3.6"
+  resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.6.tgz#498fa420c96401f787402ba21e600def9f981fff"
+  dependencies:
+    hosted-git-info "^2.1.4"
+    is-builtin-module "^1.0.0"
+    semver "2 || 3 || 4 || 5"
+    validate-npm-package-license "^3.0.1"
+
+normalize-path@^2.0.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
+  dependencies:
+    remove-trailing-separator "^1.0.1"
+
+npmlog@^4.0.2:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.0.tgz#dc59bee85f64f00ed424efb2af0783df25d1c0b5"
+  dependencies:
+    are-we-there-yet "~1.1.2"
+    console-control-strings "~1.1.0"
+    gauge "~2.7.3"
+    set-blocking "~2.0.0"
+
+number-is-nan@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
+
+"nwmatcher@>= 1.3.9 < 2.0.0":
+  version "1.3.9"
+  resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.3.9.tgz#8bab486ff7fa3dfd086656bbe8b17116d3692d2a"
+
+oauth-sign@~0.8.1:
+  version "0.8.2"
+  resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
+
+object-assign@^4.0.1, object-assign@^4.1.0:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+
+object.omit@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
+  dependencies:
+    for-own "^0.1.4"
+    is-extendable "^0.1.1"
+
+once@^1.3.0, once@^1.3.3, once@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+  dependencies:
+    wrappy "1"
+
+optimist@^0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
+  dependencies:
+    minimist "~0.0.1"
+    wordwrap "~0.0.2"
+
+optionator@^0.8.1:
+  version "0.8.2"
+  resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64"
+  dependencies:
+    deep-is "~0.1.3"
+    fast-levenshtein "~2.0.4"
+    levn "~0.3.0"
+    prelude-ls "~1.1.2"
+    type-check "~0.3.2"
+    wordwrap "~1.0.0"
+
+os-browserify@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.2.1.tgz#63fc4ccee5d2d7763d26bbf8601078e6c2e0044f"
+
+os-homedir@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
+
+os-locale@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9"
+  dependencies:
+    lcid "^1.0.0"
+
+os-tmpdir@^1.0.0, os-tmpdir@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
+
+osenv@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644"
+  dependencies:
+    os-homedir "^1.0.0"
+    os-tmpdir "^1.0.0"
+
+p-limit@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.1.0.tgz#b07ff2d9a5d88bec806035895a2bab66a27988bc"
+
+p-locate@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
+  dependencies:
+    p-limit "^1.1.0"
+
+pako@~0.2.0:
+  version "0.2.9"
+  resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
+
+parse-asn1@^5.0.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712"
+  dependencies:
+    asn1.js "^4.0.0"
+    browserify-aes "^1.0.0"
+    create-hash "^1.1.0"
+    evp_bytestokey "^1.0.0"
+    pbkdf2 "^3.0.3"
+
+parse-glob@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
+  dependencies:
+    glob-base "^0.3.0"
+    is-dotfile "^1.0.0"
+    is-extglob "^1.0.0"
+    is-glob "^2.0.0"
+
+parse-json@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
+  dependencies:
+    error-ex "^1.2.0"
+
+parse5@^1.5.1:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94"
+
+path-browserify@0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a"
+
+path-exists@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
+  dependencies:
+    pinkie-promise "^2.0.0"
+
+path-exists@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
+
+path-is-absolute@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+
+path-parse@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1"
+
+path-type@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
+  dependencies:
+    graceful-fs "^4.1.2"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+pbkdf2@^3.0.3:
+  version "3.0.12"
+  resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.12.tgz#be36785c5067ea48d806ff923288c5f750b6b8a2"
+  dependencies:
+    create-hash "^1.1.2"
+    create-hmac "^1.1.4"
+    ripemd160 "^2.0.1"
+    safe-buffer "^5.0.1"
+    sha.js "^2.4.8"
+
+performance-now@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5"
+
+pify@^2.0.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
+
+pinkie-promise@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
+  dependencies:
+    pinkie "^2.0.0"
+
+pinkie@^2.0.0:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
+
+prelude-ls@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
+
+preserve@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
+
+pretty-format@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-19.0.0.tgz#56530d32acb98a3fa4851c4e2b9d37b420684c84"
+  dependencies:
+    ansi-styles "^3.0.0"
+
+private@^0.1.6:
+  version "0.1.7"
+  resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1"
+
+process-nextick-args@~1.0.6:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
+
+process@^0.11.0:
+  version "0.11.10"
+  resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
+
+promise@^7.1.1:
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/promise/-/promise-7.1.1.tgz#489654c692616b8aa55b0724fa809bb7db49c5bf"
+  dependencies:
+    asap "~2.0.3"
+
+prr@~0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a"
+
+public-encrypt@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.0.tgz#39f699f3a46560dd5ebacbca693caf7c65c18cc6"
+  dependencies:
+    bn.js "^4.1.0"
+    browserify-rsa "^4.0.0"
+    create-hash "^1.1.0"
+    parse-asn1 "^5.0.0"
+    randombytes "^2.0.1"
+
+punycode@1.3.2:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
+
+punycode@^1.2.4, punycode@^1.4.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
+
+qs@~6.4.0:
+  version "6.4.0"
+  resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
+
+querystring-es3@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
+
+querystring@0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
+
+randomatic@^1.1.3:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb"
+  dependencies:
+    is-number "^2.0.2"
+    kind-of "^3.0.2"
+
+randombytes@^2.0.0, randombytes@^2.0.1:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.5.tgz#dc009a246b8d09a177b4b7a0ae77bc570f4b1b79"
+  dependencies:
+    safe-buffer "^5.1.0"
+
+rc@^1.1.7:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.1.tgz#2e03e8e42ee450b8cb3dce65be1bf8974e1dfd95"
+  dependencies:
+    deep-extend "~0.4.0"
+    ini "~1.3.0"
+    minimist "^1.2.0"
+    strip-json-comments "~2.0.1"
+
+react-dom@^15.4.2:
+  version "15.4.2"
+  resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.4.2.tgz#015363f05b0a1fd52ae9efdd3a0060d90695208f"
+  dependencies:
+    fbjs "^0.8.1"
+    loose-envify "^1.1.0"
+    object-assign "^4.1.0"
+
+react@^15.4.2:
+  version "15.4.2"
+  resolved "https://registry.yarnpkg.com/react/-/react-15.4.2.tgz#41f7991b26185392ba9bae96c8889e7e018397ef"
+  dependencies:
+    fbjs "^0.8.4"
+    loose-envify "^1.1.0"
+    object-assign "^4.1.0"
+
+read-pkg-up@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
+  dependencies:
+    find-up "^1.0.0"
+    read-pkg "^1.0.0"
+
+read-pkg@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
+  dependencies:
+    load-json-file "^1.0.0"
+    normalize-package-data "^2.3.2"
+    path-type "^1.0.0"
+
+readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.2.6:
+  version "2.2.11"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.11.tgz#0796b31f8d7688007ff0b93a8088d34aa17c0f72"
+  dependencies:
+    core-util-is "~1.0.0"
+    inherits "~2.0.1"
+    isarray "~1.0.0"
+    process-nextick-args "~1.0.6"
+    safe-buffer "~5.0.1"
+    string_decoder "~1.0.0"
+    util-deprecate "~1.0.1"
+
+readdirp@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78"
+  dependencies:
+    graceful-fs "^4.1.2"
+    minimatch "^3.0.2"
+    readable-stream "^2.0.2"
+    set-immediate-shim "^1.0.1"
+
+regenerator-runtime@^0.10.0:
+  version "0.10.3"
+  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.3.tgz#8c4367a904b51ea62a908ac310bf99ff90a82a3e"
+
+regex-cache@^0.4.2:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145"
+  dependencies:
+    is-equal-shallow "^0.1.3"
+    is-primitive "^2.0.0"
+
+remove-trailing-separator@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.0.1.tgz#615ebb96af559552d4bf4057c8436d486ab63cc4"
+
+repeat-element@^1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a"
+
+repeat-string@^1.5.2:
+  version "1.6.1"
+  resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
+
+repeating@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda"
+  dependencies:
+    is-finite "^1.0.0"
+
+request@^2.79.0, request@^2.81.0:
+  version "2.81.0"
+  resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0"
+  dependencies:
+    aws-sign2 "~0.6.0"
+    aws4 "^1.2.1"
+    caseless "~0.12.0"
+    combined-stream "~1.0.5"
+    extend "~3.0.0"
+    forever-agent "~0.6.1"
+    form-data "~2.1.1"
+    har-validator "~4.2.1"
+    hawk "~3.1.3"
+    http-signature "~1.1.0"
+    is-typedarray "~1.0.0"
+    isstream "~0.1.2"
+    json-stringify-safe "~5.0.1"
+    mime-types "~2.1.7"
+    oauth-sign "~0.8.1"
+    performance-now "^0.2.0"
+    qs "~6.4.0"
+    safe-buffer "^5.0.1"
+    stringstream "~0.0.4"
+    tough-cookie "~2.3.0"
+    tunnel-agent "^0.6.0"
+    uuid "^3.0.0"
+
+require-directory@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
+
+require-main-filename@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
+
+resolve@1.1.7:
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
+
+resolve@^1.2.0:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.3.2.tgz#1f0442c9e0cbb8136e87b9305f932f46c7f28235"
+  dependencies:
+    path-parse "^1.0.5"
+
+right-align@^0.1.1:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef"
+  dependencies:
+    align-text "^0.1.1"
+
+rimraf@2, rimraf@^2.4.4, rimraf@^2.5.1, rimraf@^2.6.1:
+  version "2.6.1"
+  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d"
+  dependencies:
+    glob "^7.0.5"
+
+ripemd160@^2.0.0, ripemd160@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7"
+  dependencies:
+    hash-base "^2.0.0"
+    inherits "^2.0.1"
+
+safe-buffer@^5.0.1, safe-buffer@~5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7"
+
+safe-buffer@^5.1.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.0.tgz#fe4c8460397f9eaaaa58e73be46273408a45e223"
+
+sane@~1.5.0:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/sane/-/sane-1.5.0.tgz#a4adeae764d048621ecb27d5f9ecf513101939f3"
+  dependencies:
+    anymatch "^1.3.0"
+    exec-sh "^0.2.0"
+    fb-watchman "^1.8.0"
+    minimatch "^3.0.2"
+    minimist "^1.1.1"
+    walker "~1.0.5"
+    watch "~0.10.0"
+
+sax@^1.2.1:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.2.tgz#fd8631a23bc7826bef5d871bdb87378c95647828"
+
+"semver@2 || 3 || 4 || 5", semver@^5.3.0:
+  version "5.3.0"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
+
+set-blocking@^2.0.0, set-blocking@~2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
+
+set-immediate-shim@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61"
+
+setimmediate@^1.0.4, setimmediate@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
+
+sha.js@^2.4.0, sha.js@^2.4.8:
+  version "2.4.8"
+  resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.8.tgz#37068c2c476b6baf402d14a49c67f597921f634f"
+  dependencies:
+    inherits "^2.0.1"
+
+shellwords@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.0.tgz#66afd47b6a12932d9071cbfd98a52e785cd0ba14"
+
+signal-exit@^3.0.0:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
+
+slash@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
+
+sntp@1.x.x:
+  version "1.0.9"
+  resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198"
+  dependencies:
+    hoek "2.x.x"
+
+source-list-map@^1.1.1:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-1.1.2.tgz#9889019d1024cce55cdc069498337ef6186a11a1"
+
+source-map-support@^0.4.2:
+  version "0.4.14"
+  resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.14.tgz#9d4463772598b86271b4f523f6c1f4e02a7d6aef"
+  dependencies:
+    source-map "^0.5.6"
+
+source-map@^0.4.4:
+  version "0.4.4"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b"
+  dependencies:
+    amdefine ">=0.0.4"
+
+source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.3:
+  version "0.5.6"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
+
+source-map@~0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d"
+  dependencies:
+    amdefine ">=0.0.4"
+
+spdx-correct@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40"
+  dependencies:
+    spdx-license-ids "^1.0.2"
+
+spdx-expression-parse@~1.0.0:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c"
+
+spdx-license-ids@^1.0.2:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57"
+
+sprintf-js@~1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
+
+sshpk@^1.7.0:
+  version "1.11.0"
+  resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.11.0.tgz#2d8d5ebb4a6fab28ffba37fa62a90f4a3ea59d77"
+  dependencies:
+    asn1 "~0.2.3"
+    assert-plus "^1.0.0"
+    dashdash "^1.12.0"
+    getpass "^0.1.1"
+  optionalDependencies:
+    bcrypt-pbkdf "^1.0.0"
+    ecc-jsbn "~0.1.1"
+    jodid25519 "^1.0.0"
+    jsbn "~0.1.0"
+    tweetnacl "~0.14.0"
+
+stream-browserify@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db"
+  dependencies:
+    inherits "~2.0.1"
+    readable-stream "^2.0.2"
+
+stream-http@^2.3.1:
+  version "2.7.2"
+  resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.7.2.tgz#40a050ec8dc3b53b33d9909415c02c0bf1abfbad"
+  dependencies:
+    builtin-status-codes "^3.0.0"
+    inherits "^2.0.1"
+    readable-stream "^2.2.6"
+    to-arraybuffer "^1.0.0"
+    xtend "^4.0.0"
+
+string-length@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/string-length/-/string-length-1.0.1.tgz#56970fb1c38558e9e70b728bf3de269ac45adfac"
+  dependencies:
+    strip-ansi "^3.0.0"
+
+string-width@^1.0.1, string-width@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
+  dependencies:
+    code-point-at "^1.0.0"
+    is-fullwidth-code-point "^1.0.0"
+    strip-ansi "^3.0.0"
+
+string_decoder@^0.10.25:
+  version "0.10.31"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
+
+string_decoder@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.2.tgz#b29e1f4e1125fa97a10382b8a533737b7491e179"
+  dependencies:
+    safe-buffer "~5.0.1"
+
+stringstream@~0.0.4:
+  version "0.0.5"
+  resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878"
+
+strip-ansi@^3.0.0, strip-ansi@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
+  dependencies:
+    ansi-regex "^2.0.0"
+
+strip-bom@3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
+
+strip-bom@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
+  dependencies:
+    is-utf8 "^0.2.0"
+
+strip-json-comments@~2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
+
+supports-color@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
+
+supports-color@^3.1.0, supports-color@^3.1.2:
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
+  dependencies:
+    has-flag "^1.0.0"
+
+symbol-tree@^3.2.1:
+  version "3.2.2"
+  resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6"
+
+tapable@^0.2.5, tapable@~0.2.5:
+  version "0.2.6"
+  resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.6.tgz#206be8e188860b514425375e6f1ae89bfb01fd8d"
+
+tar-pack@^3.4.0:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.0.tgz#23be2d7f671a8339376cbdb0b8fe3fdebf317984"
+  dependencies:
+    debug "^2.2.0"
+    fstream "^1.0.10"
+    fstream-ignore "^1.0.5"
+    once "^1.3.3"
+    readable-stream "^2.1.4"
+    rimraf "^2.5.1"
+    tar "^2.2.1"
+    uid-number "^0.0.6"
+
+tar@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1"
+  dependencies:
+    block-stream "*"
+    fstream "^1.0.2"
+    inherits "2"
+
+test-exclude@^4.0.3:
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-4.0.3.tgz#86a13ce3effcc60e6c90403cf31a27a60ac6c4e7"
+  dependencies:
+    arrify "^1.0.1"
+    micromatch "^2.3.11"
+    object-assign "^4.1.0"
+    read-pkg-up "^1.0.1"
+    require-main-filename "^1.0.1"
+
+throat@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/throat/-/throat-3.0.0.tgz#e7c64c867cbb3845f10877642f7b60055b8ec0d6"
+
+timers-browserify@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.2.tgz#ab4883cf597dcd50af211349a00fbca56ac86b86"
+  dependencies:
+    setimmediate "^1.0.4"
+
+tmpl@1.0.x:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1"
+
+to-arraybuffer@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
+
+to-fast-properties@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320"
+
+tough-cookie@^2.3.2, tough-cookie@~2.3.0:
+  version "2.3.2"
+  resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a"
+  dependencies:
+    punycode "^1.4.1"
+
+tr46@~0.0.3:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
+
+trim-right@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
+
+tty-browserify@0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
+
+tunnel-agent@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
+  dependencies:
+    safe-buffer "^5.0.1"
+
+tweetnacl@^0.14.3, tweetnacl@~0.14.0:
+  version "0.14.5"
+  resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
+
+type-check@~0.3.2:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
+  dependencies:
+    prelude-ls "~1.1.2"
+
+ua-parser-js@^0.7.9:
+  version "0.7.12"
+  resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb"
+
+uglify-js@^2.6, uglify-js@^2.8.27:
+  version "2.8.28"
+  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.28.tgz#e335032df9bb20dcb918f164589d5af47f38834a"
+  dependencies:
+    source-map "~0.5.1"
+    yargs "~3.10.0"
+  optionalDependencies:
+    uglify-to-browserify "~1.0.0"
+
+uglify-to-browserify@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7"
+
+uid-number@^0.0.6:
+  version "0.0.6"
+  resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81"
+
+url@^0.11.0:
+  version "0.11.0"
+  resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
+  dependencies:
+    punycode "1.3.2"
+    querystring "0.2.0"
+
+util-deprecate@~1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+
+util@0.10.3, util@^0.10.3:
+  version "0.10.3"
+  resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9"
+  dependencies:
+    inherits "2.0.1"
+
+uuid@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1"
+
+validate-npm-package-license@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc"
+  dependencies:
+    spdx-correct "~1.0.0"
+    spdx-expression-parse "~1.0.0"
+
+verror@1.3.6:
+  version "1.3.6"
+  resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c"
+  dependencies:
+    extsprintf "1.0.2"
+
+vm-browserify@0.0.4:
+  version "0.0.4"
+  resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73"
+  dependencies:
+    indexof "0.0.1"
+
+walker@~1.0.5:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb"
+  dependencies:
+    makeerror "1.0.x"
+
+watch@~0.10.0:
+  version "0.10.0"
+  resolved "https://registry.yarnpkg.com/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc"
+
+watchpack@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.3.1.tgz#7d8693907b28ce6013e7f3610aa2a1acf07dad87"
+  dependencies:
+    async "^2.1.2"
+    chokidar "^1.4.3"
+    graceful-fs "^4.1.2"
+
+webidl-conversions@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
+
+webidl-conversions@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.1.tgz#8015a17ab83e7e1b311638486ace81da6ce206a0"
+
+webpack-sources@^0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-0.2.3.tgz#17c62bfaf13c707f9d02c479e0dcdde8380697fb"
+  dependencies:
+    source-list-map "^1.1.1"
+    source-map "~0.5.3"
+
+webpack@^2.6.1:
+  version "2.6.1"
+  resolved "https://registry.yarnpkg.com/webpack/-/webpack-2.6.1.tgz#2e0457f0abb1ac5df3ab106c69c672f236785f07"
+  dependencies:
+    acorn "^5.0.0"
+    acorn-dynamic-import "^2.0.0"
+    ajv "^4.7.0"
+    ajv-keywords "^1.1.1"
+    async "^2.1.2"
+    enhanced-resolve "^3.0.0"
+    interpret "^1.0.0"
+    json-loader "^0.5.4"
+    json5 "^0.5.1"
+    loader-runner "^2.3.0"
+    loader-utils "^0.2.16"
+    memory-fs "~0.4.1"
+    mkdirp "~0.5.0"
+    node-libs-browser "^2.0.0"
+    source-map "^0.5.3"
+    supports-color "^3.1.0"
+    tapable "~0.2.5"
+    uglify-js "^2.8.27"
+    watchpack "^1.3.1"
+    webpack-sources "^0.2.3"
+    yargs "^6.0.0"
+
+whatwg-encoding@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.1.tgz#3c6c451a198ee7aec55b1ec61d0920c67801a5f4"
+  dependencies:
+    iconv-lite "0.4.13"
+
+whatwg-fetch@>=0.10.0:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84"
+
+whatwg-url@^4.3.0:
+  version "4.7.0"
+  resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-4.7.0.tgz#202035ac1955b087cdd20fa8b58ded3ab1cd2af5"
+  dependencies:
+    tr46 "~0.0.3"
+    webidl-conversions "^3.0.0"
+
+which-module@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
+
+which@^1.1.1, which@^1.2.12:
+  version "1.2.14"
+  resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5"
+  dependencies:
+    isexe "^2.0.0"
+
+wide-align@^1.1.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710"
+  dependencies:
+    string-width "^1.0.2"
+
+window-size@0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
+
+wordwrap@0.0.2, wordwrap@~0.0.2:
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
+
+wordwrap@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
+
+worker-farm@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.3.1.tgz#4333112bb49b17aa050b87895ca6b2cacf40e5ff"
+  dependencies:
+    errno ">=0.1.1 <0.2.0-0"
+    xtend ">=4.0.0 <4.1.0-0"
+
+wrap-ansi@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
+  dependencies:
+    string-width "^1.0.1"
+    strip-ansi "^3.0.1"
+
+wrappy@1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+
+xml-name-validator@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635"
+
+"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
+
+y18n@^3.2.1:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
+
+yargs-parser@^4.2.0:
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c"
+  dependencies:
+    camelcase "^3.0.0"
+
+yargs@^6.0.0, yargs@^6.3.0:
+  version "6.6.0"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208"
+  dependencies:
+    camelcase "^3.0.0"
+    cliui "^3.2.0"
+    decamelize "^1.1.1"
+    get-caller-file "^1.0.1"
+    os-locale "^1.4.0"
+    read-pkg-up "^1.0.1"
+    require-directory "^2.1.1"
+    require-main-filename "^1.0.1"
+    set-blocking "^2.0.0"
+    string-width "^1.0.2"
+    which-module "^1.0.0"
+    y18n "^3.2.1"
+    yargs-parser "^4.2.0"
+
+yargs@~3.10.0:
+  version "3.10.0"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"
+  dependencies:
+    camelcase "^1.0.2"
+    cliui "^2.1.0"
+    decamelize "^1.0.0"
+    window-size "0.1.0"
diff --git a/addons/react-addons-test-utils/LICENSE b/addons/react-addons-test-utils/LICENSE
new file mode 100644
index 000000000000..91b8f6f76ff0
--- /dev/null
+++ b/addons/react-addons-test-utils/LICENSE
@@ -0,0 +1,31 @@
+BSD License
+
+For React software
+
+Copyright (c) 2013-present, Facebook, Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+ * Neither the name Facebook nor the names of its contributors may be used to
+   endorse or promote products derived from this software without specific
+   prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/addons/react-addons-test-utils/PATENTS b/addons/react-addons-test-utils/PATENTS
new file mode 100644
index 000000000000..9c9f8e87a8f4
--- /dev/null
+++ b/addons/react-addons-test-utils/PATENTS
@@ -0,0 +1,33 @@
+Additional Grant of Patent Rights Version 2
+
+"Software" means the React software distributed by Facebook, Inc.
+
+Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software
+("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable
+(subject to the termination provision below) license under any Necessary
+Claims, to make, have made, use, sell, offer to sell, import, and otherwise
+transfer the Software. For avoidance of doubt, no license is granted under
+Facebook's rights in any patent claims that are infringed by (i) modifications
+to the Software made by you or any third party or (ii) the Software in
+combination with any software or other technology.
+
+The license granted hereunder will terminate, automatically and without notice,
+if you (or any of your subsidiaries, corporate affiliates or agents) initiate
+directly or indirectly, or take a direct financial interest in, any Patent
+Assertion: (i) against Facebook or any of its subsidiaries or corporate
+affiliates, (ii) against any party if such Patent Assertion arises in whole or
+in part from any software, technology, product or service of Facebook or any of
+its subsidiaries or corporate affiliates, or (iii) against any party relating
+to the Software. Notwithstanding the foregoing, if Facebook or any of its
+subsidiaries or corporate affiliates files a lawsuit alleging patent
+infringement against you in the first instance, and you respond by filing a
+patent infringement counterclaim in that lawsuit against that party that is
+unrelated to the Software, the license granted hereunder will not terminate
+under section (i) of this paragraph due to such counterclaim.
+
+A "Necessary Claim" is a claim of a patent owned by Facebook that is
+necessarily infringed by the Software standing alone.
+
+A "Patent Assertion" is any lawsuit or other action alleging direct, indirect,
+or contributory infringement or inducement to infringe any patent, including a
+cross-claim or counterclaim.
diff --git a/addons/react-addons-test-utils/README.md b/addons/react-addons-test-utils/README.md
new file mode 100644
index 000000000000..e08f9a101e6a
--- /dev/null
+++ b/addons/react-addons-test-utils/README.md
@@ -0,0 +1,9 @@
+# react-addons-test-utils
+
+This package provides the React TestUtils add-on.
+
+See <https://facebook.github.io/react/docs/test-utils.html> for more information.
+
+This package is deprecated as of version 15.5.0:
+* TestUtils have been moved to `react-dom/test-utils`
+* Shallow renderer has been moved to `react-test-renderer/shallow`
\ No newline at end of file
diff --git a/addons/react-addons-test-utils/index.js b/addons/react-addons-test-utils/index.js
new file mode 100644
index 000000000000..100326558a89
--- /dev/null
+++ b/addons/react-addons-test-utils/index.js
@@ -0,0 +1,75 @@
+/**
+ * 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.
+ */
+
+'use strict';
+
+var lowPriorityWarning = function lowPriorityWarning() {};
+
+if (process.env.NODE_ENV !== 'production') {
+  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));
+    }
+  };
+}
+
+// This package has been deprecated in NPM as of version 15.5.0
+// But NPM deprecation warnings are easy to overlook
+// So a more explicit runtime warning seemed appropriate
+lowPriorityWarning(
+  false,
+  'ReactTestUtils has been moved to react-dom/test-utils. ' +
+    'Update references to remove this warning.'
+);
+
+module.exports = require('react-dom/lib/ReactTestUtils');
diff --git a/addons/react-addons-test-utils/package.json b/addons/react-addons-test-utils/package.json
new file mode 100644
index 000000000000..ee7b6a25c682
--- /dev/null
+++ b/addons/react-addons-test-utils/package.json
@@ -0,0 +1,29 @@
+{
+  "name": "react-addons-test-utils",
+  "version": "15.6.0",
+  "main": "index.js",
+  "repository": "facebook/react",
+  "keywords": [
+    "react",
+    "react-addon"
+  ],
+  "license": "BSD-3-Clause",
+  "peerDependencies": {
+    "react-dom": "^15.4.2"
+  },
+  "scripts": {
+    "test": "jest",
+    "prepublish": "npm test"
+  },
+  "devDependencies": {
+    "jest": "^19.0.2",
+    "react": "^15.4.2",
+    "react-dom": "^15.4.2"
+  },
+  "files": [
+    "LICENSE",
+    "PATENTS",
+    "README.md",
+    "index.js"
+  ]
+}
diff --git a/addons/react-addons-test-utils/test.js b/addons/react-addons-test-utils/test.js
new file mode 100644
index 000000000000..a2d5cfa94018
--- /dev/null
+++ b/addons/react-addons-test-utils/test.js
@@ -0,0 +1,58 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+describe('ReactTestUtils', function() {
+  let React;
+
+  beforeEach(function() {
+    spyOn(console, 'warn');
+    React = require('react');
+  });
+
+  it('should warn on include', function() {
+    require('./index');
+    expect(console.warn).toHaveBeenCalledWith(
+      'Warning: ReactTestUtils has been moved to react-dom/test-utils. ' +
+        'Update references to remove this warning.'
+    );
+  });
+
+  it('should pass a basic smoke test', function() {
+    const ReactTestUtils = require('./index');
+    const onClick = jest.fn();
+
+    class MyComponent extends React.Component {
+      constructor(props, context) {
+        super(props, context);
+        this.state = {bar: 123};
+      }
+      render() {
+        return <div onClick={onClick}>{this.props.baz}</div>;
+      }
+    }
+
+    const instance = ReactTestUtils.renderIntoDocument(
+      <MyComponent baz="abc" />
+    );
+
+    expect(instance.state.bar).toBe(123);
+    expect(instance.props.baz).toBe('abc');
+
+    const div = ReactTestUtils.findRenderedDOMComponentWithTag(instance, 'div');
+    expect(div.textContent).toBe('abc');
+
+    expect(onClick).not.toHaveBeenCalled();
+    ReactTestUtils.Simulate.click(div);
+    expect(onClick).toHaveBeenCalled();
+  });
+});
diff --git a/addons/react-addons-test-utils/yarn.lock b/addons/react-addons-test-utils/yarn.lock
new file mode 100644
index 000000000000..04a87610adc2
--- /dev/null
+++ b/addons/react-addons-test-utils/yarn.lock
@@ -0,0 +1,2057 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+abab@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.3.tgz#b81de5f7274ec4e756d797cd834f303642724e5d"
+
+acorn-globals@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-3.1.0.tgz#fd8270f71fbb4996b004fa880ee5d46573a731bf"
+  dependencies:
+    acorn "^4.0.4"
+
+acorn@^4.0.4:
+  version "4.0.11"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.11.tgz#edcda3bd937e7556410d42ed5860f67399c794c0"
+
+ajv@^4.9.1:
+  version "4.11.5"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.5.tgz#b6ee74657b993a01dce44b7944d56f485828d5bd"
+  dependencies:
+    co "^4.6.0"
+    json-stable-stringify "^1.0.1"
+
+align-text@^0.1.1, align-text@^0.1.3:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
+  dependencies:
+    kind-of "^3.0.2"
+    longest "^1.0.1"
+    repeat-string "^1.5.2"
+
+amdefine@>=0.0.4:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
+
+ansi-escapes@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
+
+ansi-regex@^2.0.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
+
+ansi-styles@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
+
+ansi-styles@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.0.0.tgz#5404e93a544c4fec7f048262977bebfe3155e0c1"
+  dependencies:
+    color-convert "^1.0.0"
+
+anymatch@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507"
+  dependencies:
+    arrify "^1.0.0"
+    micromatch "^2.1.5"
+
+append-transform@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-0.4.0.tgz#d76ebf8ca94d276e247a36bad44a4b74ab611991"
+  dependencies:
+    default-require-extensions "^1.0.0"
+
+argparse@^1.0.7:
+  version "1.0.9"
+  resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86"
+  dependencies:
+    sprintf-js "~1.0.2"
+
+arr-diff@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf"
+  dependencies:
+    arr-flatten "^1.0.1"
+
+arr-flatten@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b"
+
+array-equal@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93"
+
+array-unique@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
+
+arrify@^1.0.0, arrify@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
+
+asap@~2.0.3:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f"
+
+asn1@~0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86"
+
+assert-plus@1.0.0, assert-plus@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
+
+assert-plus@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234"
+
+async@^1.4.0:
+  version "1.5.2"
+  resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
+
+async@^2.1.4:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/async/-/async-2.3.0.tgz#1013d1051047dd320fe24e494d5c66ecaf6147d9"
+  dependencies:
+    lodash "^4.14.0"
+
+asynckit@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+
+aws-sign2@~0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f"
+
+aws4@^1.2.1:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e"
+
+babel-code-frame@^6.22.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4"
+  dependencies:
+    chalk "^1.1.0"
+    esutils "^2.0.2"
+    js-tokens "^3.0.0"
+
+babel-core@^6.0.0, babel-core@^6.24.0:
+  version "6.24.0"
+  resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.24.0.tgz#8f36a0a77f5c155aed6f920b844d23ba56742a02"
+  dependencies:
+    babel-code-frame "^6.22.0"
+    babel-generator "^6.24.0"
+    babel-helpers "^6.23.0"
+    babel-messages "^6.23.0"
+    babel-register "^6.24.0"
+    babel-runtime "^6.22.0"
+    babel-template "^6.23.0"
+    babel-traverse "^6.23.1"
+    babel-types "^6.23.0"
+    babylon "^6.11.0"
+    convert-source-map "^1.1.0"
+    debug "^2.1.1"
+    json5 "^0.5.0"
+    lodash "^4.2.0"
+    minimatch "^3.0.2"
+    path-is-absolute "^1.0.0"
+    private "^0.1.6"
+    slash "^1.0.0"
+    source-map "^0.5.0"
+
+babel-generator@^6.18.0, babel-generator@^6.24.0:
+  version "6.24.0"
+  resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.24.0.tgz#eba270a8cc4ce6e09a61be43465d7c62c1f87c56"
+  dependencies:
+    babel-messages "^6.23.0"
+    babel-runtime "^6.22.0"
+    babel-types "^6.23.0"
+    detect-indent "^4.0.0"
+    jsesc "^1.3.0"
+    lodash "^4.2.0"
+    source-map "^0.5.0"
+    trim-right "^1.0.1"
+
+babel-helpers@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.23.0.tgz#4f8f2e092d0b6a8808a4bde79c27f1e2ecf0d992"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-template "^6.23.0"
+
+babel-jest@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-19.0.0.tgz#59323ced99a3a84d359da219ca881074ffc6ce3f"
+  dependencies:
+    babel-core "^6.0.0"
+    babel-plugin-istanbul "^4.0.0"
+    babel-preset-jest "^19.0.0"
+
+babel-messages@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e"
+  dependencies:
+    babel-runtime "^6.22.0"
+
+babel-plugin-istanbul@^4.0.0:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.1.tgz#c12de0fc6fe42adfb16be56f1ad11e4a9782eca9"
+  dependencies:
+    find-up "^2.1.0"
+    istanbul-lib-instrument "^1.6.2"
+    test-exclude "^4.0.3"
+
+babel-plugin-jest-hoist@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-19.0.0.tgz#4ae2a04ea612a6e73651f3fde52c178991304bea"
+
+babel-preset-jest@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-19.0.0.tgz#22d67201d02324a195811288eb38294bb3cac396"
+  dependencies:
+    babel-plugin-jest-hoist "^19.0.0"
+
+babel-register@^6.24.0:
+  version "6.24.0"
+  resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.24.0.tgz#5e89f8463ba9970356d02eb07dabe3308b080cfd"
+  dependencies:
+    babel-core "^6.24.0"
+    babel-runtime "^6.22.0"
+    core-js "^2.4.0"
+    home-or-tmp "^2.0.0"
+    lodash "^4.2.0"
+    mkdirp "^0.5.1"
+    source-map-support "^0.4.2"
+
+babel-runtime@^6.22.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b"
+  dependencies:
+    core-js "^2.4.0"
+    regenerator-runtime "^0.10.0"
+
+babel-template@^6.16.0, babel-template@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.23.0.tgz#04d4f270adbb3aa704a8143ae26faa529238e638"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-traverse "^6.23.0"
+    babel-types "^6.23.0"
+    babylon "^6.11.0"
+    lodash "^4.2.0"
+
+babel-traverse@^6.18.0, babel-traverse@^6.23.0, babel-traverse@^6.23.1:
+  version "6.23.1"
+  resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.23.1.tgz#d3cb59010ecd06a97d81310065f966b699e14f48"
+  dependencies:
+    babel-code-frame "^6.22.0"
+    babel-messages "^6.23.0"
+    babel-runtime "^6.22.0"
+    babel-types "^6.23.0"
+    babylon "^6.15.0"
+    debug "^2.2.0"
+    globals "^9.0.0"
+    invariant "^2.2.0"
+    lodash "^4.2.0"
+
+babel-types@^6.18.0, babel-types@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.23.0.tgz#bb17179d7538bad38cd0c9e115d340f77e7e9acf"
+  dependencies:
+    babel-runtime "^6.22.0"
+    esutils "^2.0.2"
+    lodash "^4.2.0"
+    to-fast-properties "^1.0.1"
+
+babylon@^6.11.0, babylon@^6.13.0, babylon@^6.15.0:
+  version "6.16.1"
+  resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.16.1.tgz#30c5a22f481978a9e7f8cdfdf496b11d94b404d3"
+
+balanced-match@^0.4.1:
+  version "0.4.2"
+  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
+
+bcrypt-pbkdf@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d"
+  dependencies:
+    tweetnacl "^0.14.3"
+
+boom@2.x.x:
+  version "2.10.1"
+  resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f"
+  dependencies:
+    hoek "2.x.x"
+
+brace-expansion@^1.0.0:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9"
+  dependencies:
+    balanced-match "^0.4.1"
+    concat-map "0.0.1"
+
+braces@^1.8.2:
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7"
+  dependencies:
+    expand-range "^1.8.1"
+    preserve "^0.2.0"
+    repeat-element "^1.1.2"
+
+browser-resolve@^1.11.2:
+  version "1.11.2"
+  resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.2.tgz#8ff09b0a2c421718a1051c260b32e48f442938ce"
+  dependencies:
+    resolve "1.1.7"
+
+bser@1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/bser/-/bser-1.0.2.tgz#381116970b2a6deea5646dd15dd7278444b56169"
+  dependencies:
+    node-int64 "^0.4.0"
+
+bser@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719"
+  dependencies:
+    node-int64 "^0.4.0"
+
+builtin-modules@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
+
+callsites@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50"
+
+camelcase@^1.0.2:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39"
+
+camelcase@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
+
+caseless@~0.12.0:
+  version "0.12.0"
+  resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
+
+center-align@^0.1.1:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad"
+  dependencies:
+    align-text "^0.1.3"
+    lazy-cache "^1.0.3"
+
+chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
+  dependencies:
+    ansi-styles "^2.2.1"
+    escape-string-regexp "^1.0.2"
+    has-ansi "^2.0.0"
+    strip-ansi "^3.0.0"
+    supports-color "^2.0.0"
+
+ci-info@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.0.0.tgz#dc5285f2b4e251821683681c381c3388f46ec534"
+
+cliui@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1"
+  dependencies:
+    center-align "^0.1.1"
+    right-align "^0.1.1"
+    wordwrap "0.0.2"
+
+cliui@^3.2.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
+  dependencies:
+    string-width "^1.0.1"
+    strip-ansi "^3.0.1"
+    wrap-ansi "^2.0.0"
+
+co@^4.6.0:
+  version "4.6.0"
+  resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
+
+code-point-at@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
+
+color-convert@^1.0.0:
+  version "1.9.0"
+  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a"
+  dependencies:
+    color-name "^1.1.1"
+
+color-name@^1.1.1:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.2.tgz#5c8ab72b64bd2215d617ae9559ebb148475cf98d"
+
+combined-stream@^1.0.5, combined-stream@~1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009"
+  dependencies:
+    delayed-stream "~1.0.0"
+
+concat-map@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+
+content-type-parser@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/content-type-parser/-/content-type-parser-1.0.1.tgz#c3e56988c53c65127fb46d4032a3a900246fdc94"
+
+convert-source-map@^1.1.0:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5"
+
+core-js@^1.0.0:
+  version "1.2.7"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
+
+core-js@^2.4.0:
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e"
+
+cryptiles@2.x.x:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8"
+  dependencies:
+    boom "2.x.x"
+
+cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0":
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.2.tgz#b8036170c79f07a90ff2f16e22284027a243848b"
+
+"cssstyle@>= 0.2.37 < 0.3.0":
+  version "0.2.37"
+  resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-0.2.37.tgz#541097234cb2513c83ceed3acddc27ff27987d54"
+  dependencies:
+    cssom "0.3.x"
+
+dashdash@^1.12.0:
+  version "1.14.1"
+  resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
+  dependencies:
+    assert-plus "^1.0.0"
+
+debug@^2.1.1, debug@^2.2.0:
+  version "2.6.3"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.3.tgz#0f7eb8c30965ec08c72accfa0130c8b79984141d"
+  dependencies:
+    ms "0.7.2"
+
+decamelize@^1.0.0, decamelize@^1.1.1:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
+
+deep-is@~0.1.3:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
+
+default-require-extensions@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8"
+  dependencies:
+    strip-bom "^2.0.0"
+
+delayed-stream@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+
+detect-indent@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208"
+  dependencies:
+    repeating "^2.0.0"
+
+diff@^3.0.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9"
+
+ecc-jsbn@~0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505"
+  dependencies:
+    jsbn "~0.1.0"
+
+encoding@^0.1.11:
+  version "0.1.12"
+  resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb"
+  dependencies:
+    iconv-lite "~0.4.13"
+
+"errno@>=0.1.1 <0.2.0-0":
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d"
+  dependencies:
+    prr "~0.0.0"
+
+error-ex@^1.2.0:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc"
+  dependencies:
+    is-arrayish "^0.2.1"
+
+escape-string-regexp@^1.0.2:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+
+escodegen@^1.6.1:
+  version "1.8.1"
+  resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018"
+  dependencies:
+    esprima "^2.7.1"
+    estraverse "^1.9.1"
+    esutils "^2.0.2"
+    optionator "^0.8.1"
+  optionalDependencies:
+    source-map "~0.2.0"
+
+esprima@^2.7.1:
+  version "2.7.3"
+  resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
+
+esprima@^3.1.1:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633"
+
+estraverse@^1.9.1:
+  version "1.9.3"
+  resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44"
+
+esutils@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
+
+exec-sh@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.0.tgz#14f75de3f20d286ef933099b2ce50a90359cef10"
+  dependencies:
+    merge "^1.1.3"
+
+expand-brackets@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
+  dependencies:
+    is-posix-bracket "^0.1.0"
+
+expand-range@^1.8.1:
+  version "1.8.2"
+  resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337"
+  dependencies:
+    fill-range "^2.1.0"
+
+extend@~3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4"
+
+extglob@^0.3.1:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1"
+  dependencies:
+    is-extglob "^1.0.0"
+
+extsprintf@1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550"
+
+fast-levenshtein@~2.0.4:
+  version "2.0.6"
+  resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
+
+fb-watchman@^1.8.0:
+  version "1.9.2"
+  resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-1.9.2.tgz#a24cf47827f82d38fb59a69ad70b76e3b6ae7383"
+  dependencies:
+    bser "1.0.2"
+
+fb-watchman@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58"
+  dependencies:
+    bser "^2.0.0"
+
+fbjs@^0.8.1, fbjs@^0.8.4:
+  version "0.8.12"
+  resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.12.tgz#10b5d92f76d45575fd63a217d4ea02bea2f8ed04"
+  dependencies:
+    core-js "^1.0.0"
+    isomorphic-fetch "^2.1.1"
+    loose-envify "^1.0.0"
+    object-assign "^4.1.0"
+    promise "^7.1.1"
+    setimmediate "^1.0.5"
+    ua-parser-js "^0.7.9"
+
+filename-regex@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775"
+
+fileset@^2.0.2:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/fileset/-/fileset-2.0.3.tgz#8e7548a96d3cc2327ee5e674168723a333bba2a0"
+  dependencies:
+    glob "^7.0.3"
+    minimatch "^3.0.3"
+
+fill-range@^2.1.0:
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723"
+  dependencies:
+    is-number "^2.1.0"
+    isobject "^2.0.0"
+    randomatic "^1.1.3"
+    repeat-element "^1.1.2"
+    repeat-string "^1.5.2"
+
+find-up@^1.0.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
+  dependencies:
+    path-exists "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+find-up@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
+  dependencies:
+    locate-path "^2.0.0"
+
+for-in@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
+
+for-own@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce"
+  dependencies:
+    for-in "^1.0.1"
+
+forever-agent@~0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
+
+form-data@~2.1.1:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4"
+  dependencies:
+    asynckit "^0.4.0"
+    combined-stream "^1.0.5"
+    mime-types "^2.1.12"
+
+fs.realpath@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+
+get-caller-file@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5"
+
+getpass@^0.1.1:
+  version "0.1.6"
+  resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6"
+  dependencies:
+    assert-plus "^1.0.0"
+
+glob-base@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
+  dependencies:
+    glob-parent "^2.0.0"
+    is-glob "^2.0.0"
+
+glob-parent@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28"
+  dependencies:
+    is-glob "^2.0.0"
+
+glob@^7.0.3, glob@^7.0.5:
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
+  dependencies:
+    fs.realpath "^1.0.0"
+    inflight "^1.0.4"
+    inherits "2"
+    minimatch "^3.0.2"
+    once "^1.3.0"
+    path-is-absolute "^1.0.0"
+
+globals@^9.0.0:
+  version "9.17.0"
+  resolved "https://registry.yarnpkg.com/globals/-/globals-9.17.0.tgz#0c0ca696d9b9bb694d2e5470bd37777caad50286"
+
+graceful-fs@^4.1.2, graceful-fs@^4.1.6:
+  version "4.1.11"
+  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
+
+growly@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
+
+handlebars@^4.0.3:
+  version "4.0.6"
+  resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7"
+  dependencies:
+    async "^1.4.0"
+    optimist "^0.6.1"
+    source-map "^0.4.4"
+  optionalDependencies:
+    uglify-js "^2.6"
+
+har-schema@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e"
+
+har-validator@~4.2.1:
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a"
+  dependencies:
+    ajv "^4.9.1"
+    har-schema "^1.0.5"
+
+has-ansi@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
+  dependencies:
+    ansi-regex "^2.0.0"
+
+has-flag@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
+
+hawk@~3.1.3:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4"
+  dependencies:
+    boom "2.x.x"
+    cryptiles "2.x.x"
+    hoek "2.x.x"
+    sntp "1.x.x"
+
+hoek@2.x.x:
+  version "2.16.3"
+  resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed"
+
+home-or-tmp@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8"
+  dependencies:
+    os-homedir "^1.0.0"
+    os-tmpdir "^1.0.1"
+
+hosted-git-info@^2.1.4:
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.4.1.tgz#4b0445e41c004a8bd1337773a4ff790ca40318c8"
+
+html-encoding-sniffer@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.1.tgz#79bf7a785ea495fe66165e734153f363ff5437da"
+  dependencies:
+    whatwg-encoding "^1.0.1"
+
+http-signature@~1.1.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf"
+  dependencies:
+    assert-plus "^0.2.0"
+    jsprim "^1.2.2"
+    sshpk "^1.7.0"
+
+iconv-lite@0.4.13, iconv-lite@~0.4.13:
+  version "0.4.13"
+  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2"
+
+inflight@^1.0.4:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+  dependencies:
+    once "^1.3.0"
+    wrappy "1"
+
+inherits@2:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
+
+invariant@^2.2.0:
+  version "2.2.2"
+  resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360"
+  dependencies:
+    loose-envify "^1.0.0"
+
+invert-kv@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
+
+is-arrayish@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
+
+is-buffer@^1.0.2:
+  version "1.1.5"
+  resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc"
+
+is-builtin-module@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe"
+  dependencies:
+    builtin-modules "^1.0.0"
+
+is-ci@^1.0.9:
+  version "1.0.10"
+  resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.0.10.tgz#f739336b2632365061a9d48270cd56ae3369318e"
+  dependencies:
+    ci-info "^1.0.0"
+
+is-dotfile@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d"
+
+is-equal-shallow@^0.1.3:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534"
+  dependencies:
+    is-primitive "^2.0.0"
+
+is-extendable@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
+
+is-extglob@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
+
+is-finite@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa"
+  dependencies:
+    number-is-nan "^1.0.0"
+
+is-fullwidth-code-point@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
+  dependencies:
+    number-is-nan "^1.0.0"
+
+is-glob@^2.0.0, is-glob@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
+  dependencies:
+    is-extglob "^1.0.0"
+
+is-number@^2.0.2, is-number@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
+  dependencies:
+    kind-of "^3.0.2"
+
+is-posix-bracket@^0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
+
+is-primitive@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
+
+is-stream@^1.0.1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
+
+is-typedarray@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
+
+is-utf8@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
+
+isarray@1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
+
+isexe@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+
+isobject@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
+  dependencies:
+    isarray "1.0.0"
+
+isomorphic-fetch@^2.1.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
+  dependencies:
+    node-fetch "^1.0.1"
+    whatwg-fetch ">=0.10.0"
+
+isstream@~0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
+
+istanbul-api@^1.1.0-alpha.1:
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-1.1.7.tgz#f6f37f09f8002b130f891c646b70ee4a8e7345ae"
+  dependencies:
+    async "^2.1.4"
+    fileset "^2.0.2"
+    istanbul-lib-coverage "^1.0.2"
+    istanbul-lib-hook "^1.0.5"
+    istanbul-lib-instrument "^1.7.0"
+    istanbul-lib-report "^1.0.0"
+    istanbul-lib-source-maps "^1.1.1"
+    istanbul-reports "^1.0.2"
+    js-yaml "^3.7.0"
+    mkdirp "^0.5.1"
+    once "^1.4.0"
+
+istanbul-lib-coverage@^1.0.0, istanbul-lib-coverage@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.0.2.tgz#87a0c015b6910651cb3b184814dfb339337e25e1"
+
+istanbul-lib-hook@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.0.5.tgz#6ca3d16d60c5f4082da39f7c5cd38ea8a772b88e"
+  dependencies:
+    append-transform "^0.4.0"
+
+istanbul-lib-instrument@^1.1.1, istanbul-lib-instrument@^1.6.2, istanbul-lib-instrument@^1.7.0:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.7.0.tgz#b8e0dc25709bb44e17336ab47b7bb5c97c23f659"
+  dependencies:
+    babel-generator "^6.18.0"
+    babel-template "^6.16.0"
+    babel-traverse "^6.18.0"
+    babel-types "^6.18.0"
+    babylon "^6.13.0"
+    istanbul-lib-coverage "^1.0.2"
+    semver "^5.3.0"
+
+istanbul-lib-report@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.0.0.tgz#d83dac7f26566b521585569367fe84ccfc7aaecb"
+  dependencies:
+    istanbul-lib-coverage "^1.0.2"
+    mkdirp "^0.5.1"
+    path-parse "^1.0.5"
+    supports-color "^3.1.2"
+
+istanbul-lib-source-maps@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.1.1.tgz#f8c8c2e8f2160d1d91526d97e5bd63b2079af71c"
+  dependencies:
+    istanbul-lib-coverage "^1.0.2"
+    mkdirp "^0.5.1"
+    rimraf "^2.4.4"
+    source-map "^0.5.3"
+
+istanbul-reports@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.0.2.tgz#4e8366abe6fa746cc1cd6633f108de12cc6ac6fa"
+  dependencies:
+    handlebars "^4.0.3"
+
+jest-changed-files@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-19.0.2.tgz#16c54c84c3270be408e06d2e8af3f3e37a885824"
+
+jest-cli@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-19.0.2.tgz#cc3620b62acac5f2d93a548cb6ef697d4ec85443"
+  dependencies:
+    ansi-escapes "^1.4.0"
+    callsites "^2.0.0"
+    chalk "^1.1.1"
+    graceful-fs "^4.1.6"
+    is-ci "^1.0.9"
+    istanbul-api "^1.1.0-alpha.1"
+    istanbul-lib-coverage "^1.0.0"
+    istanbul-lib-instrument "^1.1.1"
+    jest-changed-files "^19.0.2"
+    jest-config "^19.0.2"
+    jest-environment-jsdom "^19.0.2"
+    jest-haste-map "^19.0.0"
+    jest-jasmine2 "^19.0.2"
+    jest-message-util "^19.0.0"
+    jest-regex-util "^19.0.0"
+    jest-resolve-dependencies "^19.0.0"
+    jest-runtime "^19.0.2"
+    jest-snapshot "^19.0.2"
+    jest-util "^19.0.2"
+    micromatch "^2.3.11"
+    node-notifier "^5.0.1"
+    slash "^1.0.0"
+    string-length "^1.0.1"
+    throat "^3.0.0"
+    which "^1.1.1"
+    worker-farm "^1.3.1"
+    yargs "^6.3.0"
+
+jest-config@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-19.0.2.tgz#1b9bd2db0ddd16df61c2b10a54009e1768da6411"
+  dependencies:
+    chalk "^1.1.1"
+    jest-environment-jsdom "^19.0.2"
+    jest-environment-node "^19.0.2"
+    jest-jasmine2 "^19.0.2"
+    jest-regex-util "^19.0.0"
+    jest-resolve "^19.0.2"
+    jest-validate "^19.0.2"
+    pretty-format "^19.0.0"
+
+jest-diff@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-19.0.0.tgz#d1563cfc56c8b60232988fbc05d4d16ed90f063c"
+  dependencies:
+    chalk "^1.1.3"
+    diff "^3.0.0"
+    jest-matcher-utils "^19.0.0"
+    pretty-format "^19.0.0"
+
+jest-environment-jsdom@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-19.0.2.tgz#ceda859c4a4b94ab35e4de7dab54b926f293e4a3"
+  dependencies:
+    jest-mock "^19.0.0"
+    jest-util "^19.0.2"
+    jsdom "^9.11.0"
+
+jest-environment-node@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-19.0.2.tgz#6e84079db87ed21d0c05e1f9669f207b116fe99b"
+  dependencies:
+    jest-mock "^19.0.0"
+    jest-util "^19.0.2"
+
+jest-file-exists@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-file-exists/-/jest-file-exists-19.0.0.tgz#cca2e587a11ec92e24cfeab3f8a94d657f3fceb8"
+
+jest-haste-map@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-19.0.0.tgz#adde00b62b1fe04432a104b3254fc5004514b55e"
+  dependencies:
+    fb-watchman "^2.0.0"
+    graceful-fs "^4.1.6"
+    micromatch "^2.3.11"
+    sane "~1.5.0"
+    worker-farm "^1.3.1"
+
+jest-jasmine2@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-19.0.2.tgz#167991ac825981fb1a800af126e83afcca832c73"
+  dependencies:
+    graceful-fs "^4.1.6"
+    jest-matcher-utils "^19.0.0"
+    jest-matchers "^19.0.0"
+    jest-message-util "^19.0.0"
+    jest-snapshot "^19.0.2"
+
+jest-matcher-utils@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-19.0.0.tgz#5ecd9b63565d2b001f61fbf7ec4c7f537964564d"
+  dependencies:
+    chalk "^1.1.3"
+    pretty-format "^19.0.0"
+
+jest-matchers@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-matchers/-/jest-matchers-19.0.0.tgz#c74ecc6ebfec06f384767ba4d6fa4a42d6755754"
+  dependencies:
+    jest-diff "^19.0.0"
+    jest-matcher-utils "^19.0.0"
+    jest-message-util "^19.0.0"
+    jest-regex-util "^19.0.0"
+
+jest-message-util@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-19.0.0.tgz#721796b89c0e4d761606f9ba8cb828a3b6246416"
+  dependencies:
+    chalk "^1.1.1"
+    micromatch "^2.3.11"
+
+jest-mock@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-19.0.0.tgz#67038641e9607ab2ce08ec4a8cb83aabbc899d01"
+
+jest-regex-util@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-19.0.0.tgz#b7754587112aede1456510bb1f6afe74ef598691"
+
+jest-resolve-dependencies@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-19.0.0.tgz#a741ad1fa094140e64ecf2642a504f834ece22ee"
+  dependencies:
+    jest-file-exists "^19.0.0"
+
+jest-resolve@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-19.0.2.tgz#5793575de4f07aec32f7d7ff0c6c181963eefb3c"
+  dependencies:
+    browser-resolve "^1.11.2"
+    jest-haste-map "^19.0.0"
+    resolve "^1.2.0"
+
+jest-runtime@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-19.0.2.tgz#d9a43e72de416d27d196fd9c7940d98fe6685407"
+  dependencies:
+    babel-core "^6.0.0"
+    babel-jest "^19.0.0"
+    babel-plugin-istanbul "^4.0.0"
+    chalk "^1.1.3"
+    graceful-fs "^4.1.6"
+    jest-config "^19.0.2"
+    jest-file-exists "^19.0.0"
+    jest-haste-map "^19.0.0"
+    jest-regex-util "^19.0.0"
+    jest-resolve "^19.0.2"
+    jest-util "^19.0.2"
+    json-stable-stringify "^1.0.1"
+    micromatch "^2.3.11"
+    strip-bom "3.0.0"
+    yargs "^6.3.0"
+
+jest-snapshot@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-19.0.2.tgz#9c1b216214f7187c38bfd5c70b1efab16b0ff50b"
+  dependencies:
+    chalk "^1.1.3"
+    jest-diff "^19.0.0"
+    jest-file-exists "^19.0.0"
+    jest-matcher-utils "^19.0.0"
+    jest-util "^19.0.2"
+    natural-compare "^1.4.0"
+    pretty-format "^19.0.0"
+
+jest-util@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-19.0.2.tgz#e0a0232a2ab9e6b2b53668bdb3534c2b5977ed41"
+  dependencies:
+    chalk "^1.1.1"
+    graceful-fs "^4.1.6"
+    jest-file-exists "^19.0.0"
+    jest-message-util "^19.0.0"
+    jest-mock "^19.0.0"
+    jest-validate "^19.0.2"
+    leven "^2.0.0"
+    mkdirp "^0.5.1"
+
+jest-validate@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-19.0.2.tgz#dc534df5f1278d5b63df32b14241d4dbf7244c0c"
+  dependencies:
+    chalk "^1.1.1"
+    jest-matcher-utils "^19.0.0"
+    leven "^2.0.0"
+    pretty-format "^19.0.0"
+
+jest@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest/-/jest-19.0.2.tgz#b794faaf8ff461e7388f28beef559a54f20b2c10"
+  dependencies:
+    jest-cli "^19.0.2"
+
+jodid25519@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967"
+  dependencies:
+    jsbn "~0.1.0"
+
+js-tokens@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7"
+
+js-yaml@^3.7.0:
+  version "3.8.3"
+  resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.3.tgz#33a05ec481c850c8875929166fe1beb61c728766"
+  dependencies:
+    argparse "^1.0.7"
+    esprima "^3.1.1"
+
+jsbn@~0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
+
+jsdom@^9.11.0:
+  version "9.12.0"
+  resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-9.12.0.tgz#e8c546fffcb06c00d4833ca84410fed7f8a097d4"
+  dependencies:
+    abab "^1.0.3"
+    acorn "^4.0.4"
+    acorn-globals "^3.1.0"
+    array-equal "^1.0.0"
+    content-type-parser "^1.0.1"
+    cssom ">= 0.3.2 < 0.4.0"
+    cssstyle ">= 0.2.37 < 0.3.0"
+    escodegen "^1.6.1"
+    html-encoding-sniffer "^1.0.1"
+    nwmatcher ">= 1.3.9 < 2.0.0"
+    parse5 "^1.5.1"
+    request "^2.79.0"
+    sax "^1.2.1"
+    symbol-tree "^3.2.1"
+    tough-cookie "^2.3.2"
+    webidl-conversions "^4.0.0"
+    whatwg-encoding "^1.0.1"
+    whatwg-url "^4.3.0"
+    xml-name-validator "^2.0.1"
+
+jsesc@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b"
+
+json-schema@0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
+
+json-stable-stringify@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af"
+  dependencies:
+    jsonify "~0.0.0"
+
+json-stringify-safe@~5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
+
+json5@^0.5.0:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
+
+jsonify@~0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
+
+jsprim@^1.2.2:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.0.tgz#a3b87e40298d8c380552d8cc7628a0bb95a22918"
+  dependencies:
+    assert-plus "1.0.0"
+    extsprintf "1.0.2"
+    json-schema "0.2.3"
+    verror "1.3.6"
+
+kind-of@^3.0.2:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47"
+  dependencies:
+    is-buffer "^1.0.2"
+
+lazy-cache@^1.0.3:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
+
+lcid@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
+  dependencies:
+    invert-kv "^1.0.0"
+
+leven@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580"
+
+levn@~0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
+  dependencies:
+    prelude-ls "~1.1.2"
+    type-check "~0.3.2"
+
+load-json-file@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
+  dependencies:
+    graceful-fs "^4.1.2"
+    parse-json "^2.2.0"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+    strip-bom "^2.0.0"
+
+locate-path@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
+  dependencies:
+    p-locate "^2.0.0"
+    path-exists "^3.0.0"
+
+lodash@^4.14.0, lodash@^4.2.0:
+  version "4.17.4"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
+
+longest@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
+
+loose-envify@^1.0.0, loose-envify@^1.1.0:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
+  dependencies:
+    js-tokens "^3.0.0"
+
+makeerror@1.0.x:
+  version "1.0.11"
+  resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c"
+  dependencies:
+    tmpl "1.0.x"
+
+merge@^1.1.3:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da"
+
+micromatch@^2.1.5, micromatch@^2.3.11:
+  version "2.3.11"
+  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
+  dependencies:
+    arr-diff "^2.0.0"
+    array-unique "^0.2.1"
+    braces "^1.8.2"
+    expand-brackets "^0.1.4"
+    extglob "^0.3.1"
+    filename-regex "^2.0.0"
+    is-extglob "^1.0.0"
+    is-glob "^2.0.1"
+    kind-of "^3.0.2"
+    normalize-path "^2.0.1"
+    object.omit "^2.0.0"
+    parse-glob "^3.0.4"
+    regex-cache "^0.4.2"
+
+mime-db@~1.27.0:
+  version "1.27.0"
+  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1"
+
+mime-types@^2.1.12, mime-types@~2.1.7:
+  version "2.1.15"
+  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed"
+  dependencies:
+    mime-db "~1.27.0"
+
+minimatch@^3.0.2, minimatch@^3.0.3:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774"
+  dependencies:
+    brace-expansion "^1.0.0"
+
+minimist@0.0.8, minimist@~0.0.1:
+  version "0.0.8"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
+
+minimist@^1.1.1:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
+
+mkdirp@^0.5.1:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
+  dependencies:
+    minimist "0.0.8"
+
+ms@0.7.2:
+  version "0.7.2"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765"
+
+natural-compare@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
+
+node-fetch@^1.0.1:
+  version "1.6.3"
+  resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04"
+  dependencies:
+    encoding "^0.1.11"
+    is-stream "^1.0.1"
+
+node-int64@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
+
+node-notifier@^5.0.1:
+  version "5.1.2"
+  resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.1.2.tgz#2fa9e12605fa10009d44549d6fcd8a63dde0e4ff"
+  dependencies:
+    growly "^1.3.0"
+    semver "^5.3.0"
+    shellwords "^0.1.0"
+    which "^1.2.12"
+
+normalize-package-data@^2.3.2:
+  version "2.3.6"
+  resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.6.tgz#498fa420c96401f787402ba21e600def9f981fff"
+  dependencies:
+    hosted-git-info "^2.1.4"
+    is-builtin-module "^1.0.0"
+    semver "2 || 3 || 4 || 5"
+    validate-npm-package-license "^3.0.1"
+
+normalize-path@^2.0.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
+  dependencies:
+    remove-trailing-separator "^1.0.1"
+
+number-is-nan@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
+
+"nwmatcher@>= 1.3.9 < 2.0.0":
+  version "1.3.9"
+  resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.3.9.tgz#8bab486ff7fa3dfd086656bbe8b17116d3692d2a"
+
+oauth-sign@~0.8.1:
+  version "0.8.2"
+  resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
+
+object-assign@^4.1.0:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+
+object.omit@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
+  dependencies:
+    for-own "^0.1.4"
+    is-extendable "^0.1.1"
+
+once@^1.3.0, once@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+  dependencies:
+    wrappy "1"
+
+optimist@^0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
+  dependencies:
+    minimist "~0.0.1"
+    wordwrap "~0.0.2"
+
+optionator@^0.8.1:
+  version "0.8.2"
+  resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64"
+  dependencies:
+    deep-is "~0.1.3"
+    fast-levenshtein "~2.0.4"
+    levn "~0.3.0"
+    prelude-ls "~1.1.2"
+    type-check "~0.3.2"
+    wordwrap "~1.0.0"
+
+os-homedir@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
+
+os-locale@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9"
+  dependencies:
+    lcid "^1.0.0"
+
+os-tmpdir@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
+
+p-limit@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.1.0.tgz#b07ff2d9a5d88bec806035895a2bab66a27988bc"
+
+p-locate@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
+  dependencies:
+    p-limit "^1.1.0"
+
+parse-glob@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
+  dependencies:
+    glob-base "^0.3.0"
+    is-dotfile "^1.0.0"
+    is-extglob "^1.0.0"
+    is-glob "^2.0.0"
+
+parse-json@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
+  dependencies:
+    error-ex "^1.2.0"
+
+parse5@^1.5.1:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94"
+
+path-exists@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
+  dependencies:
+    pinkie-promise "^2.0.0"
+
+path-exists@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
+
+path-is-absolute@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+
+path-parse@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1"
+
+path-type@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
+  dependencies:
+    graceful-fs "^4.1.2"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+performance-now@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5"
+
+pify@^2.0.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
+
+pinkie-promise@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
+  dependencies:
+    pinkie "^2.0.0"
+
+pinkie@^2.0.0:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
+
+prelude-ls@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
+
+preserve@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
+
+pretty-format@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-19.0.0.tgz#56530d32acb98a3fa4851c4e2b9d37b420684c84"
+  dependencies:
+    ansi-styles "^3.0.0"
+
+private@^0.1.6:
+  version "0.1.7"
+  resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1"
+
+promise@^7.1.1:
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/promise/-/promise-7.1.1.tgz#489654c692616b8aa55b0724fa809bb7db49c5bf"
+  dependencies:
+    asap "~2.0.3"
+
+prr@~0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a"
+
+punycode@^1.4.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
+
+qs@~6.4.0:
+  version "6.4.0"
+  resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
+
+randomatic@^1.1.3:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb"
+  dependencies:
+    is-number "^2.0.2"
+    kind-of "^3.0.2"
+
+react-dom@^15.4.2:
+  version "15.4.2"
+  resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.4.2.tgz#015363f05b0a1fd52ae9efdd3a0060d90695208f"
+  dependencies:
+    fbjs "^0.8.1"
+    loose-envify "^1.1.0"
+    object-assign "^4.1.0"
+
+react@^15.4.2:
+  version "15.4.2"
+  resolved "https://registry.yarnpkg.com/react/-/react-15.4.2.tgz#41f7991b26185392ba9bae96c8889e7e018397ef"
+  dependencies:
+    fbjs "^0.8.4"
+    loose-envify "^1.1.0"
+    object-assign "^4.1.0"
+
+read-pkg-up@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
+  dependencies:
+    find-up "^1.0.0"
+    read-pkg "^1.0.0"
+
+read-pkg@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
+  dependencies:
+    load-json-file "^1.0.0"
+    normalize-package-data "^2.3.2"
+    path-type "^1.0.0"
+
+regenerator-runtime@^0.10.0:
+  version "0.10.3"
+  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.3.tgz#8c4367a904b51ea62a908ac310bf99ff90a82a3e"
+
+regex-cache@^0.4.2:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145"
+  dependencies:
+    is-equal-shallow "^0.1.3"
+    is-primitive "^2.0.0"
+
+remove-trailing-separator@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.0.1.tgz#615ebb96af559552d4bf4057c8436d486ab63cc4"
+
+repeat-element@^1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a"
+
+repeat-string@^1.5.2:
+  version "1.6.1"
+  resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
+
+repeating@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda"
+  dependencies:
+    is-finite "^1.0.0"
+
+request@^2.79.0:
+  version "2.81.0"
+  resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0"
+  dependencies:
+    aws-sign2 "~0.6.0"
+    aws4 "^1.2.1"
+    caseless "~0.12.0"
+    combined-stream "~1.0.5"
+    extend "~3.0.0"
+    forever-agent "~0.6.1"
+    form-data "~2.1.1"
+    har-validator "~4.2.1"
+    hawk "~3.1.3"
+    http-signature "~1.1.0"
+    is-typedarray "~1.0.0"
+    isstream "~0.1.2"
+    json-stringify-safe "~5.0.1"
+    mime-types "~2.1.7"
+    oauth-sign "~0.8.1"
+    performance-now "^0.2.0"
+    qs "~6.4.0"
+    safe-buffer "^5.0.1"
+    stringstream "~0.0.4"
+    tough-cookie "~2.3.0"
+    tunnel-agent "^0.6.0"
+    uuid "^3.0.0"
+
+require-directory@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
+
+require-main-filename@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
+
+resolve@1.1.7:
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
+
+resolve@^1.2.0:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.3.2.tgz#1f0442c9e0cbb8136e87b9305f932f46c7f28235"
+  dependencies:
+    path-parse "^1.0.5"
+
+right-align@^0.1.1:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef"
+  dependencies:
+    align-text "^0.1.1"
+
+rimraf@^2.4.4:
+  version "2.6.1"
+  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d"
+  dependencies:
+    glob "^7.0.5"
+
+safe-buffer@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7"
+
+sane@~1.5.0:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/sane/-/sane-1.5.0.tgz#a4adeae764d048621ecb27d5f9ecf513101939f3"
+  dependencies:
+    anymatch "^1.3.0"
+    exec-sh "^0.2.0"
+    fb-watchman "^1.8.0"
+    minimatch "^3.0.2"
+    minimist "^1.1.1"
+    walker "~1.0.5"
+    watch "~0.10.0"
+
+sax@^1.2.1:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.2.tgz#fd8631a23bc7826bef5d871bdb87378c95647828"
+
+"semver@2 || 3 || 4 || 5", semver@^5.3.0:
+  version "5.3.0"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
+
+set-blocking@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
+
+setimmediate@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
+
+shellwords@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.0.tgz#66afd47b6a12932d9071cbfd98a52e785cd0ba14"
+
+slash@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
+
+sntp@1.x.x:
+  version "1.0.9"
+  resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198"
+  dependencies:
+    hoek "2.x.x"
+
+source-map-support@^0.4.2:
+  version "0.4.14"
+  resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.14.tgz#9d4463772598b86271b4f523f6c1f4e02a7d6aef"
+  dependencies:
+    source-map "^0.5.6"
+
+source-map@^0.4.4:
+  version "0.4.4"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b"
+  dependencies:
+    amdefine ">=0.0.4"
+
+source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1:
+  version "0.5.6"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
+
+source-map@~0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d"
+  dependencies:
+    amdefine ">=0.0.4"
+
+spdx-correct@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40"
+  dependencies:
+    spdx-license-ids "^1.0.2"
+
+spdx-expression-parse@~1.0.0:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c"
+
+spdx-license-ids@^1.0.2:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57"
+
+sprintf-js@~1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
+
+sshpk@^1.7.0:
+  version "1.11.0"
+  resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.11.0.tgz#2d8d5ebb4a6fab28ffba37fa62a90f4a3ea59d77"
+  dependencies:
+    asn1 "~0.2.3"
+    assert-plus "^1.0.0"
+    dashdash "^1.12.0"
+    getpass "^0.1.1"
+  optionalDependencies:
+    bcrypt-pbkdf "^1.0.0"
+    ecc-jsbn "~0.1.1"
+    jodid25519 "^1.0.0"
+    jsbn "~0.1.0"
+    tweetnacl "~0.14.0"
+
+string-length@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/string-length/-/string-length-1.0.1.tgz#56970fb1c38558e9e70b728bf3de269ac45adfac"
+  dependencies:
+    strip-ansi "^3.0.0"
+
+string-width@^1.0.1, string-width@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
+  dependencies:
+    code-point-at "^1.0.0"
+    is-fullwidth-code-point "^1.0.0"
+    strip-ansi "^3.0.0"
+
+stringstream@~0.0.4:
+  version "0.0.5"
+  resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878"
+
+strip-ansi@^3.0.0, strip-ansi@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
+  dependencies:
+    ansi-regex "^2.0.0"
+
+strip-bom@3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
+
+strip-bom@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
+  dependencies:
+    is-utf8 "^0.2.0"
+
+supports-color@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
+
+supports-color@^3.1.2:
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
+  dependencies:
+    has-flag "^1.0.0"
+
+symbol-tree@^3.2.1:
+  version "3.2.2"
+  resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6"
+
+test-exclude@^4.0.3:
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-4.0.3.tgz#86a13ce3effcc60e6c90403cf31a27a60ac6c4e7"
+  dependencies:
+    arrify "^1.0.1"
+    micromatch "^2.3.11"
+    object-assign "^4.1.0"
+    read-pkg-up "^1.0.1"
+    require-main-filename "^1.0.1"
+
+throat@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/throat/-/throat-3.0.0.tgz#e7c64c867cbb3845f10877642f7b60055b8ec0d6"
+
+tmpl@1.0.x:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1"
+
+to-fast-properties@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320"
+
+tough-cookie@^2.3.2, tough-cookie@~2.3.0:
+  version "2.3.2"
+  resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a"
+  dependencies:
+    punycode "^1.4.1"
+
+tr46@~0.0.3:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
+
+trim-right@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
+
+tunnel-agent@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
+  dependencies:
+    safe-buffer "^5.0.1"
+
+tweetnacl@^0.14.3, tweetnacl@~0.14.0:
+  version "0.14.5"
+  resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
+
+type-check@~0.3.2:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
+  dependencies:
+    prelude-ls "~1.1.2"
+
+ua-parser-js@^0.7.9:
+  version "0.7.12"
+  resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb"
+
+uglify-js@^2.6:
+  version "2.8.21"
+  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.21.tgz#1733f669ae6f82fc90c7b25ec0f5c783ee375314"
+  dependencies:
+    source-map "~0.5.1"
+    yargs "~3.10.0"
+  optionalDependencies:
+    uglify-to-browserify "~1.0.0"
+
+uglify-to-browserify@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7"
+
+uuid@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1"
+
+validate-npm-package-license@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc"
+  dependencies:
+    spdx-correct "~1.0.0"
+    spdx-expression-parse "~1.0.0"
+
+verror@1.3.6:
+  version "1.3.6"
+  resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c"
+  dependencies:
+    extsprintf "1.0.2"
+
+walker@~1.0.5:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb"
+  dependencies:
+    makeerror "1.0.x"
+
+watch@~0.10.0:
+  version "0.10.0"
+  resolved "https://registry.yarnpkg.com/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc"
+
+webidl-conversions@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
+
+webidl-conversions@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.1.tgz#8015a17ab83e7e1b311638486ace81da6ce206a0"
+
+whatwg-encoding@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.1.tgz#3c6c451a198ee7aec55b1ec61d0920c67801a5f4"
+  dependencies:
+    iconv-lite "0.4.13"
+
+whatwg-fetch@>=0.10.0:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84"
+
+whatwg-url@^4.3.0:
+  version "4.7.0"
+  resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-4.7.0.tgz#202035ac1955b087cdd20fa8b58ded3ab1cd2af5"
+  dependencies:
+    tr46 "~0.0.3"
+    webidl-conversions "^3.0.0"
+
+which-module@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
+
+which@^1.1.1, which@^1.2.12:
+  version "1.2.14"
+  resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5"
+  dependencies:
+    isexe "^2.0.0"
+
+window-size@0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
+
+wordwrap@0.0.2:
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
+
+wordwrap@~0.0.2:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
+
+wordwrap@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
+
+worker-farm@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.3.1.tgz#4333112bb49b17aa050b87895ca6b2cacf40e5ff"
+  dependencies:
+    errno ">=0.1.1 <0.2.0-0"
+    xtend ">=4.0.0 <4.1.0-0"
+
+wrap-ansi@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
+  dependencies:
+    string-width "^1.0.1"
+    strip-ansi "^3.0.1"
+
+wrappy@1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+
+xml-name-validator@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635"
+
+"xtend@>=4.0.0 <4.1.0-0":
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
+
+y18n@^3.2.1:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
+
+yargs-parser@^4.2.0:
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c"
+  dependencies:
+    camelcase "^3.0.0"
+
+yargs@^6.3.0:
+  version "6.6.0"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208"
+  dependencies:
+    camelcase "^3.0.0"
+    cliui "^3.2.0"
+    decamelize "^1.1.1"
+    get-caller-file "^1.0.1"
+    os-locale "^1.4.0"
+    read-pkg-up "^1.0.1"
+    require-directory "^2.1.1"
+    require-main-filename "^1.0.1"
+    set-blocking "^2.0.0"
+    string-width "^1.0.2"
+    which-module "^1.0.0"
+    y18n "^3.2.1"
+    yargs-parser "^4.2.0"
+
+yargs@~3.10.0:
+  version "3.10.0"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"
+  dependencies:
+    camelcase "^1.0.2"
+    cliui "^2.1.0"
+    decamelize "^1.0.0"
+    window-size "0.1.0"
diff --git a/addons/react-addons-transition-group/LICENSE b/addons/react-addons-transition-group/LICENSE
new file mode 100644
index 000000000000..91b8f6f76ff0
--- /dev/null
+++ b/addons/react-addons-transition-group/LICENSE
@@ -0,0 +1,31 @@
+BSD License
+
+For React software
+
+Copyright (c) 2013-present, Facebook, Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+ * Neither the name Facebook nor the names of its contributors may be used to
+   endorse or promote products derived from this software without specific
+   prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/addons/react-addons-transition-group/PATENTS b/addons/react-addons-transition-group/PATENTS
new file mode 100644
index 000000000000..9c9f8e87a8f4
--- /dev/null
+++ b/addons/react-addons-transition-group/PATENTS
@@ -0,0 +1,33 @@
+Additional Grant of Patent Rights Version 2
+
+"Software" means the React software distributed by Facebook, Inc.
+
+Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software
+("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable
+(subject to the termination provision below) license under any Necessary
+Claims, to make, have made, use, sell, offer to sell, import, and otherwise
+transfer the Software. For avoidance of doubt, no license is granted under
+Facebook's rights in any patent claims that are infringed by (i) modifications
+to the Software made by you or any third party or (ii) the Software in
+combination with any software or other technology.
+
+The license granted hereunder will terminate, automatically and without notice,
+if you (or any of your subsidiaries, corporate affiliates or agents) initiate
+directly or indirectly, or take a direct financial interest in, any Patent
+Assertion: (i) against Facebook or any of its subsidiaries or corporate
+affiliates, (ii) against any party if such Patent Assertion arises in whole or
+in part from any software, technology, product or service of Facebook or any of
+its subsidiaries or corporate affiliates, or (iii) against any party relating
+to the Software. Notwithstanding the foregoing, if Facebook or any of its
+subsidiaries or corporate affiliates files a lawsuit alleging patent
+infringement against you in the first instance, and you respond by filing a
+patent infringement counterclaim in that lawsuit against that party that is
+unrelated to the Software, the license granted hereunder will not terminate
+under section (i) of this paragraph due to such counterclaim.
+
+A "Necessary Claim" is a claim of a patent owned by Facebook that is
+necessarily infringed by the Software standing alone.
+
+A "Patent Assertion" is any lawsuit or other action alleging direct, indirect,
+or contributory infringement or inducement to infringe any patent, including a
+cross-claim or counterclaim.
diff --git a/addons/react-addons-transition-group/README.md b/addons/react-addons-transition-group/README.md
new file mode 100644
index 000000000000..e2083f6d49cd
--- /dev/null
+++ b/addons/react-addons-transition-group/README.md
@@ -0,0 +1,17 @@
+# react-addons-transition-group
+
+The code in this package has moved. We recommend you to use `TransitionGroup` from [`react-transition-group`](https://github.com/reactjs/react-transition-group) instead.
+
+In particular, its version `1.x` is a drop-in replacement for the last released version of `react-addons-transition-group`.
+
+Run `npm install --save react-transition-group@1.x`, and replace the imports in your code:
+
+```js
+// Old
+import TransitionGroup from 'react-addons-transition-group';
+
+// New
+import TransitionGroup from 'react-transition-group/TransitionGroup';
+```
+
+The documentation branch for `react-transition-group@1.x` [can be found here](https://github.com/reactjs/react-transition-group/tree/v1-stable#low-level-api-transitiongroup).
diff --git a/addons/react-addons-transition-group/index.js b/addons/react-addons-transition-group/index.js
new file mode 100644
index 000000000000..630abb192753
--- /dev/null
+++ b/addons/react-addons-transition-group/index.js
@@ -0,0 +1,12 @@
+/**
+ * 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.
+ */
+
+'use strict';
+
+module.exports = require('react-transition-group/TransitionGroup');
diff --git a/addons/react-addons-transition-group/package.json b/addons/react-addons-transition-group/package.json
new file mode 100644
index 000000000000..9d05813aad29
--- /dev/null
+++ b/addons/react-addons-transition-group/package.json
@@ -0,0 +1,26 @@
+{
+  "name": "react-addons-transition-group",
+  "version": "15.6.0",
+  "main": "index.js",
+  "repository": "facebook/react",
+  "keywords": [
+    "react",
+    "react-addon"
+  ],
+  "license": "BSD-3-Clause",
+  "dependencies": {
+    "react-transition-group": "^1.2.0"
+  },
+  "peerDependencies": {
+    "react": "^15.4.2"
+  },
+  "scripts": {
+    "prepublish": ":"
+  },
+  "files": [
+    "LICENSE",
+    "PATENTS",
+    "README.md",
+    "index.js"
+  ]
+}
diff --git a/addons/react-addons-transition-group/yarn.lock b/addons/react-addons-transition-group/yarn.lock
new file mode 100644
index 000000000000..a451c1bc8bbd
--- /dev/null
+++ b/addons/react-addons-transition-group/yarn.lock
@@ -0,0 +1,114 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+asap@~2.0.3:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f"
+
+chain-function@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/chain-function/-/chain-function-1.0.0.tgz#0d4ab37e7e18ead0bdc47b920764118ce58733dc"
+
+core-js@^1.0.0:
+  version "1.2.7"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
+
+dom-helpers@^3.2.0:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.2.1.tgz#3203e07fed217bd1f424b019735582fc37b2825a"
+
+encoding@^0.1.11:
+  version "0.1.12"
+  resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb"
+  dependencies:
+    iconv-lite "~0.4.13"
+
+fbjs@^0.8.9:
+  version "0.8.12"
+  resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.12.tgz#10b5d92f76d45575fd63a217d4ea02bea2f8ed04"
+  dependencies:
+    core-js "^1.0.0"
+    isomorphic-fetch "^2.1.1"
+    loose-envify "^1.0.0"
+    object-assign "^4.1.0"
+    promise "^7.1.1"
+    setimmediate "^1.0.5"
+    ua-parser-js "^0.7.9"
+
+iconv-lite@~0.4.13:
+  version "0.4.17"
+  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.17.tgz#4fdaa3b38acbc2c031b045d0edcdfe1ecab18c8d"
+
+is-stream@^1.0.1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
+
+isomorphic-fetch@^2.1.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
+  dependencies:
+    node-fetch "^1.0.1"
+    whatwg-fetch ">=0.10.0"
+
+js-tokens@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7"
+
+loose-envify@^1.0.0, loose-envify@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
+  dependencies:
+    js-tokens "^3.0.0"
+
+node-fetch@^1.0.1:
+  version "1.7.1"
+  resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.1.tgz#899cb3d0a3c92f952c47f1b876f4c8aeabd400d5"
+  dependencies:
+    encoding "^0.1.11"
+    is-stream "^1.0.1"
+
+object-assign@^4.1.0:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+
+promise@^7.1.1:
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/promise/-/promise-7.1.1.tgz#489654c692616b8aa55b0724fa809bb7db49c5bf"
+  dependencies:
+    asap "~2.0.3"
+
+prop-types@^15.5.6:
+  version "15.5.10"
+  resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.10.tgz#2797dfc3126182e3a95e3dfbb2e893ddd7456154"
+  dependencies:
+    fbjs "^0.8.9"
+    loose-envify "^1.3.1"
+
+react-transition-group@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-1.2.0.tgz#b51fc921b0c3835a7ef7c571c79fc82c73e9204f"
+  dependencies:
+    chain-function "^1.0.0"
+    dom-helpers "^3.2.0"
+    loose-envify "^1.3.1"
+    prop-types "^15.5.6"
+    warning "^3.0.0"
+
+setimmediate@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
+
+ua-parser-js@^0.7.9:
+  version "0.7.12"
+  resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb"
+
+warning@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c"
+  dependencies:
+    loose-envify "^1.0.0"
+
+whatwg-fetch@>=0.10.0:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84"
diff --git a/addons/react-addons-update/.gitignore b/addons/react-addons-update/.gitignore
new file mode 100644
index 000000000000..35e4014513cc
--- /dev/null
+++ b/addons/react-addons-update/.gitignore
@@ -0,0 +1,2 @@
+react-addons-update.js
+react-addons-update.min.js
diff --git a/addons/react-addons-update/LICENSE.txt b/addons/react-addons-update/LICENSE.txt
new file mode 100644
index 000000000000..91b8f6f76ff0
--- /dev/null
+++ b/addons/react-addons-update/LICENSE.txt
@@ -0,0 +1,31 @@
+BSD License
+
+For React software
+
+Copyright (c) 2013-present, Facebook, Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+ * Neither the name Facebook nor the names of its contributors may be used to
+   endorse or promote products derived from this software without specific
+   prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/addons/react-addons-update/PATENTS b/addons/react-addons-update/PATENTS
new file mode 100644
index 000000000000..9c9f8e87a8f4
--- /dev/null
+++ b/addons/react-addons-update/PATENTS
@@ -0,0 +1,33 @@
+Additional Grant of Patent Rights Version 2
+
+"Software" means the React software distributed by Facebook, Inc.
+
+Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software
+("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable
+(subject to the termination provision below) license under any Necessary
+Claims, to make, have made, use, sell, offer to sell, import, and otherwise
+transfer the Software. For avoidance of doubt, no license is granted under
+Facebook's rights in any patent claims that are infringed by (i) modifications
+to the Software made by you or any third party or (ii) the Software in
+combination with any software or other technology.
+
+The license granted hereunder will terminate, automatically and without notice,
+if you (or any of your subsidiaries, corporate affiliates or agents) initiate
+directly or indirectly, or take a direct financial interest in, any Patent
+Assertion: (i) against Facebook or any of its subsidiaries or corporate
+affiliates, (ii) against any party if such Patent Assertion arises in whole or
+in part from any software, technology, product or service of Facebook or any of
+its subsidiaries or corporate affiliates, or (iii) against any party relating
+to the Software. Notwithstanding the foregoing, if Facebook or any of its
+subsidiaries or corporate affiliates files a lawsuit alleging patent
+infringement against you in the first instance, and you respond by filing a
+patent infringement counterclaim in that lawsuit against that party that is
+unrelated to the Software, the license granted hereunder will not terminate
+under section (i) of this paragraph due to such counterclaim.
+
+A "Necessary Claim" is a claim of a patent owned by Facebook that is
+necessarily infringed by the Software standing alone.
+
+A "Patent Assertion" is any lawsuit or other action alleging direct, indirect,
+or contributory infringement or inducement to infringe any patent, including a
+cross-claim or counterclaim.
diff --git a/addons/react-addons-update/README.md b/addons/react-addons-update/README.md
new file mode 100644
index 000000000000..1b8b934729aa
--- /dev/null
+++ b/addons/react-addons-update/README.md
@@ -0,0 +1,125 @@
+# react-addons-update
+
+>**Note:**
+>This is a legacy React addon, and is no longer maintained.
+>
+>We don't encourage using it in new code, but it exists for backwards compatibility.  
+>The recommended migration path is to use [`immutability-helper`](https://github.com/kolodny/immutability-helper). Its version `1.0.0` is a drop-in replacement.
+
+**Importing**
+
+```javascript
+import update from 'react-addons-update'; // ES6
+var update = require('react-addons-update'); // ES5 with npm
+```
+
+If you prefer a `<script>` tag, you can get it from `React.addons.update` with:
+
+```html
+<!-- development version -->
+<script src="https://unpkg.com/react-addons-update/react-addons-update.js"></script>
+
+<!-- production version -->
+<script src="https://unpkg.com/react-addons-update/react-addons-update.min.js"></script>
+```
+
+In this case, make sure to put the `<script>` tag after React.
+
+## Overview
+
+React lets you use whatever style of data management you want, including mutation. However, if you can use immutable data in performance-critical parts of your application it's easy to implement a fast [`shouldComponentUpdate()`](https://facebook.github.io/react/docs/react-component.html#shouldcomponentupdate) method to significantly speed up your app.
+
+Dealing with immutable data in JavaScript is more difficult than in languages designed for it, like [Clojure](http://clojure.org/). However, we've provided a simple immutability helper, `update()`, that makes dealing with this type of data much easier, *without* fundamentally changing how your data is represented. You can also take a look at Facebook's [Immutable-js](https://facebook.github.io/immutable-js/docs/) and the [Optimizing Performance](https://facebook.github.io/react/docs/optimizing-performance.html) section for more detail on Immutable-js.
+
+### The Main Idea
+
+If you mutate data like this:
+
+```js
+myData.x.y.z = 7;
+// or...
+myData.a.b.push(9);
+```
+
+You have no way of determining which data has changed since the previous copy has been overwritten. Instead, you need to create a new copy of `myData` and change only the parts of it that need to be changed. Then you can compare the old copy of `myData` with the new one in `shouldComponentUpdate()` using triple-equals:
+
+```js
+const newData = deepCopy(myData);
+newData.x.y.z = 7;
+newData.a.b.push(9);
+```
+
+Unfortunately, deep copies are expensive, and sometimes impossible. You can alleviate this by only copying objects that need to be changed and by reusing the objects that haven't changed. Unfortunately, in today's JavaScript this can be cumbersome:
+
+```js
+const newData = extend(myData, {
+  x: extend(myData.x, {
+    y: extend(myData.x.y, {z: 7}),
+  }),
+  a: extend(myData.a, {b: myData.a.b.concat(9)})
+});
+```
+
+While this is fairly performant (since it only makes a shallow copy of `log n` objects and reuses the rest), it's a big pain to write. Look at all the repetition! This is not only annoying, but also provides a large surface area for bugs.
+
+## `update()`
+
+`update()` provides simple syntactic sugar around this pattern to make writing this code easier. This code becomes:
+
+```js
+import update from 'react-addons-update';
+
+const newData = update(myData, {
+  x: {y: {z: {$set: 7}}},
+  a: {b: {$push: [9]}}
+});
+```
+
+While the syntax takes a little getting used to (though it's inspired by [MongoDB's query language](http://docs.mongodb.org/manual/core/crud-introduction/#query)) there's no redundancy, it's statically analyzable and it's not much more typing than the mutative version.
+
+The `$`-prefixed keys are called *commands*. The data structure they are "mutating" is called the *target*.
+
+## Available Commands
+
+  * `{$push: array}` `push()` all the items in `array` on the target.
+  * `{$unshift: array}` `unshift()` all the items in `array` on the target.
+  * `{$splice: array of arrays}` for each item in `arrays` call `splice()` on the target with the parameters provided by the item.
+  * `{$set: any}` replace the target entirely.
+  * `{$merge: object}` merge the keys of `object` with the target.
+  * `{$apply: function}` passes in the current value to the function and updates it with the new returned value.
+
+## Examples
+
+### Simple push
+
+```js
+const initialArray = [1, 2, 3];
+const newArray = update(initialArray, {$push: [4]}); // => [1, 2, 3, 4]
+```
+`initialArray` is still `[1, 2, 3]`.
+
+### Nested collections
+
+```js
+const collection = [1, 2, {a: [12, 17, 15]}];
+const newCollection = update(collection, {2: {a: {$splice: [[1, 1, 13, 14]]}}});
+// => [1, 2, {a: [12, 13, 14, 15]}]
+```
+This accesses `collection`'s index `2`, key `a`, and does a splice of one item starting from index `1` (to remove `17`) while inserting `13` and `14`.
+
+### Updating a value based on its current one
+
+```js
+const obj = {a: 5, b: 3};
+const newObj = update(obj, {b: {$apply: function(x) {return x * 2;}}});
+// => {a: 5, b: 6}
+// This is equivalent, but gets verbose for deeply nested collections:
+const newObj2 = update(obj, {b: {$set: obj.b * 2}});
+```
+
+### (Shallow) Merge
+
+```js
+const obj = {a: 5, b: 3};
+const newObj = update(obj, {$merge: {b: 6, c: 7}}); // => {a: 5, b: 6, c: 7}
+```
diff --git a/addons/react-addons-update/index.js b/addons/react-addons-update/index.js
new file mode 100644
index 000000000000..3bf4998714a5
--- /dev/null
+++ b/addons/react-addons-update/index.js
@@ -0,0 +1,166 @@
+/**
+ * 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.
+ */
+
+'use strict';
+
+var _assign = require('object-assign');
+var invariant = require('fbjs/lib/invariant');
+var hasOwnProperty = {}.hasOwnProperty;
+
+function shallowCopy(x) {
+  if (Array.isArray(x)) {
+    return x.concat();
+  } else if (x && typeof x === 'object') {
+    return _assign(new x.constructor(), x);
+  } else {
+    return x;
+  }
+}
+
+var COMMAND_PUSH = '$push';
+var COMMAND_UNSHIFT = '$unshift';
+var COMMAND_SPLICE = '$splice';
+var COMMAND_SET = '$set';
+var COMMAND_MERGE = '$merge';
+var COMMAND_APPLY = '$apply';
+
+var ALL_COMMANDS_LIST = [
+  COMMAND_PUSH,
+  COMMAND_UNSHIFT,
+  COMMAND_SPLICE,
+  COMMAND_SET,
+  COMMAND_MERGE,
+  COMMAND_APPLY
+];
+
+var ALL_COMMANDS_SET = {};
+
+ALL_COMMANDS_LIST.forEach(function(command) {
+  ALL_COMMANDS_SET[command] = true;
+});
+
+function invariantArrayCase(value, spec, command) {
+  invariant(
+    Array.isArray(value),
+    'update(): expected target of %s to be an array; got %s.',
+    command,
+    value
+  );
+  var specValue = spec[command];
+  invariant(
+    Array.isArray(specValue),
+    'update(): expected spec of %s to be an array; got %s. ' +
+      'Did you forget to wrap your parameter in an array?',
+    command,
+    specValue
+  );
+}
+
+/**
+ * Returns a updated shallow copy of an object without mutating the original.
+ * See https://facebook.github.io/react/docs/update.html for details.
+ */
+function update(value, spec) {
+  invariant(
+    typeof spec === 'object',
+    'update(): You provided a key path to update() that did not contain one ' +
+      'of %s. Did you forget to include {%s: ...}?',
+    ALL_COMMANDS_LIST.join(', '),
+    COMMAND_SET
+  );
+
+  if (hasOwnProperty.call(spec, COMMAND_SET)) {
+    invariant(
+      Object.keys(spec).length === 1,
+      'Cannot have more than one key in an object with %s',
+      COMMAND_SET
+    );
+
+    return spec[COMMAND_SET];
+  }
+
+  var nextValue = shallowCopy(value);
+
+  if (hasOwnProperty.call(spec, COMMAND_MERGE)) {
+    var mergeObj = spec[COMMAND_MERGE];
+    invariant(
+      mergeObj && typeof mergeObj === 'object',
+      "update(): %s expects a spec of type 'object'; got %s",
+      COMMAND_MERGE,
+      mergeObj
+    );
+    invariant(
+      nextValue && typeof nextValue === 'object',
+      "update(): %s expects a target of type 'object'; got %s",
+      COMMAND_MERGE,
+      nextValue
+    );
+    _assign(nextValue, spec[COMMAND_MERGE]);
+  }
+
+  if (hasOwnProperty.call(spec, COMMAND_PUSH)) {
+    invariantArrayCase(value, spec, COMMAND_PUSH);
+    spec[COMMAND_PUSH].forEach(function(item) {
+      nextValue.push(item);
+    });
+  }
+
+  if (hasOwnProperty.call(spec, COMMAND_UNSHIFT)) {
+    invariantArrayCase(value, spec, COMMAND_UNSHIFT);
+    spec[COMMAND_UNSHIFT].forEach(function(item) {
+      nextValue.unshift(item);
+    });
+  }
+
+  if (hasOwnProperty.call(spec, COMMAND_SPLICE)) {
+    invariant(
+      Array.isArray(value),
+      'Expected %s target to be an array; got %s',
+      COMMAND_SPLICE,
+      value
+    );
+    invariant(
+      Array.isArray(spec[COMMAND_SPLICE]),
+      'update(): expected spec of %s to be an array of arrays; got %s. ' +
+        'Did you forget to wrap your parameters in an array?',
+      COMMAND_SPLICE,
+      spec[COMMAND_SPLICE]
+    );
+    spec[COMMAND_SPLICE].forEach(function(args) {
+      invariant(
+        Array.isArray(args),
+        'update(): expected spec of %s to be an array of arrays; got %s. ' +
+          'Did you forget to wrap your parameters in an array?',
+        COMMAND_SPLICE,
+        spec[COMMAND_SPLICE]
+      );
+      nextValue.splice.apply(nextValue, args);
+    });
+  }
+
+  if (hasOwnProperty.call(spec, COMMAND_APPLY)) {
+    invariant(
+      typeof spec[COMMAND_APPLY] === 'function',
+      'update(): expected spec of %s to be a function; got %s.',
+      COMMAND_APPLY,
+      spec[COMMAND_APPLY]
+    );
+    nextValue = spec[COMMAND_APPLY](nextValue);
+  }
+
+  for (var k in spec) {
+    if (!(ALL_COMMANDS_SET.hasOwnProperty(k) && ALL_COMMANDS_SET[k])) {
+      nextValue[k] = update(value[k], spec[k]);
+    }
+  }
+
+  return nextValue;
+}
+
+module.exports = update;
diff --git a/addons/react-addons-update/package.json b/addons/react-addons-update/package.json
new file mode 100644
index 000000000000..98203ed73e9d
--- /dev/null
+++ b/addons/react-addons-update/package.json
@@ -0,0 +1,34 @@
+{
+  "name": "react-addons-update",
+  "version": "15.6.0",
+  "main": "index.js",
+  "repository": "facebook/react",
+  "keywords": [
+    "react",
+    "react-addon"
+  ],
+  "license": "BSD-3-Clause",
+  "dependencies": {
+    "fbjs": "^0.8.9",
+    "object-assign": "^4.1.0"
+  },
+  "devDependencies": {
+    "jest": "^19.0.2",
+    "webpack": "^2.6.1"
+  },
+  "scripts": {
+    "test": "TEST_ENTRY=./index.js jest",
+    "build:dev": "NODE_ENV=development webpack && TEST_ENTRY=./react-addons-update.js jest",
+    "build:prod": "NODE_ENV=production webpack && NODE_ENV=production TEST_ENTRY=./react-addons-update.min.js jest",
+    "build": "npm run build:dev && npm run build:prod && node ../postbuild.js",
+    "prepublish": "npm test && npm run build"
+  },
+  "files": [
+    "LICENSE",
+    "PATENTS",
+    "README.md",
+    "index.js",
+    "react-addons-update.js",
+    "react-addons-update.min.js"
+  ]
+}
diff --git a/addons/react-addons-update/test.js b/addons/react-addons-update/test.js
new file mode 100644
index 000000000000..02151df4c7e6
--- /dev/null
+++ b/addons/react-addons-update/test.js
@@ -0,0 +1,112 @@
+/**
+ * Copyright 2015-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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+// Catch stray warnings
+var env = jasmine.getEnv();
+var callCount = 0;
+var oldError = console.error;
+var newError = function() {
+  callCount++;
+  oldError.apply(this, arguments);
+};
+console.error = newError;
+env.beforeEach(() => {
+  callCount = 0;
+  jasmine.addMatchers({
+    toBeReset() {
+      return {
+        compare(actual) {
+          if (actual !== newError && !jasmine.isSpy(actual)) {
+            return {
+              pass: false,
+              message: 'Test did not tear down console.error mock properly.'
+            };
+          }
+          return {pass: true};
+        }
+      };
+    },
+    toNotHaveBeenCalled() {
+      return {
+        compare(actual) {
+          return {
+            pass: callCount === 0,
+            message:
+              'Expected test not to warn. If the warning is expected, mock ' +
+                "it out using spyOn(console, 'error'); and test that the " +
+                'warning occurs.'
+          };
+        }
+      };
+    }
+  });
+});
+env.afterEach(() => {
+  expect(console.error).toBeReset();
+  expect(console.error).toNotHaveBeenCalled();
+});
+
+const update = require(process.env.TEST_ENTRY);
+
+describe('update', () => {
+  // https://facebook.github.io/react/docs/update.html#simple-push
+  it('should support simple push', () => {
+    const array = [1, 2, 3];
+
+    const newArray = update(array, {$push: [4]});
+    expect(array).toEqual([1, 2, 3]);
+
+    expect(newArray).toEqual([1, 2, 3, 4]);
+  });
+
+  // https://facebook.github.io/react/docs/update.html#nested-collections
+  it('should support nested collections', () => {
+    const collection = [1, 2, {a: [12, 17, 15]}];
+
+    const newCollection = update(collection, {
+      2: {a: {$splice: [[1, 1, 13, 14]]}}
+    });
+    expect(collection).toEqual([1, 2, {a: [12, 17, 15]}]);
+
+    expect(newCollection).toEqual([1, 2, {a: [12, 13, 14, 15]}]);
+  });
+
+  // https://facebook.github.io/react/docs/update.html#updating-a-value-based-on-its-current-one
+  it('should support updating a value based on its current one', () => {
+    const obj = {a: 5, b: 3};
+
+    const newObj = update(obj, {
+      b: {
+        $apply: function(x) {
+          return x * 2;
+        }
+      }
+    });
+    expect(newObj).toEqual({a: 5, b: 6});
+
+    const newObj2 = update(obj, {b: {$set: obj.b * 2}});
+    expect(newObj2).toEqual({a: 5, b: 6});
+
+    expect(obj).toEqual({a: 5, b: 3});
+  });
+
+  // https://facebook.github.io/react/docs/update.html#shallow-merge
+  it('should support shallow merge', () => {
+    const obj = {a: 5, b: 3};
+
+    const newObj = update(obj, {$merge: {b: 6, c: 7}});
+    expect(newObj).toEqual({a: 5, b: 6, c: 7});
+
+    expect(obj).toEqual({a: 5, b: 3});
+  });
+});
diff --git a/addons/react-addons-update/webpack.config.js b/addons/react-addons-update/webpack.config.js
new file mode 100644
index 000000000000..1a24cc4917b9
--- /dev/null
+++ b/addons/react-addons-update/webpack.config.js
@@ -0,0 +1,53 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+const webpack = require('webpack');
+
+let __DEV__;
+switch (process.env.NODE_ENV) {
+  case 'development':
+    __DEV__ = true;
+    break;
+  case 'production':
+    __DEV__ = false;
+    break;
+  default:
+    throw new Error('Unknown environment.');
+}
+
+module.exports = {
+  entry: './index',
+  output: {
+    library: 'update',
+    libraryTarget: 'umd',
+    filename: __DEV__ ? 'react-addons-update.js' : 'react-addons-update.min.js'
+  },
+  plugins: [
+    new webpack.DefinePlugin({
+      'process.env.NODE_ENV': __DEV__ ? '"development"' : '"production"'
+    })
+  ].concat(
+    __DEV__
+      ? []
+      : [
+          new webpack.optimize.UglifyJsPlugin({
+            compress: {
+              warnings: false
+            },
+            output: {
+              comments: false
+            }
+          })
+        ]
+  )
+};
diff --git a/addons/react-addons-update/yarn.lock b/addons/react-addons-update/yarn.lock
new file mode 100644
index 000000000000..7c249bfe8926
--- /dev/null
+++ b/addons/react-addons-update/yarn.lock
@@ -0,0 +1,2811 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+abab@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.3.tgz#b81de5f7274ec4e756d797cd834f303642724e5d"
+
+abbrev@1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f"
+
+acorn-dynamic-import@^2.0.0:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz#c752bd210bef679501b6c6cb7fc84f8f47158cc4"
+  dependencies:
+    acorn "^4.0.3"
+
+acorn-globals@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-3.1.0.tgz#fd8270f71fbb4996b004fa880ee5d46573a731bf"
+  dependencies:
+    acorn "^4.0.4"
+
+acorn@^4.0.3, acorn@^4.0.4:
+  version "4.0.11"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.11.tgz#edcda3bd937e7556410d42ed5860f67399c794c0"
+
+acorn@^5.0.0:
+  version "5.0.3"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.0.3.tgz#c460df08491463f028ccb82eab3730bf01087b3d"
+
+ajv-keywords@^1.1.1:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c"
+
+ajv@^4.7.0, ajv@^4.9.1:
+  version "4.11.5"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.5.tgz#b6ee74657b993a01dce44b7944d56f485828d5bd"
+  dependencies:
+    co "^4.6.0"
+    json-stable-stringify "^1.0.1"
+
+align-text@^0.1.1, align-text@^0.1.3:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
+  dependencies:
+    kind-of "^3.0.2"
+    longest "^1.0.1"
+    repeat-string "^1.5.2"
+
+amdefine@>=0.0.4:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
+
+ansi-escapes@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
+
+ansi-regex@^2.0.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
+
+ansi-styles@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
+
+ansi-styles@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.0.0.tgz#5404e93a544c4fec7f048262977bebfe3155e0c1"
+  dependencies:
+    color-convert "^1.0.0"
+
+anymatch@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507"
+  dependencies:
+    arrify "^1.0.0"
+    micromatch "^2.1.5"
+
+append-transform@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-0.4.0.tgz#d76ebf8ca94d276e247a36bad44a4b74ab611991"
+  dependencies:
+    default-require-extensions "^1.0.0"
+
+aproba@^1.0.3:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.2.tgz#45c6629094de4e96f693ef7eab74ae079c240fc1"
+
+are-we-there-yet@~1.1.2:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d"
+  dependencies:
+    delegates "^1.0.0"
+    readable-stream "^2.0.6"
+
+argparse@^1.0.7:
+  version "1.0.9"
+  resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86"
+  dependencies:
+    sprintf-js "~1.0.2"
+
+arr-diff@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf"
+  dependencies:
+    arr-flatten "^1.0.1"
+
+arr-flatten@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b"
+
+array-equal@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93"
+
+array-unique@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
+
+arrify@^1.0.0, arrify@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
+
+asap@~2.0.3:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f"
+
+asn1.js@^4.0.0:
+  version "4.9.1"
+  resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.1.tgz#48ba240b45a9280e94748990ba597d216617fd40"
+  dependencies:
+    bn.js "^4.0.0"
+    inherits "^2.0.1"
+    minimalistic-assert "^1.0.0"
+
+asn1@~0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86"
+
+assert-plus@1.0.0, assert-plus@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
+
+assert-plus@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234"
+
+assert@^1.1.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91"
+  dependencies:
+    util "0.10.3"
+
+async-each@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
+
+async@^1.4.0:
+  version "1.5.2"
+  resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
+
+async@^2.1.2, async@^2.1.4:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/async/-/async-2.3.0.tgz#1013d1051047dd320fe24e494d5c66ecaf6147d9"
+  dependencies:
+    lodash "^4.14.0"
+
+asynckit@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+
+aws-sign2@~0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f"
+
+aws4@^1.2.1:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e"
+
+babel-code-frame@^6.22.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4"
+  dependencies:
+    chalk "^1.1.0"
+    esutils "^2.0.2"
+    js-tokens "^3.0.0"
+
+babel-core@^6.0.0, babel-core@^6.24.0:
+  version "6.24.0"
+  resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.24.0.tgz#8f36a0a77f5c155aed6f920b844d23ba56742a02"
+  dependencies:
+    babel-code-frame "^6.22.0"
+    babel-generator "^6.24.0"
+    babel-helpers "^6.23.0"
+    babel-messages "^6.23.0"
+    babel-register "^6.24.0"
+    babel-runtime "^6.22.0"
+    babel-template "^6.23.0"
+    babel-traverse "^6.23.1"
+    babel-types "^6.23.0"
+    babylon "^6.11.0"
+    convert-source-map "^1.1.0"
+    debug "^2.1.1"
+    json5 "^0.5.0"
+    lodash "^4.2.0"
+    minimatch "^3.0.2"
+    path-is-absolute "^1.0.0"
+    private "^0.1.6"
+    slash "^1.0.0"
+    source-map "^0.5.0"
+
+babel-generator@^6.18.0, babel-generator@^6.24.0:
+  version "6.24.0"
+  resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.24.0.tgz#eba270a8cc4ce6e09a61be43465d7c62c1f87c56"
+  dependencies:
+    babel-messages "^6.23.0"
+    babel-runtime "^6.22.0"
+    babel-types "^6.23.0"
+    detect-indent "^4.0.0"
+    jsesc "^1.3.0"
+    lodash "^4.2.0"
+    source-map "^0.5.0"
+    trim-right "^1.0.1"
+
+babel-helpers@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.23.0.tgz#4f8f2e092d0b6a8808a4bde79c27f1e2ecf0d992"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-template "^6.23.0"
+
+babel-jest@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-19.0.0.tgz#59323ced99a3a84d359da219ca881074ffc6ce3f"
+  dependencies:
+    babel-core "^6.0.0"
+    babel-plugin-istanbul "^4.0.0"
+    babel-preset-jest "^19.0.0"
+
+babel-messages@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e"
+  dependencies:
+    babel-runtime "^6.22.0"
+
+babel-plugin-istanbul@^4.0.0:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.1.tgz#c12de0fc6fe42adfb16be56f1ad11e4a9782eca9"
+  dependencies:
+    find-up "^2.1.0"
+    istanbul-lib-instrument "^1.6.2"
+    test-exclude "^4.0.3"
+
+babel-plugin-jest-hoist@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-19.0.0.tgz#4ae2a04ea612a6e73651f3fde52c178991304bea"
+
+babel-preset-jest@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-19.0.0.tgz#22d67201d02324a195811288eb38294bb3cac396"
+  dependencies:
+    babel-plugin-jest-hoist "^19.0.0"
+
+babel-register@^6.24.0:
+  version "6.24.0"
+  resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.24.0.tgz#5e89f8463ba9970356d02eb07dabe3308b080cfd"
+  dependencies:
+    babel-core "^6.24.0"
+    babel-runtime "^6.22.0"
+    core-js "^2.4.0"
+    home-or-tmp "^2.0.0"
+    lodash "^4.2.0"
+    mkdirp "^0.5.1"
+    source-map-support "^0.4.2"
+
+babel-runtime@^6.22.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b"
+  dependencies:
+    core-js "^2.4.0"
+    regenerator-runtime "^0.10.0"
+
+babel-template@^6.16.0, babel-template@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.23.0.tgz#04d4f270adbb3aa704a8143ae26faa529238e638"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-traverse "^6.23.0"
+    babel-types "^6.23.0"
+    babylon "^6.11.0"
+    lodash "^4.2.0"
+
+babel-traverse@^6.18.0, babel-traverse@^6.23.0, babel-traverse@^6.23.1:
+  version "6.23.1"
+  resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.23.1.tgz#d3cb59010ecd06a97d81310065f966b699e14f48"
+  dependencies:
+    babel-code-frame "^6.22.0"
+    babel-messages "^6.23.0"
+    babel-runtime "^6.22.0"
+    babel-types "^6.23.0"
+    babylon "^6.15.0"
+    debug "^2.2.0"
+    globals "^9.0.0"
+    invariant "^2.2.0"
+    lodash "^4.2.0"
+
+babel-types@^6.18.0, babel-types@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.23.0.tgz#bb17179d7538bad38cd0c9e115d340f77e7e9acf"
+  dependencies:
+    babel-runtime "^6.22.0"
+    esutils "^2.0.2"
+    lodash "^4.2.0"
+    to-fast-properties "^1.0.1"
+
+babylon@^6.11.0, babylon@^6.13.0, babylon@^6.15.0:
+  version "6.16.1"
+  resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.16.1.tgz#30c5a22f481978a9e7f8cdfdf496b11d94b404d3"
+
+balanced-match@^0.4.1:
+  version "0.4.2"
+  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
+
+base64-js@^1.0.2:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1"
+
+bcrypt-pbkdf@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d"
+  dependencies:
+    tweetnacl "^0.14.3"
+
+big.js@^3.1.3:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.1.3.tgz#4cada2193652eb3ca9ec8e55c9015669c9806978"
+
+binary-extensions@^1.0.0:
+  version "1.8.0"
+  resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.8.0.tgz#48ec8d16df4377eae5fa5884682480af4d95c774"
+
+block-stream@*:
+  version "0.0.9"
+  resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a"
+  dependencies:
+    inherits "~2.0.0"
+
+bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0:
+  version "4.11.6"
+  resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215"
+
+boom@2.x.x:
+  version "2.10.1"
+  resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f"
+  dependencies:
+    hoek "2.x.x"
+
+brace-expansion@^1.0.0:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9"
+  dependencies:
+    balanced-match "^0.4.1"
+    concat-map "0.0.1"
+
+braces@^1.8.2:
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7"
+  dependencies:
+    expand-range "^1.8.1"
+    preserve "^0.2.0"
+    repeat-element "^1.1.2"
+
+brorand@^1.0.1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
+
+browser-resolve@^1.11.2:
+  version "1.11.2"
+  resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.2.tgz#8ff09b0a2c421718a1051c260b32e48f442938ce"
+  dependencies:
+    resolve "1.1.7"
+
+browserify-aes@^1.0.0, browserify-aes@^1.0.4:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.0.6.tgz#5e7725dbdef1fd5930d4ebab48567ce451c48a0a"
+  dependencies:
+    buffer-xor "^1.0.2"
+    cipher-base "^1.0.0"
+    create-hash "^1.1.0"
+    evp_bytestokey "^1.0.0"
+    inherits "^2.0.1"
+
+browserify-cipher@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.0.tgz#9988244874bf5ed4e28da95666dcd66ac8fc363a"
+  dependencies:
+    browserify-aes "^1.0.4"
+    browserify-des "^1.0.0"
+    evp_bytestokey "^1.0.0"
+
+browserify-des@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.0.tgz#daa277717470922ed2fe18594118a175439721dd"
+  dependencies:
+    cipher-base "^1.0.1"
+    des.js "^1.0.0"
+    inherits "^2.0.1"
+
+browserify-rsa@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524"
+  dependencies:
+    bn.js "^4.1.0"
+    randombytes "^2.0.1"
+
+browserify-sign@^4.0.0:
+  version "4.0.4"
+  resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298"
+  dependencies:
+    bn.js "^4.1.1"
+    browserify-rsa "^4.0.0"
+    create-hash "^1.1.0"
+    create-hmac "^1.1.2"
+    elliptic "^6.0.0"
+    inherits "^2.0.1"
+    parse-asn1 "^5.0.0"
+
+browserify-zlib@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d"
+  dependencies:
+    pako "~0.2.0"
+
+bser@1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/bser/-/bser-1.0.2.tgz#381116970b2a6deea5646dd15dd7278444b56169"
+  dependencies:
+    node-int64 "^0.4.0"
+
+bser@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719"
+  dependencies:
+    node-int64 "^0.4.0"
+
+buffer-xor@^1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9"
+
+buffer@^4.3.0:
+  version "4.9.1"
+  resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298"
+  dependencies:
+    base64-js "^1.0.2"
+    ieee754 "^1.1.4"
+    isarray "^1.0.0"
+
+builtin-modules@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
+
+builtin-status-codes@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
+
+callsites@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50"
+
+camelcase@^1.0.2:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39"
+
+camelcase@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
+
+caseless@~0.12.0:
+  version "0.12.0"
+  resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
+
+center-align@^0.1.1:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad"
+  dependencies:
+    align-text "^0.1.3"
+    lazy-cache "^1.0.3"
+
+chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
+  dependencies:
+    ansi-styles "^2.2.1"
+    escape-string-regexp "^1.0.2"
+    has-ansi "^2.0.0"
+    strip-ansi "^3.0.0"
+    supports-color "^2.0.0"
+
+chokidar@^1.4.3:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
+  dependencies:
+    anymatch "^1.3.0"
+    async-each "^1.0.0"
+    glob-parent "^2.0.0"
+    inherits "^2.0.1"
+    is-binary-path "^1.0.0"
+    is-glob "^2.0.0"
+    path-is-absolute "^1.0.0"
+    readdirp "^2.0.0"
+  optionalDependencies:
+    fsevents "^1.0.0"
+
+ci-info@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.0.0.tgz#dc5285f2b4e251821683681c381c3388f46ec534"
+
+cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.3.tgz#eeabf194419ce900da3018c207d212f2a6df0a07"
+  dependencies:
+    inherits "^2.0.1"
+
+cliui@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1"
+  dependencies:
+    center-align "^0.1.1"
+    right-align "^0.1.1"
+    wordwrap "0.0.2"
+
+cliui@^3.2.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
+  dependencies:
+    string-width "^1.0.1"
+    strip-ansi "^3.0.1"
+    wrap-ansi "^2.0.0"
+
+co@^4.6.0:
+  version "4.6.0"
+  resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
+
+code-point-at@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
+
+color-convert@^1.0.0:
+  version "1.9.0"
+  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a"
+  dependencies:
+    color-name "^1.1.1"
+
+color-name@^1.1.1:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.2.tgz#5c8ab72b64bd2215d617ae9559ebb148475cf98d"
+
+combined-stream@^1.0.5, combined-stream@~1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009"
+  dependencies:
+    delayed-stream "~1.0.0"
+
+concat-map@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+
+console-browserify@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10"
+  dependencies:
+    date-now "^0.1.4"
+
+console-control-strings@^1.0.0, console-control-strings@~1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
+
+constants-browserify@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
+
+content-type-parser@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/content-type-parser/-/content-type-parser-1.0.1.tgz#c3e56988c53c65127fb46d4032a3a900246fdc94"
+
+convert-source-map@^1.1.0:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5"
+
+core-js@^1.0.0:
+  version "1.2.7"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
+
+core-js@^2.4.0:
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e"
+
+core-util-is@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
+
+create-ecdh@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.0.tgz#888c723596cdf7612f6498233eebd7a35301737d"
+  dependencies:
+    bn.js "^4.1.0"
+    elliptic "^6.0.0"
+
+create-hash@^1.1.0, create-hash@^1.1.1, create-hash@^1.1.2:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.3.tgz#606042ac8b9262750f483caddab0f5819172d8fd"
+  dependencies:
+    cipher-base "^1.0.1"
+    inherits "^2.0.1"
+    ripemd160 "^2.0.0"
+    sha.js "^2.4.0"
+
+create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.6.tgz#acb9e221a4e17bdb076e90657c42b93e3726cf06"
+  dependencies:
+    cipher-base "^1.0.3"
+    create-hash "^1.1.0"
+    inherits "^2.0.1"
+    ripemd160 "^2.0.0"
+    safe-buffer "^5.0.1"
+    sha.js "^2.4.8"
+
+cryptiles@2.x.x:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8"
+  dependencies:
+    boom "2.x.x"
+
+crypto-browserify@^3.11.0:
+  version "3.11.0"
+  resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.11.0.tgz#3652a0906ab9b2a7e0c3ce66a408e957a2485522"
+  dependencies:
+    browserify-cipher "^1.0.0"
+    browserify-sign "^4.0.0"
+    create-ecdh "^4.0.0"
+    create-hash "^1.1.0"
+    create-hmac "^1.1.0"
+    diffie-hellman "^5.0.0"
+    inherits "^2.0.1"
+    pbkdf2 "^3.0.3"
+    public-encrypt "^4.0.0"
+    randombytes "^2.0.0"
+
+cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0":
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.2.tgz#b8036170c79f07a90ff2f16e22284027a243848b"
+
+"cssstyle@>= 0.2.37 < 0.3.0":
+  version "0.2.37"
+  resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-0.2.37.tgz#541097234cb2513c83ceed3acddc27ff27987d54"
+  dependencies:
+    cssom "0.3.x"
+
+dashdash@^1.12.0:
+  version "1.14.1"
+  resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
+  dependencies:
+    assert-plus "^1.0.0"
+
+date-now@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
+
+debug@^2.1.1, debug@^2.2.0:
+  version "2.6.3"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.3.tgz#0f7eb8c30965ec08c72accfa0130c8b79984141d"
+  dependencies:
+    ms "0.7.2"
+
+decamelize@^1.0.0, decamelize@^1.1.1:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
+
+deep-extend@~0.4.0:
+  version "0.4.2"
+  resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f"
+
+deep-is@~0.1.3:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
+
+default-require-extensions@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8"
+  dependencies:
+    strip-bom "^2.0.0"
+
+delayed-stream@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+
+delegates@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
+
+des.js@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc"
+  dependencies:
+    inherits "^2.0.1"
+    minimalistic-assert "^1.0.0"
+
+detect-indent@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208"
+  dependencies:
+    repeating "^2.0.0"
+
+diff@^3.0.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9"
+
+diffie-hellman@^5.0.0:
+  version "5.0.2"
+  resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.2.tgz#b5835739270cfe26acf632099fded2a07f209e5e"
+  dependencies:
+    bn.js "^4.1.0"
+    miller-rabin "^4.0.0"
+    randombytes "^2.0.0"
+
+domain-browser@^1.1.1:
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc"
+
+ecc-jsbn@~0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505"
+  dependencies:
+    jsbn "~0.1.0"
+
+elliptic@^6.0.0:
+  version "6.4.0"
+  resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df"
+  dependencies:
+    bn.js "^4.4.0"
+    brorand "^1.0.1"
+    hash.js "^1.0.0"
+    hmac-drbg "^1.0.0"
+    inherits "^2.0.1"
+    minimalistic-assert "^1.0.0"
+    minimalistic-crypto-utils "^1.0.0"
+
+emojis-list@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
+
+encoding@^0.1.11:
+  version "0.1.12"
+  resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb"
+  dependencies:
+    iconv-lite "~0.4.13"
+
+enhanced-resolve@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.1.0.tgz#9f4b626f577245edcf4b2ad83d86e17f4f421dec"
+  dependencies:
+    graceful-fs "^4.1.2"
+    memory-fs "^0.4.0"
+    object-assign "^4.0.1"
+    tapable "^0.2.5"
+
+"errno@>=0.1.1 <0.2.0-0", errno@^0.1.3:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d"
+  dependencies:
+    prr "~0.0.0"
+
+error-ex@^1.2.0:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc"
+  dependencies:
+    is-arrayish "^0.2.1"
+
+escape-string-regexp@^1.0.2:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+
+escodegen@^1.6.1:
+  version "1.8.1"
+  resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018"
+  dependencies:
+    esprima "^2.7.1"
+    estraverse "^1.9.1"
+    esutils "^2.0.2"
+    optionator "^0.8.1"
+  optionalDependencies:
+    source-map "~0.2.0"
+
+esprima@^2.7.1:
+  version "2.7.3"
+  resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
+
+esprima@^3.1.1:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633"
+
+estraverse@^1.9.1:
+  version "1.9.3"
+  resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44"
+
+esutils@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
+
+events@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924"
+
+evp_bytestokey@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.0.tgz#497b66ad9fef65cd7c08a6180824ba1476b66e53"
+  dependencies:
+    create-hash "^1.1.1"
+
+exec-sh@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.0.tgz#14f75de3f20d286ef933099b2ce50a90359cef10"
+  dependencies:
+    merge "^1.1.3"
+
+expand-brackets@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
+  dependencies:
+    is-posix-bracket "^0.1.0"
+
+expand-range@^1.8.1:
+  version "1.8.2"
+  resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337"
+  dependencies:
+    fill-range "^2.1.0"
+
+extend@~3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4"
+
+extglob@^0.3.1:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1"
+  dependencies:
+    is-extglob "^1.0.0"
+
+extsprintf@1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550"
+
+fast-levenshtein@~2.0.4:
+  version "2.0.6"
+  resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
+
+fb-watchman@^1.8.0:
+  version "1.9.2"
+  resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-1.9.2.tgz#a24cf47827f82d38fb59a69ad70b76e3b6ae7383"
+  dependencies:
+    bser "1.0.2"
+
+fb-watchman@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58"
+  dependencies:
+    bser "^2.0.0"
+
+fbjs@^0.8.9:
+  version "0.8.12"
+  resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.12.tgz#10b5d92f76d45575fd63a217d4ea02bea2f8ed04"
+  dependencies:
+    core-js "^1.0.0"
+    isomorphic-fetch "^2.1.1"
+    loose-envify "^1.0.0"
+    object-assign "^4.1.0"
+    promise "^7.1.1"
+    setimmediate "^1.0.5"
+    ua-parser-js "^0.7.9"
+
+filename-regex@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775"
+
+fileset@^2.0.2:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/fileset/-/fileset-2.0.3.tgz#8e7548a96d3cc2327ee5e674168723a333bba2a0"
+  dependencies:
+    glob "^7.0.3"
+    minimatch "^3.0.3"
+
+fill-range@^2.1.0:
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723"
+  dependencies:
+    is-number "^2.1.0"
+    isobject "^2.0.0"
+    randomatic "^1.1.3"
+    repeat-element "^1.1.2"
+    repeat-string "^1.5.2"
+
+find-up@^1.0.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
+  dependencies:
+    path-exists "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+find-up@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
+  dependencies:
+    locate-path "^2.0.0"
+
+for-in@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
+
+for-own@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce"
+  dependencies:
+    for-in "^1.0.1"
+
+forever-agent@~0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
+
+form-data@~2.1.1:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4"
+  dependencies:
+    asynckit "^0.4.0"
+    combined-stream "^1.0.5"
+    mime-types "^2.1.12"
+
+fs.realpath@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+
+fsevents@^1.0.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.2.tgz#3282b713fb3ad80ede0e9fcf4611b5aa6fc033f4"
+  dependencies:
+    nan "^2.3.0"
+    node-pre-gyp "^0.6.36"
+
+fstream-ignore@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105"
+  dependencies:
+    fstream "^1.0.0"
+    inherits "2"
+    minimatch "^3.0.0"
+
+fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2:
+  version "1.0.11"
+  resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171"
+  dependencies:
+    graceful-fs "^4.1.2"
+    inherits "~2.0.0"
+    mkdirp ">=0.5 0"
+    rimraf "2"
+
+gauge@~2.7.3:
+  version "2.7.4"
+  resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
+  dependencies:
+    aproba "^1.0.3"
+    console-control-strings "^1.0.0"
+    has-unicode "^2.0.0"
+    object-assign "^4.1.0"
+    signal-exit "^3.0.0"
+    string-width "^1.0.1"
+    strip-ansi "^3.0.1"
+    wide-align "^1.1.0"
+
+get-caller-file@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5"
+
+getpass@^0.1.1:
+  version "0.1.6"
+  resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6"
+  dependencies:
+    assert-plus "^1.0.0"
+
+glob-base@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
+  dependencies:
+    glob-parent "^2.0.0"
+    is-glob "^2.0.0"
+
+glob-parent@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28"
+  dependencies:
+    is-glob "^2.0.0"
+
+glob@^7.0.3, glob@^7.0.5:
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
+  dependencies:
+    fs.realpath "^1.0.0"
+    inflight "^1.0.4"
+    inherits "2"
+    minimatch "^3.0.2"
+    once "^1.3.0"
+    path-is-absolute "^1.0.0"
+
+globals@^9.0.0:
+  version "9.17.0"
+  resolved "https://registry.yarnpkg.com/globals/-/globals-9.17.0.tgz#0c0ca696d9b9bb694d2e5470bd37777caad50286"
+
+graceful-fs@^4.1.2, graceful-fs@^4.1.6:
+  version "4.1.11"
+  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
+
+growly@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
+
+handlebars@^4.0.3:
+  version "4.0.6"
+  resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7"
+  dependencies:
+    async "^1.4.0"
+    optimist "^0.6.1"
+    source-map "^0.4.4"
+  optionalDependencies:
+    uglify-js "^2.6"
+
+har-schema@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e"
+
+har-validator@~4.2.1:
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a"
+  dependencies:
+    ajv "^4.9.1"
+    har-schema "^1.0.5"
+
+has-ansi@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
+  dependencies:
+    ansi-regex "^2.0.0"
+
+has-flag@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
+
+has-unicode@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
+
+hash-base@^2.0.0:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1"
+  dependencies:
+    inherits "^2.0.1"
+
+hash.js@^1.0.0, hash.js@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.0.3.tgz#1332ff00156c0a0ffdd8236013d07b77a0451573"
+  dependencies:
+    inherits "^2.0.1"
+
+hawk@~3.1.3:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4"
+  dependencies:
+    boom "2.x.x"
+    cryptiles "2.x.x"
+    hoek "2.x.x"
+    sntp "1.x.x"
+
+hmac-drbg@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
+  dependencies:
+    hash.js "^1.0.3"
+    minimalistic-assert "^1.0.0"
+    minimalistic-crypto-utils "^1.0.1"
+
+hoek@2.x.x:
+  version "2.16.3"
+  resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed"
+
+home-or-tmp@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8"
+  dependencies:
+    os-homedir "^1.0.0"
+    os-tmpdir "^1.0.1"
+
+hosted-git-info@^2.1.4:
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.4.1.tgz#4b0445e41c004a8bd1337773a4ff790ca40318c8"
+
+html-encoding-sniffer@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.1.tgz#79bf7a785ea495fe66165e734153f363ff5437da"
+  dependencies:
+    whatwg-encoding "^1.0.1"
+
+http-signature@~1.1.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf"
+  dependencies:
+    assert-plus "^0.2.0"
+    jsprim "^1.2.2"
+    sshpk "^1.7.0"
+
+https-browserify@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82"
+
+iconv-lite@0.4.13:
+  version "0.4.13"
+  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2"
+
+iconv-lite@~0.4.13:
+  version "0.4.15"
+  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb"
+
+ieee754@^1.1.4:
+  version "1.1.8"
+  resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4"
+
+indexof@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d"
+
+inflight@^1.0.4:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+  dependencies:
+    once "^1.3.0"
+    wrappy "1"
+
+inherits@2, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
+
+inherits@2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
+
+ini@~1.3.0:
+  version "1.3.4"
+  resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e"
+
+interpret@^1.0.0:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.3.tgz#cbc35c62eeee73f19ab7b10a801511401afc0f90"
+
+invariant@^2.2.0:
+  version "2.2.2"
+  resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360"
+  dependencies:
+    loose-envify "^1.0.0"
+
+invert-kv@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
+
+is-arrayish@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
+
+is-binary-path@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
+  dependencies:
+    binary-extensions "^1.0.0"
+
+is-buffer@^1.0.2:
+  version "1.1.5"
+  resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc"
+
+is-builtin-module@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe"
+  dependencies:
+    builtin-modules "^1.0.0"
+
+is-ci@^1.0.9:
+  version "1.0.10"
+  resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.0.10.tgz#f739336b2632365061a9d48270cd56ae3369318e"
+  dependencies:
+    ci-info "^1.0.0"
+
+is-dotfile@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d"
+
+is-equal-shallow@^0.1.3:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534"
+  dependencies:
+    is-primitive "^2.0.0"
+
+is-extendable@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
+
+is-extglob@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
+
+is-finite@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa"
+  dependencies:
+    number-is-nan "^1.0.0"
+
+is-fullwidth-code-point@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
+  dependencies:
+    number-is-nan "^1.0.0"
+
+is-glob@^2.0.0, is-glob@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
+  dependencies:
+    is-extglob "^1.0.0"
+
+is-number@^2.0.2, is-number@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
+  dependencies:
+    kind-of "^3.0.2"
+
+is-posix-bracket@^0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
+
+is-primitive@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
+
+is-stream@^1.0.1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
+
+is-typedarray@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
+
+is-utf8@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
+
+isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
+
+isexe@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+
+isobject@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
+  dependencies:
+    isarray "1.0.0"
+
+isomorphic-fetch@^2.1.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
+  dependencies:
+    node-fetch "^1.0.1"
+    whatwg-fetch ">=0.10.0"
+
+isstream@~0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
+
+istanbul-api@^1.1.0-alpha.1:
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-1.1.7.tgz#f6f37f09f8002b130f891c646b70ee4a8e7345ae"
+  dependencies:
+    async "^2.1.4"
+    fileset "^2.0.2"
+    istanbul-lib-coverage "^1.0.2"
+    istanbul-lib-hook "^1.0.5"
+    istanbul-lib-instrument "^1.7.0"
+    istanbul-lib-report "^1.0.0"
+    istanbul-lib-source-maps "^1.1.1"
+    istanbul-reports "^1.0.2"
+    js-yaml "^3.7.0"
+    mkdirp "^0.5.1"
+    once "^1.4.0"
+
+istanbul-lib-coverage@^1.0.0, istanbul-lib-coverage@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.0.2.tgz#87a0c015b6910651cb3b184814dfb339337e25e1"
+
+istanbul-lib-hook@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.0.5.tgz#6ca3d16d60c5f4082da39f7c5cd38ea8a772b88e"
+  dependencies:
+    append-transform "^0.4.0"
+
+istanbul-lib-instrument@^1.1.1, istanbul-lib-instrument@^1.6.2, istanbul-lib-instrument@^1.7.0:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.7.0.tgz#b8e0dc25709bb44e17336ab47b7bb5c97c23f659"
+  dependencies:
+    babel-generator "^6.18.0"
+    babel-template "^6.16.0"
+    babel-traverse "^6.18.0"
+    babel-types "^6.18.0"
+    babylon "^6.13.0"
+    istanbul-lib-coverage "^1.0.2"
+    semver "^5.3.0"
+
+istanbul-lib-report@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.0.0.tgz#d83dac7f26566b521585569367fe84ccfc7aaecb"
+  dependencies:
+    istanbul-lib-coverage "^1.0.2"
+    mkdirp "^0.5.1"
+    path-parse "^1.0.5"
+    supports-color "^3.1.2"
+
+istanbul-lib-source-maps@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.1.1.tgz#f8c8c2e8f2160d1d91526d97e5bd63b2079af71c"
+  dependencies:
+    istanbul-lib-coverage "^1.0.2"
+    mkdirp "^0.5.1"
+    rimraf "^2.4.4"
+    source-map "^0.5.3"
+
+istanbul-reports@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.0.2.tgz#4e8366abe6fa746cc1cd6633f108de12cc6ac6fa"
+  dependencies:
+    handlebars "^4.0.3"
+
+jest-changed-files@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-19.0.2.tgz#16c54c84c3270be408e06d2e8af3f3e37a885824"
+
+jest-cli@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-19.0.2.tgz#cc3620b62acac5f2d93a548cb6ef697d4ec85443"
+  dependencies:
+    ansi-escapes "^1.4.0"
+    callsites "^2.0.0"
+    chalk "^1.1.1"
+    graceful-fs "^4.1.6"
+    is-ci "^1.0.9"
+    istanbul-api "^1.1.0-alpha.1"
+    istanbul-lib-coverage "^1.0.0"
+    istanbul-lib-instrument "^1.1.1"
+    jest-changed-files "^19.0.2"
+    jest-config "^19.0.2"
+    jest-environment-jsdom "^19.0.2"
+    jest-haste-map "^19.0.0"
+    jest-jasmine2 "^19.0.2"
+    jest-message-util "^19.0.0"
+    jest-regex-util "^19.0.0"
+    jest-resolve-dependencies "^19.0.0"
+    jest-runtime "^19.0.2"
+    jest-snapshot "^19.0.2"
+    jest-util "^19.0.2"
+    micromatch "^2.3.11"
+    node-notifier "^5.0.1"
+    slash "^1.0.0"
+    string-length "^1.0.1"
+    throat "^3.0.0"
+    which "^1.1.1"
+    worker-farm "^1.3.1"
+    yargs "^6.3.0"
+
+jest-config@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-19.0.2.tgz#1b9bd2db0ddd16df61c2b10a54009e1768da6411"
+  dependencies:
+    chalk "^1.1.1"
+    jest-environment-jsdom "^19.0.2"
+    jest-environment-node "^19.0.2"
+    jest-jasmine2 "^19.0.2"
+    jest-regex-util "^19.0.0"
+    jest-resolve "^19.0.2"
+    jest-validate "^19.0.2"
+    pretty-format "^19.0.0"
+
+jest-diff@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-19.0.0.tgz#d1563cfc56c8b60232988fbc05d4d16ed90f063c"
+  dependencies:
+    chalk "^1.1.3"
+    diff "^3.0.0"
+    jest-matcher-utils "^19.0.0"
+    pretty-format "^19.0.0"
+
+jest-environment-jsdom@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-19.0.2.tgz#ceda859c4a4b94ab35e4de7dab54b926f293e4a3"
+  dependencies:
+    jest-mock "^19.0.0"
+    jest-util "^19.0.2"
+    jsdom "^9.11.0"
+
+jest-environment-node@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-19.0.2.tgz#6e84079db87ed21d0c05e1f9669f207b116fe99b"
+  dependencies:
+    jest-mock "^19.0.0"
+    jest-util "^19.0.2"
+
+jest-file-exists@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-file-exists/-/jest-file-exists-19.0.0.tgz#cca2e587a11ec92e24cfeab3f8a94d657f3fceb8"
+
+jest-haste-map@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-19.0.0.tgz#adde00b62b1fe04432a104b3254fc5004514b55e"
+  dependencies:
+    fb-watchman "^2.0.0"
+    graceful-fs "^4.1.6"
+    micromatch "^2.3.11"
+    sane "~1.5.0"
+    worker-farm "^1.3.1"
+
+jest-jasmine2@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-19.0.2.tgz#167991ac825981fb1a800af126e83afcca832c73"
+  dependencies:
+    graceful-fs "^4.1.6"
+    jest-matcher-utils "^19.0.0"
+    jest-matchers "^19.0.0"
+    jest-message-util "^19.0.0"
+    jest-snapshot "^19.0.2"
+
+jest-matcher-utils@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-19.0.0.tgz#5ecd9b63565d2b001f61fbf7ec4c7f537964564d"
+  dependencies:
+    chalk "^1.1.3"
+    pretty-format "^19.0.0"
+
+jest-matchers@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-matchers/-/jest-matchers-19.0.0.tgz#c74ecc6ebfec06f384767ba4d6fa4a42d6755754"
+  dependencies:
+    jest-diff "^19.0.0"
+    jest-matcher-utils "^19.0.0"
+    jest-message-util "^19.0.0"
+    jest-regex-util "^19.0.0"
+
+jest-message-util@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-19.0.0.tgz#721796b89c0e4d761606f9ba8cb828a3b6246416"
+  dependencies:
+    chalk "^1.1.1"
+    micromatch "^2.3.11"
+
+jest-mock@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-19.0.0.tgz#67038641e9607ab2ce08ec4a8cb83aabbc899d01"
+
+jest-regex-util@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-19.0.0.tgz#b7754587112aede1456510bb1f6afe74ef598691"
+
+jest-resolve-dependencies@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-19.0.0.tgz#a741ad1fa094140e64ecf2642a504f834ece22ee"
+  dependencies:
+    jest-file-exists "^19.0.0"
+
+jest-resolve@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-19.0.2.tgz#5793575de4f07aec32f7d7ff0c6c181963eefb3c"
+  dependencies:
+    browser-resolve "^1.11.2"
+    jest-haste-map "^19.0.0"
+    resolve "^1.2.0"
+
+jest-runtime@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-19.0.2.tgz#d9a43e72de416d27d196fd9c7940d98fe6685407"
+  dependencies:
+    babel-core "^6.0.0"
+    babel-jest "^19.0.0"
+    babel-plugin-istanbul "^4.0.0"
+    chalk "^1.1.3"
+    graceful-fs "^4.1.6"
+    jest-config "^19.0.2"
+    jest-file-exists "^19.0.0"
+    jest-haste-map "^19.0.0"
+    jest-regex-util "^19.0.0"
+    jest-resolve "^19.0.2"
+    jest-util "^19.0.2"
+    json-stable-stringify "^1.0.1"
+    micromatch "^2.3.11"
+    strip-bom "3.0.0"
+    yargs "^6.3.0"
+
+jest-snapshot@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-19.0.2.tgz#9c1b216214f7187c38bfd5c70b1efab16b0ff50b"
+  dependencies:
+    chalk "^1.1.3"
+    jest-diff "^19.0.0"
+    jest-file-exists "^19.0.0"
+    jest-matcher-utils "^19.0.0"
+    jest-util "^19.0.2"
+    natural-compare "^1.4.0"
+    pretty-format "^19.0.0"
+
+jest-util@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-19.0.2.tgz#e0a0232a2ab9e6b2b53668bdb3534c2b5977ed41"
+  dependencies:
+    chalk "^1.1.1"
+    graceful-fs "^4.1.6"
+    jest-file-exists "^19.0.0"
+    jest-message-util "^19.0.0"
+    jest-mock "^19.0.0"
+    jest-validate "^19.0.2"
+    leven "^2.0.0"
+    mkdirp "^0.5.1"
+
+jest-validate@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-19.0.2.tgz#dc534df5f1278d5b63df32b14241d4dbf7244c0c"
+  dependencies:
+    chalk "^1.1.1"
+    jest-matcher-utils "^19.0.0"
+    leven "^2.0.0"
+    pretty-format "^19.0.0"
+
+jest@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest/-/jest-19.0.2.tgz#b794faaf8ff461e7388f28beef559a54f20b2c10"
+  dependencies:
+    jest-cli "^19.0.2"
+
+jodid25519@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967"
+  dependencies:
+    jsbn "~0.1.0"
+
+js-tokens@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7"
+
+js-yaml@^3.7.0:
+  version "3.8.3"
+  resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.3.tgz#33a05ec481c850c8875929166fe1beb61c728766"
+  dependencies:
+    argparse "^1.0.7"
+    esprima "^3.1.1"
+
+jsbn@~0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
+
+jsdom@^9.11.0:
+  version "9.12.0"
+  resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-9.12.0.tgz#e8c546fffcb06c00d4833ca84410fed7f8a097d4"
+  dependencies:
+    abab "^1.0.3"
+    acorn "^4.0.4"
+    acorn-globals "^3.1.0"
+    array-equal "^1.0.0"
+    content-type-parser "^1.0.1"
+    cssom ">= 0.3.2 < 0.4.0"
+    cssstyle ">= 0.2.37 < 0.3.0"
+    escodegen "^1.6.1"
+    html-encoding-sniffer "^1.0.1"
+    nwmatcher ">= 1.3.9 < 2.0.0"
+    parse5 "^1.5.1"
+    request "^2.79.0"
+    sax "^1.2.1"
+    symbol-tree "^3.2.1"
+    tough-cookie "^2.3.2"
+    webidl-conversions "^4.0.0"
+    whatwg-encoding "^1.0.1"
+    whatwg-url "^4.3.0"
+    xml-name-validator "^2.0.1"
+
+jsesc@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b"
+
+json-loader@^0.5.4:
+  version "0.5.4"
+  resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.4.tgz#8baa1365a632f58a3c46d20175fc6002c96e37de"
+
+json-schema@0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
+
+json-stable-stringify@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af"
+  dependencies:
+    jsonify "~0.0.0"
+
+json-stringify-safe@~5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
+
+json5@^0.5.0, json5@^0.5.1:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
+
+jsonify@~0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
+
+jsprim@^1.2.2:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.0.tgz#a3b87e40298d8c380552d8cc7628a0bb95a22918"
+  dependencies:
+    assert-plus "1.0.0"
+    extsprintf "1.0.2"
+    json-schema "0.2.3"
+    verror "1.3.6"
+
+kind-of@^3.0.2:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47"
+  dependencies:
+    is-buffer "^1.0.2"
+
+lazy-cache@^1.0.3:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
+
+lcid@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
+  dependencies:
+    invert-kv "^1.0.0"
+
+leven@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580"
+
+levn@~0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
+  dependencies:
+    prelude-ls "~1.1.2"
+    type-check "~0.3.2"
+
+load-json-file@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
+  dependencies:
+    graceful-fs "^4.1.2"
+    parse-json "^2.2.0"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+    strip-bom "^2.0.0"
+
+loader-runner@^2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2"
+
+loader-utils@^0.2.16:
+  version "0.2.17"
+  resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348"
+  dependencies:
+    big.js "^3.1.3"
+    emojis-list "^2.0.0"
+    json5 "^0.5.0"
+    object-assign "^4.0.1"
+
+locate-path@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
+  dependencies:
+    p-locate "^2.0.0"
+    path-exists "^3.0.0"
+
+lodash@^4.14.0, lodash@^4.2.0:
+  version "4.17.4"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
+
+longest@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
+
+loose-envify@^1.0.0:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
+  dependencies:
+    js-tokens "^3.0.0"
+
+makeerror@1.0.x:
+  version "1.0.11"
+  resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c"
+  dependencies:
+    tmpl "1.0.x"
+
+memory-fs@^0.4.0, memory-fs@~0.4.1:
+  version "0.4.1"
+  resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"
+  dependencies:
+    errno "^0.1.3"
+    readable-stream "^2.0.1"
+
+merge@^1.1.3:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da"
+
+micromatch@^2.1.5, micromatch@^2.3.11:
+  version "2.3.11"
+  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
+  dependencies:
+    arr-diff "^2.0.0"
+    array-unique "^0.2.1"
+    braces "^1.8.2"
+    expand-brackets "^0.1.4"
+    extglob "^0.3.1"
+    filename-regex "^2.0.0"
+    is-extglob "^1.0.0"
+    is-glob "^2.0.1"
+    kind-of "^3.0.2"
+    normalize-path "^2.0.1"
+    object.omit "^2.0.0"
+    parse-glob "^3.0.4"
+    regex-cache "^0.4.2"
+
+miller-rabin@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.0.tgz#4a62fb1d42933c05583982f4c716f6fb9e6c6d3d"
+  dependencies:
+    bn.js "^4.0.0"
+    brorand "^1.0.1"
+
+mime-db@~1.27.0:
+  version "1.27.0"
+  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1"
+
+mime-types@^2.1.12, mime-types@~2.1.7:
+  version "2.1.15"
+  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed"
+  dependencies:
+    mime-db "~1.27.0"
+
+minimalistic-assert@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3"
+
+minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
+
+minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774"
+  dependencies:
+    brace-expansion "^1.0.0"
+
+minimist@0.0.8, minimist@~0.0.1:
+  version "0.0.8"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
+
+minimist@^1.1.1, minimist@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
+
+"mkdirp@>=0.5 0", mkdirp@^0.5.1, mkdirp@~0.5.0:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
+  dependencies:
+    minimist "0.0.8"
+
+ms@0.7.2:
+  version "0.7.2"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765"
+
+nan@^2.3.0:
+  version "2.6.2"
+  resolved "https://registry.yarnpkg.com/nan/-/nan-2.6.2.tgz#e4ff34e6c95fdfb5aecc08de6596f43605a7db45"
+
+natural-compare@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
+
+node-fetch@^1.0.1:
+  version "1.6.3"
+  resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04"
+  dependencies:
+    encoding "^0.1.11"
+    is-stream "^1.0.1"
+
+node-int64@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
+
+node-libs-browser@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.0.0.tgz#a3a59ec97024985b46e958379646f96c4b616646"
+  dependencies:
+    assert "^1.1.1"
+    browserify-zlib "^0.1.4"
+    buffer "^4.3.0"
+    console-browserify "^1.1.0"
+    constants-browserify "^1.0.0"
+    crypto-browserify "^3.11.0"
+    domain-browser "^1.1.1"
+    events "^1.0.0"
+    https-browserify "0.0.1"
+    os-browserify "^0.2.0"
+    path-browserify "0.0.0"
+    process "^0.11.0"
+    punycode "^1.2.4"
+    querystring-es3 "^0.2.0"
+    readable-stream "^2.0.5"
+    stream-browserify "^2.0.1"
+    stream-http "^2.3.1"
+    string_decoder "^0.10.25"
+    timers-browserify "^2.0.2"
+    tty-browserify "0.0.0"
+    url "^0.11.0"
+    util "^0.10.3"
+    vm-browserify "0.0.4"
+
+node-notifier@^5.0.1:
+  version "5.1.2"
+  resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.1.2.tgz#2fa9e12605fa10009d44549d6fcd8a63dde0e4ff"
+  dependencies:
+    growly "^1.3.0"
+    semver "^5.3.0"
+    shellwords "^0.1.0"
+    which "^1.2.12"
+
+node-pre-gyp@^0.6.36:
+  version "0.6.36"
+  resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.36.tgz#db604112cb74e0d477554e9b505b17abddfab786"
+  dependencies:
+    mkdirp "^0.5.1"
+    nopt "^4.0.1"
+    npmlog "^4.0.2"
+    rc "^1.1.7"
+    request "^2.81.0"
+    rimraf "^2.6.1"
+    semver "^5.3.0"
+    tar "^2.2.1"
+    tar-pack "^3.4.0"
+
+nopt@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
+  dependencies:
+    abbrev "1"
+    osenv "^0.1.4"
+
+normalize-package-data@^2.3.2:
+  version "2.3.6"
+  resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.6.tgz#498fa420c96401f787402ba21e600def9f981fff"
+  dependencies:
+    hosted-git-info "^2.1.4"
+    is-builtin-module "^1.0.0"
+    semver "2 || 3 || 4 || 5"
+    validate-npm-package-license "^3.0.1"
+
+normalize-path@^2.0.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
+  dependencies:
+    remove-trailing-separator "^1.0.1"
+
+npmlog@^4.0.2:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.0.tgz#dc59bee85f64f00ed424efb2af0783df25d1c0b5"
+  dependencies:
+    are-we-there-yet "~1.1.2"
+    console-control-strings "~1.1.0"
+    gauge "~2.7.3"
+    set-blocking "~2.0.0"
+
+number-is-nan@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
+
+"nwmatcher@>= 1.3.9 < 2.0.0":
+  version "1.3.9"
+  resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.3.9.tgz#8bab486ff7fa3dfd086656bbe8b17116d3692d2a"
+
+oauth-sign@~0.8.1:
+  version "0.8.2"
+  resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
+
+object-assign@^4.0.1, object-assign@^4.1.0:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+
+object.omit@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
+  dependencies:
+    for-own "^0.1.4"
+    is-extendable "^0.1.1"
+
+once@^1.3.0, once@^1.3.3, once@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+  dependencies:
+    wrappy "1"
+
+optimist@^0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
+  dependencies:
+    minimist "~0.0.1"
+    wordwrap "~0.0.2"
+
+optionator@^0.8.1:
+  version "0.8.2"
+  resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64"
+  dependencies:
+    deep-is "~0.1.3"
+    fast-levenshtein "~2.0.4"
+    levn "~0.3.0"
+    prelude-ls "~1.1.2"
+    type-check "~0.3.2"
+    wordwrap "~1.0.0"
+
+os-browserify@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.2.1.tgz#63fc4ccee5d2d7763d26bbf8601078e6c2e0044f"
+
+os-homedir@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
+
+os-locale@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9"
+  dependencies:
+    lcid "^1.0.0"
+
+os-tmpdir@^1.0.0, os-tmpdir@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
+
+osenv@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644"
+  dependencies:
+    os-homedir "^1.0.0"
+    os-tmpdir "^1.0.0"
+
+p-limit@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.1.0.tgz#b07ff2d9a5d88bec806035895a2bab66a27988bc"
+
+p-locate@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
+  dependencies:
+    p-limit "^1.1.0"
+
+pako@~0.2.0:
+  version "0.2.9"
+  resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
+
+parse-asn1@^5.0.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712"
+  dependencies:
+    asn1.js "^4.0.0"
+    browserify-aes "^1.0.0"
+    create-hash "^1.1.0"
+    evp_bytestokey "^1.0.0"
+    pbkdf2 "^3.0.3"
+
+parse-glob@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
+  dependencies:
+    glob-base "^0.3.0"
+    is-dotfile "^1.0.0"
+    is-extglob "^1.0.0"
+    is-glob "^2.0.0"
+
+parse-json@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
+  dependencies:
+    error-ex "^1.2.0"
+
+parse5@^1.5.1:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94"
+
+path-browserify@0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a"
+
+path-exists@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
+  dependencies:
+    pinkie-promise "^2.0.0"
+
+path-exists@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
+
+path-is-absolute@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+
+path-parse@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1"
+
+path-type@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
+  dependencies:
+    graceful-fs "^4.1.2"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+pbkdf2@^3.0.3:
+  version "3.0.12"
+  resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.12.tgz#be36785c5067ea48d806ff923288c5f750b6b8a2"
+  dependencies:
+    create-hash "^1.1.2"
+    create-hmac "^1.1.4"
+    ripemd160 "^2.0.1"
+    safe-buffer "^5.0.1"
+    sha.js "^2.4.8"
+
+performance-now@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5"
+
+pify@^2.0.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
+
+pinkie-promise@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
+  dependencies:
+    pinkie "^2.0.0"
+
+pinkie@^2.0.0:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
+
+prelude-ls@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
+
+preserve@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
+
+pretty-format@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-19.0.0.tgz#56530d32acb98a3fa4851c4e2b9d37b420684c84"
+  dependencies:
+    ansi-styles "^3.0.0"
+
+private@^0.1.6:
+  version "0.1.7"
+  resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1"
+
+process-nextick-args@~1.0.6:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
+
+process@^0.11.0:
+  version "0.11.10"
+  resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
+
+promise@^7.1.1:
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/promise/-/promise-7.1.1.tgz#489654c692616b8aa55b0724fa809bb7db49c5bf"
+  dependencies:
+    asap "~2.0.3"
+
+prr@~0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a"
+
+public-encrypt@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.0.tgz#39f699f3a46560dd5ebacbca693caf7c65c18cc6"
+  dependencies:
+    bn.js "^4.1.0"
+    browserify-rsa "^4.0.0"
+    create-hash "^1.1.0"
+    parse-asn1 "^5.0.0"
+    randombytes "^2.0.1"
+
+punycode@1.3.2:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
+
+punycode@^1.2.4, punycode@^1.4.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
+
+qs@~6.4.0:
+  version "6.4.0"
+  resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
+
+querystring-es3@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
+
+querystring@0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
+
+randomatic@^1.1.3:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb"
+  dependencies:
+    is-number "^2.0.2"
+    kind-of "^3.0.2"
+
+randombytes@^2.0.0, randombytes@^2.0.1:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.5.tgz#dc009a246b8d09a177b4b7a0ae77bc570f4b1b79"
+  dependencies:
+    safe-buffer "^5.1.0"
+
+rc@^1.1.7:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.1.tgz#2e03e8e42ee450b8cb3dce65be1bf8974e1dfd95"
+  dependencies:
+    deep-extend "~0.4.0"
+    ini "~1.3.0"
+    minimist "^1.2.0"
+    strip-json-comments "~2.0.1"
+
+read-pkg-up@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
+  dependencies:
+    find-up "^1.0.0"
+    read-pkg "^1.0.0"
+
+read-pkg@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
+  dependencies:
+    load-json-file "^1.0.0"
+    normalize-package-data "^2.3.2"
+    path-type "^1.0.0"
+
+readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.2.6:
+  version "2.2.11"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.11.tgz#0796b31f8d7688007ff0b93a8088d34aa17c0f72"
+  dependencies:
+    core-util-is "~1.0.0"
+    inherits "~2.0.1"
+    isarray "~1.0.0"
+    process-nextick-args "~1.0.6"
+    safe-buffer "~5.0.1"
+    string_decoder "~1.0.0"
+    util-deprecate "~1.0.1"
+
+readdirp@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78"
+  dependencies:
+    graceful-fs "^4.1.2"
+    minimatch "^3.0.2"
+    readable-stream "^2.0.2"
+    set-immediate-shim "^1.0.1"
+
+regenerator-runtime@^0.10.0:
+  version "0.10.3"
+  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.3.tgz#8c4367a904b51ea62a908ac310bf99ff90a82a3e"
+
+regex-cache@^0.4.2:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145"
+  dependencies:
+    is-equal-shallow "^0.1.3"
+    is-primitive "^2.0.0"
+
+remove-trailing-separator@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.0.1.tgz#615ebb96af559552d4bf4057c8436d486ab63cc4"
+
+repeat-element@^1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a"
+
+repeat-string@^1.5.2:
+  version "1.6.1"
+  resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
+
+repeating@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda"
+  dependencies:
+    is-finite "^1.0.0"
+
+request@^2.79.0, request@^2.81.0:
+  version "2.81.0"
+  resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0"
+  dependencies:
+    aws-sign2 "~0.6.0"
+    aws4 "^1.2.1"
+    caseless "~0.12.0"
+    combined-stream "~1.0.5"
+    extend "~3.0.0"
+    forever-agent "~0.6.1"
+    form-data "~2.1.1"
+    har-validator "~4.2.1"
+    hawk "~3.1.3"
+    http-signature "~1.1.0"
+    is-typedarray "~1.0.0"
+    isstream "~0.1.2"
+    json-stringify-safe "~5.0.1"
+    mime-types "~2.1.7"
+    oauth-sign "~0.8.1"
+    performance-now "^0.2.0"
+    qs "~6.4.0"
+    safe-buffer "^5.0.1"
+    stringstream "~0.0.4"
+    tough-cookie "~2.3.0"
+    tunnel-agent "^0.6.0"
+    uuid "^3.0.0"
+
+require-directory@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
+
+require-main-filename@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
+
+resolve@1.1.7:
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
+
+resolve@^1.2.0:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.3.2.tgz#1f0442c9e0cbb8136e87b9305f932f46c7f28235"
+  dependencies:
+    path-parse "^1.0.5"
+
+right-align@^0.1.1:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef"
+  dependencies:
+    align-text "^0.1.1"
+
+rimraf@2, rimraf@^2.4.4, rimraf@^2.5.1, rimraf@^2.6.1:
+  version "2.6.1"
+  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d"
+  dependencies:
+    glob "^7.0.5"
+
+ripemd160@^2.0.0, ripemd160@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7"
+  dependencies:
+    hash-base "^2.0.0"
+    inherits "^2.0.1"
+
+safe-buffer@^5.0.1, safe-buffer@~5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7"
+
+safe-buffer@^5.1.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.0.tgz#fe4c8460397f9eaaaa58e73be46273408a45e223"
+
+sane@~1.5.0:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/sane/-/sane-1.5.0.tgz#a4adeae764d048621ecb27d5f9ecf513101939f3"
+  dependencies:
+    anymatch "^1.3.0"
+    exec-sh "^0.2.0"
+    fb-watchman "^1.8.0"
+    minimatch "^3.0.2"
+    minimist "^1.1.1"
+    walker "~1.0.5"
+    watch "~0.10.0"
+
+sax@^1.2.1:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.2.tgz#fd8631a23bc7826bef5d871bdb87378c95647828"
+
+"semver@2 || 3 || 4 || 5", semver@^5.3.0:
+  version "5.3.0"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
+
+set-blocking@^2.0.0, set-blocking@~2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
+
+set-immediate-shim@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61"
+
+setimmediate@^1.0.4, setimmediate@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
+
+sha.js@^2.4.0, sha.js@^2.4.8:
+  version "2.4.8"
+  resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.8.tgz#37068c2c476b6baf402d14a49c67f597921f634f"
+  dependencies:
+    inherits "^2.0.1"
+
+shellwords@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.0.tgz#66afd47b6a12932d9071cbfd98a52e785cd0ba14"
+
+signal-exit@^3.0.0:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
+
+slash@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
+
+sntp@1.x.x:
+  version "1.0.9"
+  resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198"
+  dependencies:
+    hoek "2.x.x"
+
+source-list-map@^1.1.1:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-1.1.2.tgz#9889019d1024cce55cdc069498337ef6186a11a1"
+
+source-map-support@^0.4.2:
+  version "0.4.14"
+  resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.14.tgz#9d4463772598b86271b4f523f6c1f4e02a7d6aef"
+  dependencies:
+    source-map "^0.5.6"
+
+source-map@^0.4.4:
+  version "0.4.4"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b"
+  dependencies:
+    amdefine ">=0.0.4"
+
+source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.3:
+  version "0.5.6"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
+
+source-map@~0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d"
+  dependencies:
+    amdefine ">=0.0.4"
+
+spdx-correct@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40"
+  dependencies:
+    spdx-license-ids "^1.0.2"
+
+spdx-expression-parse@~1.0.0:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c"
+
+spdx-license-ids@^1.0.2:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57"
+
+sprintf-js@~1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
+
+sshpk@^1.7.0:
+  version "1.11.0"
+  resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.11.0.tgz#2d8d5ebb4a6fab28ffba37fa62a90f4a3ea59d77"
+  dependencies:
+    asn1 "~0.2.3"
+    assert-plus "^1.0.0"
+    dashdash "^1.12.0"
+    getpass "^0.1.1"
+  optionalDependencies:
+    bcrypt-pbkdf "^1.0.0"
+    ecc-jsbn "~0.1.1"
+    jodid25519 "^1.0.0"
+    jsbn "~0.1.0"
+    tweetnacl "~0.14.0"
+
+stream-browserify@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db"
+  dependencies:
+    inherits "~2.0.1"
+    readable-stream "^2.0.2"
+
+stream-http@^2.3.1:
+  version "2.7.2"
+  resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.7.2.tgz#40a050ec8dc3b53b33d9909415c02c0bf1abfbad"
+  dependencies:
+    builtin-status-codes "^3.0.0"
+    inherits "^2.0.1"
+    readable-stream "^2.2.6"
+    to-arraybuffer "^1.0.0"
+    xtend "^4.0.0"
+
+string-length@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/string-length/-/string-length-1.0.1.tgz#56970fb1c38558e9e70b728bf3de269ac45adfac"
+  dependencies:
+    strip-ansi "^3.0.0"
+
+string-width@^1.0.1, string-width@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
+  dependencies:
+    code-point-at "^1.0.0"
+    is-fullwidth-code-point "^1.0.0"
+    strip-ansi "^3.0.0"
+
+string_decoder@^0.10.25:
+  version "0.10.31"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
+
+string_decoder@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.2.tgz#b29e1f4e1125fa97a10382b8a533737b7491e179"
+  dependencies:
+    safe-buffer "~5.0.1"
+
+stringstream@~0.0.4:
+  version "0.0.5"
+  resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878"
+
+strip-ansi@^3.0.0, strip-ansi@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
+  dependencies:
+    ansi-regex "^2.0.0"
+
+strip-bom@3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
+
+strip-bom@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
+  dependencies:
+    is-utf8 "^0.2.0"
+
+strip-json-comments@~2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
+
+supports-color@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
+
+supports-color@^3.1.0, supports-color@^3.1.2:
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
+  dependencies:
+    has-flag "^1.0.0"
+
+symbol-tree@^3.2.1:
+  version "3.2.2"
+  resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6"
+
+tapable@^0.2.5, tapable@~0.2.5:
+  version "0.2.6"
+  resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.6.tgz#206be8e188860b514425375e6f1ae89bfb01fd8d"
+
+tar-pack@^3.4.0:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.0.tgz#23be2d7f671a8339376cbdb0b8fe3fdebf317984"
+  dependencies:
+    debug "^2.2.0"
+    fstream "^1.0.10"
+    fstream-ignore "^1.0.5"
+    once "^1.3.3"
+    readable-stream "^2.1.4"
+    rimraf "^2.5.1"
+    tar "^2.2.1"
+    uid-number "^0.0.6"
+
+tar@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1"
+  dependencies:
+    block-stream "*"
+    fstream "^1.0.2"
+    inherits "2"
+
+test-exclude@^4.0.3:
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-4.0.3.tgz#86a13ce3effcc60e6c90403cf31a27a60ac6c4e7"
+  dependencies:
+    arrify "^1.0.1"
+    micromatch "^2.3.11"
+    object-assign "^4.1.0"
+    read-pkg-up "^1.0.1"
+    require-main-filename "^1.0.1"
+
+throat@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/throat/-/throat-3.0.0.tgz#e7c64c867cbb3845f10877642f7b60055b8ec0d6"
+
+timers-browserify@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.2.tgz#ab4883cf597dcd50af211349a00fbca56ac86b86"
+  dependencies:
+    setimmediate "^1.0.4"
+
+tmpl@1.0.x:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1"
+
+to-arraybuffer@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
+
+to-fast-properties@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320"
+
+tough-cookie@^2.3.2, tough-cookie@~2.3.0:
+  version "2.3.2"
+  resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a"
+  dependencies:
+    punycode "^1.4.1"
+
+tr46@~0.0.3:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
+
+trim-right@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
+
+tty-browserify@0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
+
+tunnel-agent@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
+  dependencies:
+    safe-buffer "^5.0.1"
+
+tweetnacl@^0.14.3, tweetnacl@~0.14.0:
+  version "0.14.5"
+  resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
+
+type-check@~0.3.2:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
+  dependencies:
+    prelude-ls "~1.1.2"
+
+ua-parser-js@^0.7.9:
+  version "0.7.12"
+  resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb"
+
+uglify-js@^2.6:
+  version "2.8.21"
+  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.21.tgz#1733f669ae6f82fc90c7b25ec0f5c783ee375314"
+  dependencies:
+    source-map "~0.5.1"
+    yargs "~3.10.0"
+  optionalDependencies:
+    uglify-to-browserify "~1.0.0"
+
+uglify-js@^2.8.27:
+  version "2.8.28"
+  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.28.tgz#e335032df9bb20dcb918f164589d5af47f38834a"
+  dependencies:
+    source-map "~0.5.1"
+    yargs "~3.10.0"
+  optionalDependencies:
+    uglify-to-browserify "~1.0.0"
+
+uglify-to-browserify@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7"
+
+uid-number@^0.0.6:
+  version "0.0.6"
+  resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81"
+
+url@^0.11.0:
+  version "0.11.0"
+  resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
+  dependencies:
+    punycode "1.3.2"
+    querystring "0.2.0"
+
+util-deprecate@~1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+
+util@0.10.3, util@^0.10.3:
+  version "0.10.3"
+  resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9"
+  dependencies:
+    inherits "2.0.1"
+
+uuid@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1"
+
+validate-npm-package-license@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc"
+  dependencies:
+    spdx-correct "~1.0.0"
+    spdx-expression-parse "~1.0.0"
+
+verror@1.3.6:
+  version "1.3.6"
+  resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c"
+  dependencies:
+    extsprintf "1.0.2"
+
+vm-browserify@0.0.4:
+  version "0.0.4"
+  resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73"
+  dependencies:
+    indexof "0.0.1"
+
+walker@~1.0.5:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb"
+  dependencies:
+    makeerror "1.0.x"
+
+watch@~0.10.0:
+  version "0.10.0"
+  resolved "https://registry.yarnpkg.com/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc"
+
+watchpack@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.3.1.tgz#7d8693907b28ce6013e7f3610aa2a1acf07dad87"
+  dependencies:
+    async "^2.1.2"
+    chokidar "^1.4.3"
+    graceful-fs "^4.1.2"
+
+webidl-conversions@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
+
+webidl-conversions@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.1.tgz#8015a17ab83e7e1b311638486ace81da6ce206a0"
+
+webpack-sources@^0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-0.2.3.tgz#17c62bfaf13c707f9d02c479e0dcdde8380697fb"
+  dependencies:
+    source-list-map "^1.1.1"
+    source-map "~0.5.3"
+
+webpack@^2.6.1:
+  version "2.6.1"
+  resolved "https://registry.yarnpkg.com/webpack/-/webpack-2.6.1.tgz#2e0457f0abb1ac5df3ab106c69c672f236785f07"
+  dependencies:
+    acorn "^5.0.0"
+    acorn-dynamic-import "^2.0.0"
+    ajv "^4.7.0"
+    ajv-keywords "^1.1.1"
+    async "^2.1.2"
+    enhanced-resolve "^3.0.0"
+    interpret "^1.0.0"
+    json-loader "^0.5.4"
+    json5 "^0.5.1"
+    loader-runner "^2.3.0"
+    loader-utils "^0.2.16"
+    memory-fs "~0.4.1"
+    mkdirp "~0.5.0"
+    node-libs-browser "^2.0.0"
+    source-map "^0.5.3"
+    supports-color "^3.1.0"
+    tapable "~0.2.5"
+    uglify-js "^2.8.27"
+    watchpack "^1.3.1"
+    webpack-sources "^0.2.3"
+    yargs "^6.0.0"
+
+whatwg-encoding@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.1.tgz#3c6c451a198ee7aec55b1ec61d0920c67801a5f4"
+  dependencies:
+    iconv-lite "0.4.13"
+
+whatwg-fetch@>=0.10.0:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84"
+
+whatwg-url@^4.3.0:
+  version "4.7.0"
+  resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-4.7.0.tgz#202035ac1955b087cdd20fa8b58ded3ab1cd2af5"
+  dependencies:
+    tr46 "~0.0.3"
+    webidl-conversions "^3.0.0"
+
+which-module@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
+
+which@^1.1.1, which@^1.2.12:
+  version "1.2.14"
+  resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5"
+  dependencies:
+    isexe "^2.0.0"
+
+wide-align@^1.1.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710"
+  dependencies:
+    string-width "^1.0.2"
+
+window-size@0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
+
+wordwrap@0.0.2:
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
+
+wordwrap@~0.0.2:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
+
+wordwrap@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
+
+worker-farm@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.3.1.tgz#4333112bb49b17aa050b87895ca6b2cacf40e5ff"
+  dependencies:
+    errno ">=0.1.1 <0.2.0-0"
+    xtend ">=4.0.0 <4.1.0-0"
+
+wrap-ansi@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
+  dependencies:
+    string-width "^1.0.1"
+    strip-ansi "^3.0.1"
+
+wrappy@1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+
+xml-name-validator@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635"
+
+"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
+
+y18n@^3.2.1:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
+
+yargs-parser@^4.2.0:
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c"
+  dependencies:
+    camelcase "^3.0.0"
+
+yargs@^6.0.0, yargs@^6.3.0:
+  version "6.6.0"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208"
+  dependencies:
+    camelcase "^3.0.0"
+    cliui "^3.2.0"
+    decamelize "^1.1.1"
+    get-caller-file "^1.0.1"
+    os-locale "^1.4.0"
+    read-pkg-up "^1.0.1"
+    require-directory "^2.1.1"
+    require-main-filename "^1.0.1"
+    set-blocking "^2.0.0"
+    string-width "^1.0.2"
+    which-module "^1.0.0"
+    y18n "^3.2.1"
+    yargs-parser "^4.2.0"
+
+yargs@~3.10.0:
+  version "3.10.0"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"
+  dependencies:
+    camelcase "^1.0.2"
+    cliui "^2.1.0"
+    decamelize "^1.0.0"
+    window-size "0.1.0"
diff --git a/addons/react-linked-input/.gitignore b/addons/react-linked-input/.gitignore
new file mode 100644
index 000000000000..3515ba5c8f1f
--- /dev/null
+++ b/addons/react-linked-input/.gitignore
@@ -0,0 +1,2 @@
+react-linked-input.js
+react-linked-input.min.js
diff --git a/addons/react-linked-input/LICENSE.txt b/addons/react-linked-input/LICENSE.txt
new file mode 100644
index 000000000000..91b8f6f76ff0
--- /dev/null
+++ b/addons/react-linked-input/LICENSE.txt
@@ -0,0 +1,31 @@
+BSD License
+
+For React software
+
+Copyright (c) 2013-present, Facebook, Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+ * Neither the name Facebook nor the names of its contributors may be used to
+   endorse or promote products derived from this software without specific
+   prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/addons/react-linked-input/PATENTS b/addons/react-linked-input/PATENTS
new file mode 100644
index 000000000000..9c9f8e87a8f4
--- /dev/null
+++ b/addons/react-linked-input/PATENTS
@@ -0,0 +1,33 @@
+Additional Grant of Patent Rights Version 2
+
+"Software" means the React software distributed by Facebook, Inc.
+
+Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software
+("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable
+(subject to the termination provision below) license under any Necessary
+Claims, to make, have made, use, sell, offer to sell, import, and otherwise
+transfer the Software. For avoidance of doubt, no license is granted under
+Facebook's rights in any patent claims that are infringed by (i) modifications
+to the Software made by you or any third party or (ii) the Software in
+combination with any software or other technology.
+
+The license granted hereunder will terminate, automatically and without notice,
+if you (or any of your subsidiaries, corporate affiliates or agents) initiate
+directly or indirectly, or take a direct financial interest in, any Patent
+Assertion: (i) against Facebook or any of its subsidiaries or corporate
+affiliates, (ii) against any party if such Patent Assertion arises in whole or
+in part from any software, technology, product or service of Facebook or any of
+its subsidiaries or corporate affiliates, or (iii) against any party relating
+to the Software. Notwithstanding the foregoing, if Facebook or any of its
+subsidiaries or corporate affiliates files a lawsuit alleging patent
+infringement against you in the first instance, and you respond by filing a
+patent infringement counterclaim in that lawsuit against that party that is
+unrelated to the Software, the license granted hereunder will not terminate
+under section (i) of this paragraph due to such counterclaim.
+
+A "Necessary Claim" is a claim of a patent owned by Facebook that is
+necessarily infringed by the Software standing alone.
+
+A "Patent Assertion" is any lawsuit or other action alleging direct, indirect,
+or contributory infringement or inducement to infringe any patent, including a
+cross-claim or counterclaim.
diff --git a/addons/react-linked-input/README.md b/addons/react-linked-input/README.md
new file mode 100644
index 000000000000..abc37dcd6154
--- /dev/null
+++ b/addons/react-linked-input/README.md
@@ -0,0 +1,11 @@
+# react-linked-input
+
+>**Note:**
+>This is a legacy React addon, and is no longer maintained.
+>
+>We don't encourage using it in new code, but it exists for backwards compatibility.  
+>The recommended migration path is to set `value` and `onChange` props directly instead of `valueLink` or `checkedLink`.
+
+This component supports the legacy `valueLink` API for `<input>` components. The built-in support for it is being removed from React. This component may be used as a migration plan (so your code doesn't break in React 16) or may be used if you just like the `valueLink` data binding semantics. However, this component is not maintained, so use at your own risk.
+
+For details on how to use it, refer to the [`LinkedStateMixin`](https://www.npmjs.com/package/react-addons-linked-state-mixin) documentation, since they usually appear together.
diff --git a/addons/react-linked-input/index.js b/addons/react-linked-input/index.js
new file mode 100644
index 000000000000..eee29d4ee601
--- /dev/null
+++ b/addons/react-linked-input/index.js
@@ -0,0 +1,167 @@
+/**
+ * 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.
+ */
+
+'use strict';
+
+var React = require('react');
+
+if (typeof React === 'undefined') {
+  throw Error(
+    'react-linked-input could not find the React object. If you are using script tags, ' +
+      'make sure that React is being loaded before react-linked-input.'
+  );
+}
+
+var invariant = require('fbjs/lib/invariant');
+
+function _assertSingleLink(inputProps) {
+  invariant(
+    inputProps.checkedLink == null || inputProps.valueLink == null,
+    'Cannot provide a checkedLink and a valueLink. If you want to use ' +
+      "checkedLink, you probably don't want to use valueLink and vice versa."
+  );
+}
+function _assertValueLink(inputProps) {
+  _assertSingleLink(inputProps);
+  invariant(
+    inputProps.value == null && inputProps.onChange == null,
+    '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."
+  );
+}
+
+function _assertCheckedLink(inputProps) {
+  _assertSingleLink(inputProps);
+  invariant(
+    inputProps.checked == null && inputProps.onChange == null,
+    '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'
+  );
+}
+
+/**
+ * Provide a linked `value` attribute for controlled forms. You should not use
+ * this outside of the ReactDOM controlled form components.
+ */
+var LinkedValueUtils = {
+  /**
+   * @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);
+    }
+  }
+};
+
+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) {
+    if (Object.setPrototypeOf) {
+      Object.setPrototypeOf(subClass, superClass);
+    } else {
+      // eslint-disable-next-line no-proto
+      subClass.__proto__ = superClass;
+    }
+  }
+}
+
+var LI = (function(_React$Component) {
+  _inherits(LinkedInput, _React$Component);
+
+  function LinkedInput() {
+    _classCallCheck(this, LinkedInput);
+
+    var _this = _possibleConstructorReturn(this, _React$Component.call(this));
+
+    _this.handleChange = _this.handleChange.bind(_this);
+    return _this;
+  }
+
+  LinkedInput.prototype.handleChange = function handleChange(e) {
+    LinkedValueUtils.executeOnChange(this.props, e);
+  };
+
+  LinkedInput.prototype.render = function render() {
+    var newProps = Object.assign({}, this.props);
+    newProps.value = LinkedValueUtils.getValue(this.props);
+    newProps.checked = LinkedValueUtils.getChecked(this.props);
+    newProps.onChange = this.handleChange;
+    delete newProps.valueLink;
+    delete newProps.checkedLink;
+    return React.createElement('input', newProps);
+  };
+
+  return LinkedInput;
+})(React.Component);
+
+module.exports = LI;
diff --git a/addons/react-linked-input/package.json b/addons/react-linked-input/package.json
new file mode 100644
index 000000000000..73bfbb76122c
--- /dev/null
+++ b/addons/react-linked-input/package.json
@@ -0,0 +1,43 @@
+{
+  "name": "react-linked-input",
+  "version": "15.6.0",
+  "description": "LinkedInput supports the ReactLink semantics",
+  "main": "index.js",
+  "scripts": {
+    "test": "TEST_ENTRY=./index.js jest",
+    "build:dev": "NODE_ENV=development webpack && TEST_ENTRY=./react-linked-input.js jest",
+    "build:prod": "NODE_ENV=production webpack && NODE_ENV=production TEST_ENTRY=./react-linked-input.min.js jest",
+    "build": "npm run build:dev && npm run build:prod",
+    "prepublish": "npm test && npm run build"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/facebook/react.git"
+  },
+  "files": [
+    "LICENSE",
+    "PATENTS",
+    "factory.js",
+    "index.js",
+    "react-linked-input.js",
+    "react-linked-input.min.js"
+  ],
+  "keywords": [
+    "react",
+    "linkedinput",
+    "input",
+    "linked",
+    "reactlink"
+  ],
+  "license": "BSD-3-Clause",
+  "devDependencies": {
+    "babel-preset-es2015": "^6.24.0",
+    "jest": "^19.0.2",
+    "react": "^15.4.2",
+    "react-dom": "^15.4.2",
+    "webpack": "^2.6.1"
+  },
+  "dependencies": {
+    "fbjs": "^0.8.9"
+  }
+}
diff --git a/addons/react-linked-input/test.js b/addons/react-linked-input/test.js
new file mode 100644
index 000000000000..f0304d2d38c7
--- /dev/null
+++ b/addons/react-linked-input/test.js
@@ -0,0 +1,109 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+// Catch stray warnings
+var env = jasmine.getEnv();
+var callCount = 0;
+var oldError = console.error;
+var newError = function() {
+  callCount++;
+  oldError.apply(this, arguments);
+};
+console.error = newError;
+env.beforeEach(() => {
+  callCount = 0;
+  jasmine.addMatchers({
+    toBeReset() {
+      return {
+        compare(actual) {
+          if (actual !== newError && !jasmine.isSpy(actual)) {
+            return {
+              pass: false,
+              message: 'Test did not tear down console.error mock properly.'
+            };
+          }
+          return {pass: true};
+        }
+      };
+    },
+    toNotHaveBeenCalled() {
+      return {
+        compare(actual) {
+          return {
+            pass: callCount === 0,
+            message:
+              'Expected test not to warn. If the warning is expected, mock ' +
+                "it out using spyOn(console, 'error'); and test that the " +
+                'warning occurs.'
+          };
+        }
+      };
+    }
+  });
+});
+env.afterEach(() => {
+  expect(console.error).toBeReset();
+  expect(console.error).toNotHaveBeenCalled();
+});
+
+function noop() {}
+
+// Tests adapted from ReactComponentWithPureRendererMixin and ReactPureComponent tests
+describe('LinkedInput', function() {
+  let LinkedInput;
+  let React;
+  let ReactDOM;
+
+  beforeEach(function() {
+    React = require('react');
+    ReactDOM = require('react-dom');
+    LinkedInput = require(process.env.TEST_ENTRY);
+  });
+
+  it('should basically work', function() {
+    spyOn(console, 'error'); // Unknown prop `requestChange` on <input> tag
+
+    const container = document.createElement('div');
+    const component = ReactDOM.render(
+      React.createElement(LinkedInput, {
+        value: 'foo',
+        onChange: noop
+      }),
+      container
+    );
+    const input = ReactDOM.findDOMNode(component);
+    expect(input.value).toBe('foo');
+    ReactDOM.render(
+      React.createElement(LinkedInput, {
+        valueLink: {value: 'boo'},
+        requestChange: noop
+      }),
+      container
+    );
+    expect(input.value).toBe('boo');
+  });
+
+  it('should throw', function() {
+    const container = document.createElement('div');
+    const element = React.createElement(LinkedInput, {
+      value: 'foo',
+      valueLink: {
+        value: 'boo',
+        requestChange: noop
+      }
+    });
+    expect(function() {
+      ReactDOM.render(element, container);
+    }).toThrow();
+  });
+});
diff --git a/addons/react-linked-input/webpack.config.js b/addons/react-linked-input/webpack.config.js
new file mode 100644
index 000000000000..c290aa28bc4e
--- /dev/null
+++ b/addons/react-linked-input/webpack.config.js
@@ -0,0 +1,61 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+const webpack = require('webpack');
+
+let __DEV__;
+switch (process.env.NODE_ENV) {
+  case 'development':
+    __DEV__ = true;
+    break;
+  case 'production':
+    __DEV__ = false;
+    break;
+  default:
+    throw new Error('Unknown environment.');
+}
+
+module.exports = {
+  entry: './index',
+  output: {
+    library: 'LinkedInput',
+    libraryTarget: 'umd',
+    filename: __DEV__ ? 'react-linked-input.js' : 'react-linked-input.min.js'
+  },
+  externals: {
+    react: {
+      root: 'React',
+      commonjs2: 'react',
+      commonjs: 'react',
+      amd: 'react'
+    }
+  },
+  plugins: [
+    new webpack.DefinePlugin({
+      'process.env.NODE_ENV': __DEV__ ? '"development"' : '"production"'
+    })
+  ].concat(
+    __DEV__
+      ? []
+      : [
+          new webpack.optimize.UglifyJsPlugin({
+            compress: {
+              warnings: false
+            },
+            output: {
+              comments: false
+            }
+          })
+        ]
+  )
+};
diff --git a/addons/react-linked-input/yarn.lock b/addons/react-linked-input/yarn.lock
new file mode 100644
index 000000000000..7ceba5eca795
--- /dev/null
+++ b/addons/react-linked-input/yarn.lock
@@ -0,0 +1,3145 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+abab@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.3.tgz#b81de5f7274ec4e756d797cd834f303642724e5d"
+
+abbrev@1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f"
+
+acorn-dynamic-import@^2.0.0:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz#c752bd210bef679501b6c6cb7fc84f8f47158cc4"
+  dependencies:
+    acorn "^4.0.3"
+
+acorn-globals@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-3.1.0.tgz#fd8270f71fbb4996b004fa880ee5d46573a731bf"
+  dependencies:
+    acorn "^4.0.4"
+
+acorn@^4.0.3, acorn@^4.0.4:
+  version "4.0.11"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.11.tgz#edcda3bd937e7556410d42ed5860f67399c794c0"
+
+acorn@^5.0.0:
+  version "5.0.3"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.0.3.tgz#c460df08491463f028ccb82eab3730bf01087b3d"
+
+ajv-keywords@^1.1.1:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c"
+
+ajv@^4.7.0, ajv@^4.9.1:
+  version "4.11.5"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.5.tgz#b6ee74657b993a01dce44b7944d56f485828d5bd"
+  dependencies:
+    co "^4.6.0"
+    json-stable-stringify "^1.0.1"
+
+align-text@^0.1.1, align-text@^0.1.3:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
+  dependencies:
+    kind-of "^3.0.2"
+    longest "^1.0.1"
+    repeat-string "^1.5.2"
+
+amdefine@>=0.0.4:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
+
+ansi-escapes@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
+
+ansi-regex@^2.0.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
+
+ansi-styles@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
+
+ansi-styles@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.0.0.tgz#5404e93a544c4fec7f048262977bebfe3155e0c1"
+  dependencies:
+    color-convert "^1.0.0"
+
+anymatch@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507"
+  dependencies:
+    arrify "^1.0.0"
+    micromatch "^2.1.5"
+
+append-transform@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-0.4.0.tgz#d76ebf8ca94d276e247a36bad44a4b74ab611991"
+  dependencies:
+    default-require-extensions "^1.0.0"
+
+aproba@^1.0.3:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.2.tgz#45c6629094de4e96f693ef7eab74ae079c240fc1"
+
+are-we-there-yet@~1.1.2:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d"
+  dependencies:
+    delegates "^1.0.0"
+    readable-stream "^2.0.6"
+
+argparse@^1.0.7:
+  version "1.0.9"
+  resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86"
+  dependencies:
+    sprintf-js "~1.0.2"
+
+arr-diff@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf"
+  dependencies:
+    arr-flatten "^1.0.1"
+
+arr-flatten@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b"
+
+array-equal@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93"
+
+array-unique@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
+
+arrify@^1.0.0, arrify@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
+
+asap@~2.0.3:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f"
+
+asn1.js@^4.0.0:
+  version "4.9.1"
+  resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.1.tgz#48ba240b45a9280e94748990ba597d216617fd40"
+  dependencies:
+    bn.js "^4.0.0"
+    inherits "^2.0.1"
+    minimalistic-assert "^1.0.0"
+
+asn1@~0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86"
+
+assert-plus@1.0.0, assert-plus@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
+
+assert-plus@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234"
+
+assert@^1.1.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91"
+  dependencies:
+    util "0.10.3"
+
+async-each@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
+
+async@^1.4.0:
+  version "1.5.2"
+  resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
+
+async@^2.1.2, async@^2.1.4:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/async/-/async-2.3.0.tgz#1013d1051047dd320fe24e494d5c66ecaf6147d9"
+  dependencies:
+    lodash "^4.14.0"
+
+asynckit@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+
+aws-sign2@~0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f"
+
+aws4@^1.2.1:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e"
+
+babel-code-frame@^6.22.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4"
+  dependencies:
+    chalk "^1.1.0"
+    esutils "^2.0.2"
+    js-tokens "^3.0.0"
+
+babel-core@^6.0.0, babel-core@^6.24.0:
+  version "6.24.0"
+  resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.24.0.tgz#8f36a0a77f5c155aed6f920b844d23ba56742a02"
+  dependencies:
+    babel-code-frame "^6.22.0"
+    babel-generator "^6.24.0"
+    babel-helpers "^6.23.0"
+    babel-messages "^6.23.0"
+    babel-register "^6.24.0"
+    babel-runtime "^6.22.0"
+    babel-template "^6.23.0"
+    babel-traverse "^6.23.1"
+    babel-types "^6.23.0"
+    babylon "^6.11.0"
+    convert-source-map "^1.1.0"
+    debug "^2.1.1"
+    json5 "^0.5.0"
+    lodash "^4.2.0"
+    minimatch "^3.0.2"
+    path-is-absolute "^1.0.0"
+    private "^0.1.6"
+    slash "^1.0.0"
+    source-map "^0.5.0"
+
+babel-generator@^6.18.0, babel-generator@^6.24.0:
+  version "6.24.0"
+  resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.24.0.tgz#eba270a8cc4ce6e09a61be43465d7c62c1f87c56"
+  dependencies:
+    babel-messages "^6.23.0"
+    babel-runtime "^6.22.0"
+    babel-types "^6.23.0"
+    detect-indent "^4.0.0"
+    jsesc "^1.3.0"
+    lodash "^4.2.0"
+    source-map "^0.5.0"
+    trim-right "^1.0.1"
+
+babel-helper-call-delegate@^6.22.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.22.0.tgz#119921b56120f17e9dae3f74b4f5cc7bcc1b37ef"
+  dependencies:
+    babel-helper-hoist-variables "^6.22.0"
+    babel-runtime "^6.22.0"
+    babel-traverse "^6.22.0"
+    babel-types "^6.22.0"
+
+babel-helper-define-map@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.23.0.tgz#1444f960c9691d69a2ced6a205315f8fd00804e7"
+  dependencies:
+    babel-helper-function-name "^6.23.0"
+    babel-runtime "^6.22.0"
+    babel-types "^6.23.0"
+    lodash "^4.2.0"
+
+babel-helper-function-name@^6.22.0, babel-helper-function-name@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.23.0.tgz#25742d67175c8903dbe4b6cb9d9e1fcb8dcf23a6"
+  dependencies:
+    babel-helper-get-function-arity "^6.22.0"
+    babel-runtime "^6.22.0"
+    babel-template "^6.23.0"
+    babel-traverse "^6.23.0"
+    babel-types "^6.23.0"
+
+babel-helper-get-function-arity@^6.22.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.22.0.tgz#0beb464ad69dc7347410ac6ade9f03a50634f5ce"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-types "^6.22.0"
+
+babel-helper-hoist-variables@^6.22.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.22.0.tgz#3eacbf731d80705845dd2e9718f600cfb9b4ba72"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-types "^6.22.0"
+
+babel-helper-optimise-call-expression@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.23.0.tgz#f3ee7eed355b4282138b33d02b78369e470622f5"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-types "^6.23.0"
+
+babel-helper-regex@^6.22.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.22.0.tgz#79f532be1647b1f0ee3474b5f5c3da58001d247d"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-types "^6.22.0"
+    lodash "^4.2.0"
+
+babel-helper-replace-supers@^6.22.0, babel-helper-replace-supers@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.23.0.tgz#eeaf8ad9b58ec4337ca94223bacdca1f8d9b4bfd"
+  dependencies:
+    babel-helper-optimise-call-expression "^6.23.0"
+    babel-messages "^6.23.0"
+    babel-runtime "^6.22.0"
+    babel-template "^6.23.0"
+    babel-traverse "^6.23.0"
+    babel-types "^6.23.0"
+
+babel-helpers@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.23.0.tgz#4f8f2e092d0b6a8808a4bde79c27f1e2ecf0d992"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-template "^6.23.0"
+
+babel-jest@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-19.0.0.tgz#59323ced99a3a84d359da219ca881074ffc6ce3f"
+  dependencies:
+    babel-core "^6.0.0"
+    babel-plugin-istanbul "^4.0.0"
+    babel-preset-jest "^19.0.0"
+
+babel-messages@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e"
+  dependencies:
+    babel-runtime "^6.22.0"
+
+babel-plugin-check-es2015-constants@^6.22.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a"
+  dependencies:
+    babel-runtime "^6.22.0"
+
+babel-plugin-istanbul@^4.0.0:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.1.tgz#c12de0fc6fe42adfb16be56f1ad11e4a9782eca9"
+  dependencies:
+    find-up "^2.1.0"
+    istanbul-lib-instrument "^1.6.2"
+    test-exclude "^4.0.3"
+
+babel-plugin-jest-hoist@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-19.0.0.tgz#4ae2a04ea612a6e73651f3fde52c178991304bea"
+
+babel-plugin-transform-es2015-arrow-functions@^6.22.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221"
+  dependencies:
+    babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-block-scoped-functions@^6.22.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141"
+  dependencies:
+    babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-block-scoping@^6.22.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.23.0.tgz#e48895cf0b375be148cd7c8879b422707a053b51"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-template "^6.23.0"
+    babel-traverse "^6.23.0"
+    babel-types "^6.23.0"
+    lodash "^4.2.0"
+
+babel-plugin-transform-es2015-classes@^6.22.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.23.0.tgz#49b53f326202a2fd1b3bbaa5e2edd8a4f78643c1"
+  dependencies:
+    babel-helper-define-map "^6.23.0"
+    babel-helper-function-name "^6.23.0"
+    babel-helper-optimise-call-expression "^6.23.0"
+    babel-helper-replace-supers "^6.23.0"
+    babel-messages "^6.23.0"
+    babel-runtime "^6.22.0"
+    babel-template "^6.23.0"
+    babel-traverse "^6.23.0"
+    babel-types "^6.23.0"
+
+babel-plugin-transform-es2015-computed-properties@^6.22.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.22.0.tgz#7c383e9629bba4820c11b0425bdd6290f7f057e7"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-template "^6.22.0"
+
+babel-plugin-transform-es2015-destructuring@^6.22.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d"
+  dependencies:
+    babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-duplicate-keys@^6.22.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.22.0.tgz#672397031c21610d72dd2bbb0ba9fb6277e1c36b"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-types "^6.22.0"
+
+babel-plugin-transform-es2015-for-of@^6.22.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691"
+  dependencies:
+    babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-function-name@^6.22.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.22.0.tgz#f5fcc8b09093f9a23c76ac3d9e392c3ec4b77104"
+  dependencies:
+    babel-helper-function-name "^6.22.0"
+    babel-runtime "^6.22.0"
+    babel-types "^6.22.0"
+
+babel-plugin-transform-es2015-literals@^6.22.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e"
+  dependencies:
+    babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-modules-amd@^6.24.0:
+  version "6.24.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.0.tgz#a1911fb9b7ec7e05a43a63c5995007557bcf6a2e"
+  dependencies:
+    babel-plugin-transform-es2015-modules-commonjs "^6.24.0"
+    babel-runtime "^6.22.0"
+    babel-template "^6.22.0"
+
+babel-plugin-transform-es2015-modules-commonjs@^6.24.0:
+  version "6.24.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.24.0.tgz#e921aefb72c2cc26cb03d107626156413222134f"
+  dependencies:
+    babel-plugin-transform-strict-mode "^6.22.0"
+    babel-runtime "^6.22.0"
+    babel-template "^6.23.0"
+    babel-types "^6.23.0"
+
+babel-plugin-transform-es2015-modules-systemjs@^6.22.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.23.0.tgz#ae3469227ffac39b0310d90fec73bfdc4f6317b0"
+  dependencies:
+    babel-helper-hoist-variables "^6.22.0"
+    babel-runtime "^6.22.0"
+    babel-template "^6.23.0"
+
+babel-plugin-transform-es2015-modules-umd@^6.24.0:
+  version "6.24.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.0.tgz#fd5fa63521cae8d273927c3958afd7c067733450"
+  dependencies:
+    babel-plugin-transform-es2015-modules-amd "^6.24.0"
+    babel-runtime "^6.22.0"
+    babel-template "^6.23.0"
+
+babel-plugin-transform-es2015-object-super@^6.22.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.22.0.tgz#daa60e114a042ea769dd53fe528fc82311eb98fc"
+  dependencies:
+    babel-helper-replace-supers "^6.22.0"
+    babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-parameters@^6.22.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.23.0.tgz#3a2aabb70c8af945d5ce386f1a4250625a83ae3b"
+  dependencies:
+    babel-helper-call-delegate "^6.22.0"
+    babel-helper-get-function-arity "^6.22.0"
+    babel-runtime "^6.22.0"
+    babel-template "^6.23.0"
+    babel-traverse "^6.23.0"
+    babel-types "^6.23.0"
+
+babel-plugin-transform-es2015-shorthand-properties@^6.22.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.22.0.tgz#8ba776e0affaa60bff21e921403b8a652a2ff723"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-types "^6.22.0"
+
+babel-plugin-transform-es2015-spread@^6.22.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1"
+  dependencies:
+    babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-sticky-regex@^6.22.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.22.0.tgz#ab316829e866ee3f4b9eb96939757d19a5bc4593"
+  dependencies:
+    babel-helper-regex "^6.22.0"
+    babel-runtime "^6.22.0"
+    babel-types "^6.22.0"
+
+babel-plugin-transform-es2015-template-literals@^6.22.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d"
+  dependencies:
+    babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-typeof-symbol@^6.22.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372"
+  dependencies:
+    babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-unicode-regex@^6.22.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.22.0.tgz#8d9cc27e7ee1decfe65454fb986452a04a613d20"
+  dependencies:
+    babel-helper-regex "^6.22.0"
+    babel-runtime "^6.22.0"
+    regexpu-core "^2.0.0"
+
+babel-plugin-transform-regenerator@^6.22.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.22.0.tgz#65740593a319c44522157538d690b84094617ea6"
+  dependencies:
+    regenerator-transform "0.9.8"
+
+babel-plugin-transform-strict-mode@^6.22.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.22.0.tgz#e008df01340fdc87e959da65991b7e05970c8c7c"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-types "^6.22.0"
+
+babel-preset-es2015@^6.24.0:
+  version "6.24.0"
+  resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.24.0.tgz#c162d68b1932696e036cd3110dc1ccd303d2673a"
+  dependencies:
+    babel-plugin-check-es2015-constants "^6.22.0"
+    babel-plugin-transform-es2015-arrow-functions "^6.22.0"
+    babel-plugin-transform-es2015-block-scoped-functions "^6.22.0"
+    babel-plugin-transform-es2015-block-scoping "^6.22.0"
+    babel-plugin-transform-es2015-classes "^6.22.0"
+    babel-plugin-transform-es2015-computed-properties "^6.22.0"
+    babel-plugin-transform-es2015-destructuring "^6.22.0"
+    babel-plugin-transform-es2015-duplicate-keys "^6.22.0"
+    babel-plugin-transform-es2015-for-of "^6.22.0"
+    babel-plugin-transform-es2015-function-name "^6.22.0"
+    babel-plugin-transform-es2015-literals "^6.22.0"
+    babel-plugin-transform-es2015-modules-amd "^6.24.0"
+    babel-plugin-transform-es2015-modules-commonjs "^6.24.0"
+    babel-plugin-transform-es2015-modules-systemjs "^6.22.0"
+    babel-plugin-transform-es2015-modules-umd "^6.24.0"
+    babel-plugin-transform-es2015-object-super "^6.22.0"
+    babel-plugin-transform-es2015-parameters "^6.22.0"
+    babel-plugin-transform-es2015-shorthand-properties "^6.22.0"
+    babel-plugin-transform-es2015-spread "^6.22.0"
+    babel-plugin-transform-es2015-sticky-regex "^6.22.0"
+    babel-plugin-transform-es2015-template-literals "^6.22.0"
+    babel-plugin-transform-es2015-typeof-symbol "^6.22.0"
+    babel-plugin-transform-es2015-unicode-regex "^6.22.0"
+    babel-plugin-transform-regenerator "^6.22.0"
+
+babel-preset-jest@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-19.0.0.tgz#22d67201d02324a195811288eb38294bb3cac396"
+  dependencies:
+    babel-plugin-jest-hoist "^19.0.0"
+
+babel-register@^6.24.0:
+  version "6.24.0"
+  resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.24.0.tgz#5e89f8463ba9970356d02eb07dabe3308b080cfd"
+  dependencies:
+    babel-core "^6.24.0"
+    babel-runtime "^6.22.0"
+    core-js "^2.4.0"
+    home-or-tmp "^2.0.0"
+    lodash "^4.2.0"
+    mkdirp "^0.5.1"
+    source-map-support "^0.4.2"
+
+babel-runtime@^6.18.0, babel-runtime@^6.22.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b"
+  dependencies:
+    core-js "^2.4.0"
+    regenerator-runtime "^0.10.0"
+
+babel-template@^6.16.0, babel-template@^6.22.0, babel-template@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.23.0.tgz#04d4f270adbb3aa704a8143ae26faa529238e638"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-traverse "^6.23.0"
+    babel-types "^6.23.0"
+    babylon "^6.11.0"
+    lodash "^4.2.0"
+
+babel-traverse@^6.18.0, babel-traverse@^6.22.0, babel-traverse@^6.23.0, babel-traverse@^6.23.1:
+  version "6.23.1"
+  resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.23.1.tgz#d3cb59010ecd06a97d81310065f966b699e14f48"
+  dependencies:
+    babel-code-frame "^6.22.0"
+    babel-messages "^6.23.0"
+    babel-runtime "^6.22.0"
+    babel-types "^6.23.0"
+    babylon "^6.15.0"
+    debug "^2.2.0"
+    globals "^9.0.0"
+    invariant "^2.2.0"
+    lodash "^4.2.0"
+
+babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.22.0, babel-types@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.23.0.tgz#bb17179d7538bad38cd0c9e115d340f77e7e9acf"
+  dependencies:
+    babel-runtime "^6.22.0"
+    esutils "^2.0.2"
+    lodash "^4.2.0"
+    to-fast-properties "^1.0.1"
+
+babylon@^6.11.0, babylon@^6.13.0, babylon@^6.15.0:
+  version "6.16.1"
+  resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.16.1.tgz#30c5a22f481978a9e7f8cdfdf496b11d94b404d3"
+
+balanced-match@^0.4.1:
+  version "0.4.2"
+  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
+
+base64-js@^1.0.2:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1"
+
+bcrypt-pbkdf@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d"
+  dependencies:
+    tweetnacl "^0.14.3"
+
+big.js@^3.1.3:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.1.3.tgz#4cada2193652eb3ca9ec8e55c9015669c9806978"
+
+binary-extensions@^1.0.0:
+  version "1.8.0"
+  resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.8.0.tgz#48ec8d16df4377eae5fa5884682480af4d95c774"
+
+block-stream@*:
+  version "0.0.9"
+  resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a"
+  dependencies:
+    inherits "~2.0.0"
+
+bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0:
+  version "4.11.6"
+  resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215"
+
+boom@2.x.x:
+  version "2.10.1"
+  resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f"
+  dependencies:
+    hoek "2.x.x"
+
+brace-expansion@^1.0.0:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9"
+  dependencies:
+    balanced-match "^0.4.1"
+    concat-map "0.0.1"
+
+braces@^1.8.2:
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7"
+  dependencies:
+    expand-range "^1.8.1"
+    preserve "^0.2.0"
+    repeat-element "^1.1.2"
+
+brorand@^1.0.1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
+
+browser-resolve@^1.11.2:
+  version "1.11.2"
+  resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.2.tgz#8ff09b0a2c421718a1051c260b32e48f442938ce"
+  dependencies:
+    resolve "1.1.7"
+
+browserify-aes@^1.0.0, browserify-aes@^1.0.4:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.0.6.tgz#5e7725dbdef1fd5930d4ebab48567ce451c48a0a"
+  dependencies:
+    buffer-xor "^1.0.2"
+    cipher-base "^1.0.0"
+    create-hash "^1.1.0"
+    evp_bytestokey "^1.0.0"
+    inherits "^2.0.1"
+
+browserify-cipher@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.0.tgz#9988244874bf5ed4e28da95666dcd66ac8fc363a"
+  dependencies:
+    browserify-aes "^1.0.4"
+    browserify-des "^1.0.0"
+    evp_bytestokey "^1.0.0"
+
+browserify-des@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.0.tgz#daa277717470922ed2fe18594118a175439721dd"
+  dependencies:
+    cipher-base "^1.0.1"
+    des.js "^1.0.0"
+    inherits "^2.0.1"
+
+browserify-rsa@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524"
+  dependencies:
+    bn.js "^4.1.0"
+    randombytes "^2.0.1"
+
+browserify-sign@^4.0.0:
+  version "4.0.4"
+  resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298"
+  dependencies:
+    bn.js "^4.1.1"
+    browserify-rsa "^4.0.0"
+    create-hash "^1.1.0"
+    create-hmac "^1.1.2"
+    elliptic "^6.0.0"
+    inherits "^2.0.1"
+    parse-asn1 "^5.0.0"
+
+browserify-zlib@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d"
+  dependencies:
+    pako "~0.2.0"
+
+bser@1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/bser/-/bser-1.0.2.tgz#381116970b2a6deea5646dd15dd7278444b56169"
+  dependencies:
+    node-int64 "^0.4.0"
+
+bser@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719"
+  dependencies:
+    node-int64 "^0.4.0"
+
+buffer-xor@^1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9"
+
+buffer@^4.3.0:
+  version "4.9.1"
+  resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298"
+  dependencies:
+    base64-js "^1.0.2"
+    ieee754 "^1.1.4"
+    isarray "^1.0.0"
+
+builtin-modules@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
+
+builtin-status-codes@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
+
+callsites@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50"
+
+camelcase@^1.0.2:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39"
+
+camelcase@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
+
+caseless@~0.12.0:
+  version "0.12.0"
+  resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
+
+center-align@^0.1.1:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad"
+  dependencies:
+    align-text "^0.1.3"
+    lazy-cache "^1.0.3"
+
+chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
+  dependencies:
+    ansi-styles "^2.2.1"
+    escape-string-regexp "^1.0.2"
+    has-ansi "^2.0.0"
+    strip-ansi "^3.0.0"
+    supports-color "^2.0.0"
+
+chokidar@^1.4.3:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
+  dependencies:
+    anymatch "^1.3.0"
+    async-each "^1.0.0"
+    glob-parent "^2.0.0"
+    inherits "^2.0.1"
+    is-binary-path "^1.0.0"
+    is-glob "^2.0.0"
+    path-is-absolute "^1.0.0"
+    readdirp "^2.0.0"
+  optionalDependencies:
+    fsevents "^1.0.0"
+
+ci-info@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.0.0.tgz#dc5285f2b4e251821683681c381c3388f46ec534"
+
+cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.3.tgz#eeabf194419ce900da3018c207d212f2a6df0a07"
+  dependencies:
+    inherits "^2.0.1"
+
+cliui@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1"
+  dependencies:
+    center-align "^0.1.1"
+    right-align "^0.1.1"
+    wordwrap "0.0.2"
+
+cliui@^3.2.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
+  dependencies:
+    string-width "^1.0.1"
+    strip-ansi "^3.0.1"
+    wrap-ansi "^2.0.0"
+
+co@^4.6.0:
+  version "4.6.0"
+  resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
+
+code-point-at@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
+
+color-convert@^1.0.0:
+  version "1.9.0"
+  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a"
+  dependencies:
+    color-name "^1.1.1"
+
+color-name@^1.1.1:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.2.tgz#5c8ab72b64bd2215d617ae9559ebb148475cf98d"
+
+combined-stream@^1.0.5, combined-stream@~1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009"
+  dependencies:
+    delayed-stream "~1.0.0"
+
+concat-map@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+
+console-browserify@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10"
+  dependencies:
+    date-now "^0.1.4"
+
+console-control-strings@^1.0.0, console-control-strings@~1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
+
+constants-browserify@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
+
+content-type-parser@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/content-type-parser/-/content-type-parser-1.0.1.tgz#c3e56988c53c65127fb46d4032a3a900246fdc94"
+
+convert-source-map@^1.1.0:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5"
+
+core-js@^1.0.0:
+  version "1.2.7"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
+
+core-js@^2.4.0:
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e"
+
+core-util-is@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
+
+create-ecdh@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.0.tgz#888c723596cdf7612f6498233eebd7a35301737d"
+  dependencies:
+    bn.js "^4.1.0"
+    elliptic "^6.0.0"
+
+create-hash@^1.1.0, create-hash@^1.1.1, create-hash@^1.1.2:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.3.tgz#606042ac8b9262750f483caddab0f5819172d8fd"
+  dependencies:
+    cipher-base "^1.0.1"
+    inherits "^2.0.1"
+    ripemd160 "^2.0.0"
+    sha.js "^2.4.0"
+
+create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.6.tgz#acb9e221a4e17bdb076e90657c42b93e3726cf06"
+  dependencies:
+    cipher-base "^1.0.3"
+    create-hash "^1.1.0"
+    inherits "^2.0.1"
+    ripemd160 "^2.0.0"
+    safe-buffer "^5.0.1"
+    sha.js "^2.4.8"
+
+cryptiles@2.x.x:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8"
+  dependencies:
+    boom "2.x.x"
+
+crypto-browserify@^3.11.0:
+  version "3.11.0"
+  resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.11.0.tgz#3652a0906ab9b2a7e0c3ce66a408e957a2485522"
+  dependencies:
+    browserify-cipher "^1.0.0"
+    browserify-sign "^4.0.0"
+    create-ecdh "^4.0.0"
+    create-hash "^1.1.0"
+    create-hmac "^1.1.0"
+    diffie-hellman "^5.0.0"
+    inherits "^2.0.1"
+    pbkdf2 "^3.0.3"
+    public-encrypt "^4.0.0"
+    randombytes "^2.0.0"
+
+cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0":
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.2.tgz#b8036170c79f07a90ff2f16e22284027a243848b"
+
+"cssstyle@>= 0.2.37 < 0.3.0":
+  version "0.2.37"
+  resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-0.2.37.tgz#541097234cb2513c83ceed3acddc27ff27987d54"
+  dependencies:
+    cssom "0.3.x"
+
+dashdash@^1.12.0:
+  version "1.14.1"
+  resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
+  dependencies:
+    assert-plus "^1.0.0"
+
+date-now@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
+
+debug@^2.1.1, debug@^2.2.0:
+  version "2.6.3"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.3.tgz#0f7eb8c30965ec08c72accfa0130c8b79984141d"
+  dependencies:
+    ms "0.7.2"
+
+decamelize@^1.0.0, decamelize@^1.1.1:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
+
+deep-extend@~0.4.0:
+  version "0.4.2"
+  resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f"
+
+deep-is@~0.1.3:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
+
+default-require-extensions@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8"
+  dependencies:
+    strip-bom "^2.0.0"
+
+delayed-stream@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+
+delegates@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
+
+des.js@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc"
+  dependencies:
+    inherits "^2.0.1"
+    minimalistic-assert "^1.0.0"
+
+detect-indent@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208"
+  dependencies:
+    repeating "^2.0.0"
+
+diff@^3.0.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9"
+
+diffie-hellman@^5.0.0:
+  version "5.0.2"
+  resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.2.tgz#b5835739270cfe26acf632099fded2a07f209e5e"
+  dependencies:
+    bn.js "^4.1.0"
+    miller-rabin "^4.0.0"
+    randombytes "^2.0.0"
+
+domain-browser@^1.1.1:
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc"
+
+ecc-jsbn@~0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505"
+  dependencies:
+    jsbn "~0.1.0"
+
+elliptic@^6.0.0:
+  version "6.4.0"
+  resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df"
+  dependencies:
+    bn.js "^4.4.0"
+    brorand "^1.0.1"
+    hash.js "^1.0.0"
+    hmac-drbg "^1.0.0"
+    inherits "^2.0.1"
+    minimalistic-assert "^1.0.0"
+    minimalistic-crypto-utils "^1.0.0"
+
+emojis-list@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
+
+encoding@^0.1.11:
+  version "0.1.12"
+  resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb"
+  dependencies:
+    iconv-lite "~0.4.13"
+
+enhanced-resolve@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.1.0.tgz#9f4b626f577245edcf4b2ad83d86e17f4f421dec"
+  dependencies:
+    graceful-fs "^4.1.2"
+    memory-fs "^0.4.0"
+    object-assign "^4.0.1"
+    tapable "^0.2.5"
+
+"errno@>=0.1.1 <0.2.0-0", errno@^0.1.3:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d"
+  dependencies:
+    prr "~0.0.0"
+
+error-ex@^1.2.0:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc"
+  dependencies:
+    is-arrayish "^0.2.1"
+
+escape-string-regexp@^1.0.2:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+
+escodegen@^1.6.1:
+  version "1.8.1"
+  resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018"
+  dependencies:
+    esprima "^2.7.1"
+    estraverse "^1.9.1"
+    esutils "^2.0.2"
+    optionator "^0.8.1"
+  optionalDependencies:
+    source-map "~0.2.0"
+
+esprima@^2.7.1:
+  version "2.7.3"
+  resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
+
+esprima@^3.1.1:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633"
+
+estraverse@^1.9.1:
+  version "1.9.3"
+  resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44"
+
+esutils@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
+
+events@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924"
+
+evp_bytestokey@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.0.tgz#497b66ad9fef65cd7c08a6180824ba1476b66e53"
+  dependencies:
+    create-hash "^1.1.1"
+
+exec-sh@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.0.tgz#14f75de3f20d286ef933099b2ce50a90359cef10"
+  dependencies:
+    merge "^1.1.3"
+
+expand-brackets@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
+  dependencies:
+    is-posix-bracket "^0.1.0"
+
+expand-range@^1.8.1:
+  version "1.8.2"
+  resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337"
+  dependencies:
+    fill-range "^2.1.0"
+
+extend@~3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4"
+
+extglob@^0.3.1:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1"
+  dependencies:
+    is-extglob "^1.0.0"
+
+extsprintf@1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550"
+
+fast-levenshtein@~2.0.4:
+  version "2.0.6"
+  resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
+
+fb-watchman@^1.8.0:
+  version "1.9.2"
+  resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-1.9.2.tgz#a24cf47827f82d38fb59a69ad70b76e3b6ae7383"
+  dependencies:
+    bser "1.0.2"
+
+fb-watchman@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58"
+  dependencies:
+    bser "^2.0.0"
+
+fbjs@^0.8.1, fbjs@^0.8.4, fbjs@^0.8.9:
+  version "0.8.12"
+  resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.12.tgz#10b5d92f76d45575fd63a217d4ea02bea2f8ed04"
+  dependencies:
+    core-js "^1.0.0"
+    isomorphic-fetch "^2.1.1"
+    loose-envify "^1.0.0"
+    object-assign "^4.1.0"
+    promise "^7.1.1"
+    setimmediate "^1.0.5"
+    ua-parser-js "^0.7.9"
+
+filename-regex@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775"
+
+fileset@^2.0.2:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/fileset/-/fileset-2.0.3.tgz#8e7548a96d3cc2327ee5e674168723a333bba2a0"
+  dependencies:
+    glob "^7.0.3"
+    minimatch "^3.0.3"
+
+fill-range@^2.1.0:
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723"
+  dependencies:
+    is-number "^2.1.0"
+    isobject "^2.0.0"
+    randomatic "^1.1.3"
+    repeat-element "^1.1.2"
+    repeat-string "^1.5.2"
+
+find-up@^1.0.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
+  dependencies:
+    path-exists "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+find-up@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
+  dependencies:
+    locate-path "^2.0.0"
+
+for-in@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
+
+for-own@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce"
+  dependencies:
+    for-in "^1.0.1"
+
+forever-agent@~0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
+
+form-data@~2.1.1:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4"
+  dependencies:
+    asynckit "^0.4.0"
+    combined-stream "^1.0.5"
+    mime-types "^2.1.12"
+
+fs.realpath@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+
+fsevents@^1.0.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.2.tgz#3282b713fb3ad80ede0e9fcf4611b5aa6fc033f4"
+  dependencies:
+    nan "^2.3.0"
+    node-pre-gyp "^0.6.36"
+
+fstream-ignore@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105"
+  dependencies:
+    fstream "^1.0.0"
+    inherits "2"
+    minimatch "^3.0.0"
+
+fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2:
+  version "1.0.11"
+  resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171"
+  dependencies:
+    graceful-fs "^4.1.2"
+    inherits "~2.0.0"
+    mkdirp ">=0.5 0"
+    rimraf "2"
+
+gauge@~2.7.3:
+  version "2.7.4"
+  resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
+  dependencies:
+    aproba "^1.0.3"
+    console-control-strings "^1.0.0"
+    has-unicode "^2.0.0"
+    object-assign "^4.1.0"
+    signal-exit "^3.0.0"
+    string-width "^1.0.1"
+    strip-ansi "^3.0.1"
+    wide-align "^1.1.0"
+
+get-caller-file@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5"
+
+getpass@^0.1.1:
+  version "0.1.6"
+  resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6"
+  dependencies:
+    assert-plus "^1.0.0"
+
+glob-base@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
+  dependencies:
+    glob-parent "^2.0.0"
+    is-glob "^2.0.0"
+
+glob-parent@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28"
+  dependencies:
+    is-glob "^2.0.0"
+
+glob@^7.0.3, glob@^7.0.5:
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
+  dependencies:
+    fs.realpath "^1.0.0"
+    inflight "^1.0.4"
+    inherits "2"
+    minimatch "^3.0.2"
+    once "^1.3.0"
+    path-is-absolute "^1.0.0"
+
+globals@^9.0.0:
+  version "9.17.0"
+  resolved "https://registry.yarnpkg.com/globals/-/globals-9.17.0.tgz#0c0ca696d9b9bb694d2e5470bd37777caad50286"
+
+graceful-fs@^4.1.2, graceful-fs@^4.1.6:
+  version "4.1.11"
+  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
+
+growly@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
+
+handlebars@^4.0.3:
+  version "4.0.6"
+  resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7"
+  dependencies:
+    async "^1.4.0"
+    optimist "^0.6.1"
+    source-map "^0.4.4"
+  optionalDependencies:
+    uglify-js "^2.6"
+
+har-schema@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e"
+
+har-validator@~4.2.1:
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a"
+  dependencies:
+    ajv "^4.9.1"
+    har-schema "^1.0.5"
+
+has-ansi@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
+  dependencies:
+    ansi-regex "^2.0.0"
+
+has-flag@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
+
+has-unicode@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
+
+hash-base@^2.0.0:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1"
+  dependencies:
+    inherits "^2.0.1"
+
+hash.js@^1.0.0, hash.js@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.0.3.tgz#1332ff00156c0a0ffdd8236013d07b77a0451573"
+  dependencies:
+    inherits "^2.0.1"
+
+hawk@~3.1.3:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4"
+  dependencies:
+    boom "2.x.x"
+    cryptiles "2.x.x"
+    hoek "2.x.x"
+    sntp "1.x.x"
+
+hmac-drbg@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
+  dependencies:
+    hash.js "^1.0.3"
+    minimalistic-assert "^1.0.0"
+    minimalistic-crypto-utils "^1.0.1"
+
+hoek@2.x.x:
+  version "2.16.3"
+  resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed"
+
+home-or-tmp@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8"
+  dependencies:
+    os-homedir "^1.0.0"
+    os-tmpdir "^1.0.1"
+
+hosted-git-info@^2.1.4:
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.4.1.tgz#4b0445e41c004a8bd1337773a4ff790ca40318c8"
+
+html-encoding-sniffer@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.1.tgz#79bf7a785ea495fe66165e734153f363ff5437da"
+  dependencies:
+    whatwg-encoding "^1.0.1"
+
+http-signature@~1.1.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf"
+  dependencies:
+    assert-plus "^0.2.0"
+    jsprim "^1.2.2"
+    sshpk "^1.7.0"
+
+https-browserify@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82"
+
+iconv-lite@0.4.13:
+  version "0.4.13"
+  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2"
+
+iconv-lite@~0.4.13:
+  version "0.4.15"
+  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb"
+
+ieee754@^1.1.4:
+  version "1.1.8"
+  resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4"
+
+indexof@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d"
+
+inflight@^1.0.4:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+  dependencies:
+    once "^1.3.0"
+    wrappy "1"
+
+inherits@2, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
+
+inherits@2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
+
+ini@~1.3.0:
+  version "1.3.4"
+  resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e"
+
+interpret@^1.0.0:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.3.tgz#cbc35c62eeee73f19ab7b10a801511401afc0f90"
+
+invariant@^2.2.0:
+  version "2.2.2"
+  resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360"
+  dependencies:
+    loose-envify "^1.0.0"
+
+invert-kv@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
+
+is-arrayish@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
+
+is-binary-path@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
+  dependencies:
+    binary-extensions "^1.0.0"
+
+is-buffer@^1.0.2:
+  version "1.1.5"
+  resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc"
+
+is-builtin-module@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe"
+  dependencies:
+    builtin-modules "^1.0.0"
+
+is-ci@^1.0.9:
+  version "1.0.10"
+  resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.0.10.tgz#f739336b2632365061a9d48270cd56ae3369318e"
+  dependencies:
+    ci-info "^1.0.0"
+
+is-dotfile@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d"
+
+is-equal-shallow@^0.1.3:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534"
+  dependencies:
+    is-primitive "^2.0.0"
+
+is-extendable@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
+
+is-extglob@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
+
+is-finite@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa"
+  dependencies:
+    number-is-nan "^1.0.0"
+
+is-fullwidth-code-point@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
+  dependencies:
+    number-is-nan "^1.0.0"
+
+is-glob@^2.0.0, is-glob@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
+  dependencies:
+    is-extglob "^1.0.0"
+
+is-number@^2.0.2, is-number@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
+  dependencies:
+    kind-of "^3.0.2"
+
+is-posix-bracket@^0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
+
+is-primitive@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
+
+is-stream@^1.0.1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
+
+is-typedarray@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
+
+is-utf8@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
+
+isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
+
+isexe@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+
+isobject@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
+  dependencies:
+    isarray "1.0.0"
+
+isomorphic-fetch@^2.1.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
+  dependencies:
+    node-fetch "^1.0.1"
+    whatwg-fetch ">=0.10.0"
+
+isstream@~0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
+
+istanbul-api@^1.1.0-alpha.1:
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-1.1.7.tgz#f6f37f09f8002b130f891c646b70ee4a8e7345ae"
+  dependencies:
+    async "^2.1.4"
+    fileset "^2.0.2"
+    istanbul-lib-coverage "^1.0.2"
+    istanbul-lib-hook "^1.0.5"
+    istanbul-lib-instrument "^1.7.0"
+    istanbul-lib-report "^1.0.0"
+    istanbul-lib-source-maps "^1.1.1"
+    istanbul-reports "^1.0.2"
+    js-yaml "^3.7.0"
+    mkdirp "^0.5.1"
+    once "^1.4.0"
+
+istanbul-lib-coverage@^1.0.0, istanbul-lib-coverage@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.0.2.tgz#87a0c015b6910651cb3b184814dfb339337e25e1"
+
+istanbul-lib-hook@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.0.5.tgz#6ca3d16d60c5f4082da39f7c5cd38ea8a772b88e"
+  dependencies:
+    append-transform "^0.4.0"
+
+istanbul-lib-instrument@^1.1.1, istanbul-lib-instrument@^1.6.2, istanbul-lib-instrument@^1.7.0:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.7.0.tgz#b8e0dc25709bb44e17336ab47b7bb5c97c23f659"
+  dependencies:
+    babel-generator "^6.18.0"
+    babel-template "^6.16.0"
+    babel-traverse "^6.18.0"
+    babel-types "^6.18.0"
+    babylon "^6.13.0"
+    istanbul-lib-coverage "^1.0.2"
+    semver "^5.3.0"
+
+istanbul-lib-report@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.0.0.tgz#d83dac7f26566b521585569367fe84ccfc7aaecb"
+  dependencies:
+    istanbul-lib-coverage "^1.0.2"
+    mkdirp "^0.5.1"
+    path-parse "^1.0.5"
+    supports-color "^3.1.2"
+
+istanbul-lib-source-maps@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.1.1.tgz#f8c8c2e8f2160d1d91526d97e5bd63b2079af71c"
+  dependencies:
+    istanbul-lib-coverage "^1.0.2"
+    mkdirp "^0.5.1"
+    rimraf "^2.4.4"
+    source-map "^0.5.3"
+
+istanbul-reports@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.0.2.tgz#4e8366abe6fa746cc1cd6633f108de12cc6ac6fa"
+  dependencies:
+    handlebars "^4.0.3"
+
+jest-changed-files@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-19.0.2.tgz#16c54c84c3270be408e06d2e8af3f3e37a885824"
+
+jest-cli@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-19.0.2.tgz#cc3620b62acac5f2d93a548cb6ef697d4ec85443"
+  dependencies:
+    ansi-escapes "^1.4.0"
+    callsites "^2.0.0"
+    chalk "^1.1.1"
+    graceful-fs "^4.1.6"
+    is-ci "^1.0.9"
+    istanbul-api "^1.1.0-alpha.1"
+    istanbul-lib-coverage "^1.0.0"
+    istanbul-lib-instrument "^1.1.1"
+    jest-changed-files "^19.0.2"
+    jest-config "^19.0.2"
+    jest-environment-jsdom "^19.0.2"
+    jest-haste-map "^19.0.0"
+    jest-jasmine2 "^19.0.2"
+    jest-message-util "^19.0.0"
+    jest-regex-util "^19.0.0"
+    jest-resolve-dependencies "^19.0.0"
+    jest-runtime "^19.0.2"
+    jest-snapshot "^19.0.2"
+    jest-util "^19.0.2"
+    micromatch "^2.3.11"
+    node-notifier "^5.0.1"
+    slash "^1.0.0"
+    string-length "^1.0.1"
+    throat "^3.0.0"
+    which "^1.1.1"
+    worker-farm "^1.3.1"
+    yargs "^6.3.0"
+
+jest-config@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-19.0.2.tgz#1b9bd2db0ddd16df61c2b10a54009e1768da6411"
+  dependencies:
+    chalk "^1.1.1"
+    jest-environment-jsdom "^19.0.2"
+    jest-environment-node "^19.0.2"
+    jest-jasmine2 "^19.0.2"
+    jest-regex-util "^19.0.0"
+    jest-resolve "^19.0.2"
+    jest-validate "^19.0.2"
+    pretty-format "^19.0.0"
+
+jest-diff@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-19.0.0.tgz#d1563cfc56c8b60232988fbc05d4d16ed90f063c"
+  dependencies:
+    chalk "^1.1.3"
+    diff "^3.0.0"
+    jest-matcher-utils "^19.0.0"
+    pretty-format "^19.0.0"
+
+jest-environment-jsdom@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-19.0.2.tgz#ceda859c4a4b94ab35e4de7dab54b926f293e4a3"
+  dependencies:
+    jest-mock "^19.0.0"
+    jest-util "^19.0.2"
+    jsdom "^9.11.0"
+
+jest-environment-node@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-19.0.2.tgz#6e84079db87ed21d0c05e1f9669f207b116fe99b"
+  dependencies:
+    jest-mock "^19.0.0"
+    jest-util "^19.0.2"
+
+jest-file-exists@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-file-exists/-/jest-file-exists-19.0.0.tgz#cca2e587a11ec92e24cfeab3f8a94d657f3fceb8"
+
+jest-haste-map@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-19.0.0.tgz#adde00b62b1fe04432a104b3254fc5004514b55e"
+  dependencies:
+    fb-watchman "^2.0.0"
+    graceful-fs "^4.1.6"
+    micromatch "^2.3.11"
+    sane "~1.5.0"
+    worker-farm "^1.3.1"
+
+jest-jasmine2@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-19.0.2.tgz#167991ac825981fb1a800af126e83afcca832c73"
+  dependencies:
+    graceful-fs "^4.1.6"
+    jest-matcher-utils "^19.0.0"
+    jest-matchers "^19.0.0"
+    jest-message-util "^19.0.0"
+    jest-snapshot "^19.0.2"
+
+jest-matcher-utils@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-19.0.0.tgz#5ecd9b63565d2b001f61fbf7ec4c7f537964564d"
+  dependencies:
+    chalk "^1.1.3"
+    pretty-format "^19.0.0"
+
+jest-matchers@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-matchers/-/jest-matchers-19.0.0.tgz#c74ecc6ebfec06f384767ba4d6fa4a42d6755754"
+  dependencies:
+    jest-diff "^19.0.0"
+    jest-matcher-utils "^19.0.0"
+    jest-message-util "^19.0.0"
+    jest-regex-util "^19.0.0"
+
+jest-message-util@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-19.0.0.tgz#721796b89c0e4d761606f9ba8cb828a3b6246416"
+  dependencies:
+    chalk "^1.1.1"
+    micromatch "^2.3.11"
+
+jest-mock@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-19.0.0.tgz#67038641e9607ab2ce08ec4a8cb83aabbc899d01"
+
+jest-regex-util@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-19.0.0.tgz#b7754587112aede1456510bb1f6afe74ef598691"
+
+jest-resolve-dependencies@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-19.0.0.tgz#a741ad1fa094140e64ecf2642a504f834ece22ee"
+  dependencies:
+    jest-file-exists "^19.0.0"
+
+jest-resolve@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-19.0.2.tgz#5793575de4f07aec32f7d7ff0c6c181963eefb3c"
+  dependencies:
+    browser-resolve "^1.11.2"
+    jest-haste-map "^19.0.0"
+    resolve "^1.2.0"
+
+jest-runtime@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-19.0.2.tgz#d9a43e72de416d27d196fd9c7940d98fe6685407"
+  dependencies:
+    babel-core "^6.0.0"
+    babel-jest "^19.0.0"
+    babel-plugin-istanbul "^4.0.0"
+    chalk "^1.1.3"
+    graceful-fs "^4.1.6"
+    jest-config "^19.0.2"
+    jest-file-exists "^19.0.0"
+    jest-haste-map "^19.0.0"
+    jest-regex-util "^19.0.0"
+    jest-resolve "^19.0.2"
+    jest-util "^19.0.2"
+    json-stable-stringify "^1.0.1"
+    micromatch "^2.3.11"
+    strip-bom "3.0.0"
+    yargs "^6.3.0"
+
+jest-snapshot@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-19.0.2.tgz#9c1b216214f7187c38bfd5c70b1efab16b0ff50b"
+  dependencies:
+    chalk "^1.1.3"
+    jest-diff "^19.0.0"
+    jest-file-exists "^19.0.0"
+    jest-matcher-utils "^19.0.0"
+    jest-util "^19.0.2"
+    natural-compare "^1.4.0"
+    pretty-format "^19.0.0"
+
+jest-util@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-19.0.2.tgz#e0a0232a2ab9e6b2b53668bdb3534c2b5977ed41"
+  dependencies:
+    chalk "^1.1.1"
+    graceful-fs "^4.1.6"
+    jest-file-exists "^19.0.0"
+    jest-message-util "^19.0.0"
+    jest-mock "^19.0.0"
+    jest-validate "^19.0.2"
+    leven "^2.0.0"
+    mkdirp "^0.5.1"
+
+jest-validate@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-19.0.2.tgz#dc534df5f1278d5b63df32b14241d4dbf7244c0c"
+  dependencies:
+    chalk "^1.1.1"
+    jest-matcher-utils "^19.0.0"
+    leven "^2.0.0"
+    pretty-format "^19.0.0"
+
+jest@^19.0.2:
+  version "19.0.2"
+  resolved "https://registry.yarnpkg.com/jest/-/jest-19.0.2.tgz#b794faaf8ff461e7388f28beef559a54f20b2c10"
+  dependencies:
+    jest-cli "^19.0.2"
+
+jodid25519@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967"
+  dependencies:
+    jsbn "~0.1.0"
+
+js-tokens@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7"
+
+js-yaml@^3.7.0:
+  version "3.8.3"
+  resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.3.tgz#33a05ec481c850c8875929166fe1beb61c728766"
+  dependencies:
+    argparse "^1.0.7"
+    esprima "^3.1.1"
+
+jsbn@~0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
+
+jsdom@^9.11.0:
+  version "9.12.0"
+  resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-9.12.0.tgz#e8c546fffcb06c00d4833ca84410fed7f8a097d4"
+  dependencies:
+    abab "^1.0.3"
+    acorn "^4.0.4"
+    acorn-globals "^3.1.0"
+    array-equal "^1.0.0"
+    content-type-parser "^1.0.1"
+    cssom ">= 0.3.2 < 0.4.0"
+    cssstyle ">= 0.2.37 < 0.3.0"
+    escodegen "^1.6.1"
+    html-encoding-sniffer "^1.0.1"
+    nwmatcher ">= 1.3.9 < 2.0.0"
+    parse5 "^1.5.1"
+    request "^2.79.0"
+    sax "^1.2.1"
+    symbol-tree "^3.2.1"
+    tough-cookie "^2.3.2"
+    webidl-conversions "^4.0.0"
+    whatwg-encoding "^1.0.1"
+    whatwg-url "^4.3.0"
+    xml-name-validator "^2.0.1"
+
+jsesc@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b"
+
+jsesc@~0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
+
+json-loader@^0.5.4:
+  version "0.5.4"
+  resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.4.tgz#8baa1365a632f58a3c46d20175fc6002c96e37de"
+
+json-schema@0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
+
+json-stable-stringify@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af"
+  dependencies:
+    jsonify "~0.0.0"
+
+json-stringify-safe@~5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
+
+json5@^0.5.0, json5@^0.5.1:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
+
+jsonify@~0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
+
+jsprim@^1.2.2:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.0.tgz#a3b87e40298d8c380552d8cc7628a0bb95a22918"
+  dependencies:
+    assert-plus "1.0.0"
+    extsprintf "1.0.2"
+    json-schema "0.2.3"
+    verror "1.3.6"
+
+kind-of@^3.0.2:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47"
+  dependencies:
+    is-buffer "^1.0.2"
+
+lazy-cache@^1.0.3:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
+
+lcid@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
+  dependencies:
+    invert-kv "^1.0.0"
+
+leven@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580"
+
+levn@~0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
+  dependencies:
+    prelude-ls "~1.1.2"
+    type-check "~0.3.2"
+
+load-json-file@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
+  dependencies:
+    graceful-fs "^4.1.2"
+    parse-json "^2.2.0"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+    strip-bom "^2.0.0"
+
+loader-runner@^2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2"
+
+loader-utils@^0.2.16:
+  version "0.2.17"
+  resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348"
+  dependencies:
+    big.js "^3.1.3"
+    emojis-list "^2.0.0"
+    json5 "^0.5.0"
+    object-assign "^4.0.1"
+
+locate-path@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
+  dependencies:
+    p-locate "^2.0.0"
+    path-exists "^3.0.0"
+
+lodash@^4.14.0, lodash@^4.2.0:
+  version "4.17.4"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
+
+longest@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
+
+loose-envify@^1.0.0, loose-envify@^1.1.0:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
+  dependencies:
+    js-tokens "^3.0.0"
+
+makeerror@1.0.x:
+  version "1.0.11"
+  resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c"
+  dependencies:
+    tmpl "1.0.x"
+
+memory-fs@^0.4.0, memory-fs@~0.4.1:
+  version "0.4.1"
+  resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"
+  dependencies:
+    errno "^0.1.3"
+    readable-stream "^2.0.1"
+
+merge@^1.1.3:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da"
+
+micromatch@^2.1.5, micromatch@^2.3.11:
+  version "2.3.11"
+  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
+  dependencies:
+    arr-diff "^2.0.0"
+    array-unique "^0.2.1"
+    braces "^1.8.2"
+    expand-brackets "^0.1.4"
+    extglob "^0.3.1"
+    filename-regex "^2.0.0"
+    is-extglob "^1.0.0"
+    is-glob "^2.0.1"
+    kind-of "^3.0.2"
+    normalize-path "^2.0.1"
+    object.omit "^2.0.0"
+    parse-glob "^3.0.4"
+    regex-cache "^0.4.2"
+
+miller-rabin@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.0.tgz#4a62fb1d42933c05583982f4c716f6fb9e6c6d3d"
+  dependencies:
+    bn.js "^4.0.0"
+    brorand "^1.0.1"
+
+mime-db@~1.27.0:
+  version "1.27.0"
+  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1"
+
+mime-types@^2.1.12, mime-types@~2.1.7:
+  version "2.1.15"
+  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed"
+  dependencies:
+    mime-db "~1.27.0"
+
+minimalistic-assert@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3"
+
+minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
+
+minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774"
+  dependencies:
+    brace-expansion "^1.0.0"
+
+minimist@0.0.8, minimist@~0.0.1:
+  version "0.0.8"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
+
+minimist@^1.1.1, minimist@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
+
+"mkdirp@>=0.5 0", mkdirp@^0.5.1, mkdirp@~0.5.0:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
+  dependencies:
+    minimist "0.0.8"
+
+ms@0.7.2:
+  version "0.7.2"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765"
+
+nan@^2.3.0:
+  version "2.6.2"
+  resolved "https://registry.yarnpkg.com/nan/-/nan-2.6.2.tgz#e4ff34e6c95fdfb5aecc08de6596f43605a7db45"
+
+natural-compare@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
+
+node-fetch@^1.0.1:
+  version "1.6.3"
+  resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04"
+  dependencies:
+    encoding "^0.1.11"
+    is-stream "^1.0.1"
+
+node-int64@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
+
+node-libs-browser@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.0.0.tgz#a3a59ec97024985b46e958379646f96c4b616646"
+  dependencies:
+    assert "^1.1.1"
+    browserify-zlib "^0.1.4"
+    buffer "^4.3.0"
+    console-browserify "^1.1.0"
+    constants-browserify "^1.0.0"
+    crypto-browserify "^3.11.0"
+    domain-browser "^1.1.1"
+    events "^1.0.0"
+    https-browserify "0.0.1"
+    os-browserify "^0.2.0"
+    path-browserify "0.0.0"
+    process "^0.11.0"
+    punycode "^1.2.4"
+    querystring-es3 "^0.2.0"
+    readable-stream "^2.0.5"
+    stream-browserify "^2.0.1"
+    stream-http "^2.3.1"
+    string_decoder "^0.10.25"
+    timers-browserify "^2.0.2"
+    tty-browserify "0.0.0"
+    url "^0.11.0"
+    util "^0.10.3"
+    vm-browserify "0.0.4"
+
+node-notifier@^5.0.1:
+  version "5.1.2"
+  resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.1.2.tgz#2fa9e12605fa10009d44549d6fcd8a63dde0e4ff"
+  dependencies:
+    growly "^1.3.0"
+    semver "^5.3.0"
+    shellwords "^0.1.0"
+    which "^1.2.12"
+
+node-pre-gyp@^0.6.36:
+  version "0.6.36"
+  resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.36.tgz#db604112cb74e0d477554e9b505b17abddfab786"
+  dependencies:
+    mkdirp "^0.5.1"
+    nopt "^4.0.1"
+    npmlog "^4.0.2"
+    rc "^1.1.7"
+    request "^2.81.0"
+    rimraf "^2.6.1"
+    semver "^5.3.0"
+    tar "^2.2.1"
+    tar-pack "^3.4.0"
+
+nopt@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
+  dependencies:
+    abbrev "1"
+    osenv "^0.1.4"
+
+normalize-package-data@^2.3.2:
+  version "2.3.6"
+  resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.6.tgz#498fa420c96401f787402ba21e600def9f981fff"
+  dependencies:
+    hosted-git-info "^2.1.4"
+    is-builtin-module "^1.0.0"
+    semver "2 || 3 || 4 || 5"
+    validate-npm-package-license "^3.0.1"
+
+normalize-path@^2.0.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
+  dependencies:
+    remove-trailing-separator "^1.0.1"
+
+npmlog@^4.0.2:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.0.tgz#dc59bee85f64f00ed424efb2af0783df25d1c0b5"
+  dependencies:
+    are-we-there-yet "~1.1.2"
+    console-control-strings "~1.1.0"
+    gauge "~2.7.3"
+    set-blocking "~2.0.0"
+
+number-is-nan@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
+
+"nwmatcher@>= 1.3.9 < 2.0.0":
+  version "1.3.9"
+  resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.3.9.tgz#8bab486ff7fa3dfd086656bbe8b17116d3692d2a"
+
+oauth-sign@~0.8.1:
+  version "0.8.2"
+  resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
+
+object-assign@^4.0.1, object-assign@^4.1.0:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+
+object.omit@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
+  dependencies:
+    for-own "^0.1.4"
+    is-extendable "^0.1.1"
+
+once@^1.3.0, once@^1.3.3, once@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+  dependencies:
+    wrappy "1"
+
+optimist@^0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
+  dependencies:
+    minimist "~0.0.1"
+    wordwrap "~0.0.2"
+
+optionator@^0.8.1:
+  version "0.8.2"
+  resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64"
+  dependencies:
+    deep-is "~0.1.3"
+    fast-levenshtein "~2.0.4"
+    levn "~0.3.0"
+    prelude-ls "~1.1.2"
+    type-check "~0.3.2"
+    wordwrap "~1.0.0"
+
+os-browserify@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.2.1.tgz#63fc4ccee5d2d7763d26bbf8601078e6c2e0044f"
+
+os-homedir@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
+
+os-locale@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9"
+  dependencies:
+    lcid "^1.0.0"
+
+os-tmpdir@^1.0.0, os-tmpdir@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
+
+osenv@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644"
+  dependencies:
+    os-homedir "^1.0.0"
+    os-tmpdir "^1.0.0"
+
+p-limit@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.1.0.tgz#b07ff2d9a5d88bec806035895a2bab66a27988bc"
+
+p-locate@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
+  dependencies:
+    p-limit "^1.1.0"
+
+pako@~0.2.0:
+  version "0.2.9"
+  resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
+
+parse-asn1@^5.0.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712"
+  dependencies:
+    asn1.js "^4.0.0"
+    browserify-aes "^1.0.0"
+    create-hash "^1.1.0"
+    evp_bytestokey "^1.0.0"
+    pbkdf2 "^3.0.3"
+
+parse-glob@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
+  dependencies:
+    glob-base "^0.3.0"
+    is-dotfile "^1.0.0"
+    is-extglob "^1.0.0"
+    is-glob "^2.0.0"
+
+parse-json@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
+  dependencies:
+    error-ex "^1.2.0"
+
+parse5@^1.5.1:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94"
+
+path-browserify@0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a"
+
+path-exists@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
+  dependencies:
+    pinkie-promise "^2.0.0"
+
+path-exists@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
+
+path-is-absolute@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+
+path-parse@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1"
+
+path-type@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
+  dependencies:
+    graceful-fs "^4.1.2"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+pbkdf2@^3.0.3:
+  version "3.0.12"
+  resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.12.tgz#be36785c5067ea48d806ff923288c5f750b6b8a2"
+  dependencies:
+    create-hash "^1.1.2"
+    create-hmac "^1.1.4"
+    ripemd160 "^2.0.1"
+    safe-buffer "^5.0.1"
+    sha.js "^2.4.8"
+
+performance-now@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5"
+
+pify@^2.0.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
+
+pinkie-promise@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
+  dependencies:
+    pinkie "^2.0.0"
+
+pinkie@^2.0.0:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
+
+prelude-ls@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
+
+preserve@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
+
+pretty-format@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-19.0.0.tgz#56530d32acb98a3fa4851c4e2b9d37b420684c84"
+  dependencies:
+    ansi-styles "^3.0.0"
+
+private@^0.1.6:
+  version "0.1.7"
+  resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1"
+
+process-nextick-args@~1.0.6:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
+
+process@^0.11.0:
+  version "0.11.10"
+  resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
+
+promise@^7.1.1:
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/promise/-/promise-7.1.1.tgz#489654c692616b8aa55b0724fa809bb7db49c5bf"
+  dependencies:
+    asap "~2.0.3"
+
+prr@~0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a"
+
+public-encrypt@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.0.tgz#39f699f3a46560dd5ebacbca693caf7c65c18cc6"
+  dependencies:
+    bn.js "^4.1.0"
+    browserify-rsa "^4.0.0"
+    create-hash "^1.1.0"
+    parse-asn1 "^5.0.0"
+    randombytes "^2.0.1"
+
+punycode@1.3.2:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
+
+punycode@^1.2.4, punycode@^1.4.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
+
+qs@~6.4.0:
+  version "6.4.0"
+  resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
+
+querystring-es3@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
+
+querystring@0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
+
+randomatic@^1.1.3:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb"
+  dependencies:
+    is-number "^2.0.2"
+    kind-of "^3.0.2"
+
+randombytes@^2.0.0, randombytes@^2.0.1:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.5.tgz#dc009a246b8d09a177b4b7a0ae77bc570f4b1b79"
+  dependencies:
+    safe-buffer "^5.1.0"
+
+rc@^1.1.7:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.1.tgz#2e03e8e42ee450b8cb3dce65be1bf8974e1dfd95"
+  dependencies:
+    deep-extend "~0.4.0"
+    ini "~1.3.0"
+    minimist "^1.2.0"
+    strip-json-comments "~2.0.1"
+
+react-dom@^15.4.2:
+  version "15.4.2"
+  resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.4.2.tgz#015363f05b0a1fd52ae9efdd3a0060d90695208f"
+  dependencies:
+    fbjs "^0.8.1"
+    loose-envify "^1.1.0"
+    object-assign "^4.1.0"
+
+react@^15.4.2:
+  version "15.4.2"
+  resolved "https://registry.yarnpkg.com/react/-/react-15.4.2.tgz#41f7991b26185392ba9bae96c8889e7e018397ef"
+  dependencies:
+    fbjs "^0.8.4"
+    loose-envify "^1.1.0"
+    object-assign "^4.1.0"
+
+read-pkg-up@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
+  dependencies:
+    find-up "^1.0.0"
+    read-pkg "^1.0.0"
+
+read-pkg@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
+  dependencies:
+    load-json-file "^1.0.0"
+    normalize-package-data "^2.3.2"
+    path-type "^1.0.0"
+
+readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.2.6:
+  version "2.2.11"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.11.tgz#0796b31f8d7688007ff0b93a8088d34aa17c0f72"
+  dependencies:
+    core-util-is "~1.0.0"
+    inherits "~2.0.1"
+    isarray "~1.0.0"
+    process-nextick-args "~1.0.6"
+    safe-buffer "~5.0.1"
+    string_decoder "~1.0.0"
+    util-deprecate "~1.0.1"
+
+readdirp@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78"
+  dependencies:
+    graceful-fs "^4.1.2"
+    minimatch "^3.0.2"
+    readable-stream "^2.0.2"
+    set-immediate-shim "^1.0.1"
+
+regenerate@^1.2.1:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260"
+
+regenerator-runtime@^0.10.0:
+  version "0.10.3"
+  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.3.tgz#8c4367a904b51ea62a908ac310bf99ff90a82a3e"
+
+regenerator-transform@0.9.8:
+  version "0.9.8"
+  resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.9.8.tgz#0f88bb2bc03932ddb7b6b7312e68078f01026d6c"
+  dependencies:
+    babel-runtime "^6.18.0"
+    babel-types "^6.19.0"
+    private "^0.1.6"
+
+regex-cache@^0.4.2:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145"
+  dependencies:
+    is-equal-shallow "^0.1.3"
+    is-primitive "^2.0.0"
+
+regexpu-core@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240"
+  dependencies:
+    regenerate "^1.2.1"
+    regjsgen "^0.2.0"
+    regjsparser "^0.1.4"
+
+regjsgen@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7"
+
+regjsparser@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c"
+  dependencies:
+    jsesc "~0.5.0"
+
+remove-trailing-separator@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.0.1.tgz#615ebb96af559552d4bf4057c8436d486ab63cc4"
+
+repeat-element@^1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a"
+
+repeat-string@^1.5.2:
+  version "1.6.1"
+  resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
+
+repeating@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda"
+  dependencies:
+    is-finite "^1.0.0"
+
+request@^2.79.0, request@^2.81.0:
+  version "2.81.0"
+  resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0"
+  dependencies:
+    aws-sign2 "~0.6.0"
+    aws4 "^1.2.1"
+    caseless "~0.12.0"
+    combined-stream "~1.0.5"
+    extend "~3.0.0"
+    forever-agent "~0.6.1"
+    form-data "~2.1.1"
+    har-validator "~4.2.1"
+    hawk "~3.1.3"
+    http-signature "~1.1.0"
+    is-typedarray "~1.0.0"
+    isstream "~0.1.2"
+    json-stringify-safe "~5.0.1"
+    mime-types "~2.1.7"
+    oauth-sign "~0.8.1"
+    performance-now "^0.2.0"
+    qs "~6.4.0"
+    safe-buffer "^5.0.1"
+    stringstream "~0.0.4"
+    tough-cookie "~2.3.0"
+    tunnel-agent "^0.6.0"
+    uuid "^3.0.0"
+
+require-directory@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
+
+require-main-filename@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
+
+resolve@1.1.7:
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
+
+resolve@^1.2.0:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.3.2.tgz#1f0442c9e0cbb8136e87b9305f932f46c7f28235"
+  dependencies:
+    path-parse "^1.0.5"
+
+right-align@^0.1.1:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef"
+  dependencies:
+    align-text "^0.1.1"
+
+rimraf@2, rimraf@^2.4.4, rimraf@^2.5.1, rimraf@^2.6.1:
+  version "2.6.1"
+  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d"
+  dependencies:
+    glob "^7.0.5"
+
+ripemd160@^2.0.0, ripemd160@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7"
+  dependencies:
+    hash-base "^2.0.0"
+    inherits "^2.0.1"
+
+safe-buffer@^5.0.1, safe-buffer@~5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7"
+
+safe-buffer@^5.1.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.0.tgz#fe4c8460397f9eaaaa58e73be46273408a45e223"
+
+sane@~1.5.0:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/sane/-/sane-1.5.0.tgz#a4adeae764d048621ecb27d5f9ecf513101939f3"
+  dependencies:
+    anymatch "^1.3.0"
+    exec-sh "^0.2.0"
+    fb-watchman "^1.8.0"
+    minimatch "^3.0.2"
+    minimist "^1.1.1"
+    walker "~1.0.5"
+    watch "~0.10.0"
+
+sax@^1.2.1:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.2.tgz#fd8631a23bc7826bef5d871bdb87378c95647828"
+
+"semver@2 || 3 || 4 || 5", semver@^5.3.0:
+  version "5.3.0"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
+
+set-blocking@^2.0.0, set-blocking@~2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
+
+set-immediate-shim@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61"
+
+setimmediate@^1.0.4, setimmediate@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
+
+sha.js@^2.4.0, sha.js@^2.4.8:
+  version "2.4.8"
+  resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.8.tgz#37068c2c476b6baf402d14a49c67f597921f634f"
+  dependencies:
+    inherits "^2.0.1"
+
+shellwords@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.0.tgz#66afd47b6a12932d9071cbfd98a52e785cd0ba14"
+
+signal-exit@^3.0.0:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
+
+slash@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
+
+sntp@1.x.x:
+  version "1.0.9"
+  resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198"
+  dependencies:
+    hoek "2.x.x"
+
+source-list-map@^1.1.1:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-1.1.2.tgz#9889019d1024cce55cdc069498337ef6186a11a1"
+
+source-map-support@^0.4.2:
+  version "0.4.14"
+  resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.14.tgz#9d4463772598b86271b4f523f6c1f4e02a7d6aef"
+  dependencies:
+    source-map "^0.5.6"
+
+source-map@^0.4.4:
+  version "0.4.4"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b"
+  dependencies:
+    amdefine ">=0.0.4"
+
+source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.3:
+  version "0.5.6"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
+
+source-map@~0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d"
+  dependencies:
+    amdefine ">=0.0.4"
+
+spdx-correct@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40"
+  dependencies:
+    spdx-license-ids "^1.0.2"
+
+spdx-expression-parse@~1.0.0:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c"
+
+spdx-license-ids@^1.0.2:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57"
+
+sprintf-js@~1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
+
+sshpk@^1.7.0:
+  version "1.11.0"
+  resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.11.0.tgz#2d8d5ebb4a6fab28ffba37fa62a90f4a3ea59d77"
+  dependencies:
+    asn1 "~0.2.3"
+    assert-plus "^1.0.0"
+    dashdash "^1.12.0"
+    getpass "^0.1.1"
+  optionalDependencies:
+    bcrypt-pbkdf "^1.0.0"
+    ecc-jsbn "~0.1.1"
+    jodid25519 "^1.0.0"
+    jsbn "~0.1.0"
+    tweetnacl "~0.14.0"
+
+stream-browserify@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db"
+  dependencies:
+    inherits "~2.0.1"
+    readable-stream "^2.0.2"
+
+stream-http@^2.3.1:
+  version "2.7.2"
+  resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.7.2.tgz#40a050ec8dc3b53b33d9909415c02c0bf1abfbad"
+  dependencies:
+    builtin-status-codes "^3.0.0"
+    inherits "^2.0.1"
+    readable-stream "^2.2.6"
+    to-arraybuffer "^1.0.0"
+    xtend "^4.0.0"
+
+string-length@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/string-length/-/string-length-1.0.1.tgz#56970fb1c38558e9e70b728bf3de269ac45adfac"
+  dependencies:
+    strip-ansi "^3.0.0"
+
+string-width@^1.0.1, string-width@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
+  dependencies:
+    code-point-at "^1.0.0"
+    is-fullwidth-code-point "^1.0.0"
+    strip-ansi "^3.0.0"
+
+string_decoder@^0.10.25:
+  version "0.10.31"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
+
+string_decoder@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.2.tgz#b29e1f4e1125fa97a10382b8a533737b7491e179"
+  dependencies:
+    safe-buffer "~5.0.1"
+
+stringstream@~0.0.4:
+  version "0.0.5"
+  resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878"
+
+strip-ansi@^3.0.0, strip-ansi@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
+  dependencies:
+    ansi-regex "^2.0.0"
+
+strip-bom@3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
+
+strip-bom@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
+  dependencies:
+    is-utf8 "^0.2.0"
+
+strip-json-comments@~2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
+
+supports-color@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
+
+supports-color@^3.1.0, supports-color@^3.1.2:
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
+  dependencies:
+    has-flag "^1.0.0"
+
+symbol-tree@^3.2.1:
+  version "3.2.2"
+  resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6"
+
+tapable@^0.2.5, tapable@~0.2.5:
+  version "0.2.6"
+  resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.6.tgz#206be8e188860b514425375e6f1ae89bfb01fd8d"
+
+tar-pack@^3.4.0:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.0.tgz#23be2d7f671a8339376cbdb0b8fe3fdebf317984"
+  dependencies:
+    debug "^2.2.0"
+    fstream "^1.0.10"
+    fstream-ignore "^1.0.5"
+    once "^1.3.3"
+    readable-stream "^2.1.4"
+    rimraf "^2.5.1"
+    tar "^2.2.1"
+    uid-number "^0.0.6"
+
+tar@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1"
+  dependencies:
+    block-stream "*"
+    fstream "^1.0.2"
+    inherits "2"
+
+test-exclude@^4.0.3:
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-4.0.3.tgz#86a13ce3effcc60e6c90403cf31a27a60ac6c4e7"
+  dependencies:
+    arrify "^1.0.1"
+    micromatch "^2.3.11"
+    object-assign "^4.1.0"
+    read-pkg-up "^1.0.1"
+    require-main-filename "^1.0.1"
+
+throat@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/throat/-/throat-3.0.0.tgz#e7c64c867cbb3845f10877642f7b60055b8ec0d6"
+
+timers-browserify@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.2.tgz#ab4883cf597dcd50af211349a00fbca56ac86b86"
+  dependencies:
+    setimmediate "^1.0.4"
+
+tmpl@1.0.x:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1"
+
+to-arraybuffer@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
+
+to-fast-properties@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320"
+
+tough-cookie@^2.3.2, tough-cookie@~2.3.0:
+  version "2.3.2"
+  resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a"
+  dependencies:
+    punycode "^1.4.1"
+
+tr46@~0.0.3:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
+
+trim-right@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
+
+tty-browserify@0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
+
+tunnel-agent@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
+  dependencies:
+    safe-buffer "^5.0.1"
+
+tweetnacl@^0.14.3, tweetnacl@~0.14.0:
+  version "0.14.5"
+  resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
+
+type-check@~0.3.2:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
+  dependencies:
+    prelude-ls "~1.1.2"
+
+ua-parser-js@^0.7.9:
+  version "0.7.12"
+  resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb"
+
+uglify-js@^2.6:
+  version "2.8.21"
+  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.21.tgz#1733f669ae6f82fc90c7b25ec0f5c783ee375314"
+  dependencies:
+    source-map "~0.5.1"
+    yargs "~3.10.0"
+  optionalDependencies:
+    uglify-to-browserify "~1.0.0"
+
+uglify-js@^2.8.27:
+  version "2.8.28"
+  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.28.tgz#e335032df9bb20dcb918f164589d5af47f38834a"
+  dependencies:
+    source-map "~0.5.1"
+    yargs "~3.10.0"
+  optionalDependencies:
+    uglify-to-browserify "~1.0.0"
+
+uglify-to-browserify@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7"
+
+uid-number@^0.0.6:
+  version "0.0.6"
+  resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81"
+
+url@^0.11.0:
+  version "0.11.0"
+  resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
+  dependencies:
+    punycode "1.3.2"
+    querystring "0.2.0"
+
+util-deprecate@~1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+
+util@0.10.3, util@^0.10.3:
+  version "0.10.3"
+  resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9"
+  dependencies:
+    inherits "2.0.1"
+
+uuid@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1"
+
+validate-npm-package-license@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc"
+  dependencies:
+    spdx-correct "~1.0.0"
+    spdx-expression-parse "~1.0.0"
+
+verror@1.3.6:
+  version "1.3.6"
+  resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c"
+  dependencies:
+    extsprintf "1.0.2"
+
+vm-browserify@0.0.4:
+  version "0.0.4"
+  resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73"
+  dependencies:
+    indexof "0.0.1"
+
+walker@~1.0.5:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb"
+  dependencies:
+    makeerror "1.0.x"
+
+watch@~0.10.0:
+  version "0.10.0"
+  resolved "https://registry.yarnpkg.com/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc"
+
+watchpack@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.3.1.tgz#7d8693907b28ce6013e7f3610aa2a1acf07dad87"
+  dependencies:
+    async "^2.1.2"
+    chokidar "^1.4.3"
+    graceful-fs "^4.1.2"
+
+webidl-conversions@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
+
+webidl-conversions@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.1.tgz#8015a17ab83e7e1b311638486ace81da6ce206a0"
+
+webpack-sources@^0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-0.2.3.tgz#17c62bfaf13c707f9d02c479e0dcdde8380697fb"
+  dependencies:
+    source-list-map "^1.1.1"
+    source-map "~0.5.3"
+
+webpack@^2.6.1:
+  version "2.6.1"
+  resolved "https://registry.yarnpkg.com/webpack/-/webpack-2.6.1.tgz#2e0457f0abb1ac5df3ab106c69c672f236785f07"
+  dependencies:
+    acorn "^5.0.0"
+    acorn-dynamic-import "^2.0.0"
+    ajv "^4.7.0"
+    ajv-keywords "^1.1.1"
+    async "^2.1.2"
+    enhanced-resolve "^3.0.0"
+    interpret "^1.0.0"
+    json-loader "^0.5.4"
+    json5 "^0.5.1"
+    loader-runner "^2.3.0"
+    loader-utils "^0.2.16"
+    memory-fs "~0.4.1"
+    mkdirp "~0.5.0"
+    node-libs-browser "^2.0.0"
+    source-map "^0.5.3"
+    supports-color "^3.1.0"
+    tapable "~0.2.5"
+    uglify-js "^2.8.27"
+    watchpack "^1.3.1"
+    webpack-sources "^0.2.3"
+    yargs "^6.0.0"
+
+whatwg-encoding@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.1.tgz#3c6c451a198ee7aec55b1ec61d0920c67801a5f4"
+  dependencies:
+    iconv-lite "0.4.13"
+
+whatwg-fetch@>=0.10.0:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84"
+
+whatwg-url@^4.3.0:
+  version "4.7.0"
+  resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-4.7.0.tgz#202035ac1955b087cdd20fa8b58ded3ab1cd2af5"
+  dependencies:
+    tr46 "~0.0.3"
+    webidl-conversions "^3.0.0"
+
+which-module@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
+
+which@^1.1.1, which@^1.2.12:
+  version "1.2.14"
+  resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5"
+  dependencies:
+    isexe "^2.0.0"
+
+wide-align@^1.1.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710"
+  dependencies:
+    string-width "^1.0.2"
+
+window-size@0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
+
+wordwrap@0.0.2:
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
+
+wordwrap@~0.0.2:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
+
+wordwrap@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
+
+worker-farm@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.3.1.tgz#4333112bb49b17aa050b87895ca6b2cacf40e5ff"
+  dependencies:
+    errno ">=0.1.1 <0.2.0-0"
+    xtend ">=4.0.0 <4.1.0-0"
+
+wrap-ansi@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
+  dependencies:
+    string-width "^1.0.1"
+    strip-ansi "^3.0.1"
+
+wrappy@1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+
+xml-name-validator@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635"
+
+"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
+
+y18n@^3.2.1:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
+
+yargs-parser@^4.2.0:
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c"
+  dependencies:
+    camelcase "^3.0.0"
+
+yargs@^6.0.0, yargs@^6.3.0:
+  version "6.6.0"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208"
+  dependencies:
+    camelcase "^3.0.0"
+    cliui "^3.2.0"
+    decamelize "^1.1.1"
+    get-caller-file "^1.0.1"
+    os-locale "^1.4.0"
+    read-pkg-up "^1.0.1"
+    require-directory "^2.1.1"
+    require-main-filename "^1.0.1"
+    set-blocking "^2.0.0"
+    string-width "^1.0.2"
+    which-module "^1.0.0"
+    y18n "^3.2.1"
+    yargs-parser "^4.2.0"
+
+yargs@~3.10.0:
+  version "3.10.0"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"
+  dependencies:
+    camelcase "^1.0.2"
+    cliui "^2.1.0"
+    decamelize "^1.0.0"
+    window-size "0.1.0"
diff --git a/addons/test.js b/addons/test.js
new file mode 100644
index 000000000000..cea39f0cf5f7
--- /dev/null
+++ b/addons/test.js
@@ -0,0 +1,23 @@
+var fs = require('fs');
+var path = require('path');
+var spawnSync = require('child_process').spawnSync;
+
+function runNpmCommand(dir, args) {
+  const result = spawnSync('npm', args, {
+    cwd: path.join(__dirname, dir),
+    stdio: 'inherit'
+  });
+  if (result.status !== 0) {
+    process.exit('npm test exited with non-zero code.');
+  }
+}
+
+fs
+  .readdirSync(__dirname)
+  .filter(file => {
+    return fs.statSync(path.join(__dirname, file)).isDirectory();
+  })
+  .forEach(dir => {
+    runNpmCommand(dir, ['install']);
+    runNpmCommand(dir, ['run', 'prepublish']);
+  });
diff --git a/circle.yml b/circle.yml
new file mode 100644
index 000000000000..76b7f99bbaa4
--- /dev/null
+++ b/circle.yml
@@ -0,0 +1,46 @@
+---
+machine:
+  timezone: America/Los_Angeles
+  node:
+    version: 6
+  ruby:
+    version: 2.2.3
+  environment:
+    TRAVIS_REPO_SLUG: facebook/react
+    YARN_VERSION: 0.17.8
+    PATH: "${PATH}:${HOME}/.yarn/bin"
+
+dependencies:
+  pre:
+    # This is equivalent to $TRAVIS_COMMIT_RANGE
+    # Need to figure out how to bail early if this is a "docs only" build
+    - echo $CIRCLE_COMPARE_URL | cut -d/ -f7
+    # install yarn if it's not already installed
+    - |
+      if [[ ! -e ~/.yarn/bin/yarn || $(yarn --version) != "${YARN_VERSION}" ]]; then
+        curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version $YARN_VERSION
+      fi
+  override:
+    - bundle install --gemfile=docs/Gemfile --deployment --path=vendor/bundle --jobs=3 --retry=3
+    - yarn install
+    - scripts/circleci/set_up_github_keys.sh
+  post:
+    # - npm ls --depth=0
+  cache_directories:
+    - docs/vendor/bundle
+    - .grunt # Show size comparisons between builds
+    - ~/react-gh-pages # docs checkout
+    - ~/.yarn
+    - ~/.yarn-cache
+
+test:
+  override:
+    - ./scripts/circleci/test_entry_point.sh:
+        parallel: true
+
+deployment:
+  staging:
+    branch: /.*/
+    commands:
+      - ./scripts/circleci/upload_build.sh
+      - ./scripts/circleci/build_gh_pages.sh
diff --git a/docs/404.md b/docs/404.md
index 6d4039fb3d49..ab9ba1d60cf5 100644
--- a/docs/404.md
+++ b/docs/404.md
@@ -1,6 +1,7 @@
 ---
 layout: single
 title: Page Not Found
+permalink: 404.html
 ---
 
 We couldn't find what you were looking for.
diff --git a/docs/Gemfile b/docs/Gemfile
index 4f4991e3b2a6..f144584eff35 100644
--- a/docs/Gemfile
+++ b/docs/Gemfile
@@ -3,11 +3,12 @@ source 'https://rubygems.org'
 gem 'rake'
 
 # jekyll, which builds it all
-# 2.0 includes sass processing
-gem 'jekyll', '~>2.0'
+# 3.0 includes sass processing
+gem 'jekyll', '~>3.1'
 
-# Auto redirect pages
+# Jekyll extensions
 gem 'jekyll-redirect-from'
+gem 'jekyll-paginate'
 
 # JSON
 gem 'json'
@@ -17,3 +18,12 @@ gem 'rb-fsevent'
 
 # For markdown header cleanup
 gem 'sanitize', '~>2.0'
+
+# Markdown
+gem 'redcarpet'
+
+# Syntax highlighting
+gem 'pygments.rb'
+
+# Avoid having to poll for changes on Windows
+gem 'wdm', '>= 0.1.0' if Gem.win_platform?
\ No newline at end of file
diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock
index 89a0f264aab1..e882cb6df037 100644
--- a/docs/Gemfile.lock
+++ b/docs/Gemfile.lock
@@ -1,85 +1,67 @@
 GEM
   remote: https://rubygems.org/
   specs:
-    blankslate (2.1.2.4)
-    celluloid (0.15.2)
-      timers (~> 1.1.0)
-    classifier (1.3.4)
-      fast-stemmer (>= 1.0.0)
-    coffee-script (2.3.0)
-      coffee-script-source
-      execjs
-    coffee-script-source (1.7.1)
     colorator (0.1)
-    execjs (2.2.1)
-    fast-stemmer (1.0.2)
-    ffi (1.9.3)
-    jekyll (2.2.0)
-      classifier (~> 1.3)
+    ffi (1.9.14)
+    ffi (1.9.14-x64-mingw32)
+    jekyll (3.1.6)
       colorator (~> 0.1)
-      jekyll-coffeescript (~> 1.0)
-      jekyll-gist (~> 1.0)
-      jekyll-paginate (~> 1.0)
       jekyll-sass-converter (~> 1.0)
-      jekyll-watch (~> 1.0)
+      jekyll-watch (~> 1.1)
       kramdown (~> 1.3)
-      liquid (~> 2.6.1)
+      liquid (~> 3.0)
       mercenary (~> 0.3.3)
-      pygments.rb (~> 0.6.0)
-      redcarpet (~> 3.1)
+      rouge (~> 1.7)
       safe_yaml (~> 1.0)
-      toml (~> 0.1.0)
-    jekyll-coffeescript (1.0.0)
-      coffee-script (~> 2.2)
-    jekyll-gist (1.1.0)
-    jekyll-paginate (1.0.0)
-    jekyll-redirect-from (0.5.0)
-      jekyll (~> 2.0)
-    jekyll-sass-converter (1.2.0)
-      sass (~> 3.2)
-    jekyll-watch (1.1.0)
-      listen (~> 2.7)
-    json (1.8.1)
-    kramdown (1.4.1)
-    liquid (2.6.1)
-    listen (2.7.9)
-      celluloid (>= 0.15.2)
-      rb-fsevent (>= 0.9.3)
-      rb-inotify (>= 0.9)
-    mercenary (0.3.4)
-    mini_portile (0.6.0)
-    nokogiri (1.6.3.1)
-      mini_portile (= 0.6.0)
-    parslet (1.5.0)
-      blankslate (~> 2.0)
-    posix-spawn (0.3.9)
-    pygments.rb (0.6.0)
+    jekyll-paginate (1.1.0)
+    jekyll-redirect-from (0.11.0)
+      jekyll (>= 2.0)
+    jekyll-sass-converter (1.4.0)
+      sass (~> 3.4)
+    jekyll-watch (1.4.0)
+      listen (~> 3.0, < 3.1)
+    json (2.0.1)
+    kramdown (1.11.1)
+    liquid (3.0.6)
+    listen (3.0.8)
+      rb-fsevent (~> 0.9, >= 0.9.4)
+      rb-inotify (~> 0.9, >= 0.9.7)
+    mercenary (0.3.6)
+    mini_portile2 (2.1.0)
+    nokogiri (1.6.8)
+      mini_portile2 (~> 2.1.0)
+      pkg-config (~> 1.1.7)
+    nokogiri (1.6.8-x64-mingw32)
+      mini_portile2 (~> 2.1.0)
+      pkg-config (~> 1.1.7)
+    pkg-config (1.1.7)
+    posix-spawn (0.3.11)
+    pygments.rb (0.6.3)
       posix-spawn (~> 0.3.6)
-      yajl-ruby (~> 1.1.0)
-    rake (10.3.2)
-    rb-fsevent (0.9.4)
-    rb-inotify (0.9.5)
+      yajl-ruby (~> 1.2.0)
+    rake (11.2.2)
+    rb-fsevent (0.9.7)
+    rb-inotify (0.9.7)
       ffi (>= 0.5.0)
-    redcarpet (3.1.2)
+    redcarpet (3.3.4)
+    rouge (1.11.1)
     safe_yaml (1.0.4)
-    sanitize (2.0.6)
+    sanitize (2.1.0)
       nokogiri (>= 1.4.4)
-    sass (3.3.14)
-    timers (1.1.0)
-    toml (0.1.1)
-      parslet (~> 1.5.0)
-    yajl-ruby (1.1.0)
+    sass (3.4.22)
+    yajl-ruby (1.2.1)
 
 PLATFORMS
   ruby
+  x64-mingw32
 
 DEPENDENCIES
-  jekyll (~> 2.0)
+  jekyll (~> 3.1)
+  jekyll-paginate
   jekyll-redirect-from
   json
+  pygments.rb
   rake
   rb-fsevent
+  redcarpet
   sanitize (~> 2.0)
-
-BUNDLED WITH
-   1.10.1
diff --git a/docs/README.md b/docs/README.md
index 50448f4a71e9..f03c32dc2c75 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -34,7 +34,7 @@ Use Jekyll to serve the website locally (by default, at `http://localhost:4000`)
 $ cd react/docs
 $ bundle exec rake
 $ bundle exec jekyll serve -w
-$ open http://localhost:4000/react/
+$ open http://localhost:4000/react/index.html
 ```
 
 We use [SASS](http://sass-lang.com/) (with [Bourbon](http://bourbon.io/)) for our CSS, and we use JSX to transform some of our JS.
diff --git a/docs/Rakefile b/docs/Rakefile
index 546f7dba12be..7a9872b7c057 100644
--- a/docs/Rakefile
+++ b/docs/Rakefile
@@ -6,8 +6,8 @@ require('open-uri')
 desc "download babel-browser"
 task :fetch_remotes do
   IO.copy_stream(
-    open('https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.min.js'),
-    'js/babel-browser.min.js'
+    open('https://unpkg.com/babel-standalone@6.15.0/babel.min.js'),
+    'js/babel.min.js'
   )
 end
 
@@ -61,8 +61,15 @@ task :update_acknowledgements do
   File.open('_data/acknowledgements.yml', 'w+') { |f| f.write(cols.to_yaml) }
 end
 
+desc "copy error codes to docs"
+task :copy_error_codes do
+  codes_json = File.read('../scripts/error-codes/codes.json')
+  codes_js = "var errorMap = #{codes_json.chomp};\n"
+  File.write('js/errorMap.js', codes_js)
+end
+
 desc "build into ../../react-gh-pages"
-task :release => [:update_version, :js, :fetch_remotes] do
+task :release => [:update_version, :js, :fetch_remotes, :copy_error_codes] do
   system "jekyll build -d ../../react-gh-pages"
 end
 
diff --git a/docs/_config.yml b/docs/_config.yml
index f14db0ba7be7..e43b7484506b 100644
--- a/docs/_config.yml
+++ b/docs/_config.yml
@@ -2,24 +2,47 @@
 name: React
 description: A JavaScript library for building user interfaces
 url: https://facebook.github.io
-baseurl: "/react"
-permalink: "/blog/:year/:month/:day/:title.html"
-paginate_path: "/blog/page:num/"
-relative_permalinks: true
+baseurl: /react
+permalink: /blog/:year/:month/:day/:title.html
+paginate_path: /blog/page:num/
 paginate: 5
 timezone: America/Los_Angeles
 highlighter: pygments
 defaults:
 - scope:
     path: ''
-    type: post
+    type: posts
   values:
     layout: post
+    sectionid: blog
+- scope:
+    path: blog
+    type: pages
+  values:
+    sectionid: blog
+- scope:
+    path: tutorial
+    type: pages
+  values:
+    layout: tutorial
+    sectionid: tutorial
 - scope:
     path: docs
-    type: page
+    type: pages
   values:
     layout: docs
+    sectionid: docs
+- scope:
+    path: contributing
+    type: pages
+  values:
+    sectionid: docs
+- scope:
+    path: community
+    type: pages
+  values:
+    layout: community
+    sectionid: community
 exclude:
 - Gemfile
 - Gemfile.lock
@@ -36,13 +59,14 @@ sass:
   sass_dir: _css
 gems:
 - jekyll-redirect-from
-react_version: 0.14.7
+- jekyll-paginate
+react_version: 15.5.4
 react_hashes:
-  dev: xQae1pUPdAKUe0u0KUTNt09zzdwheX4VSUsV8vatqM+t6X7rta01qOzessL808ox
-  prod: zTm/dblzLXQNp3CgY+hfaC/WJ6h4XtNrePh2CW2+rO9GPuNiPb9jmthvAL+oI/dQ
-  addons_dev: I5TF2q2QDmB31aN5lcClArdUo+WJH/Yi3hcH3PBVXFe5DYtYCFh7Jx/dmpba12zn
-  addons_prod: KPHTQfiYMhtsIRbZcY4ri1lBYZQbj4ePsSdzODR2Bu5L5ts3APVyqwKPBThO5Hgc
-  dom_dev: A1t0GCrR06cTHvMjaxeSE8XOiz6j7NvWdmxhN/9z748wEvJTVk13Rr8gMzTUnd8G
-  dom_prod: ntqCsHbLdMxT352UbhPbT7fqjE8xi4jLmQYQa8mYR+ylAapbXRfdsDweueDObf7m
-  dom_server_dev: 3I5+eGB/ILYa6pQQX+rM9O0SyDltamM40RiZ5JvIijSYEfVGZU0vY4Iwx9a1eYyD
-  dom_server_prod: Kt9dEqXzv00orFPW2o3H+kxQtSiNO8EqXsXJT3i99rCcp74N/Km98V0kUxAzy44k
+  dev: buVLzxzBI8Ps3svVMSUurNdb5dozNidH5Ow4H0YgZeia3t6Oeui2VLpvtAq1fwtK
+  prod: nCjsa0kjNQPQdxWm12/ReVJzfBJaVubEwwDswyQDGMKYJmeWv3qShMuETfU5fisu
+  addons_dev: /u97pKzBwasbC1yj8gSIq1z30o4ZTUX9j1Mv/hyAjmG41ydTNHw9JFOhwFbDgxmR
+  addons_prod: /p86n4b5VTlWoA/INEHQZ+zjx9g1pJduoFmTEJ6fSzFTq1mBaXaBcWVGtZJXD68L
+  dom_dev: lUxkeWjg3I3lXmxcM1gvgo0yvm2w9alc1osa4L8yWZFO6l/vg9h5hSlHPFioltrm
+  dom_prod: u8x1yIGN9IjGNYbBaDMsp1D4MK3sCmMU13mcBX+bm+aMo5+gaT8HIwIj39GlXaRS
+  dom_server_dev: Okj1hVX1VF+oZSkPcJQ/YcnW6bsIpeni222ylwUaMnSmdCe0zWKmMwpFMVqzy4Ws
+  dom_server_prod: wiA4u+G5fEfF4xzhhVnNWeSifVyttoEIpgc3APaMKQgw5A4wHbEMihf63tk1qoyt
diff --git a/docs/_css/_solarized.scss b/docs/_css/_solarized.scss
index a2e223987d0a..2776017ea7de 100644
--- a/docs/_css/_solarized.scss
+++ b/docs/_css/_solarized.scss
@@ -37,7 +37,7 @@ html * {
     border-bottom: 1px dotted #cb4b16;
   }
   .cm-s-solarized-light span.cm-keyword {
-    color: #268bd2;
+    color: #859900;
   }
   .cm-s-solarized-light span.cm-atom {
     color: #2aa198;
@@ -61,7 +61,7 @@ html * {
     color: #93a1a1;
   }
   .cm-s-solarized-light span.cm-property {
-    color: #637c84;
+    color: #657b83;
   }
   .cm-s-solarized-light span.cm-operator {
     color: #657b83;
@@ -74,14 +74,13 @@ html * {
     border-bottom: 1px dotted #cb4b16;
   }
   .cm-s-solarized-light span.cm-bracket {
-    color: #cb4b16;
+    color: #268bd2;
   }
   .cm-s-solarized-light span.cm-tag {
-    color: #657b83;
+    color: #268bd2;
   }
   .cm-s-solarized-light span.cm-attribute {
     color: #586e75;
-    font-weight: bold;
   }
   .cm-s-solarized-light span.cm-meta {
     color: #268bd2;
@@ -166,7 +165,6 @@ html * {
   }
   .cm-s-solarized-dark span.cm-attribute {
     color: #93a1a1;
-    font-weight: bold;
   }
   .cm-s-solarized-dark span.cm-meta {
     color: #268bd2;
diff --git a/docs/_css/_typography.scss b/docs/_css/_typography.scss
index 4c3158a20e62..3d94ba05b6af 100644
--- a/docs/_css/_typography.scss
+++ b/docs/_css/_typography.scss
@@ -112,8 +112,6 @@ li {
   line-height: 20px;
 }
 
-
-
 a {
   color: $linkColor;
   text-decoration: none;
@@ -131,3 +129,7 @@ a {
 .center {
   text-align: center;
 }
+
+input {
+  font-family: inherit;
+}
diff --git a/docs/_data/acknowledgements.yml b/docs/_data/acknowledgements.yml
index d625dbc18bb8..45e934230bf0 100644
--- a/docs/_data/acknowledgements.yml
+++ b/docs/_data/acknowledgements.yml
@@ -2,17 +2,21 @@
 - - '839'
   - Aaron Franks
   - Aaron Gelter
+  - Adam Bloomston
   - Adam Krebs
   - Adam Mark
   - Adam Solove
   - Adam Timberlake
   - Adam Zapletal
   - Ahmad Wali Sidiqi
+  - Alan Plum
   - Alan Souza
   - Alan deLevie
   - Alastair Hole
   - Alex
+  - Alex Boatwright
   - Alex Boyd
+  - Alex Dajani
   - Alex Lopatin
   - Alex Mykyta
   - Alex Pien
@@ -24,22 +28,28 @@
   - Alexandre Gaudencio
   - Alexey Raspopov
   - Alexey Shamrin
+  - Ali Ukani
   - Andre Z Sanchez
   - Andreas Savvides
   - Andreas Svensson
   - Andres Kalle
   - Andres Suarez
+  - Andrew Clark
   - Andrew Cobby
   - Andrew Davey
+  - Andrew Henderson
+  - Andrew Kulakov
   - Andrew Rasmussen
   - Andrew Sokolov
   - Andrew Zich
   - Andrey Popp
   - Anthony van der Hoorn
+  - Anto Aravinth
   - Antonio Ruberto
   - Antti Ahti
   - Anuj Tomar
   - AoDev
+  - April Arcus
   - Areeb Malik
   - Aria Buckles
   - Aria Stewart
@@ -54,7 +64,9 @@
   - Beau Smith
   - Ben Alpert
   - Ben Anderson
+  - Ben Brooks
   - Ben Foxall
+  - Ben Halpern
   - Ben Jaffe
   - Ben Moss
   - Ben Newman
@@ -62,16 +74,20 @@
   - Benjamin Keen
   - Benjamin Leiken
   - Benjamin Woodruff
+  - Benjy Cui
+  - Bill Blanchard
   - Bill Fisher
   - Blaine Hatab
   - Blaine Kasten
   - Bob Eagan
   - Bob Ralian
   - Bob Renwick
+  - Bobby
   - Bojan Mihelac
   - Bradley Spaulding
   - Brandon Bloom
   - Brandon Tilley
+  - Brenard Cubacub
   - Brian Cooke
   - Brian Holt
   - Brian Hsu
@@ -82,14 +98,19 @@
   - Bruno Škvorc
   - Cam Song
   - Cam Spiers
+  - Cameron Chamberlain
+  - Cameron Matheson
   - Carter Chung
   - Cassus Adam Banko
   - Cat Chen
   - Cedric Sohrauer
+  - Cesar William Alvarenga
+  - Changsoon Bok
   - Charles Marsh
   - Chase Adams
   - Cheng Lou
   - Chitharanjan Das
+  - Chris Bolin
   - Chris Grovers
   - Chris Ha
   - Chris Rebert
@@ -97,12 +118,15 @@
   - Christian Alfoni
   - Christian Oliff
   - Christian Roman
+  - Christoffer Sawicki
   - Christoph Pojer
   - Christopher Monsanto
   - Clay Allsopp
   - Connor McSheffrey
+  - Conor Hastings
   - Cory House
   - Cotton Hou
+  - Craig Akimoto
   - Cristovao Verstraeten
   - Damien Pellier
   - Dan Abramov
@@ -113,6 +137,7 @@
   - Daniel Friesen
   - Daniel Gasienica
   - Daniel Hejl
+  - Daniel Hejl
   - Daniel Lo Nigro
   - Daniel Mané
   - Daniel Miladinov
@@ -122,23 +147,31 @@
   - Darcy
   - Daryl Lau
   - Darío Javier Cravero
+  - Dave Galbraith
   - David Baker
+  - David Ed Mellum
   - David Goldberg
+  - David Granado
   - David Greenspan
   - David Hellsing
   - David Hu
+  - David Khourshid
   - David Mininger
   - David Neubauer
   - David Percy
+  - Dean Shi
   - Denis Sokolov
+  - Deniss Jacenko
   - Dennis Johnson
   - Devon Blandin
   - Devon Harvey
   - Dmitrii Abramov
+  - Dmitriy Rozhkov
   - Dmitry Blues
   - Dmitry Mazuro
   - Domenico Matteo
   - Don Abrams
+  - Dongsheng Liu
   - Dustan Kasten
   - Dustin Getz
   - Dylan Harrington
@@ -154,6 +187,7 @@
   - Erik Harper
   - Espen Hovlandsdal
   - Evan Coonrod
+  - Evan Vosberg
   - Fabio M. Costa
   - Federico Rampazzo
   - Felipe Oliveira Carvalho
@@ -163,11 +197,15 @@
   - Frankie Bagnardi
   - François-Xavier Bois
   - Fred Zhao
+  - Freddy Rangel
+  - Fyodor Ivanishchev
   - G Scott Olson
   - G. Kay Lee
   - Gabe Levi
+  - Gajus Kuizinas
   - Gareth Nicholson
   - Garren Smith
+  - Gavin McQuistin
   - Geert Pasteels
   - Geert-Jan Brits
   - George A Sisco III
@@ -183,44 +221,57 @@
   - Guido Bouman
   - Harry Hull
   - Harry Marr
-- - Harry Moreno
+  - Harry Moreno
   - Harshad Sabne
   - Hekar Khani
   - Hendrik Swanepoel
   - Henrik Nyh
+  - Henry Wong
   - Henry Zhu
+  - Hideo Matsumoto
   - Hou Chia
+  - Huang-Wei Chang
+- - Hugo Agbonon
   - Hugo Jobling
+  - Hyeock Kwon
   - Héliton Nordt
   - Ian Obermiller
   - Ignacio Carbajo
   - Igor Scekic
+  - Ilia Pavlenkov
   - Ilya Shuklin
   - Ilyá Belsky
   - Ingvar Stepanyan
   - Irae Carvalho
   - Isaac Salier-Hellendag
+  - Iurii Kucherov
   - Ivan Kozik
   - Ivan Krechetov
   - Ivan Vergiliev
   - J. Andrew Brassington
   - J. Renée Beach
   - JD Isaacks
+  - JJ Weber
   - JW
   - Jack Zhang
+  - Jackie Wung
   - Jacob Gable
   - Jacob Greenleaf
   - Jae Hun Ro
+  - Jaeho Lee
   - Jaime Mingo
+  - Jake Worth
   - Jakub Malinowski
   - James
   - James Brantly
   - James Burnett
+  - James Friend
   - James Ide
   - James Long
   - James Pearce
   - James Seppi
   - James South
+  - James Wen
   - Jamie Wong
   - Jamis Charles
   - Jamison Dance
@@ -246,6 +297,7 @@
   - Jeff Morrison
   - Jeff Welch
   - Jeffrey Lin
+  - Jeremy Fairbank
   - Jesse Skinner
   - Jignesh Kakadiya
   - Jim OBrien
@@ -253,14 +305,19 @@
   - Jimmy Jea
   - Jing Chen
   - Jinwoo Oh
+  - Jinxiu Lee
   - Jiyeon Seo
+  - Jody McIntyre
+  - Joe Critchley
   - Joe Stein
   - Joel Auterson
   - Johannes Baiter
   - Johannes Emerich
   - Johannes Lumpe
   - John Heroy
+  - John Ryan
   - John Watson
+  - John-David Dalton
   - Jon Beebe
   - Jon Chester
   - Jon Hester
@@ -270,6 +327,7 @@
   - Jonas Enlund
   - Jonas Gebhardt
   - Jonathan Hsu
+  - Jonathan Persson
   - Jordan Harband
   - Jordan Walke
   - Jorrit Schippers
@@ -277,7 +335,9 @@
   - Joseph Savona
   - Josh Bassett
   - Josh Duck
+  - Josh Perez
   - Josh Yudaken
+  - Joshua Evans
   - Joshua Go
   - Joshua Goldberg
   - Joshua Ma
@@ -286,23 +346,34 @@
   - Julen Ruiz Aizpuru
   - Julian Viereck
   - Julien Bordellier
+  - Julio Lopez
   - Jun Wu
   - Juraj Dudak
+  - Justas Brazauskas
   - Justin Jaffray
   - Justin Robison
   - Justin Woo
+  - Kale
   - Kamron Batman
   - Karl Mikkelsen
   - Karpich Dmitry
   - Keito Uchiyama
+  - Ken Powers
+  - Kent C. Dodds
+  - Kevin Cheng
   - Kevin Coughlin
   - Kevin Huang
+  - Kevin Lau
   - Kevin Old
+  - Kevin Robinson
+  - Kewei Jiang
+  - Kier Borromeo
   - KimCoding
   - Kirk Steven Hansen
   - Kit Randel
   - Kohei TAKATA
   - Koo Youngmin
+  - Krystian Karczewski
   - Kunal Mehta
   - Kurt Ruppel
   - Kyle Kelley
@@ -312,6 +383,7 @@
   - Lee Byron
   - Lee Jaeyoung
   - Lei
+  - Leland Richardson
   - Leon Fedotov
   - Leon Yip
   - Leonardo YongUk Kim
@@ -319,9 +391,13 @@
   - Levi McCallum
   - Lily
   - Logan Allen
+  - Lovisa Svallingson
+  - Ludovico Fischer
   - Luigy Leon
   - Luke Horvat
   - MIKAMI Yoshiyuki
+  - Maher Beg
+  - Manas
   - Marcin K.
   - Marcin Kwiatkowski
   - Marcin Szczepanski
@@ -331,59 +407,83 @@
   - Mark Funk
   - Mark Hintz
   - Mark IJbema
+  - Mark Murphy
   - Mark Richardson
+  - Mark Rushakoff
+  - Mark Sun
   - Marlon Landaverde
   - Marshall Roch
   - Martin Andert
+  - Martin Hujer
   - Martin Jul
   - Martin Konicek
   - Martin Mihaylov
   - Masaki KOBAYASHI
   - Mathieu M-Gosselin
+  - Mathieu Savy
   - Matias Singers
   - Matsunoki
   - Matt Brookes
   - Matt Dunn-Rankin
   - Matt Harrison
   - Matt Huggins
+  - Matt Stow
   - Matt Zabriskie
   - Matthew Dapena-Tretter
+  - Matthew Herbst
+  - Matthew Hodgson
   - Matthew Johnston
   - Matthew King
+  - Matthew Looi
   - Matthew Miner
   - Matthias Le Brun
   - Matti Nelimarkka
+  - Mattijs Kneppers
   - Max F. Albrecht
   - Max Heiber
+  - Max Stoiber
   - Maxi Ferreira
   - Maxim Abramchuk
   - Merrick Christensen
   - Mert Kahyaoğlu
   - Michael Chan
+  - Michael McDermott
   - Michael Randers-Pehrson
   - Michael Ridgway
   - Michael Warner
+  - Michael Wiencek
+  - Michael Ziwisky
   - Michal Srb
   - Michelle Todd
   - Mihai Parparita
   - Mike D Pilsbury
-- - Mike Groseclose
+  - Mike Groseclose
+  - Mike Nordick
   - Mikolaj Dadela
+  - Miles Johnson
   - Minwe LUO
   - Miorel Palii
-  - Morhaus
+- - Morhaus
+  - Moshe Kolodny
   - Mouad Debbar
   - Murad
   - Murray M. Moss
   - Nadeesha Cabral
   - Naman Goel
   - Nate Hunzaker
+  - Nate Lee
+  - Nathan Smith
   - Nathan White
+  - Nee
   - Neri Marschik
+  - Nguyen Truong Duy
   - Nicholas Bergson-Shilcock
+  - Nicholas Clawson
+  - Nick Balestra
   - Nick Fitzgerald
   - Nick Gavalas
   - Nick Merwin
+  - Nick Presta
   - Nick Raienko
   - Nick Thompson
   - Nick Williams
@@ -399,8 +499,10 @@
   - Pablo Lacerda de Miranda
   - Paolo Moretti
   - Pascal Hartig
+  - Patrick
   - Patrick Laughlin
   - Patrick Stapleton
+  - Paul Benigeri
   - Paul Harper
   - Paul O’Shannessy
   - Paul Seiffert
@@ -410,19 +512,25 @@
   - Peter Blazejewicz
   - Peter Cottle
   - Peter Jaros
+  - Peter Newnham
   - Petri Lehtinen
   - Petri Lievonen
   - Pieter Vanderwerff
   - Pouja Nikray
   - Prathamesh Sonpatki
+  - Prayag Verma
   - Preston Parry
   - Rafael
   - Rafal Dittwald
+  - Rainer Oviir
+  - Rajat Sehgal
   - Rajiv Tirumalareddy
+  - Ram Kaniyur
   - Randall Randall
   - Ray
   - Raymond Ha
   - Reed Loden
+  - Remko Tronçon
   - Richard D. Worth
   - Richard Feldman
   - Richard Kho
@@ -430,16 +538,22 @@
   - Richard Livesey
   - Richard Wood
   - Rick Beerendonk
+  - Rick Ford
   - Riley Tomasek
   - Rob Arnold
+  - Robert Binna
   - Robert Knight
   - Robert Sedovsek
   - Robin Berjon
+  - Robin Frischmann
+  - Roman Pominov
   - Roman Vanesyan
   - Russ
   - Ryan Seddon
   - Sahat Yalkabov
   - Saif Hakim
+  - Saiichi Hashimoto
+  - Sam Beveridge
   - Sam Saccone
   - Sam Selikoff
   - Samy Al Zahrani
@@ -448,7 +562,9 @@
   - Scott Feeney
   - Sean Kinsey
   - Sebastian Markbåge
+  - Sebastian McKenzie
   - Seoh Char
+  - Sercan Eraslan
   - Serg
   - Sergey Generalov
   - Sergey Rubanov
@@ -457,18 +573,25 @@
   - Shaun Trennery
   - ShihChi Huang
   - Shim Won
+  - Shinnosuke Watanabe
+  - Shogun Sea
   - Shota Kubota
   - Shripad K
   - Sibi
+  - Simen Bekkhus
   - Simon Højberg
   - Simon Welsh
+  - Simone Vittori
+  - Soichiro Kawamura
   - Sophia Westwood
+  - Sota Ohara
   - Spencer Handley
   - Stefan Dombrowski
   - Stephen Murphy
   - Sterling Cobb
   - Steve Baker
   - Steven Luscher
+  - Steven Vachon
   - Stoyan Stefanov
   - Sundeep Malladi
   - Sunny Juneja
@@ -479,9 +602,11 @@
   - Taeho Kim
   - Tay Yang Shun
   - Ted Kim
+  - Tengfei Guo
   - Teodor Szente
   - Thomas Aylott
   - Thomas Boyt
+  - Thomas Broadley
   - Thomas Reggi
   - Thomas Röggla
   - Thomas Shaddox
@@ -491,12 +616,15 @@
   - Tim Routowicz
   - Tim Schaub
   - Timothy Yung
+  - Timur Carpeev
   - Tobias Reiss
+  - Tom Duncalf
   - Tom Haggie
   - Tom Hauburger
   - Tom MacWright
   - Tom Occhino
   - Tomasz Kołodziejski
+  - Tomoya Suzuki
   - Tony Spiro
   - Toru Kobayashi
   - Trinh Hoang Nhu
@@ -507,14 +635,17 @@
   - Varun Rau
   - Vasiliy Loginevskiy
   - Victor Alvarez
+  - Victor Homyakov
   - Victor Koenders
   - Ville Immonen
   - Vincent Riemer
   - Vincent Siao
   - Vipul A M
   - Vitaly Kramskikh
+  - Vitor Balocco
   - Vjeux
   - Volkan Unsal
+  - Wander Wang
   - Wayne Larsen
   - WickyNilliams
   - Wincent Colaiuta
@@ -526,9 +657,14 @@
   - YouBao Nong
   - Yuichi Hagio
   - Yuriy Dybskiy
+  - Yutaka Nakajima
   - Yuval Dekel
   - Zach Bruggeman
+  - Zach Ramaekers
   - Zacharias
+  - Zeke Sikelianos
+  - Zhangjd
+  - adraeth
   - arush
   - brafdlog
   - chen
@@ -539,14 +675,23 @@
   - dongmeng.ldm
   - iamchenxin
   - iamdoron
+  - iawia002
   - imagentleman
+  - koh-taka
+  - kohashi85
   - laiso
+  - leeyoungalias
   - li.li
+  - maxprafferty
+  - rgarifullin
+  - songawee
   - sugarshin
   - wali-s
   - yiminghe
   - youmoo
   - zhangjg
-  - Árni Hermann Reynisson
-  - 凌恒
-  - 张敏
+  - zwhitchcox
+  - "Árni Hermann Reynisson"
+  - "元彦"
+  - "凌恒"
+  - "张敏"
diff --git a/docs/_data/authors.yml b/docs/_data/authors.yml
index 5be3ee5b3dee..e7be6478973c 100644
--- a/docs/_data/authors.yml
+++ b/docs/_data/authors.yml
@@ -1,6 +1,9 @@
 # Map of short name to more information. `name` will be used but if you don't
 # want to use your real name, just use whatever. If url is included, your name
 # will be a link to the provided url.
+acdlite:
+  name: Andrew Clark
+  url: https://twitter.com/acdlite
 benigeri:
   name: Paul Benigeri
   url: https://github.com/benigeri
@@ -13,6 +16,9 @@ Daniel15:
 fisherwebdev:
   name: Bill Fisher
   url: https://twitter.com/fisherwebdev
+flarnie:
+  name: Flarnie Marchan
+  url: https://twitter.com/ProbablyFlarnie
 gaearon:
   name: Dan Abramov
   url: https://twitter.com/dan_abramov
@@ -31,6 +37,9 @@ jingc:
 josephsavona:
   name: Joseph Savona
   url: https://twitter.com/en_JS
+keyanzhang:
+  name: Keyan Zhang
+  url: https://twitter.com/keyanzhang
 kmeht:
   name: Kunal Mehta
   url: https://github.com/kmeht
diff --git a/docs/_data/nav_community.yml b/docs/_data/nav_community.yml
new file mode 100644
index 000000000000..3740d3af7e89
--- /dev/null
+++ b/docs/_data/nav_community.yml
@@ -0,0 +1,14 @@
+- title: Community Resources
+  items:
+    - id: support
+      title: Where To Get Support
+    - id: conferences
+      title: Conferences
+    - id: videos
+      title: Videos
+    - id: complementary-tools
+      title: Complementary Tools
+      href: https://github.com/facebook/react/wiki/Complementary-Tools
+    - id: examples
+      title: Examples
+      href: https://github.com/facebook/react/wiki/Examples
diff --git a/docs/_data/nav_contributing.yml b/docs/_data/nav_contributing.yml
new file mode 100644
index 000000000000..1e1f02fd5b6c
--- /dev/null
+++ b/docs/_data/nav_contributing.yml
@@ -0,0 +1,10 @@
+- title: Contributing
+  items:
+  - id: how-to-contribute
+    title: How to Contribute
+  - id: codebase-overview
+    title: Codebase Overview
+  - id: implementation-notes
+    title: Implementation Notes
+  - id: design-principles
+    title: Design Principles
diff --git a/docs/_data/nav_docs.yml b/docs/_data/nav_docs.yml
index e3b5183ffa03..b133b36186d2 100644
--- a/docs/_data/nav_docs.yml
+++ b/docs/_data/nav_docs.yml
@@ -1,105 +1,73 @@
 - title: Quick Start
   items:
-  - id: getting-started
-    title: Getting Started
-  - id: tutorial
-    title: Tutorial
-  - id: thinking-in-react
-    title: Thinking in React
-- title: Community Resources
+    - id: installation
+      title: Installation
+    - id: hello-world
+      title: Hello World
+    - id: introducing-jsx
+      title: Introducing JSX
+    - id: rendering-elements
+      title: Rendering Elements
+    - id: components-and-props
+      title: Components and Props
+    - id: state-and-lifecycle
+      title: State and Lifecycle
+    - id: handling-events
+      title: Handling Events
+    - id: conditional-rendering
+      title: Conditional Rendering
+    - id: lists-and-keys
+      title: Lists and Keys
+    - id: forms
+      title: Forms
+    - id: lifting-state-up
+      title: Lifting State Up
+    - id: composition-vs-inheritance
+      title: Composition vs Inheritance
+    - id: thinking-in-react
+      title: Thinking In React
+- title: Advanced Guides
   items:
-  - id: conferences
-    title: Conferences
-  - id: videos
-    title: Videos
-  - id: complementary-tools
-    title: Complementary Tools
-    href: https://github.com/facebook/react/wiki/Complementary-Tools
-  - id: examples
-    title: Examples
-    href: https://github.com/facebook/react/wiki/Examples
-- title: Guides
-  items:
-  - id: why-react
-    title: Why React?
-  - id: displaying-data
-    title: Displaying Data
-    subitems:
     - id: jsx-in-depth
-      title: JSX in Depth
-    - id: jsx-spread
-      title: JSX Spread Attributes
-    - id: jsx-gotchas
-      title: JSX Gotchas
-  - id: interactivity-and-dynamic-uis
-    title: Interactivity and Dynamic UIs
-  - id: multiple-components
-    title: Multiple Components
-  - id: reusable-components
-    title: Reusable Components
-  - id: transferring-props
-    title: Transferring Props
-  - id: forms
-    title: Forms
-  - id: working-with-the-browser
-    title: Working With the Browser
-    subitems:
-    - id: more-about-refs
-      title: Refs to Components
-  - id: tooling-integration
-    title: Tooling Integration
-  - id: addons
-    title: Add-Ons
-    subitems:
-    - id: animation
-      title: Animation
-    - id: two-way-binding-helpers
-      title: Two-Way Binding Helpers
-    - id: test-utils
-      title: Test Utilities
-    - id: clone-with-props
-      title: Cloning Elements
-    - id: create-fragment
-      title: Keyed Fragments
-    - id: update
-      title: Immutability Helpers
-    - id: pure-render-mixin
-      title: PureRenderMixin
-    - id: perf
-      title: Performance Tools
-    - id: shallow-compare
-      title: Shallow Compare
-  - id: advanced-performance
-    title: Advanced Performance
-  - id: context
-    title: Context
+      title: JSX In Depth
+    - id: typechecking-with-proptypes
+      title: Typechecking With PropTypes
+    - id: refs-and-the-dom
+      title: Refs and the DOM
+    - id: uncontrolled-components
+      title: Uncontrolled Components
+    - id: optimizing-performance
+      title: Optimizing Performance
+    - id: react-without-es6
+      title: React Without ES6
+    - id: react-without-jsx
+      title: React Without JSX
+    - id: reconciliation
+      title: Reconciliation
+    - id: context
+      title: Context
+    - id: web-components
+      title: Web Components
+    - id: higher-order-components
+      title: Higher-Order Components
+    - id: integrating-with-other-libraries
+      title: Integrating with Other Libraries
 - title: Reference
   items:
-  - id: top-level-api
-    title: Top-Level API
-  - id: component-api
-    title: Component API
-  - id: component-specs
-    title: Component Specs and Lifecycle
-  - id: tags-and-attributes
-    title: Supported Tags and Attributes
-  - id: events
-    title: Event System
-  - id: dom-differences
-    title: DOM Differences
-  - id: special-non-dom-attributes
-    title: Special Non-DOM Attributes
-  - id: reconciliation
-    title: Reconciliation
-  - id: webcomponents
-    title: Web Components
-  - id: glossary
-    title: React (Virtual) DOM Terminology
-- title: Flux
-  items:
-  - id: flux-overview
-    title: Flux Overview
-    href: https://facebook.github.io/flux/docs/overview.html
-  - id: flux-todo-list
-    title: Flux TodoMVC Tutorial
-    href: https://facebook.github.io/flux/docs/todo-list.html
+    - id: react-api
+      title: React
+      subitems:
+        - id: react-component
+          title: React.Component
+    - id: react-dom
+      title: ReactDOM
+    - id: react-dom-server
+      title: ReactDOMServer
+    - id: dom-elements
+      title: DOM Elements
+    - id: events
+      title: SyntheticEvent
+    - id: test-utils
+      title: Test Utilities
+    - id: shallow-renderer
+      title: Shallow Renderer
diff --git a/docs/_data/nav_tips.yml b/docs/_data/nav_tips.yml
deleted file mode 100644
index f568311444bd..000000000000
--- a/docs/_data/nav_tips.yml
+++ /dev/null
@@ -1,38 +0,0 @@
-- title: Tips
-  items:
-  - id: introduction
-    title: Introduction
-  - id: inline-styles
-    title: Inline Styles
-  - id: if-else-in-JSX
-    title: If-Else in JSX
-  - id: self-closing-tag
-    title: Self-Closing Tag
-  - id: maximum-number-of-jsx-root-nodes
-    title: Maximum Number of JSX Root Nodes
-  - id: style-props-value-px
-    title: Shorthand for Specifying Pixel Values in style props
-  - id: children-props-type
-    title: Type of the Children props
-  - id: controlled-input-null-value
-    title: Value of null for Controlled Input
-  - id: componentWillReceiveProps-not-triggered-after-mounting
-    title: componentWillReceiveProps Not Triggered After Mounting
-  - id: props-in-getInitialState-as-anti-pattern
-    title: Props in getInitialState Is an Anti-Pattern
-  - id: dom-event-listeners
-    title: DOM Event Listeners in a Component
-  - id: initial-ajax
-    title: Load Initial Data via AJAX
-  - id: false-in-jsx
-    title: False in JSX
-  - id: communicate-between-components
-    title: Communicate Between Components
-  - id: expose-component-functions
-    title: Expose Component Functions
-  - id: children-undefined
-    title: this.props.children undefined
-  - id: use-react-with-other-libraries
-    title: Use React with Other Libraries
-  - id: dangerously-set-inner-html
-    title: Dangerously Set innerHTML
diff --git a/docs/_data/nav_tutorial.yml b/docs/_data/nav_tutorial.yml
new file mode 100644
index 000000000000..49cc7557f911
--- /dev/null
+++ b/docs/_data/nav_tutorial.yml
@@ -0,0 +1,88 @@
+- title: Tutorial
+  items:
+    - id: tutorial
+      title: Before We Start
+      subitems:
+        - id: what-were-building 
+          title: What We're Building
+          href: /react/tutorial/tutorial.html#what-were-building
+          forceInternal: true
+        - id: prerequisites
+          title: Prerequisites
+          href: /react/tutorial/tutorial.html#prerequisites
+          forceInternal: true
+        - id: how-to-follow-along
+          title: How to Follow Along
+          href: /react/tutorial/tutorial.html#how-to-follow-along
+          forceInternal: true
+        - id: help-im-stuck
+          title: Help, I'm Stuck!
+          href: /react/tutorial/tutorial.html#help-im-stuck
+          forceInternal: true
+    - id: overview
+      title: Overview
+      href: /react/tutorial/tutorial.html#overview
+      forceInternal: true
+      subitems:
+        - id: what-is-react
+          title: What is React?
+          href: /react/tutorial/tutorial.html#what-is-react
+          forceInternal: true
+        - id: getting-started
+          title: Getting Started
+          href: /react/tutorial/tutorial.html#getting-started
+          forceInternal: true
+        - id: passing-data-through-props
+          title: Passing Data Through Props
+          href: /react/tutorial/tutorial.html#passing-data-through-props
+          forceInternal: true
+        - id: an-interactive-component
+          title: An Interactive Component
+          href: /react/tutorial/tutorial.html#an-interactive-component
+          forceInternal: true
+        - id: developer-tools 
+          title: Developer Tools
+          href: /react/tutorial/tutorial.html#developer-tools
+          forceInternal: true
+    - id: lifting-state-up
+      title: Lifting State Up
+      href: /react/tutorial/tutorial.html#lifting-state-up
+      forceInternal: true
+      subitems:
+        - id: why-immutability-is-important 
+          title: Why Immutability Is Important
+          href: /react/tutorial/tutorial.html#why-immutability-is-important
+          forceInternal: true
+        - id: functional-components 
+          title: Functional Components
+          href: /react/tutorial/tutorial.html#functional-components
+          forceInternal: true
+        - id: taking-turns
+          title: Taking Turns
+          href: /react/tutorial/tutorial.html#taking-turns
+          forceInternal: true
+        - id: declaring-a-winner
+          title: Declaring a Winner
+          href: /react/tutorial/tutorial.html#declaring-a-winner
+          forceInternal: true
+    - id: storing-a-history
+      title: Storing A History
+      href: /react/tutorial/tutorial.html#storing-a-history
+      forceInternal: true
+      subitems:
+        - id: showing-the-moves
+          title: Showing the Moves
+          href: /react/tutorial/tutorial.html#showing-the-moves
+          forceInternal: true
+        - id: keys
+          title: Keys
+          href: /react/tutorial/tutorial.html#keys
+          forceInternal: true
+        - id: implementing-time-travel 
+          title: Implementing Time Travel
+          href: /react/tutorial/tutorial.html#implementing-time-travel
+          forceInternal: true
+        - id: wrapping-up
+          title: Wrapping Up
+          href: /react/tutorial/tutorial.html#wrapping-up
+          forceInternal: true
diff --git a/docs/_includes/footer.html b/docs/_includes/footer.html
new file mode 100644
index 000000000000..e2e6fdb65861
--- /dev/null
+++ b/docs/_includes/footer.html
@@ -0,0 +1,41 @@
+<footer class="nav-footer">
+  <section class="sitemap">
+    <a href="/react/" class="nav-home">
+    </a>
+    <div>
+      <h5><a href="/react/docs/">Docs</a></h5>
+      <a href="/react/docs/hello-world.html">Quick Start</a>
+      <a href="/react/docs/thinking-in-react.html">Thinking in React</a>
+      <a href="/react/tutorial/tutorial.html">Tutorial</a>
+      <a href="/react/docs/jsx-in-depth.html">Advanced Guides</a>
+    </div>
+    <div>
+      <h5><a href="/react/community/support.html">Community</a></h5>
+      <a href="http://stackoverflow.com/questions/tagged/reactjs" target="_blank">Stack Overflow</a>
+      <a href="https://discuss.reactjs.org/" target="_blank">Discussion Forum</a>
+      <a href="https://discord.gg/0ZcbPKXt5bZjGY5n" target="_blank">Reactiflux Chat</a>
+      <a href="https://www.facebook.com/react" target="_blank">Facebook</a>
+      <a href="https://twitter.com/reactjs" target="_blank">Twitter</a>
+    </div>
+    <div>
+      <h5><a href="/react/community/support.html">Resources</a></h5>
+      <a href="/react/community/conferences.html">Conferences</a>
+      <a href="/react/community/videos.html">Videos</a>
+      <a href="https://github.com/facebook/react/wiki/Examples" target="_blank">Examples</a>
+      <a href="https://github.com/facebook/react/wiki/Complementary-Tools" target="_blank">Complementary Tools</a>
+    </div>
+    <div>
+      <h5>More</h5>
+      <a href="/react/blog/">Blog</a>
+      <a href="https://github.com/facebook/react" target="_blank">GitHub</a>
+      <a href="http://facebook.github.io/react-native/" target="_blank">React Native</a>
+      <a href="/react/acknowledgements.html">Acknowledgements</a>
+    </div>
+  </section>
+  <a href="https://code.facebook.com/projects/" target="_blank" class="fbOpenSource">
+    <img src="/react/img/oss_logo.png" alt="Facebook Open Source" width="170" height="45"/>
+  </a>
+  <section class="copyright">
+    Copyright © {{ site.time | date: '%Y' }} Facebook Inc.
+  </section>
+</footer>
diff --git a/docs/_includes/hero.html b/docs/_includes/hero.html
new file mode 100644
index 000000000000..10530a7060dd
--- /dev/null
+++ b/docs/_includes/hero.html
@@ -0,0 +1,13 @@
+<div class="hero">
+  <div class="wrap">
+    <div class="text"><strong>React</strong></div>
+    <div class="minitext">
+      A JavaScript library for building user interfaces
+    </div>
+
+    <div class="buttons-unit">
+      <a href="/react/docs/hello-world.html" class="button">Get Started</a>
+      <a href="/react/tutorial/tutorial.html" class="button">Take the Tutorial</a>
+    </div>
+  </div>
+</div>
diff --git a/docs/_includes/nav_community.html b/docs/_includes/nav_community.html
new file mode 100644
index 000000000000..7b26b8df93e7
--- /dev/null
+++ b/docs/_includes/nav_community.html
@@ -0,0 +1,24 @@
+<div class="nav-docs">
+  <!-- Community Nav -->
+  {% for section in site.data.nav_community %}
+    <div class="nav-docs-section">
+      <h3>{{ section.title }}</h3>
+      <ul>
+        {% for item in section.items %}
+          <li>
+            {{ item | community_sidebar_link }}
+            {% if item.subitems %}
+              <ul>
+                {% for subitem in item.subitems %}
+                  <li>
+                    {{ subitem | community_sidebar_link }}
+                  </li>
+                {% endfor %}
+              </ul>
+            {% endif %}
+          </li>
+        {% endfor %}
+      </ul>
+    </div>
+  {% endfor %}
+</div>
diff --git a/docs/_includes/nav_docs.html b/docs/_includes/nav_docs.html
index b3e8a277f5dc..be10a9c51319 100644
--- a/docs/_includes/nav_docs.html
+++ b/docs/_includes/nav_docs.html
@@ -6,12 +6,12 @@ <h3>{{ section.title }}</h3>
       <ul>
         {% for item in section.items %}
           <li>
-            {{ item | sidebar_item_link}}
+            {{ item | docs_sidebar_link}}
             {% if item.subitems %}
               <ul>
                 {% for subitem in item.subitems %}
                   <li>
-                    {{ subitem | sidebar_item_link}}
+                    {{ subitem | docs_sidebar_link }}
                   </li>
                 {% endfor %}
               </ul>
@@ -22,17 +22,18 @@ <h3>{{ section.title }}</h3>
     </div>
   {% endfor %}
 
-  <!-- Tips Nav -->
-  {% for section in site.data.nav_tips %}
+  <!-- Contributing Nav -->
+  {% for section in site.data.nav_contributing %}
     <div class="nav-docs-section">
       <h3>{{ section.title }}</h3>
       <ul>
         {% for item in section.items %}
           <li>
-            <a href="/react/tips/{{ item.id }}.html"{% if page.id == item.id %} class="active"{% endif %}>{{ item.title }}</a>
+            <a href="/react/contributing/{{ item.id }}.html"{% if page.id == item.id %} class="active"{% endif %}>{{ item.title }}</a>
           </li>
         {% endfor %}
       </ul>
     </div>
   {% endfor %}
+
 </div>
diff --git a/docs/_includes/nav_tutorial.html b/docs/_includes/nav_tutorial.html
new file mode 100644
index 000000000000..2a720cbdd0bd
--- /dev/null
+++ b/docs/_includes/nav_tutorial.html
@@ -0,0 +1,24 @@
+<div class="nav-docs">
+  <!-- Tutorial Nav -->
+  {% for section in site.data.nav_tutorial %}
+    <div class="nav-docs-section">
+      <h3>{{ section.title }}</h3>
+      <ul>
+        {% for item in section.items %}
+          <li>
+            {{ item | tutorial_sidebar_link }}
+            {% if item.subitems %}
+              <ul>
+                {% for subitem in item.subitems %}
+                  <li>
+                    {{ subitem | tutorial_sidebar_link }}
+                  </li>
+                {% endfor %}
+              </ul>
+            {% endif %}
+          </li>
+        {% endfor %}
+      </ul>
+    </div>
+  {% endfor %}
+</div>
diff --git a/docs/_includes/navigation.html b/docs/_includes/navigation.html
new file mode 100644
index 000000000000..31ecd5b69785
--- /dev/null
+++ b/docs/_includes/navigation.html
@@ -0,0 +1,23 @@
+<div class="nav-main">
+  <div class="wrap">
+    <a class="nav-home" href="/react/">
+      <img class="nav-logo" src="/react/img/logo.svg" width="36" height="36">
+      React
+    </a>
+    <div class="nav-lists">
+      <ul class="nav-site nav-site-internal">
+        <li><a href="/react/docs/hello-world.html"{% if page.sectionid == 'docs' or page.sectionid == 'tips' or page.sectionid == 'contributing' %} class="active"{% endif %}>Docs</a></li>
+        <li><a href="/react/tutorial/tutorial.html"{% if page.sectionid == 'tutorial' %} class="active"{% endif %}>Tutorial</a></li>
+        <li><a href="/react/community/support.html"{% if page.sectionid == 'community' %} class="active"{% endif %}>Community</a></li>
+        <li><a href="/react/blog/"{% if page.sectionid == 'blog' %} class="active"{% endif %}>Blog</a></li>
+        <li class="nav-site-search">
+          <input id="algolia-doc-search" type="text" placeholder="Search docs..." />
+        </li>
+      </ul>
+      <ul class="nav-site nav-site-external">
+        <li><a href="https://github.com/facebook/react">GitHub</a></li>
+        <li><a href="https://github.com/facebook/react/releases">v{{site.react_version}}</a></li>
+      </ul>
+    </div>
+  </div>
+</div>
diff --git a/docs/_js/ErrorDecoderComponent.js b/docs/_js/ErrorDecoderComponent.js
new file mode 100644
index 000000000000..7ac945228e54
--- /dev/null
+++ b/docs/_js/ErrorDecoderComponent.js
@@ -0,0 +1,111 @@
+/**
+ * Copyright (c) 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.
+ */
+/* global React ReactDOM errorMap:true */
+'use strict';
+
+function replaceArgs(msg, argList) {
+  let argIdx = 0;
+  return msg.replace(/%s/g, function() {
+    const arg = argList[argIdx++];
+    return arg === undefined ? '[missing argument]' : arg;
+  });
+}
+
+function urlify(str) {
+  const urlRegex = /(https:\/\/fb\.me\/[a-z\-]+)/g;
+
+  const segments = str.split(urlRegex);
+
+  for (let i = 0; i < segments.length; i++) {
+    if (i % 2 === 1) {
+      segments[i] = (<a key={i} target="_blank" href={segments[i]}>{segments[i]}</a>);
+    }
+  }
+
+  return segments;
+}
+
+// ?invariant=123&args[]=foo&args[]=bar
+function parseQueryString() {
+  const rawQueryString = window.location.search.substring(1);
+  if (!rawQueryString) {
+    return null;
+  }
+
+  let code = '';
+  let args = [];
+
+  const queries = rawQueryString.split('&');
+  for (let i = 0; i < queries.length; i++) {
+    const query = decodeURIComponent(queries[i]);
+    if (query.indexOf('invariant=') === 0) {
+      code = query.slice(10);
+    } else if (query.indexOf('args[]=') === 0) {
+      args.push(query.slice(7));
+    }
+  }
+
+  return [code, args];
+}
+
+function ErrorResult(props) {
+  const code = props.code;
+  const errorMsg = props.msg;
+
+  if (!code) {
+    return (
+      <p>When you encounter an error, you'll receive a link to this page for that specific error and we'll show you the full error text.</p>
+    );
+  }
+
+  return (
+    <div>
+      <p>The full text of the error you just encountered is:</p>
+      <code>{urlify(errorMsg)}</code>
+    </div>
+  );
+}
+
+class ErrorDecoder extends React.Component {
+  constructor(...args) {
+    super(...args);
+
+    this.state = {
+      code: null,
+      errorMsg: '',
+    };
+  }
+
+  componentWillMount() {
+    const parseResult = parseQueryString();
+    if (parseResult != null) {
+      const [code, args] = parseResult;
+      if (errorMap[code]) {
+        this.setState({
+          code: code,
+          errorMsg: replaceArgs(errorMap[code], args),
+        });
+      }
+    }
+  }
+
+  render() {
+    return (
+      <ErrorResult
+        code={this.state.code}
+        msg={this.state.errorMsg}
+      />
+    );
+  }
+}
+
+ReactDOM.render(
+  <ErrorDecoder />,
+  document.querySelector('.error-decoder-container')
+);
diff --git a/docs/_js/anchor-links.js b/docs/_js/anchor-links.js
new file mode 100644
index 000000000000..c8a1c86890ef
--- /dev/null
+++ b/docs/_js/anchor-links.js
@@ -0,0 +1,30 @@
+// Add anchors to headings client-side, which prevents them from showing up
+// in RSS feeds. See https://github.com/facebook/react/issues/4124.
+(function() {
+  var selector = '.inner-content h2, .inner-content h3, .inner-content h4';
+  var elements = document.querySelectorAll(selector);
+  for (var i = 0; i < elements.length; i++) {
+    var textMethod = document.body.textContent ? "textContent" : "innerText";
+    var roughText = elements[i][textMethod];
+
+    // Regex rule for making the title URL-friendly.
+    var urlFriendlyText = roughText.trim()
+          .toLowerCase()
+          .replace(/\s+/g, '-')
+          .replace(/[^A-Za-z0-9\-_.\p{Cyrillic}\p{Hangul}\p{Hiragana}\p{Katakana}\p{Han}]/g, '');
+
+    // Create the anchor we'll jump to.
+    var anchor = document.createElement('a');
+    anchor.className = 'anchor';
+    anchor.name = urlFriendlyText;
+    elements[i].insertBefore(anchor, elements[i].firstChild);
+
+    // Create the clickable "#" icon.
+    var hashLink = document.createElement('a');
+    var icon = document.createTextNode("#");
+    hashLink.appendChild(icon);
+    hashLink.className = 'hash-link';
+    hashLink.href = '#' + urlFriendlyText;
+    elements[i].appendChild(hashLink);
+  }
+}());
diff --git a/docs/_js/examples/hello.js b/docs/_js/examples/hello.js
index bab86329c698..16f7f1a4094b 100644
--- a/docs/_js/examples/hello.js
+++ b/docs/_js/examples/hello.js
@@ -1,12 +1,13 @@
+var name = Math.random() > 0.5 ? 'Jane' : 'John';
 var HELLO_COMPONENT = `
-var HelloMessage = React.createClass({
-  render: function() {
+class HelloMessage extends React.Component {
+  render() {
     return <div>Hello {this.props.name}</div>;
   }
-});
+}
 
-ReactDOM.render(<HelloMessage name="John" />, mountNode);
-`;
+ReactDOM.render(<HelloMessage name="${name}" />, mountNode);
+`.trim();
 
 ReactDOM.render(
   <ReactPlayground codeText={HELLO_COMPONENT} />,
diff --git a/docs/_js/examples/markdown.js b/docs/_js/examples/markdown.js
index a1abfe0131e5..f0cab2b8b0da 100644
--- a/docs/_js/examples/markdown.js
+++ b/docs/_js/examples/markdown.js
@@ -1,34 +1,39 @@
 var MARKDOWN_COMPONENT = `
-var MarkdownEditor = React.createClass({
-  getInitialState: function() {
-    return {value: 'Type some *markdown* here!'};
-  },
-  handleChange: function() {
-    this.setState({value: this.refs.textarea.value});
-  },
-  rawMarkup: function() {
-    return { __html: marked(this.state.value, {sanitize: true}) };
-  },
-  render: function() {
+class MarkdownEditor extends React.Component {
+  constructor(props) {
+    super(props);
+    this.handleChange = this.handleChange.bind(this);
+    this.state = {value: 'Type some *markdown* here!'};
+  }
+
+  handleChange(e) {
+    this.setState({value: e.target.value});
+  }
+
+  getRawMarkup() {
+    var md = new Remarkable();
+    return { __html: md.render(this.state.value) };
+  }
+
+  render() {
     return (
       <div className="MarkdownEditor">
         <h3>Input</h3>
         <textarea
           onChange={this.handleChange}
-          ref="textarea"
           defaultValue={this.state.value} />
         <h3>Output</h3>
         <div
           className="content"
-          dangerouslySetInnerHTML={this.rawMarkup()}
+          dangerouslySetInnerHTML={this.getRawMarkup()}
         />
       </div>
     );
   }
-});
+}
 
 ReactDOM.render(<MarkdownEditor />, mountNode);
-`;
+`.trim();
 
 ReactDOM.render(
   <ReactPlayground codeText={MARKDOWN_COMPONENT} />,
diff --git a/docs/_js/examples/timer.js b/docs/_js/examples/timer.js
index af9ebbd8af7e..3d8cfc4c60d0 100644
--- a/docs/_js/examples/timer.js
+++ b/docs/_js/examples/timer.js
@@ -1,26 +1,33 @@
 var TIMER_COMPONENT = `
-var Timer = React.createClass({
-  getInitialState: function() {
-    return {secondsElapsed: 0};
-  },
-  tick: function() {
-    this.setState({secondsElapsed: this.state.secondsElapsed + 1});
-  },
-  componentDidMount: function() {
-    this.interval = setInterval(this.tick, 1000);
-  },
-  componentWillUnmount: function() {
+class Timer extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {secondsElapsed: 0};
+  }
+
+  tick() {
+    this.setState((prevState) => ({
+      secondsElapsed: prevState.secondsElapsed + 1
+    }));
+  }
+
+  componentDidMount() {
+    this.interval = setInterval(() => this.tick(), 1000);
+  }
+
+  componentWillUnmount() {
     clearInterval(this.interval);
-  },
-  render: function() {
+  }
+
+  render() {
     return (
       <div>Seconds Elapsed: {this.state.secondsElapsed}</div>
     );
   }
-});
+}
 
 ReactDOM.render(<Timer />, mountNode);
-`;
+`.trim();
 
 ReactDOM.render(
   <ReactPlayground codeText={TIMER_COMPONENT} />,
diff --git a/docs/_js/examples/todo.js b/docs/_js/examples/todo.js
index cc7c979c30e3..eaac631decb9 100644
--- a/docs/_js/examples/todo.js
+++ b/docs/_js/examples/todo.js
@@ -1,41 +1,56 @@
 var TODO_COMPONENT = `
-var TodoList = React.createClass({
-  render: function() {
-    var createItem = function(item) {
-      return <li key={item.id}>{item.text}</li>;
-    };
-    return <ul>{this.props.items.map(createItem)}</ul>;
+class TodoApp extends React.Component {
+  constructor(props) {
+    super(props);
+    this.handleChange = this.handleChange.bind(this);
+    this.handleSubmit = this.handleSubmit.bind(this);
+    this.state = {items: [], text: ''};
   }
-});
-var TodoApp = React.createClass({
-  getInitialState: function() {
-    return {items: [], text: ''};
-  },
-  onChange: function(e) {
-    this.setState({text: e.target.value});
-  },
-  handleSubmit: function(e) {
-    e.preventDefault();
-    var nextItems = this.state.items.concat([{text: this.state.text, id: Date.now()}]);
-    var nextText = '';
-    this.setState({items: nextItems, text: nextText});
-  },
-  render: function() {
+
+  render() {
     return (
       <div>
         <h3>TODO</h3>
         <TodoList items={this.state.items} />
         <form onSubmit={this.handleSubmit}>
-          <input onChange={this.onChange} value={this.state.text} />
+          <input onChange={this.handleChange} value={this.state.text} />
           <button>{'Add #' + (this.state.items.length + 1)}</button>
         </form>
       </div>
     );
   }
-});
+
+  handleChange(e) {
+    this.setState({text: e.target.value});
+  }
+
+  handleSubmit(e) {
+    e.preventDefault();
+    var newItem = {
+      text: this.state.text,
+      id: Date.now()
+    };
+    this.setState((prevState) => ({
+      items: prevState.items.concat(newItem),
+      text: ''
+    }));
+  }
+}
+
+class TodoList extends React.Component {
+  render() {
+    return (
+      <ul>
+        {this.props.items.map(item => (
+          <li key={item.id}>{item.text}</li>
+        ))}
+      </ul>
+    );
+  }
+}
 
 ReactDOM.render(<TodoApp />, mountNode);
-`;
+`.trim();
 
 ReactDOM.render(
   <ReactPlayground codeText={TODO_COMPONENT} />,
diff --git a/docs/_js/html-jsx-lib.js b/docs/_js/html-jsx-lib.js
index 2e94a4db4fc7..aff725699018 100644
--- a/docs/_js/html-jsx-lib.js
+++ b/docs/_js/html-jsx-lib.js
@@ -1,4 +1,4 @@
-// Ideally it would be nice to just redirect, but Github Pages is very basic and
+// Ideally it would be nice to just redirect, but GitHub Pages is very basic and
 // lacks that functionality.
 console.warn(
   'html-jsx-lib.js has moved to http://reactjs.github.io/react-magic/' +
diff --git a/docs/_js/html-jsx.js b/docs/_js/html-jsx.js
deleted file mode 100644
index 4e6937bdd1e0..000000000000
--- a/docs/_js/html-jsx.js
+++ /dev/null
@@ -1,82 +0,0 @@
-/**
- * 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.
- */
-
-/**
- * This is a web interface for the HTML to JSX converter contained in
- * `html-jsx-lib.js`.
- */
-;(function() {
-
-var HELLO_COMPONENT = "\
-<!-- Hello world -->\n\
-<div class=\"awesome\" style=\"border: 1px solid red\">\n\
-  <label for=\"name\">Enter your name: </label>\n\
-  <input type=\"text\" id=\"name\" />\n\
-</div>\n\
-<p>Enter your HTML here</p>\
-";
-
-  var HTMLtoJSXComponent = React.createClass({
-    getInitialState: function() {
-      return {
-        outputClassName: 'NewComponent',
-        createClass: true
-      };
-    },
-    onReactClassNameChange: function(evt) {
-      this.setState({ outputClassName: evt.target.value });
-    },
-    onCreateClassChange: function(evt) {
-      this.setState({ createClass: evt.target.checked });
-    },
-    setInput: function(input) {
-      this.setState({ input: input });
-      this.convertToJsx();
-    },
-    convertToJSX: function(input) {
-      var converter = new HTMLtoJSX({
-        outputClassName: this.state.outputClassName,
-        createClass: this.state.createClass
-      });
-      return converter.convert(input);
-    },
-  	render: function() {
-      return (
-        <div>
-          <div id="options">
-            <label>
-              <input
-                type="checkbox"
-                checked={this.state.createClass}
-                onChange={this.onCreateClassChange} />
-                Create class
-            </label>
-            <label style={{display: this.state.createClass ? '' : 'none'}}>
-              ·
-              Class name:
-              <input
-                type="text"
-                value={this.state.outputClassName}
-                onChange={this.onReactClassNameChange} />
-            </label>
-          </div>
-          <ReactPlayground
-            codeText={HELLO_COMPONENT}
-            renderCode={true}
-            transformer={this.convertToJSX}
-            showCompiledJSTab={false}
-            editorTabTitle="Live HTML Editor"
-            />
-        </div>
-      );
-    }
-  });
-
-  ReactDOM.render(<HTMLtoJSXComponent />, document.getElementById('jsxCompiler'));
-}());
diff --git a/docs/_js/live_editor.js b/docs/_js/live_editor.js
index 531dca802fc0..d2d83905390b 100644
--- a/docs/_js/live_editor.js
+++ b/docs/_js/live_editor.js
@@ -22,7 +22,7 @@ var CodeMirrorEditor = React.createClass({
     if (IS_MOBILE) return;
 
     this.editor = CodeMirror.fromTextArea(ReactDOM.findDOMNode(this.refs.editor), {
-      mode: 'javascript',
+      mode: 'jsx',
       lineNumbers: this.props.lineNumbers,
       lineWrapping: true,
       smartIndent: false,  // javascript mode does bad things with jsx indents
@@ -90,8 +90,14 @@ var ReactPlayground = React.createClass({
 
   getDefaultProps: function() {
     return {
-      transformer: function(code) {
-        return babel.transform(code).code;
+      transformer: function(code, options) {
+        var presets = ['react'];
+        if (!options || !options.skipES2015Transform) {
+          presets.push('es2015');
+        }
+        return Babel.transform(code, {
+          presets
+        }).code;
       },
       editorTabTitle: 'Live JSX Editor',
       showCompiledJSTab: true,
@@ -115,15 +121,15 @@ var ReactPlayground = React.createClass({
     this.setState({mode: mode});
   },
 
-  compileCode: function() {
-    return this.props.transformer(this.state.code);
+  compileCode: function(options) {
+    return this.props.transformer(this.state.code, options);
   },
 
   render: function() {
     var isJS = this.state.mode === this.MODES.JS;
     var compiledCode = '';
     try {
-      compiledCode = this.compileCode();
+      compiledCode = this.compileCode({skipES2015Transform: true});
     } catch (err) {}
 
     var JSContent =
@@ -201,19 +207,25 @@ var ReactPlayground = React.createClass({
     } catch (e) { }
 
     try {
-      var compiledCode = this.compileCode();
+      var compiledCode;
       if (this.props.renderCode) {
+        compiledCode = this.compileCode({skipES2015Transform: true});
         ReactDOM.render(
           <CodeMirrorEditor codeText={compiledCode} readOnly={true} />,
           mountNode
         );
       } else {
+        compiledCode = this.compileCode({skipES2015Transform: false});
         eval(compiledCode);
       }
     } catch (err) {
+      // Babel errors are preformatted, runtime errors are not.
+      const errorMessage = err._babel ?
+        <pre style={{overflowX: 'auto'}} className="playgroundError">{err.toString()}</pre> :
+        <div className="playgroundError">{err.toString()}</div>;
       this.setTimeout(function() {
         ReactDOM.render(
-          <div className="playgroundError">{err.toString()}</div>,
+          errorMessage,
           mountNode
         );
       }, 500);
diff --git a/docs/_layouts/community.html b/docs/_layouts/community.html
new file mode 100644
index 000000000000..9fda4ceb60c4
--- /dev/null
+++ b/docs/_layouts/community.html
@@ -0,0 +1,29 @@
+---
+layout: default
+sectionid: community
+---
+
+<section class="content wrap communityContent">
+  <div class="inner-content">
+    <a class="edit-page-link"
+    href="https://github.com/facebook/react/tree/master/docs/{{ page.path }}"
+    target="_blank">Edit on GitHub</a>
+    <h1>
+      {{ page.title }}
+    </h1>
+    <div class="subHeader">{{ page.description }}</div>
+
+    {{ content }}
+
+    <div class="docs-prevnext">
+      {% if page.prev %}
+        <a class="docs-prev" href="/react/community/{{ page.prev }}">&larr; Prev</a>
+      {% endif %}
+      {% if page.next %}
+        <a class="docs-next" href="/react/community/{{ page.next }}">Next &rarr;</a>
+      {% endif %}
+    </div>
+  </div>
+
+  {% include nav_community.html %}
+</section>
diff --git a/docs/_layouts/contributing.html b/docs/_layouts/contributing.html
new file mode 100644
index 000000000000..7d04c66a6a74
--- /dev/null
+++ b/docs/_layouts/contributing.html
@@ -0,0 +1,23 @@
+---
+layout: default
+sectionid: contributing
+---
+
+<section class="content wrap documentationContent">
+  <div class="inner-content">
+    <h1>{{ page.title }}</h1>
+    <div class="subHeader">{{ page.description }}</div>
+    {{ content }}
+
+    <div class="docs-prevnext">
+      {% if page.prev %}
+        <a class="docs-prev" href="/react/contributing/{{ page.prev }}">&larr; Prev</a>
+      {% endif %}
+      {% if page.next %}
+        <a class="docs-next" href="/react/contributing/{{ page.next }}">Next &rarr;</a>
+      {% endif %}
+    </div>
+  </div>
+
+  {% include nav_docs.html %}
+</section>
diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html
index f8fc098973fe..0dc4dd952248 100644
--- a/docs/_layouts/default.html
+++ b/docs/_layouts/default.html
@@ -1,16 +1,30 @@
+{% if page.excerpt %}
+{% assign type = 'article' %}
+{% assign sectionTitle = 'React Blog' %}
+{% assign description = page.excerpt | strip_html %}
+{% else %}
+{% assign type = 'website' %}
+{% assign sectionTitle = 'React' %}
+{% assign description = 'A JavaScript library for building user interfaces' %}
+{% endif %}
+{% if page.id == 'home' %}
+  {% assign title = sectionTitle | append: ' - ' | append: page.title %}
+{% else %}
+  {% assign title = page.title | append: ' - ' | append: sectionTitle %}
+{% endif %}
 <!DOCTYPE html>
 <!--[if IE]><![endif]-->
 <html>
 <head>
   <meta charset="utf-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
-  <title>{{ page.title }} | React</title>
-  <meta name="viewport" content="width=device-width">
-  <meta property="og:title" content="{{ page.title }} | React">
-  <meta property="og:type" content="website">
+  <title>{{ title }}</title>
+  <meta name="viewport" content="width=device-width, initial-scale=1">
+  <meta property="og:title" content="{{ title }}">
+  <meta property="og:type" content="{{ type }}">
   <meta property="og:url" content="https://facebook.github.io/react{{ page.url }}">
   <meta property="og:image" content="https://facebook.github.io/react/img/logo_og.png">
-  <meta property="og:description" content="A JavaScript library for building user interfaces">
+  <meta property="og:description" content="{{ description }}">
   <meta property="fb:app_id" content="623268441017527">
 
   <link rel="shortcut icon" href="/react/favicon.ico">
@@ -25,76 +39,33 @@
   <script>try{Typekit.load();}catch(e){}</script>
 
   <!--[if lte IE 8]>
-  <script src="/react/js/html5shiv.min.js"></script>
-  <script src="/react/js/es5-shim.min.js"></script>
-  <script src="/react/js/es5-sham.min.js"></script>
+  <script src="https://unpkg.com/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
+  <script src="https://unpkg.com/es5-shim@4.5.9/es5-shim.min.js"></script>
+  <script src="https://unpkg.com/es5-shim@4.5.9/es5-sham.min.js"></script>
   <![endif]-->
-  <script type="text/javascript" src="https://cdn.jsdelivr.net/docsearch.js/1/docsearch.min.js"></script>
-  <script src="/react/js/codemirror.js"></script>
-  <script src="/react/js/javascript.js"></script>
-  <script src="/react/js/react.js"></script>
-  <script src="/react/js/react-dom.js"></script>
-  <script src="/react/js/babel-browser.min.js"></script>
+  <script src="https://unpkg.com/docsearch.js@1.5.0/dist/cdn/docsearch.min.js"></script>
+  <script src="https://unpkg.com/codemirror@5.15.2"></script>
+  <script src="https://unpkg.com/codemirror@5.15.2/mode/javascript/javascript.js"></script>
+  <script src="https://unpkg.com/codemirror@5.15.2/mode/xml/xml.js"></script>
+  <script src="https://unpkg.com/codemirror@5.15.2/mode/jsx/jsx.js"></script>
+  <script src="https://unpkg.com/react/dist/react.min.js"></script>
+  <script src="https://unpkg.com/react-dom/dist/react-dom.min.js"></script>
+  <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
   <script src="/react/js/live_editor.js"></script>
 </head>
 <body>
 
   <div class="container">
 
-    <div class="nav-main">
-      <div class="wrap">
-        <a class="nav-home" href="/react/index.html">
-          <img class="nav-logo" src="/react/img/logo.svg" width="36" height="36">
-          React
-        </a>
-        <ul class="nav-site nav-site-internal">
-          <li><a href="/react/docs/getting-started.html"{% if page.sectionid == 'docs' or page.sectionid == 'tips' %} class="active"{% endif %}>Docs</a></li>
-          <li><a href="/react/support.html"{% if page.id == 'support' %} class="active"{% endif %}>Support</a></li>
-          <li><a href="/react/downloads.html"{% if page.id == 'downloads' %} class="active"{% endif %}>Download</a></li>
-          <li><a href="/react/blog/"{% if page.sectionid == 'blog' %} class="active"{% endif %}>Blog</a></li>
-          <li>
-            <input id="algolia-doc-search" type="text" placeholder="Search docs..." />
-          </li>
-        </ul>
-
-        <ul class="nav-site nav-site-external">
-          <li><a href="https://github.com/facebook/react">GitHub</a></li>
-          <li><a href="https://facebook.github.io/react-native/">React Native</a></li>
-        </ul>
-      </div>
-    </div>
-
-    {% if page.id == 'home' %}
-    <div class="hero">
-      <div class="wrap">
-        <div class="text"><strong>React</strong></div>
-        <div class="minitext">
-          A JavaScript library for building user interfaces
-        </div>
-
-        <div class="buttons-unit">
-          <a href="/react/docs/getting-started.html" class="button">Get Started</a>
-          <a href="/react/downloads.html" class="button">Download React v{{site.react_version}}</a>
-        </div>
-      </div>
-    </div>
-    {% endif %}
+    {% include navigation.html %}
 
     {{ content }}
 
-    <footer class="wrap">
-      <div class="left">
-        A Facebook &amp; Instagram collaboration.<br>
-        <a href="/react/acknowledgements.html">Acknowledgements</a>
-      </div>
-      <div class="right">
-        &copy; 2013&ndash;{{ site.time | date: '%Y' }} Facebook Inc.<br>
-        Documentation licensed under <a href="https://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a>.
-      </div>
-    </footer>
+    {% include footer.html %}
   </div>
-  <div id="fb-root"></div>
 
+  <div id="fb-root"></div>
+  <script src="/react/js/anchor-links.js"></script>
   <script>
     (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
     (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
@@ -109,7 +80,7 @@
       var js, fjs = d.getElementsByTagName(s)[0];
       if (d.getElementById(id)) return;
       js = d.createElement(s); js.id = id;
-      js.src = "//connect.facebook.net/en_US/all.js#xfbml=1&appId=623268441017527";
+      js.src = "//connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.6&appId=623268441017527";
       fjs.parentNode.insertBefore(js, fjs);
     }(document, 'script', 'facebook-jssdk'));
 
diff --git a/docs/_layouts/docs.html b/docs/_layouts/docs.html
index 9df579e637e7..b036ebf2947c 100644
--- a/docs/_layouts/docs.html
+++ b/docs/_layouts/docs.html
@@ -4,8 +4,6 @@
 ---
 
 <section class="content wrap documentationContent">
-  {% include nav_docs.html %}
-
   <div class="inner-content">
     <a class="edit-page-link" href="https://github.com/facebook/react/tree/master/docs/{{ page.path }}" target="_blank">Edit on GitHub</a>
     <h1>
@@ -24,4 +22,6 @@ <h1>
       {% endif %}
     </div>
   </div>
+
+  {% include nav_docs.html %}
 </section>
diff --git a/docs/_layouts/hero.html b/docs/_layouts/hero.html
new file mode 100644
index 000000000000..0eaf4951d515
--- /dev/null
+++ b/docs/_layouts/hero.html
@@ -0,0 +1,11 @@
+---
+layout: default
+---
+
+{% if page.id == 'home' %}
+  {% include hero.html %}
+{% endif %}
+
+<section class="content wrap">
+  {{ content }}
+</section>
diff --git a/docs/_layouts/post.html b/docs/_layouts/post.html
index bdc0ff03250d..00945830b0bd 100644
--- a/docs/_layouts/post.html
+++ b/docs/_layouts/post.html
@@ -4,8 +4,9 @@
 ---
 
 <section class="content wrap blogContent">
-  {% include nav_blog.html %}
+
   <div class="inner-content">
     {% include blog_post.html isPermalink="true" page=page content=content %}
   </div>
+  {% include nav_blog.html %}
 </section>
diff --git a/docs/_layouts/tips.html b/docs/_layouts/tips.html
deleted file mode 100644
index 9339bb995fb1..000000000000
--- a/docs/_layouts/tips.html
+++ /dev/null
@@ -1,23 +0,0 @@
----
-layout: default
-sectionid: tips
----
-
-<section class="content wrap documentationContent">
-  {% include nav_docs.html %}
-
-  <div class="inner-content">
-    <h1>{{ page.title }}</h1>
-    <div class="subHeader">{{ page.description }}</div>
-    {{ content }}
-
-    <div class="docs-prevnext">
-      {% if page.prev %}
-        <a class="docs-prev" href="/react/tips/{{ page.prev }}">&larr; Prev</a>
-      {% endif %}
-      {% if page.next %}
-        <a class="docs-next" href="/react/tips/{{ page.next }}">Next &rarr;</a>
-      {% endif %}
-    </div>
-  </div>
-</section>
diff --git a/docs/_layouts/tutorial.html b/docs/_layouts/tutorial.html
new file mode 100644
index 000000000000..c6bd4832dfe7
--- /dev/null
+++ b/docs/_layouts/tutorial.html
@@ -0,0 +1,29 @@
+---
+layout: default
+sectionid: tutorial
+---
+
+<section class="content wrap documentationContent">
+  {% include nav_tutorial.html %}
+
+  <div class="inner-content">
+    <a class="edit-page-link"
+    href="https://github.com/facebook/react/tree/master/docs/{{ page.path }}"
+    target="_blank">Edit on GitHub</a>
+    <h1>
+      {{ page.title }}
+    </h1>
+    <div class="subHeader">{{ page.description }}</div>
+
+    {{ content }}
+
+    <div class="docs-prevnext">
+      {% if page.prev %}
+        <a class="docs-prev" href="/react/tutorial/{{ page.prev }}">&larr; Prev</a>
+      {% endif %}
+      {% if page.next %}
+        <a class="docs-next" href="/react/tutorial/{{ page.next }}">Next &rarr;</a>
+      {% endif %}
+    </div>
+  </div>
+</section>
diff --git a/docs/_plugins/authors.rb b/docs/_plugins/authors.rb
index e3ce378ce968..956ee7fd3ba5 100644
--- a/docs/_plugins/authors.rb
+++ b/docs/_plugins/authors.rb
@@ -6,7 +6,7 @@
 module Authors
   class Generator < Jekyll::Generator
     def generate(site)
-      site.posts.each do |post|
+      site.posts.docs.each do |post|
         authors = []
         if post['author'].kind_of?(Array)
           for author in post['author']
diff --git a/docs/_plugins/header_links.rb b/docs/_plugins/header_links.rb
deleted file mode 100644
index 1172bde484f2..000000000000
--- a/docs/_plugins/header_links.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-require 'redcarpet'
-require 'sanitize'
-
-# Simple converter that is probably better than RedCarpet's built in TOC id
-# generator (which ends up with things lik id="toc_1"... terrible).
-
-class Redcarpet::Render::HTML
-  def header(title, level)
-    clean_title = Sanitize.clean(title)
-      .downcase
-      .gsub(/\s+/, "-")
-      .gsub(/[^A-Za-z0-9\-_.]/, "")
-
-    return "<h#{level}><a class=\"anchor\" name=\"#{clean_title}\"></a>#{title} <a class=\"hash-link\" href=\"##{clean_title}\">#</a></h#{level}>"
-  end
-end
-
diff --git a/docs/_plugins/sidebar_item.rb b/docs/_plugins/sidebar_item.rb
index 77a9740e135a..061414fea643 100644
--- a/docs/_plugins/sidebar_item.rb
+++ b/docs/_plugins/sidebar_item.rb
@@ -1,20 +1,39 @@
 module Jekyll
   module SidebarItemFilter
-    def sidebar_item_link(item)
+    def docs_sidebar_link(item)
+      return sidebar_helper(item, 'docs')
+    end
+
+    def docs_old_sidebar_link(item)
+      return sidebar_helper(item, 'docs-old')
+    end
+
+    def community_sidebar_link(item)
+      return sidebar_helper(item, 'community')
+    end
+
+    def tutorial_sidebar_link(item)
+      return sidebar_helper(item, 'tutorial')
+    end
+
+    def sidebar_helper(item, group)
+      forceInternal = item["forceInternal"]
+
       pageID = @context.registers[:page]["id"]
       itemID = item["id"]
-      href = item["href"] || "/react/docs/#{itemID}.html"
+      href = item["href"] || "/react/#{group}/#{itemID}.html"
       classes = []
       if pageID == itemID
         classes.push("active")
       end
-      if item["href"]
+      if item["href"] && (forceInternal == nil)
         classes.push("external")
       end
       className = classes.size > 0  ? " class=\"#{classes.join(' ')}\"" : ""
 
       return "<a href=\"#{href}\"#{className}>#{item["title"]}</a>"
     end
+
   end
 end
 
diff --git a/docs/_posts/2013-06-05-why-react.md b/docs/_posts/2013-06-05-why-react.md
index 102a76215e33..1979c196ff79 100644
--- a/docs/_posts/2013-06-05-why-react.md
+++ b/docs/_posts/2013-06-05-why-react.md
@@ -56,7 +56,7 @@ to the DOM.
 > lightweight description of what the DOM should look like.
 
 We call this process **reconciliation**. Check out
-[this jsFiddle](http://jsfiddle.net/fv6RD/3/) to see an example of
+[this jsFiddle](http://jsfiddle.net/2h6th4ju/) to see an example of
 reconciliation in action.
 
 Because this re-render is so fast (around 1ms for TodoMVC), the developer
diff --git a/docs/_posts/2013-06-12-community-roundup.md b/docs/_posts/2013-06-12-community-roundup.md
index b1a57a51d151..ebe082c283f9 100644
--- a/docs/_posts/2013-06-12-community-roundup.md
+++ b/docs/_posts/2013-06-12-community-roundup.md
@@ -32,7 +32,7 @@ It looks like [Ben Alpert](http://benalpert.com/) is the first person outside of
 
 [Mario Mueller](http://blog.xenji.com/) wrote a menu component in React and was able to easily integrate it with require.js, EventEmitter2 and bower.
 
-> I recently stumbled upon facebook's React library, which is a Javascript library for building reusable frontend components. Even if this lib is only at version 0.3.x it behaves very stable, it is fast and is fun to code. I'm a big fan of require.js, so I tried to use React within the require.js eco system. It was not as hard as expected and here are some examples and some thoughts about it.
+> I recently stumbled upon facebook's React library, which is a JavaScript library for building reusable frontend components. Even if this lib is only at version 0.3.x it behaves very stable, it is fast and is fun to code. I'm a big fan of require.js, so I tried to use React within the require.js eco system. It was not as hard as expected and here are some examples and some thoughts about it.
 >
 > [Read the full post...](http://blog.xenji.com/2013/06/facebooks-react-require-js.html)
 
@@ -40,7 +40,7 @@ It looks like [Ben Alpert](http://benalpert.com/) is the first person outside of
 
 [Pete Hunt](http://www.petehunt.net/blog/) explained what differentiates React from other JavaScript libraries in [a previous blog post](/react/blog/2013/06/05/why-react.html). [Lee Byron](http://leebyron.com/) gives another perspective on Quora:
 
-> React isn't quite like any other popular Javascript libraries, and it solves a very specific problem: complex UI rendering. It's also intended to be used along side many other popular libraries. For example, React works well with Backbone.js, amongst many others.
+> React isn't quite like any other popular JavaScript libraries, and it solves a very specific problem: complex UI rendering. It's also intended to be used along side many other popular libraries. For example, React works well with Backbone.js, amongst many others.
 >
 > React was born out of frustrations with the common pattern of writing two-way data bindings in complex MVC apps. React is an implementation of one-way data bindings.
 >
diff --git a/docs/_posts/2013-06-19-community-roundup-2.md b/docs/_posts/2013-06-19-community-roundup-2.md
index 1de3fe34f940..3ac7f9b79635 100644
--- a/docs/_posts/2013-06-19-community-roundup-2.md
+++ b/docs/_posts/2013-06-19-community-roundup-2.md
@@ -9,7 +9,7 @@ Since the launch we have received a lot of feedback and are actively working on
 
 [Andrew Greig](http://www.andrewgreig.com/) made a blog post that gives a high level description of what React is.
 
-> I have been using Facebooks recently released Javascript framework called React.js for the last few days and have managed to obtain a rather high level understanding of how it works and formed a good perspective on how it fits in to the entire javascript framework ecosystem.
+> I have been using Facebooks recently released JavaScript framework called React.js for the last few days and have managed to obtain a rather high level understanding of how it works and formed a good perspective on how it fits in to the entire javascript framework ecosystem.
 >
 > Basically, React is not an MVC framework. It is not a replacement for Backbone or Knockout or Angular, instead it is designed to work with existing frameworks and help extend their functionality.
 >
diff --git a/docs/_posts/2013-06-27-community-roundup-3.md b/docs/_posts/2013-06-27-community-roundup-3.md
index d46d490b84f6..b2a221c1f88d 100644
--- a/docs/_posts/2013-06-27-community-roundup-3.md
+++ b/docs/_posts/2013-06-27-community-roundup-3.md
@@ -19,7 +19,7 @@ The highlight of this week is that an interaction-heavy app has been ported to R
 
 ## Grunt Task for JSX
 
-[Eric Clemmons](https://ericclemmons.github.io/) wrote a task for [Grunt](http://gruntjs.com/) that applies the JSX transformation to your Javascript files. It also works with [Browserify](http://browserify.org/) if you want all your files to be concatenated and minified together.
+[Eric Clemmons](https://ericclemmons.github.io/) wrote a task for [Grunt](http://gruntjs.com/) that applies the JSX transformation to your JavaScript files. It also works with [Browserify](http://browserify.org/) if you want all your files to be concatenated and minified together.
 
 > Grunt task for compiling Facebook React's .jsx templates into .js
 >
@@ -81,9 +81,9 @@ browserify: {
 >
 > [Read the full post...](http://blog.vjeux.com/2013/javascript/react-coffeescript.html)
 
-## Tutorial in Plain Javascript
+## Tutorial in Plain JavaScript
 
-We've seen a lot of people comparing React with various frameworks. [Ricardo Tomasi](http://ricardo.cc/) decided to re-implement the tutorial without any framework, just plain Javascript.
+We've seen a lot of people comparing React with various frameworks. [Ricardo Tomasi](http://ricardo.cc/) decided to re-implement the tutorial without any framework, just plain JavaScript.
 
 > Facebook & Instagram launched the React framework and an accompanying tutorial. Developer Vlad Yazhbin decided to rewrite that using AngularJS. The end result is pretty neat, but if you're like me you will not actually appreciate the HTML speaking for itself and doing all the hard work. So let's see what that looks like in plain javascript.
 >
diff --git a/docs/_posts/2013-07-03-community-roundup-4.md b/docs/_posts/2013-07-03-community-roundup-4.md
index 42db7f3effef..af3660728fce 100644
--- a/docs/_posts/2013-07-03-community-roundup-4.md
+++ b/docs/_posts/2013-07-03-community-roundup-4.md
@@ -47,11 +47,11 @@ Over the past several weeks, members of our team, [Pete Hunt](http://www.petehun
 
 [Pete Hunt](http://www.petehunt.net/) recorded himself implementing a simple `<Blink>` tag in React.
 
-<figure><iframe src="https://player.vimeo.com/video/67248575" width="500" height="340" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe></figure>
+<figure><iframe src="https://player.vimeo.com/video/67248575" width="100%" height="340" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe></figure>
 
 ## Snake in React
 
 [Tom Occhino](http://tomocchino.com/) implemented Snake in 150 lines with React.
 
-> [Check the source on Github](https://github.com/tomocchino/react-snake/blob/master/src/snake.js)
+> [Check the source on GitHub](https://github.com/tomocchino/react-snake/blob/master/src/snake.js)
 > <figure>[![](/react/img/blog/snake.png)](https://tomocchino.github.io/react-snake/)</figure>
diff --git a/docs/_posts/2013-07-23-community-roundup-5.md b/docs/_posts/2013-07-23-community-roundup-5.md
index 434f675f1b3c..3673d40e5c19 100644
--- a/docs/_posts/2013-07-23-community-roundup-5.md
+++ b/docs/_posts/2013-07-23-community-roundup-5.md
@@ -18,7 +18,7 @@ We launched the [React Facebook Page](https://www.facebook.com/react) along with
 
 ## React Samples
 
-Learning a new library is always easier when you have working examples you can play with. [jwh](https://github.com/jhw) put many of them on his [react-samples Github repo](https://github.com/jhw/react-samples).
+Learning a new library is always easier when you have working examples you can play with. [jwh](https://github.com/jhw) put many of them on his [react-samples GitHub repo](https://github.com/jhw/react-samples).
 
 > Some simple examples with Facebook's React framework
 >
@@ -68,14 +68,14 @@ React.renderComponent(
 
 [Domenic Denicola](http://domenicdenicola.com/) wrote a slide deck about the great applications of ES6 features and one slide shows how we could use Template Strings to compile JSX at run-time without the need for a pre-processing phase.
 
-<figure><iframe src="https://www.slideshare.net/slideshow/embed_code/24187146?rel=0&startSlide=36" width="600" height="356" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC;border-width:1px 1px 0;margin-bottom:5px" allowfullscreen webkitallowfullscreen mozallowfullscreen> </iframe></figure>
+<figure><iframe src="https://www.slideshare.net/slideshow/embed_code/24187146?rel=0&startSlide=36" width="100%" height="356" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC;border-width:1px 1px 0;margin-bottom:5px" allowfullscreen webkitallowfullscreen mozallowfullscreen> </iframe></figure>
 
 
 ## React Presentation
 
 [Tom Occhino](http://tomocchino.com/) and [Jordan Walke](https://github.com/jordwalke), React developers, did a presentation of React at Facebook Seattle's office. Check out the first 25 minutes for the presentation and the remaining 45 for a Q&A. I highly recommend you watching this video.
 
-<figure><iframe width="650" height="400" src="//www.youtube-nocookie.com/embed/XxVg_s8xAms" frameborder="0" allowfullscreen></iframe></figure>
+<figure><iframe width="100%" height="400" src="//www.youtube-nocookie.com/embed/XxVg_s8xAms" frameborder="0" allowfullscreen></iframe></figure>
 
 
 ## Docs
diff --git a/docs/_posts/2013-08-05-community-roundup-6.md b/docs/_posts/2013-08-05-community-roundup-6.md
index 24fd564fe17e..152683740a5c 100644
--- a/docs/_posts/2013-08-05-community-roundup-6.md
+++ b/docs/_posts/2013-08-05-community-roundup-6.md
@@ -23,7 +23,7 @@ This is the first Community Round-up where none of the items are from Facebook/I
 >
 > `reactify` transform activates for files with either `.jsx` extension or `/** @jsx React.DOM */` pragma as a first line for any `.js` file.
 >
-> [Check it out on Github...](https://github.com/andreypopp/reactify)
+> [Check it out on GitHub...](https://github.com/andreypopp/reactify)
 
 
 
@@ -49,7 +49,7 @@ este.demos.react.todoApp = este.react.create (`/** @lends {React.ReactComponent.
     ]
 ```
 
-[Check it out on Github...](https://github.com/steida/este-library/blob/master/este/demos/thirdparty/react/start.coffee)
+[Check it out on GitHub...](https://github.com/steida/este-library/blob/master/este/demos/thirdparty/react/start.coffee)
 
 
 ## React Stylus Boilerplate
@@ -64,7 +64,7 @@ este.demos.react.todoApp = este.react.create (`/** @lends {React.ReactComponent.
 >   - `grunt build` to compile JSX and Stylus into a development build
 >   - `grunt dist` to minify and optimize the development build for production
 >
-> [Check it out on Github...](https://github.com/zaim/react-stylus-boilerplate)
+> [Check it out on GitHub...](https://github.com/zaim/react-stylus-boilerplate)
 
 
 ## WebFUI
diff --git a/docs/_posts/2013-08-26-community-roundup-7.md b/docs/_posts/2013-08-26-community-roundup-7.md
index baf0a1edcf2a..c43b1a688aab 100644
--- a/docs/_posts/2013-08-26-community-roundup-7.md
+++ b/docs/_posts/2013-08-26-community-roundup-7.md
@@ -8,7 +8,7 @@ It's been three months since we open sourced React and it is going well. Some st
 * 114 285 unique visitors on this website
 * [1933 stars](https://github.com/facebook/react/stargazers) and [210 forks](https://github.com/facebook/react/network/members)
 * [226 posts on Google Group](https://groups.google.com/forum/#!forum/reactjs)
-* [76 Github projects using React](https://gist.github.com/vjeux/6335762)
+* [76 GitHub projects using React](https://gist.github.com/vjeux/6335762)
 * [30 contributors](https://github.com/facebook/react/graphs/contributors)
 * [15 blog posts](/react/blog/)
 * 2 early adopters: [Khan Academy](http://benalpert.com/2013/06/09/using-react-to-speed-up-khan-academy.html) and [Propeller](http://usepropeller.com/blog/posts/from-backbone-to-react/)
diff --git a/docs/_posts/2013-09-24-community-roundup-8.md b/docs/_posts/2013-09-24-community-roundup-8.md
index 3f75ece68918..f3189042f239 100644
--- a/docs/_posts/2013-09-24-community-roundup-8.md
+++ b/docs/_posts/2013-09-24-community-roundup-8.md
@@ -9,9 +9,9 @@ First, we are organizing a [React Hackathon](http://reactjshack-a-thon.splashtha
 
 We've also reached a point where there are too many questions for us to handle directly. We're encouraging people to ask questions on [StackOverflow](http://stackoverflow.com/questions/tagged/reactjs) using the tag [[reactjs]](http://stackoverflow.com/questions/tagged/reactjs). Many members of the team and community have subscribed to the tag, so feel free to ask questions there. We think these will be more discoverable than Google Groups archives or IRC logs.
 
-## Javascript Jabber
+## JavaScript Jabber
 
-[Pete Hunt](http://www.petehunt.net/) and [Jordan Walke](https://github.com/jordwalke) were interviewed on [Javascript Jabber](http://javascriptjabber.com/073-jsj-react-with-pete-hunt-and-jordan-walke/) for an hour.  They go over many aspects of React such as 60 FPS, Data binding, Performance, Diffing Algorithm, DOM Manipulation, Node.js support, server-side rendering, JSX, requestAnimationFrame and the community. This is a gold mine of information about React.
+[Pete Hunt](http://www.petehunt.net/) and [Jordan Walke](https://github.com/jordwalke) were interviewed on [JavaScript Jabber](http://javascriptjabber.com/073-jsj-react-with-pete-hunt-and-jordan-walke/) for an hour.  They go over many aspects of React such as 60 FPS, Data binding, Performance, Diffing Algorithm, DOM Manipulation, Node.js support, server-side rendering, JSX, requestAnimationFrame and the community. This is a gold mine of information about React.
 
 > **PETE:**  So React was designed all around that. Conceptually, how you build a React app is that every time your data changes, it's like hitting the refresh button in a server-rendered app. What we do is we conceptually throw out all of the markup and event handlers that you've registered and we reset the whole page and then we redraw the entire page. If you're writing a server-rendered app, handling updates is really easy because you hit the refresh button and you're pretty much guaranteed to get what you expect.
 >
@@ -53,7 +53,7 @@ While this is not going to work for all the attributes since they are camelCased
 
 ## Markdown in React
 
-[Ben Alpert](http://benalpert.com/) converted [marked](https://github.com/chjj/marked), a Markdown Javascript implementation, in React: [marked-react](https://github.com/spicyj/marked-react). Even without using JSX, the HTML generation is now a lot cleaner. It is also safer as forgetting a call to `escape` will not introduce an XSS vulnerability.
+[Ben Alpert](http://benalpert.com/) converted [marked](https://github.com/chjj/marked), a Markdown JavaScript implementation, in React: [marked-react](https://github.com/spicyj/marked-react). Even without using JSX, the HTML generation is now a lot cleaner. It is also safer as forgetting a call to `escape` will not introduce an XSS vulnerability.
 <figure>[![](/react/img/blog/markdown_refactor.png)](https://github.com/spicyj/marked-react/commit/cb70c9df6542c7c34ede9efe16f9b6580692a457)</figure>
 
 
diff --git a/docs/_posts/2013-10-3-community-roundup-9.md b/docs/_posts/2013-10-3-community-roundup-9.md
index 9aa070623203..c884db69b381 100644
--- a/docs/_posts/2013-10-3-community-roundup-9.md
+++ b/docs/_posts/2013-10-3-community-roundup-9.md
@@ -29,7 +29,7 @@ We organized a React hackathon last week-end in the Facebook Seattle office. 50
 
 The video will be available soon on the [JSConf EU website](http://2013.jsconf.eu/speakers/pete-hunt-react-rethinking-best-practices.html), but in the meantime, here are Pete's slides:
 
-<figure><iframe src="https://www.slideshare.net/slideshow/embed_code/26589373" width="550" height="450" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" allowfullscreen></iframe></figure>
+<figure><iframe src="https://www.slideshare.net/slideshow/embed_code/26589373" width="100%" height="450" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" allowfullscreen></iframe></figure>
 
 
 ## Pump - Clojure bindings for React
@@ -96,4 +96,3 @@ var Table = React.createClass({
 > You see that React components are defined using a regular JS object. Some properties and methods of the object such as render() have special meanings, the rest is upforgrabs.
 >
 > [Read the full article...](http://www.phpied.com/reactive-table/)
-
diff --git a/docs/_posts/2013-11-06-community-roundup-10.md b/docs/_posts/2013-11-06-community-roundup-10.md
index 4743008d53d6..74a1697dc4df 100644
--- a/docs/_posts/2013-11-06-community-roundup-10.md
+++ b/docs/_posts/2013-11-06-community-roundup-10.md
@@ -26,7 +26,7 @@ The best part is that no drastic changes have been required to support all those
 
 [Pete Hunt](http://www.petehunt.net/)'s talk at JSConf EU 2013 is now available in video.
 
-<figure><iframe width="600" height="370" src="//www.youtube-nocookie.com/embed/x7cQ3mrcKaY" frameborder="0" allowfullscreen></iframe></figure>
+<figure><iframe width="100%" height="370" src="//www.youtube-nocookie.com/embed/x7cQ3mrcKaY" frameborder="0" allowfullscreen></iframe></figure>
 
 
 ## Server-side React with PHP
diff --git a/docs/_posts/2013-11-18-community-roundup-11.md b/docs/_posts/2013-11-18-community-roundup-11.md
index bf111c6a4da0..af91ff60b105 100644
--- a/docs/_posts/2013-11-18-community-roundup-11.md
+++ b/docs/_posts/2013-11-18-community-roundup-11.md
@@ -9,7 +9,7 @@ This round-up is the proof that React has taken off from its Facebook's root: it
 
 [Steve Luscher](https://github.com/steveluscher) working at [LeanPub](https://leanpub.com/) made a 30 min talk at [Super VanJS](https://twitter.com/vanjs). He does a remarkable job at explaining why React is so fast with very exciting demos using the HTML5 Audio API.
 
-<figure><iframe width="600" height="338" src="//www.youtube-nocookie.com/embed/1OeXsL5mr4g" frameborder="0" allowfullscreen></iframe></figure>
+<figure><iframe width="100%" height="338" src="//www.youtube-nocookie.com/embed/1OeXsL5mr4g" frameborder="0" allowfullscreen></iframe></figure>
 
 
 ## React Tips
@@ -64,7 +64,7 @@ This round-up is the proof that React has taken off from its Facebook's root: it
 >
 > [Read the full article...](http://rz.scale-it.pl/2013/10/20/frontend_components_in_react.html)
 
-<figure><iframe src="https://docs.google.com/presentation/d/1JSFbjCuuexwOHCeHWBMNRIJdyfD2Z0ZQwX65WOWkfaI/embed?start=false" frameborder="0" width="600" height="468" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true"> </iframe></figure>
+<figure><iframe src="https://docs.google.com/presentation/d/1JSFbjCuuexwOHCeHWBMNRIJdyfD2Z0ZQwX65WOWkfaI/embed?start=false" frameborder="0" width="100%" height="468" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true"> </iframe></figure>
 
 
 ## JSX
diff --git a/docs/_posts/2013-12-23-community-roundup-12.md b/docs/_posts/2013-12-23-community-roundup-12.md
index 55bf87a65022..8c5cd25b03f8 100644
--- a/docs/_posts/2013-12-23-community-roundup-12.md
+++ b/docs/_posts/2013-12-23-community-roundup-12.md
@@ -5,7 +5,7 @@ author: vjeux
 
 React got featured on the front-page of Hacker News thanks to the Om library. If you try it out for the first time, take a look at the [docs](/react/docs/getting-started.html) and do not hesitate to ask questions on the [Google Group](https://groups.google.com/group/reactjs), [IRC](irc://chat.freenode.net/reactjs) or [Stack Overflow](http://stackoverflow.com/questions/tagged/reactjs). We are trying our best to help you out!
 
-## The Future of Javascript MVC
+## The Future of JavaScript MVC
 
 [David Nolen](https://swannodette.github.io/) announced Om, a thin wrapper on-top of React in ClojureScript. It stands out by only using immutable data structures. This unlocks the ability to write a very efficient [shouldComponentUpdate](/react/docs/component-specs.html#updating-shouldcomponentupdate) and get huge performance improvements on some tasks.
 
diff --git a/docs/_posts/2013-12-30-community-roundup-13.md b/docs/_posts/2013-12-30-community-roundup-13.md
index 951488ac44ce..2acf62ea5cdd 100644
--- a/docs/_posts/2013-12-30-community-roundup-13.md
+++ b/docs/_posts/2013-12-30-community-roundup-13.md
@@ -10,7 +10,7 @@ Happy holidays! This blog post is a little-late Christmas present for all the Re
 
 [Pete Hunt](http://www.petehunt.net/) wrote three demos showing that React can be used to run 60fps native-like experiences on mobile web. A frosted glass effect, an image gallery with 3d animations and an infinite scroll view.
 
-<figure><iframe src="//player.vimeo.com/video/79659941" width="220" height="400" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></figure>
+<figure><iframe src="//player.vimeo.com/video/79659941" width="100%" height="400" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></figure>
 
 [Try out the demos!](https://petehunt.github.io/react-touch/)
 
@@ -19,18 +19,18 @@ Happy holidays! This blog post is a little-late Christmas present for all the Re
 
 [Stoyan Stefanov](http://www.phpied.com/) talked at Joe Dev On Tech about React. He goes over all the features of the library and ends with a concrete example.
 
-<figure><iframe width="560" height="315" src="//www.youtube-nocookie.com/embed/SMMRJif5QW0" frameborder="0" allowfullscreen></iframe></figure>
+<figure><iframe width="100%" height="315" src="//www.youtube-nocookie.com/embed/SMMRJif5QW0" frameborder="0" allowfullscreen></iframe></figure>
 
 
 ## JSX: E4X The Good Parts
 
 JSX is often compared to the now defunct E4X, [Vjeux](http://blog.vjeux.com/) went over all the E4X features and explained how JSX is different and hopefully doesn't repeat the same mistakes.
 
-> E4X (ECMAScript for XML) is a Javascript syntax extension and a runtime to manipulate XML. It was promoted by Mozilla but failed to become mainstream and is now deprecated. JSX was inspired by E4X. In this article, I'm going to go over all the features of E4X and explain the design decisions behind JSX.
+> E4X (ECMAScript for XML) is a JavaScript syntax extension and a runtime to manipulate XML. It was promoted by Mozilla but failed to become mainstream and is now deprecated. JSX was inspired by E4X. In this article, I'm going to go over all the features of E4X and explain the design decisions behind JSX.
 >
 > **Historical Context**
 >
-> E4X has been created in 2002 by John Schneider. This was the golden age of XML where it was being used for everything: data, configuration files, code, interfaces (DOM) ... E4X was first implemented inside of Rhino, a Javascript implementation from Mozilla written in Java.
+> E4X has been created in 2002 by John Schneider. This was the golden age of XML where it was being used for everything: data, configuration files, code, interfaces (DOM) ... E4X was first implemented inside of Rhino, a JavaScript implementation from Mozilla written in Java.
 >
 > [Continue reading ...](http://blog.vjeux.com/2013/javascript/jsx-e4x-the-good-parts.html)
 
@@ -115,4 +115,3 @@ var MyComponent = React.createClass({
 ## Random Tweet
 
 <center><blockquote class="twitter-tweet" lang="en"><p>I may be starting to get annoying with this, but ReactJS is really exciting. I truly feel the virtual DOM is a game changer.</p>&mdash; Eric Florenzano (@ericflo) <a href="https://twitter.com/ericflo/statuses/413842834974732288">December 20, 2013</a></blockquote></center>
-
diff --git a/docs/_posts/2014-01-02-react-chrome-developer-tools.md b/docs/_posts/2014-01-02-react-chrome-developer-tools.md
index 96d9ea2ce529..4331edb0fd32 100644
--- a/docs/_posts/2014-01-02-react-chrome-developer-tools.md
+++ b/docs/_posts/2014-01-02-react-chrome-developer-tools.md
@@ -5,7 +5,7 @@ author: sebmarkbage
 
 With the new year, we thought you'd enjoy some new tools for debugging React code. Today we're releasing the [React Developer Tools](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi), an extension to the Chrome Developer Tools. [Download them from the Chrome Web Store](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi).
 
-<figure><iframe width="560" height="315" src="//www.youtube-nocookie.com/embed/Cey7BS6dE0M" frameborder="0" allowfullscreen></iframe></figure>
+<figure><iframe width="100%" height="315" src="//www.youtube-nocookie.com/embed/Cey7BS6dE0M" frameborder="0" allowfullscreen></iframe></figure>
 
 You will get a new tab titled "React" in your Chrome DevTools. This tab shows you a list of the root React Components that are rendered on the page as well as the subcomponents that each root renders.
 
@@ -15,4 +15,3 @@ When you inspect a DOM element using the regular Elements tab, you can switch ov
 <figure>[![](/react/img/blog/react-dev-tools.jpg)](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi)</figure>
 
 We hope these tools will help your team better understand your component hierarchy and track down bugs. We're very excited about this initial launch and appreciate any feedback you may have. As always, we also accept [pull requests on GitHub](https://github.com/facebook/react-devtools).
-
diff --git a/docs/_posts/2014-01-06-community-roundup-14.md b/docs/_posts/2014-01-06-community-roundup-14.md
index 2c55dea4d36b..49d32bdad168 100644
--- a/docs/_posts/2014-01-06-community-roundup-14.md
+++ b/docs/_posts/2014-01-06-community-roundup-14.md
@@ -28,7 +28,7 @@ React is only one-piece of your web application stack. [Mark Lussier](https://gi
 
 ## React Rails Tutorial
 
-[Selem Delul](http://selem.im) bundled the [React Tutorial](/react/docs/tutorial.html) into a rails app. This is a good example on how to get started with a rails project.
+[Selem Delul](http://selem.im) bundled the [React Tutorial](/react/tutorial/tutorial.html) into a rails app. This is a good example on how to get started with a rails project.
 
 > ```
 git clone https://github.com/necrodome/react-rails-tutorial
diff --git a/docs/_posts/2014-02-05-community-roundup-15.md b/docs/_posts/2014-02-05-community-roundup-15.md
index 547e54c85da5..2e702f633cdb 100644
--- a/docs/_posts/2014-02-05-community-roundup-15.md
+++ b/docs/_posts/2014-02-05-community-roundup-15.md
@@ -3,7 +3,7 @@ title: "Community Round-up #15"
 author: jgebhardt
 ---
 
-Interest in React seems to have surged ever since David Nolen ([@swannodette](https://twitter.com/swannodette))'s introduction of [Om](https://github.com/swannodette/om) in his post ["The Future of Javascript MVC Frameworks"](https://swannodette.github.io/2013/12/17/the-future-of-javascript-mvcs/).
+Interest in React seems to have surged ever since David Nolen ([@swannodette](https://twitter.com/swannodette))'s introduction of [Om](https://github.com/swannodette/om) in his post ["The Future of JavaScript MVC Frameworks"](https://swannodette.github.io/2013/12/17/the-future-of-javascript-mvcs/).
 
 In this React Community Round-up, we are taking a closer look at React from a functional programming perspective.
 
@@ -21,7 +21,7 @@ Dan Holmsand ([@holmsand](https://twitter.com/holmsand)) created [Reagent](https
 >
 > The goal of Reagent is to make it possible to define arbitrarily complex UIs using just a couple of basic concepts, and to be fast enough by default that you rarely have to care about performance.
 >
-> [Check it out on Github...](https://holmsand.github.io/reagent/)
+> [Check it out on GitHub...](https://holmsand.github.io/reagent/)
 
 
 ## Functional DOM programming
@@ -34,7 +34,7 @@ React's one-way data-binding naturally lends itself to a functional programming
 
 Pete also explains this in detail at his #MeteorDevShop talk (about 30 Minutes):
 
-<iframe width="560" height="315" src="//www.youtube-nocookie.com/embed/Lqcs6hPOcFw?start=2963" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="315" src="//www.youtube-nocookie.com/embed/Lqcs6hPOcFw?start=2963" frameborder="0" allowfullscreen></iframe>
 
 
 
diff --git a/docs/_posts/2014-02-15-community-roundup-16.md b/docs/_posts/2014-02-15-community-roundup-16.md
index c032b0712606..7bb30864ae83 100644
--- a/docs/_posts/2014-02-15-community-roundup-16.md
+++ b/docs/_posts/2014-02-15-community-roundup-16.md
@@ -9,7 +9,7 @@ There have been many posts recently covering the <i>why</i> and <i>how</i> of Re
 ## React in a nutshell
 Got five minutes to pitch React to your coworkers? John Lynch ([@johnrlynch](https://twitter.com/johnrlynch)) put together [this excellent and refreshing slideshow](http://slid.es/johnlynch/reactjs):
 
-<iframe src="//slid.es/johnlynch/reactjs/embed" width="576" height="420" scrolling="no" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
+<iframe src="//slid.es/johnlynch/reactjs/embed" width="100%" height="420" scrolling="no" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
 
 
 
@@ -60,7 +60,7 @@ Joe Maddalone ([@joemaddalone](https://twitter.com/joemaddalone)) of [egghead.io
 
 Eric Florenzano ([@ericflo](https://twitter.com/ericflo)) sheds some light on what makes React perfect for server rendering:
 
-> [...] the ideal solution would fully render the markup on the server, deliver it to the client so that it can be shown to the user instantly. Then it would asynchronously load some Javascript that would attach to the rendered markup, and invisibly promote the page into a full app that can render its own markup. [...]
+> [...] the ideal solution would fully render the markup on the server, deliver it to the client so that it can be shown to the user instantly. Then it would asynchronously load some JavaScript that would attach to the rendered markup, and invisibly promote the page into a full app that can render its own markup. [...]
 
 > What I've discovered is that enough of the pieces have come together, that this futuristic-sounding web environment is actually surprisingly easy to do now with React.js.
 
diff --git a/docs/_posts/2014-02-24-community-roundup-17.md b/docs/_posts/2014-02-24-community-roundup-17.md
index ff3ca80dc8d9..75d573c5c7a6 100644
--- a/docs/_posts/2014-02-24-community-roundup-17.md
+++ b/docs/_posts/2014-02-24-community-roundup-17.md
@@ -55,7 +55,7 @@ Rafał Cieślak ([@Ravicious](https://twitter.com/Ravicious)) wrote a [React ver
 
 Emanuele shared this awesome demo video with us:
 
-<iframe width="560" height="315" src="//www.youtube-nocookie.com/embed/jYcpaemt90M" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="315" src="//www.youtube-nocookie.com/embed/jYcpaemt90M" frameborder="0" allowfullscreen></iframe>
 
 
 
diff --git a/docs/_posts/2014-03-14-community-roundup-18.md b/docs/_posts/2014-03-14-community-roundup-18.md
index a6dc5ec043cb..da82d30dc774 100644
--- a/docs/_posts/2014-03-14-community-roundup-18.md
+++ b/docs/_posts/2014-03-14-community-roundup-18.md
@@ -75,7 +75,7 @@ Ian Bicking ([@ianbicking](https://twitter.com/ianbicking)) of Mozilla Labs [exp
 
 React was also recently mentioned at ng-conf, where the Angular team commented on React's concept of the virtual DOM:
 
-<iframe width="560" height="315" src="//www.youtube-nocookie.com/embed/srt3OBP2kGc?start=113" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="315" src="//www.youtube-nocookie.com/embed/srt3OBP2kGc?start=113" frameborder="0" allowfullscreen></iframe>
 
 ## React and Web Components
 
diff --git a/docs/_posts/2014-05-06-flux.md b/docs/_posts/2014-05-06-flux.md
index d3c7b11262c2..095d36710385 100644
--- a/docs/_posts/2014-05-06-flux.md
+++ b/docs/_posts/2014-05-06-flux.md
@@ -5,7 +5,7 @@ author: [fisherwebdev, jingc]
 
 We recently spoke at one of f8's breakout session about Flux, a data flow architecture that works well with React.  Check out the video here:
 
-<figure><iframe width="560" height="315" src="//www.youtube-nocookie.com/embed/nYkdrAPrdcw?list=PLb0IAmt7-GS188xDYE-u1ShQmFFGbrk0v&start=621" frameborder="0" allowfullscreen></iframe></figure>
+<figure><iframe width="100%" height="315" src="//www.youtube-nocookie.com/embed/nYkdrAPrdcw?list=PLb0IAmt7-GS188xDYE-u1ShQmFFGbrk0v&start=621" frameborder="0" allowfullscreen></iframe></figure>
 
 To summarize, Flux works well for us because the single directional data flow makes it easy to understand and modify an application as it becomes more complicated. We found that two-way data bindings lead to cascading updates, where changing one data model led to another data model updating, making it very difficult to predict what would change as the result of a single user interaction.
 
diff --git a/docs/_posts/2014-05-29-one-year-of-open-source-react.md b/docs/_posts/2014-05-29-one-year-of-open-source-react.md
index 5a8e812eff53..ae35bea013ab 100644
--- a/docs/_posts/2014-05-29-one-year-of-open-source-react.md
+++ b/docs/_posts/2014-05-29-one-year-of-open-source-react.md
@@ -5,7 +5,7 @@ author: chenglou
 
 Today marks the one-year open-source anniversary of React.
 
-It’s been a crazy ride. 2.3k commits and 1.5k issues and pull requests later, we’re approaching version 1.0 and nearing 7k Github stars, with big names such as Khan Academy, New York Times, and Airbnb (and naturally, Facebook and Instagram) using React in production, and many more developers blogging their success stories with it. The [roadmap](/react/blog/2014/03/28/the-road-to-1.0.html) gives a glimpse into the future of the library; exciting stuff lies ahead!
+It’s been a crazy ride. 2.3k commits and 1.5k issues and pull requests later, we’re approaching version 1.0 and nearing 7k GitHub stars, with big names such as Khan Academy, New York Times, and Airbnb (and naturally, Facebook and Instagram) using React in production, and many more developers blogging their success stories with it. The [roadmap](/react/blog/2014/03/28/the-road-to-1.0.html) gives a glimpse into the future of the library; exciting stuff lies ahead!
 
 Every success has its story. React was born out of our frustration at existing solutions for building UIs. When it was first suggested at Facebook, few people thought that functionally re-rendering everything and diffing the results could ever perform well. However, support grew after we built the first implementation and people wrote their first components. When we open-sourced React, the initial reception was [similarly skeptical](https://www.reddit.com/r/programming/comments/1fak87/react_facebooks_latest_javascript_client_library/). It challenges many pre-established conventions and received mostly disapproving first-impressions, intermingled with positive ones that often were votes of confidence in Facebook’s engineering capabilities. On an open, competitive platform such as the web, it's been hard to convince people to try React. [JSX](/react/docs/jsx-in-depth.html), in particular, filtered out a huge chunk of potential early adopters.
 
diff --git a/docs/_posts/2014-06-27-community-roundup-19.md b/docs/_posts/2014-06-27-community-roundup-19.md
index b46d249e9854..da4457bd827c 100644
--- a/docs/_posts/2014-06-27-community-roundup-19.md
+++ b/docs/_posts/2014-06-27-community-roundup-19.md
@@ -23,7 +23,7 @@ These are some of the links that often pop up on the #reactjs IRC channel. If yo
 
 The core concepts React themselves is something very valuable that the community is exploring and pushing further. A year ago, we wouldn't have imagined something like [Bruce Hauman](http://rigsomelight.com)'s [Flappy Bird ClojureScript port](http://rigsomelight.com/2014/05/01/interactive-programming-flappy-bird-clojurescript.html), whose interactive programming has been made possible through React:
 
-<iframe width="560" height="315" src="//www.youtube-nocookie.com/embed/KZjFVdU8VLI" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="315" src="//www.youtube-nocookie.com/embed/KZjFVdU8VLI" frameborder="0" allowfullscreen></iframe>
 
 And don't forget [Pete Hunt](https://github.com/petehunt)'s Wolfenstein 3D rendering engine in React ([source code](https://github.com/petehunt/wolfenstein3D-react/blob/master/js/renderer.js#L183)). While it's nearly a year old, it's still a nice demo.
 
diff --git a/docs/_posts/2014-07-28-community-roundup-20.md b/docs/_posts/2014-07-28-community-roundup-20.md
index cf6fc0e9d8fc..426df8c018c4 100644
--- a/docs/_posts/2014-07-28-community-roundup-20.md
+++ b/docs/_posts/2014-07-28-community-roundup-20.md
@@ -16,14 +16,14 @@ It's an exciting time for React as there are now more commits from open source c
 
 At the last [JSConf.us](http://2014.jsconf.us/), Vjeux talked about the design decisions made in the API that allows it to scale to a large number of developers. If you don't have 20 minutes, take a look at the [annotated slides](https://speakerdeck.com/vjeux/why-does-react-scale-jsconf-2014).
 
-<iframe width="650" height="315" src="//www.youtube-nocookie.com/embed/D-ioDiacTm8" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="315" src="//www.youtube-nocookie.com/embed/D-ioDiacTm8" frameborder="0" allowfullscreen></iframe>
 
 
 ## Live Editing
 
 One of the best features of React is that it provides the foundations to implement concepts that were otherwise extremely difficult, like server-side rendering, undo-redo, rendering to non-DOM environments like canvas... [Dan Abramov](https://twitter.com/dan_abramov) got hot code reloading working with webpack in order to [live edit a React project](https://gaearon.github.io/react-hot-loader/)!
 
-<iframe src="//player.vimeo.com/video/100010922" width="650" height="315" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
+<iframe src="//player.vimeo.com/video/100010922" width="100%" height="315" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
 
 
 ## ReactIntl Mixin by Yahoo
@@ -63,7 +63,7 @@ If you missed the last [London React Meetup](http://www.meetup.com/London-React-
 - React on Rails - How to use React with Ruby on Rails to build isomorphic apps
 - Building an isomorphic, real-time to-do list with moped and node.js
 
-<iframe width="650" height="315" src="//www.youtube-nocookie.com/embed/CP3lvm5Ppqo" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="315" src="//www.youtube-nocookie.com/embed/CP3lvm5Ppqo" frameborder="0" allowfullscreen></iframe>
 
 In related news, the next [React SF Meetup](http://www.meetup.com/ReactJS-San-Francisco/events/195518392/) will be from Prezi: [“Immediate Mode on the Web: How We Implemented the Prezi Viewer in JavaScript”](https://medium.com/prezi-engineering/how-and-why-prezi-turned-to-javascript-56e0ca57d135). While not in React, their tech is really awesome and shares a lot of React's design principles and perf optimizations.
 
diff --git a/docs/_posts/2014-08-03-community-roundup-21.md b/docs/_posts/2014-08-03-community-roundup-21.md
index eb0c78f8231a..7a310cd3d02f 100644
--- a/docs/_posts/2014-08-03-community-roundup-21.md
+++ b/docs/_posts/2014-08-03-community-roundup-21.md
@@ -21,7 +21,7 @@ React.renderComponent((
 
 ## Going Big with React
 
-Areeb Malik, from Facebook, talks about his experience using React. "On paper, all those JS frameworks look promising: clean implementations, quick code design, flawless execution. But what happens when you stress test Javascript? What happens when you throw 6 megabytes of code at it? In this talk, we'll investigate how React performs in a high stress situation, and how it has helped our team build safe code on a massive scale"
+Areeb Malik, from Facebook, talks about his experience using React. "On paper, all those JS frameworks look promising: clean implementations, quick code design, flawless execution. But what happens when you stress test JavaScript? What happens when you throw 6 megabytes of code at it? In this talk, we'll investigate how React performs in a high stress situation, and how it has helped our team build safe code on a massive scale"
 
 [![](/react/img/blog/skills-matter.png)](https://skillsmatter.com/skillscasts/5429-going-big-with-react)
 
@@ -32,7 +32,7 @@ Areeb Malik, from Facebook, talks about his experience using React. "On paper, a
 
 ## What is React?
 
-[Craig McKeachie](http://www.funnyant.com/author/admin/) author of [Javascript Framework Guide](http://www.funnyant.com/javascript-framework-guide/) wrote an excellent news named ["What is React.js? Another Template Library?](http://www.funnyant.com/reactjs-what-is-it/)
+[Craig McKeachie](http://www.funnyant.com/author/admin/) author of [JavaScript Framework Guide](http://www.funnyant.com/javascript-framework-guide/) wrote an excellent news named ["What is React.js? Another Template Library?](http://www.funnyant.com/reactjs-what-is-it/)
 
 - Is React a template library?
 - Is React similar to Web Components?
@@ -104,7 +104,7 @@ var parsedComponent = reactParser(html, React);
 
 If you haven't yet tried out React, Jacob Rios did a Hangout where he covers the most important aspects and thankfully he recorded it!
 
-<iframe width="650" height="315" src="//www.youtube-nocookie.com/embed/lAn7GVoGlKU" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="315" src="//www.youtube-nocookie.com/embed/lAn7GVoGlKU" frameborder="0" allowfullscreen></iframe>
 
 
 ## Random Tweets
diff --git a/docs/_posts/2014-09-12-community-round-up-22.md b/docs/_posts/2014-09-12-community-round-up-22.md
index e79cb1b140e0..12abc6a37833 100644
--- a/docs/_posts/2014-09-12-community-round-up-22.md
+++ b/docs/_posts/2014-09-12-community-round-up-22.md
@@ -20,7 +20,7 @@ This has been an exciting summer as four big companies: Yahoo, Mozilla, Airbnb a
 
 [Vjeux](http://blog.vjeux.com/), from the React team, gave a talk at OSCON on the history of React and the various optimizations strategies that are implemented. You can also check out the [annotated slides](https://speakerdeck.com/vjeux/oscon-react-architecture) or [Chris Dawson](http://thenewstack.io/author/chrisdawson/)'s notes titled [JavaScript’s History and How it Led To React](http://thenewstack.io/javascripts-history-and-how-it-led-to-reactjs/).
 
-<iframe width="650" height="315" src="//www.youtube-nocookie.com/embed/eCf5CquV_Bw" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="315" src="//www.youtube-nocookie.com/embed/eCf5CquV_Bw" frameborder="0" allowfullscreen></iframe>
 
 
 ## v8 optimizations
@@ -89,7 +89,7 @@ var Button = React.createClass({
 
 If you are getting started with React, [Joe Maddalone](http://www.joemaddalone.com/) made a good tutorial on how to build your first component.
 
-<iframe width="650" height="200" src="//www.youtube-nocookie.com/embed/rFvZydtmsxM" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="200" src="//www.youtube-nocookie.com/embed/rFvZydtmsxM" frameborder="0" allowfullscreen></iframe>
 
 
 ## Saving time & staying sane?
diff --git a/docs/_posts/2014-10-17-community-roundup-23.md b/docs/_posts/2014-10-17-community-roundup-23.md
index 6b00f82e1142..3a5e3791f4f0 100644
--- a/docs/_posts/2014-10-17-community-roundup-23.md
+++ b/docs/_posts/2014-10-17-community-roundup-23.md
@@ -10,7 +10,7 @@ This round-up is a special edition on [Flux](https://facebook.github.io/flux/).
 
 Facebook engineers [Jing Chen](https://github.com/jingc) and [Bill Fisher](https://github.com/fisherwebdev) gave a talk about Flux and React at [ForwardJS](http://forwardjs.com/), and how using an application architecture with a unidirectional data flow helped solve recurring bugs.
 
-<iframe width="650" height="315" src="//www.youtube-nocookie.com/embed/i__969noyAM" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="315" src="//www.youtube-nocookie.com/embed/i__969noyAM" frameborder="0" allowfullscreen></iframe>
 
 # Yahoo
 
@@ -102,7 +102,7 @@ undo: function() {
 
 [Dan Abramov](https://twitter.com/dan_abramov) working at Stampsy made a talk about React and Flux. It's a very good overview of the concepts at play.
 
-<iframe src="//slides.com/danabramov/components-react-flux-wip/embed"  width="650" height="315" scrolling="no" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
+<iframe src="//slides.com/danabramov/components-react-flux-wip/embed"  width="100%" height="315" scrolling="no" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
 
 
 ## React and Flux
@@ -144,7 +144,7 @@ undo: function() {
 
 Last but not least, Flux and React ideas are not limited to JavaScript inside of the browser. The iOS team at Facebook re-implemented Newsfeed using very similar patterns.
 
-<iframe width="650" height="315" src="//www.youtube-nocookie.com/embed/XhXC4SKOGfQ" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="315" src="//www.youtube-nocookie.com/embed/XhXC4SKOGfQ" frameborder="0" allowfullscreen></iframe>
 
 
 ## Random Tweet
diff --git a/docs/_posts/2014-11-24-react-js-conf-updates.md b/docs/_posts/2014-11-24-react-js-conf-updates.md
index e0cefeb9630e..d5956f2fd2a8 100644
--- a/docs/_posts/2014-11-24-react-js-conf-updates.md
+++ b/docs/_posts/2014-11-24-react-js-conf-updates.md
@@ -10,7 +10,7 @@ amazed that 600 people requested to be notified when ticket go on sale. This is
 When we organized the conference, we decided to start small since this is the
 first React.js conference. Also, we weren't sure what level of demand to expect,
 so we planned for a single-track, two-day conference on Facebook's campus. The
-largest room available would accomodate 18 speaking slots and 200 attendees.
+largest room available would accommodate 18 speaking slots and 200 attendees.
 The spacial configuration makes it difficult to add a second track and changing
 venues only two months in advance would be too difficult, so we are deciding to
 stick with the originally planned format and venue on Facebook's campus.
diff --git a/docs/_posts/2014-11-25-community-roundup-24.md b/docs/_posts/2014-11-25-community-roundup-24.md
index b86ad4934726..fb891aead588 100644
--- a/docs/_posts/2014-11-25-community-roundup-24.md
+++ b/docs/_posts/2014-11-25-community-roundup-24.md
@@ -14,11 +14,11 @@ Murilo Pereira ([mpereira](https://github.com/mpereira)) tussles with the topic
 
 I ([steveluscher](https://github.com/steveluscher)) spoke at Manning Publications' “Powered By JavaScript” Strangeloop pre-conf in St. Louis. There, I proposed a new notation to talk about development complexity – Big-Coffee Notation ☕(n) – and spoke about the features of React that help keep our Big-Coffee from going quadratic, as our user interfaces get more complex.
 
-<iframe width="560" height="315" src="//www.youtube-nocookie.com/embed/rI0GQc__0SM" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="315" src="//www.youtube-nocookie.com/embed/rI0GQc__0SM" frameborder="0" allowfullscreen></iframe>
 
 James Pearce ([jamesgpearce](https://github.com/jamesgpearce)) carried Big-Coffee all the way to Raleigh, NC. At the _All Things Open_ conference, he spoke about some of the design decisions that went into React, particularly those that lend themselves to simpler, more reliable code.
 
-<iframe width="560" height="315" src="//www.youtube-nocookie.com/embed/m2fuO2wl_3c" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="315" src="//www.youtube-nocookie.com/embed/m2fuO2wl_3c" frameborder="0" allowfullscreen></iframe>
 
 ## All About Isomorphism
 
@@ -38,7 +38,7 @@ Ryan Florence ([rpflorence](https://github.com/rpflorence])) and Michael Jackson
 
 Jonathan Beebe ([somethingkindawierd](https://github.com/somethingkindawierd)) spoke about how he uses React to build tools that deliver hope to those trying to make the best of a bad situation. Watch his talk from this year's _Nodevember_ conference in Nashville
 
-<iframe width="420" height="315" src="//www.youtube-nocookie.com/embed/uZgAq1CZ1N8" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="315" src="//www.youtube-nocookie.com/embed/uZgAq1CZ1N8" frameborder="0" allowfullscreen></iframe>
 
 If you take a peek under the covers, you'll find that React powers [Carousel](https://blog.carousel.com/2014/11/introducing-carousel-for-web-ipad-and-android-tablet/), Dropbox's new photo and video gallery app.
 
@@ -48,7 +48,7 @@ We enjoyed a cinematic/narrative experience with this React-powered, interactive
 
 Spend the next 60 seconds watching Daniel Woelfel ([dwwoelfel](https://github.com/dwwoelfel)) serialize a React app's state as a string, then deserialize it to produce a working UI. Read about how he uses this technique to [reproduce bugs](http://blog.circleci.com/local-state-global-concerns/) reported to him by his users.
 
-<iframe width="420" height="315" src="//www.youtube-nocookie.com/embed/5yHFTN-_mOo" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="315" src="//www.youtube-nocookie.com/embed/5yHFTN-_mOo" frameborder="0" allowfullscreen></iframe>
 
 ## Community Components
 
diff --git a/docs/_posts/2015-02-18-react-conf-roundup-2015.md b/docs/_posts/2015-02-18-react-conf-roundup-2015.md
index 19b0d309f3a0..1687f2c44446 100644
--- a/docs/_posts/2015-02-18-react-conf-roundup-2015.md
+++ b/docs/_posts/2015-02-18-react-conf-roundup-2015.md
@@ -16,7 +16,7 @@ It was a privilege to welcome the React community to Facebook HQ on January 28
     </p>
   </div>
   <div class="skinny-col">
-    <iframe width="305" height="171" src="https://www.youtube-nocookie.com/embed/KVZ-P-ZI6W4" frameborder="0" allowfullscreen></iframe>
+    <iframe width="100%" height="171" src="https://www.youtube-nocookie.com/embed/KVZ-P-ZI6W4" frameborder="0" allowfullscreen></iframe>
   </div>
 </div>
 
@@ -24,11 +24,11 @@ It was a privilege to welcome the React community to Facebook HQ on January 28
   <div class="skinny-col">
     <h3 style="margin-top:0"><a class="anchor" name="talk-tweak"></a>Tweaking in real time <a class="hash-link" href="#talk-tweak">#</a></h3>
     <p>
-      <strong>Brenton Simpson</strong> showed us how eBay brings Bret Victor’s feedback loop to your favorite editor using Webpack, react-hot-loader, and <a href="https://github.com/appsforartists/ambidex">Ambidex</a>.
+      <strong>Brenton Simpson</strong> showed us how eBay brings Bret Victor’s feedback loop to your favorite editor using webpack, react-hot-loader, and <a href="https://github.com/appsforartists/ambidex">Ambidex</a>.
     </p>
   </div>
   <div class="skinny-col">
-    <iframe width="305" height="171" src="https://www.youtube-nocookie.com/embed/yaymfLj5tjA" frameborder="0" allowfullscreen></iframe>
+    <iframe width="100%" height="171" src="https://www.youtube-nocookie.com/embed/yaymfLj5tjA" frameborder="0" allowfullscreen></iframe>
   </div>
 </div>
 
@@ -40,7 +40,7 @@ It was a privilege to welcome the React community to Facebook HQ on January 28
     </p>
   </div>
   <div class="skinny-col">
-    <iframe width="305" height="171" src="https://www.youtube-nocookie.com/embed/OZGgVxFxSIs" frameborder="0" allowfullscreen></iframe>
+    <iframe width="100%" height="171" src="https://www.youtube-nocookie.com/embed/OZGgVxFxSIs" frameborder="0" allowfullscreen></iframe>
   </div>
 </div>
 
@@ -52,7 +52,7 @@ It was a privilege to welcome the React community to Facebook HQ on January 28
     </p>
   </div>
   <div class="skinny-col">
-    <iframe width="305" height="171" src="https://www.youtube-nocookie.com/embed/9sc8Pyc51uU" frameborder="0" allowfullscreen></iframe>
+    <iframe width="100%" height="171" src="https://www.youtube-nocookie.com/embed/9sc8Pyc51uU" frameborder="0" allowfullscreen></iframe>
   </div>
 </div>
 
@@ -64,7 +64,7 @@ It was a privilege to welcome the React community to Facebook HQ on January 28
     </p>
   </div>
   <div class="skinny-col">
-    <iframe width="305" height="171" src="https://www.youtube-nocookie.com/embed/W2DgDNQZOwo" frameborder="0" allowfullscreen></iframe>
+    <iframe width="100%" height="171" src="https://www.youtube-nocookie.com/embed/W2DgDNQZOwo" frameborder="0" allowfullscreen></iframe>
   </div>
 </div>
 
@@ -76,7 +76,7 @@ It was a privilege to welcome the React community to Facebook HQ on January 28
     </p>
   </div>
   <div class="skinny-col">
-    <iframe width="305" height="171" src="https://www.youtube-nocookie.com/embed/XZfvW1a8Xac" frameborder="0" allowfullscreen></iframe>
+    <iframe width="100%" height="171" src="https://www.youtube-nocookie.com/embed/XZfvW1a8Xac" frameborder="0" allowfullscreen></iframe>
   </div>
 </div>
 
@@ -88,7 +88,7 @@ It was a privilege to welcome the React community to Facebook HQ on January 28
     </p>
   </div>
   <div class="skinny-col">
-    <iframe width="305" height="171" src="https://www.youtube-nocookie.com/embed/KtmjkCuV-EU" frameborder="0" allowfullscreen></iframe>
+    <iframe width="100%" height="171" src="https://www.youtube-nocookie.com/embed/KtmjkCuV-EU" frameborder="0" allowfullscreen></iframe>
   </div>
 </div>
 
@@ -100,7 +100,7 @@ It was a privilege to welcome the React community to Facebook HQ on January 28
     </p>
   </div>
   <div class="skinny-col">
-    <iframe width="305" height="171" src="https://www.youtube-nocookie.com/embed/KYzlpRvWZ6c" frameborder="0" allowfullscreen></iframe>
+    <iframe width="100%" height="171" src="https://www.youtube-nocookie.com/embed/KYzlpRvWZ6c" frameborder="0" allowfullscreen></iframe>
   </div>
 </div>
 
@@ -112,7 +112,7 @@ It was a privilege to welcome the React community to Facebook HQ on January 28
     </p>
   </div>
   <div class="skinny-col">
-    <iframe width="305" height="171" src="https://www.youtube-nocookie.com/embed/Sla-DkvmIHY" frameborder="0" allowfullscreen></iframe>
+    <iframe width="100%" height="171" src="https://www.youtube-nocookie.com/embed/Sla-DkvmIHY" frameborder="0" allowfullscreen></iframe>
   </div>
 </div>
 
@@ -124,7 +124,7 @@ It was a privilege to welcome the React community to Facebook HQ on January 28
     </p>
   </div>
   <div class="skinny-col">
-    <iframe width="305" height="171" src="https://www.youtube-nocookie.com/embed/z5e7kWSHWTg" frameborder="0" allowfullscreen></iframe>
+    <iframe width="100%" height="171" src="https://www.youtube-nocookie.com/embed/z5e7kWSHWTg" frameborder="0" allowfullscreen></iframe>
   </div>
 </div>
 
@@ -136,7 +136,7 @@ It was a privilege to welcome the React community to Facebook HQ on January 28
     </p>
   </div>
   <div class="skinny-col">
-    <iframe width="305" height="171" src="https://www.youtube-nocookie.com/embed/7rDsRXj9-cU" frameborder="0" allowfullscreen></iframe>
+    <iframe width="100%" height="171" src="https://www.youtube-nocookie.com/embed/7rDsRXj9-cU" frameborder="0" allowfullscreen></iframe>
   </div>
 </div>
 
@@ -148,7 +148,7 @@ It was a privilege to welcome the React community to Facebook HQ on January 28
     </p>
   </div>
   <div class="skinny-col">
-    <iframe width="305" height="171" src="https://www.youtube-nocookie.com/embed/g0TD0efcwVg" frameborder="0" allowfullscreen></iframe>
+    <iframe width="100%" height="171" src="https://www.youtube-nocookie.com/embed/g0TD0efcwVg" frameborder="0" allowfullscreen></iframe>
   </div>
 </div>
 
@@ -156,11 +156,11 @@ It was a privilege to welcome the React community to Facebook HQ on January 28
   <div class="skinny-col">
     <h3 style="margin-top:0"><a class="anchor" name="talk-immutable"></a>Immutability <a class="hash-link" href="#talk-immutable">#</a></h3>
     <p>
-      <strong>Lee Byron</strong> led a master-class on persistent immutable data structures, showing us the world of possibility that they can unlock for your software, and perhaps Javascript in general.
+      <strong>Lee Byron</strong> led a master-class on persistent immutable data structures, showing us the world of possibility that they can unlock for your software, and perhaps JavaScript in general.
     </p>
   </div>
   <div class="skinny-col">
-    <iframe width="305" height="171" src="https://www.youtube-nocookie.com/embed/I7IdS-PbEgI" frameborder="0" allowfullscreen></iframe>
+    <iframe width="100%" height="171" src="https://www.youtube-nocookie.com/embed/I7IdS-PbEgI" frameborder="0" allowfullscreen></iframe>
   </div>
 </div>
 
@@ -171,7 +171,7 @@ It was a privilege to welcome the React community to Facebook HQ on January 28
       <strong>Jafar Husain</strong> told us a story about how Netflix was able to push React into places where the DOM could not go.
   </div>
   <div class="skinny-col">
-    <iframe width="305" height="171" src="https://www.youtube-nocookie.com/embed/eNC0mRYGWgc" frameborder="0" allowfullscreen></iframe>
+    <iframe width="100%" height="171" src="https://www.youtube-nocookie.com/embed/eNC0mRYGWgc" frameborder="0" allowfullscreen></iframe>
   </div>
 </div>
 
@@ -182,7 +182,7 @@ It was a privilege to welcome the React community to Facebook HQ on January 28
       <strong>Zach Nation</strong> showed us how we can produce visualizations from over 45 million data points without breaking a sweat.
   </div>
   <div class="skinny-col">
-    <iframe width="305" height="171" src="https://www.youtube-nocookie.com/embed/2ii1lEkIv1s" frameborder="0" allowfullscreen></iframe>
+    <iframe width="100%" height="171" src="https://www.youtube-nocookie.com/embed/2ii1lEkIv1s" frameborder="0" allowfullscreen></iframe>
   </div>
 </div>
 
@@ -193,7 +193,7 @@ It was a privilege to welcome the React community to Facebook HQ on January 28
       <strong>David Nolen</strong> gave us a view of React from a non-JavaScript perspective, challenging some common intuition along the way.
   </div>
   <div class="skinny-col">
-    <iframe width="305" height="171" src="https://www.youtube-nocookie.com/embed/5hGHdETNteE" frameborder="0" allowfullscreen></iframe>
+    <iframe width="100%" height="171" src="https://www.youtube-nocookie.com/embed/5hGHdETNteE" frameborder="0" allowfullscreen></iframe>
   </div>
 </div>
 
@@ -204,7 +204,7 @@ It was a privilege to welcome the React community to Facebook HQ on January 28
       <strong>Bill Fisher</strong> coordinated a Flux panel together with <strong>Michael Ridgway</strong>, <strong>Spike Brehm</strong>, <strong>Andres Suarez</strong>, <strong>Jing Chen</strong>, <strong>Ian Obermiller</strong>, and <strong>Kyle Davis</strong>.
   </div>
   <div class="skinny-col">
-    <iframe width="305" height="171" src="https://www.youtube-nocookie.com/embed/LTj4O7WJJ98" frameborder="0" allowfullscreen></iframe>
+    <iframe width="100%" height="171" src="https://www.youtube-nocookie.com/embed/LTj4O7WJJ98" frameborder="0" allowfullscreen></iframe>
   </div>
 </div>
 
@@ -215,7 +215,7 @@ It was a privilege to welcome the React community to Facebook HQ on January 28
       <strong>Bonnie Eisenman</strong> led us through the ‘adapter’ approach to inter-component communication taken by her team at Codecademy.
   </div>
   <div class="skinny-col">
-    <iframe width="305" height="171" src="https://www.youtube-nocookie.com/embed/ZM6wXoFTY3o" frameborder="0" allowfullscreen></iframe>
+    <iframe width="100%" height="171" src="https://www.youtube-nocookie.com/embed/ZM6wXoFTY3o" frameborder="0" allowfullscreen></iframe>
   </div>
 </div>
 
@@ -226,7 +226,7 @@ It was a privilege to welcome the React community to Facebook HQ on January 28
       <strong>James Brantly</strong> demonstrated how we can reap the benefits of static typing using both Flow and TypeScript.
   </div>
   <div class="skinny-col">
-    <iframe width="305" height="171" src="https://www.youtube-nocookie.com/embed/9PTa9-PPVAc" frameborder="0" allowfullscreen></iframe>
+    <iframe width="100%" height="171" src="https://www.youtube-nocookie.com/embed/9PTa9-PPVAc" frameborder="0" allowfullscreen></iframe>
   </div>
 </div>
 
@@ -237,7 +237,7 @@ It was a privilege to welcome the React community to Facebook HQ on January 28
       <strong>Tom Occhino</strong>, <strong>Ben Alpert</strong>, <strong>Lee Byron</strong>, <strong>Christopher Chedeau</strong>, <strong>Sebastian Markbåge</strong>, <strong>Jing Chen</strong>, and <strong>Dan Schafer</strong> closed the conference with a Q&amp;A session.
   </div>
   <div class="skinny-col">
-    <iframe width="305" height="171" src="https://www.youtube-nocookie.com/embed/EPpkboSKvPI" frameborder="0" allowfullscreen></iframe>
+    <iframe width="100%" height="171" src="https://www.youtube-nocookie.com/embed/EPpkboSKvPI" frameborder="0" allowfullscreen></iframe>
   </div>
 </div>
 
@@ -245,7 +245,7 @@ It was a privilege to welcome the React community to Facebook HQ on January 28
 
 The conference is over, but the conversation has just begun.
 
-**Mihai Parparita** detailed his efforts to [hack his way to a React.js Conf ticket](http://blog.persistent.info/2014/12/html-munging-my-way-to-reactjs-conf.html); **James Long** blogged about [his first encounter with React Native](http://jlongster.com/First-Impressions-using-React-Native); **Eric Florenzano** talked about how he perceives the [impact of Relay, GraphQL, and React Native](https://medium.com/@ericflo/facebook-just-taught-us-all-how-to-build-websites-51f1e7e996f2) on software development; **Margaret Staples** blogged about her experience of [being on-campus at Facebook HQ](http://deadlugosi.blogspot.com/2015/02/facebook-gave-me-ice-cream.html); **Jeff Barczewski** tied his experience of attending the conference up with a bow in this [blog post filled with photos, videos, and links](http://codewinds.com/blog/2015-02-04-reactjs-conf.html); **Kevin Old** left us with [his takeaways](http://kevinold.com/2015/01/31/takeaways-from-reactjs-conf-2015.html); **Paul Wittmann** found React Native [freshly on his radar](http://www.railslove.com/stories/fresh-on-our-radar-react-native); and finally, undeterred by not being able to attend the conference in person, **Justin Ball** [summarized it from afar](http://www.justinball.com/2015/02/03/i-didn't-attend-react.js-conf/).
+**Mihai Parparita** detailed his efforts to [hack his way to a React.js Conf ticket](http://blog.persistent.info/2014/12/html-munging-my-way-to-reactjs-conf.html); **James Long** blogged about [his first encounter with React Native](http://jlongster.com/First-Impressions-using-React-Native); **Eric Florenzano** talked about how he perceives the [impact of Relay, GraphQL, and React Native](https://medium.com/@ericflo/facebook-just-taught-us-all-how-to-build-websites-51f1e7e996f2) on software development; **Margaret Staples** blogged about her experience of [being on-campus at Facebook HQ](http://deadlugosi.blogspot.com/2015/02/facebook-gave-me-ice-cream.html); **Jeff Barczewski** tied his experience of attending the conference up with a bow in this [blog post filled with photos, videos, and links](http://codewinds.com/blog/2015-02-04-reactjs-conf.html); **Kevin Old** left us with [his takeaways](http://kevinold.com/2015/01/31/takeaways-from-reactjs-conf-2015.html); **Paul Wittmann** found React Native [freshly on his radar](http://www.railslove.com/stories/fresh-on-our-radar-react-native); and finally, undeterred by not being able to attend the conference in person, **Justin Ball** [summarized it from afar](http://www.justinball.com/2015/02/02/i-didn't-attend-react.js-conf.html).
 
 And, in case you missed a session, you can borrow **Michael Chan’s** [drawings](http://chantastic.io/2015-reactjs-conf/), **Mihai Parparita’s** [summary](https://quip.com/uJQeABv7nkFN), or **Shaohua Zhou’s** [day 1](http://getshao.com/2015/01/29/react-js-conf-notes-day1/) / [day 2](http://getshao.com/2015/01/29/react-js-conf-notes-day-2/) notes.
 
@@ -266,4 +266,4 @@ And, in case you missed a session, you can borrow **Michael Chan’s** [drawings
 
 **All proceeds from React.js Conf 2015 were donated to the wonderful programs at [code.org](http://code.org)**. These programs aim to increase access to the field of computer science by underrepresented members of our community. Watch this video to learn more.
 
-<iframe width="305" height="171" src="https://www.youtube-nocookie.com/embed/FC5FbmsH4fw" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="171" src="https://www.youtube-nocookie.com/embed/FC5FbmsH4fw" frameborder="0" allowfullscreen></iframe>
diff --git a/docs/_posts/2015-02-20-introducing-relay-and-graphql.md b/docs/_posts/2015-02-20-introducing-relay-and-graphql.md
index 6152c30896d9..98488de8e965 100644
--- a/docs/_posts/2015-02-20-introducing-relay-and-graphql.md
+++ b/docs/_posts/2015-02-20-introducing-relay-and-graphql.md
@@ -8,7 +8,7 @@ author: wincent
 
 There's more to building an application than creating a user interface. Data fetching is still a tricky problem, especially as applications become more complicated. At [React.js Conf](http://conf.reactjs.com/) we announced two projects we've created at Facebook to make data fetching simple for developers, even as a product grows to include dozens of contributors and the application becomes as complex as Facebook itself.
 
-<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/9sc8Pyc51uU" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="315" src="https://www.youtube-nocookie.com/embed/9sc8Pyc51uU" frameborder="0" allowfullscreen></iframe>
 
 The two projects &mdash; Relay and GraphQL &mdash; have been in use in production at Facebook for some time, and we're excited to be bringing them to the world as open source in the future. In the meantime, we wanted to share some additional information about the projects here.
 
diff --git a/docs/_posts/2015-03-04-community-roundup-25.md b/docs/_posts/2015-03-04-community-roundup-25.md
index 261dad31b7a2..c7b027836929 100644
--- a/docs/_posts/2015-03-04-community-roundup-25.md
+++ b/docs/_posts/2015-03-04-community-roundup-25.md
@@ -12,7 +12,7 @@ Interest in React has been exploding recently, so it's a good time to explore so
 
 [Formidable Labs](https://github.com/FormidableLabs) and [Seattle JS](http://www.meetup.com/seattlejs/) recently hosted a series of React, Flux, and Flow workshops, and the first part is available to watch online:
 
-<iframe width="650" height="300" src="//www.youtube-nocookie.com/embed/Pd6Ub7Ju2RM" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="300" src="//www.youtube-nocookie.com/embed/Pd6Ub7Ju2RM" frameborder="0" allowfullscreen></iframe>
 
 [AEFlash](https://github.com/aearly) writes up [some best practices and tips](http://aeflash.com/2015-02/react-tips-and-best-practices.html) to help you avoid potential pitfalls when developing with React.
 
@@ -20,7 +20,7 @@ Black Mutt Media [takes us through their usage of React](http://blackmuttmedia.c
 
 Our own [Sebastian Markbåge](https://github.com/sebmarkbage) was on the [Web Platform Podcast](http://thewebplatform.libsyn.com/31-building-with-reactjs) to have a chat about all aspects of React.
 
-<iframe style="border: none" src="//html5-player.libsyn.com/embed/episode/id/3370114/height/75/width/200/theme/standard-mini/direction/no/autoplay/no/autonext/no/thumbnail/yes/preload/no/no_addthis/no/" height="26" width="650" scrolling="no" allowfullscreen="" webkitallowfullscreen="" mozallowfullscreen="" oallowfullscreen="" msallowfullscreen=""></iframe>
+<iframe style="border: none" src="//html5-player.libsyn.com/embed/episode/id/3370114/height/75/width/200/theme/standard-mini/direction/no/autoplay/no/autonext/no/thumbnail/yes/preload/no/no_addthis/no/" height="26" width="100%" scrolling="no" allowfullscreen="" webkitallowfullscreen="" mozallowfullscreen="" oallowfullscreen="" msallowfullscreen=""></iframe>
 
 ## Community Additions
 
diff --git a/docs/_posts/2015-03-30-community-roundup-26.md b/docs/_posts/2015-03-30-community-roundup-26.md
index 4e205b98b220..df7ee04cc64e 100644
--- a/docs/_posts/2015-03-30-community-roundup-26.md
+++ b/docs/_posts/2015-03-30-community-roundup-26.md
@@ -13,7 +13,7 @@ We open sourced React Native last week and the community reception blew away all
 
 **Give us 6 months**. At Facebook, we strive to only open-source projects that we are using in production. While the Android backend for React Native is starting to work (see video below at 37min), it hasn't been shipped to any users yet. There's a lot of work that goes into open-sourcing a project, and we want to do it right so that you have a great experience when using it.
 
-<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/X6YbAKiLCLU?start=2220" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="315" src="https://www.youtube-nocookie.com/embed/X6YbAKiLCLU?start=2220" frameborder="0" allowfullscreen></iframe>
 
 
 ## Ray Wenderlich - Property Finder
@@ -75,11 +75,11 @@ Jay Garcia spent a lot of time during the beta working on a NES music player wit
 </center>
 
 
-## React Native with Babel and Webpack
+## React Native with Babel and webpack
 
-React Native ships with a custom packager and custom ES6 transforms instead of using what the open source community settled on such as Webpack and Babel. The main reason for this is performance – we couldn't get those tools to have sub-second reload time on a large codebase.
+React Native ships with a custom packager and custom ES6 transforms instead of using what the open source community settled on such as webpack and Babel. The main reason for this is performance – we couldn't get those tools to have sub-second reload time on a large codebase.
 
-Roman Liutikov found a way to [use Webpack and Babel to run on React Native](https://github.com/roman01la/react-native-babel)! In the future, we want to work with those projects to provide cleaner extension mechanisms.
+Roman Liutikov found a way to [use webpack and Babel to run on React Native](https://github.com/roman01la/react-native-babel)! In the future, we want to work with those projects to provide cleaner extension mechanisms.
 
 
 ## A Dynamic, Crazy, Native Mobile Future—Powered by JavaScript
@@ -92,4 +92,3 @@ Clay Allsopp wrote a post about [all the crazy things you could do with a JavaSc
 We've spent a lot of efforts getting the onboarding as easy as possible and we're really happy that people noticed. We still have a lot of work to do on documentation, stay tuned!
 
 <blockquote class="twitter-tweet" lang="en"><p>Wow. Getting started with React Native might have been the smoothest experience I’ve ever had with a new developer product.</p>&mdash; Andreas Eldh (@eldh) <a href="https://twitter.com/eldh/status/581186172094980096">March 26, 2015</a></blockquote>
-
diff --git a/docs/_posts/2015-05-22-react-native-release-process.md b/docs/_posts/2015-05-22-react-native-release-process.md
index 615a87802010..bd8eaa68ff1f 100644
--- a/docs/_posts/2015-05-22-react-native-release-process.md
+++ b/docs/_posts/2015-05-22-react-native-release-process.md
@@ -19,4 +19,4 @@ You now have three ways to get React Native. You should chose the one you want b
 
 If you want more details, I highly recommend this video that explains how Facebook mobile release process works and why it was setup this way.
 
-<iframe width="650" height="300" src="https://www.youtube.com/embed/mOyoTUETmSM" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="300" src="https://www.youtube.com/embed/mOyoTUETmSM" frameborder="0" allowfullscreen></iframe>
diff --git a/docs/_posts/2015-08-13-reacteurope-roundup.md b/docs/_posts/2015-08-13-reacteurope-roundup.md
index 6a9c51b85405..993c77fbfa60 100644
--- a/docs/_posts/2015-08-13-reacteurope-roundup.md
+++ b/docs/_posts/2015-08-13-reacteurope-roundup.md
@@ -8,46 +8,46 @@ Last month, the first React.js European conference took place in the city of Par
 
 [Christopher Chedeau](https://github.com/vjeux) gave the opening keynote to the conference:
 
-<iframe width="650" height="366" src="//www.youtube.com/embed/PAA9O4E1IM4" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="//www.youtube.com/embed/PAA9O4E1IM4" frameborder="0" allowfullscreen></iframe>
 
 [Spencer Ahrens](https://github.com/sahrens) walks through building an advanced gestural UI leveraging the unique power of the React Native layout and animation systems to build a complex and fluid experience:
 
-<iframe width="650" height="366" src="//www.youtube.com/embed/xDlfrcM6YBk" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="//www.youtube.com/embed/xDlfrcM6YBk" frameborder="0" allowfullscreen></iframe>
 
 [Lee Byron](https://github.com/leebyron) explores GraphQL, its core principles, how it works, and what makes it a powerful tool:
 
-<iframe width="650" height="366" src="//www.youtube.com/embed/WQLzZf34FJ8" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="//www.youtube.com/embed/WQLzZf34FJ8" frameborder="0" allowfullscreen></iframe>
 
 [Joseph Savona](https://github.com/josephsavona) explores the problems Relay solves, its architecture and the query lifecycle, and how can you use Relay to build more scalable apps. There are examples of how Relay powers applications as complex as the Facebook News Feed:
 
-<iframe width="650" height="366" src="//www.youtube.com/embed/IrgHurBjQbg" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="//www.youtube.com/embed/IrgHurBjQbg" frameborder="0" allowfullscreen></iframe>
 
 [Nick Schrock](https://github.com/schrockn) and [Dan Schafer](https://github.com/dschafer) take a deeper dive into putting GraphQL to work. How can we build a GraphQL API to work with an existing REST API or server-side data model? What are best practices when building a GraphQL API, and how do they differ from traditional REST best practices? How does Facebook use GraphQL? Most importantly, what does a complete and coherent GraphQL API looks like, and how can we get started building one?
 
-<iframe width="650" height="366" src="//www.youtube.com/embed/gY48GW87Feo" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="//www.youtube.com/embed/gY48GW87Feo" frameborder="0" allowfullscreen></iframe>
 
 [Sebastian Markbåge](https://github.com/sebmarkbage) talks about why the DOM is flawed and how it is becoming a second-class citizen in the land of React apps:
 
-<iframe width="650" height="366" src="//www.youtube.com/embed/Zemce4Y1Y-A" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="//www.youtube.com/embed/Zemce4Y1Y-A" frameborder="0" allowfullscreen></iframe>
 
 [Sebastian McKenzie](https://github.com/sebmck) goes over how existing JSX build pipeline infrastructure can be further utilised to perform even more significant code transformations such as transpilation, optimisation, profiling and more, reducing bugs, making your code faster and you as a developer more productive and happy:
 
-<iframe width="650" height="366" src="//www.youtube.com/embed/OFuDvqZmUrE" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="//www.youtube.com/embed/OFuDvqZmUrE" frameborder="0" allowfullscreen></iframe>
 
 [Cheng Lou](https://github.com/chenglou) gives a talk on the past, the present and the future of animation, and the place React can potentially take in this:
 
-<iframe width="650" height="366" src="//www.youtube.com/embed/1tavDv5hXpo" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="//www.youtube.com/embed/1tavDv5hXpo" frameborder="0" allowfullscreen></iframe>
 
 And there was a Q&A session with the whole team covering a range of React topics:
 
-<iframe width="650" height="366" src="//www.youtube.com/embed/CRJZBZ_-6hQ" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="//www.youtube.com/embed/CRJZBZ_-6hQ" frameborder="0" allowfullscreen></iframe>
 
 And there were lots of great talks from the React community:
 
 * [Michael Chan](https://www.youtube.com/watch?v=ERB1TJBn32c&list=PLCC436JpVnK0Phxld2dD4tM4xPMxJCiRD&index=2) looks at how to solve problems like CSS theming and media queries with contexts and plain old JavaScript. He also looks at the role of container-components and when it's better to "just use CSS.".
 * [Elie Rotenberg](https://www.youtube.com/watch?v=JSjhhUvB9DY&index=3&list=PLCC436JpVnK0Phxld2dD4tM4xPMxJCiRD) talks about Flux over the Wire, building isomorphic, real-time React apps using a novel interpretation of Flux.
 * [Ryan Florence](https://www.youtube.com/watch?v=BF58ZJ1ZQxY&list=PLCC436JpVnK0Phxld2dD4tM4xPMxJCiRD&index=6) says “Your front and back ends are already successfully in production but you don't have to miss out on the productivity that React brings. Forget the rewrites, this is brownfield!”.
-* [Dan Abramov](https://www.youtube.com/watch?v=xsSnOQynTHs&index=7&list=PLCC436JpVnK0Phxld2dD4tM4xPMxJCiRD) demonstrates how React can be used together with Webpack Hot Module Replacement to create a live editing environment with time travel that supercharges your debugging experience and transforms the way you work on real apps every day.
+* [Dan Abramov](https://www.youtube.com/watch?v=xsSnOQynTHs&index=7&list=PLCC436JpVnK0Phxld2dD4tM4xPMxJCiRD) demonstrates how React can be used together with webpack Hot Module Replacement to create a live editing environment with time travel that supercharges your debugging experience and transforms the way you work on real apps every day.
 * [Mikhail Davydov](https://www.youtube.com/watch?v=ee_U2t-8L48&index=10&list=PLCC436JpVnK0Phxld2dD4tM4xPMxJCiRD) shows you how to ask the browser layout engine for help, how to avoid slavery of DSL, and build declarative Text UI using only web-technologies like HTML, JS, CSS and React.
 * [Kevin Robinson](https://www.youtube.com/watch?v=EOz4D_714R8&list=PLCC436JpVnK3HvUSAHpt-LRJkIK8pQG6R&index=3) shares how user experience choices are a primary influence on how Twitter design the data layer, especially for teams developing new products with full-stack capabilities.
 * [Jed Watson](https://www.youtube.com/watch?v=ctwmd5L1U_Q&list=PLCC436JpVnK3HvUSAHpt-LRJkIK8pQG6R&index=4) shares what Thinkmill have learned about React and mobile app development, and how they've approached the unique challenges of mobile web apps - with tools that are useful to all developers building touch interfaces with React, as well as a walkthrough of their development process and framework.
diff --git a/docs/_posts/2015-12-16-ismounted-antipattern.md b/docs/_posts/2015-12-16-ismounted-antipattern.md
index 6390baa04819..a819b04f0fa6 100644
--- a/docs/_posts/2015-12-16-ismounted-antipattern.md
+++ b/docs/_posts/2015-12-16-ismounted-antipattern.md
@@ -54,18 +54,16 @@ cancelablePromise
 cancelablePromise.cancel(); // Cancel the promise
 ```
 
-Where `makeCancelable` is [defined by @istarkov](https://github.com/facebook/react/issues/5465#issuecomment-157888325) as:
+Where `makeCancelable` was originally [defined by @istarkov](https://github.com/facebook/react/issues/5465#issuecomment-157888325) as:
 
 ```js
 const makeCancelable = (promise) => {
   let hasCanceled_ = false;
 
   const wrappedPromise = new Promise((resolve, reject) => {
-    promise.then((val) =>
-      hasCanceled_ ? reject({isCanceled: true}) : resolve(val)
-    );
-    promise.catch((error) =>
-      hasCanceled_ ? reject({isCanceled: true}) : reject(error)
+    promise.then(
+      val => hasCanceled_ ? reject({isCanceled: true}) : resolve(val),
+      error => hasCanceled_ ? reject({isCanceled: true}) : reject(error)
     );
   });
 
@@ -77,4 +75,5 @@ const makeCancelable = (promise) => {
   };
 };
 ```
+
 As an added bonus for getting your code cleaned up early, getting rid of `isMounted()` makes it one step easier for you to upgrade to ES6 classes, where using `isMounted()` is already prohibited.  Happy coding!
diff --git a/docs/_posts/2016-04-07-react-v15.md b/docs/_posts/2016-04-07-react-v15.md
new file mode 100644
index 000000000000..b4719ffe9570
--- /dev/null
+++ b/docs/_posts/2016-04-07-react-v15.md
@@ -0,0 +1,259 @@
+---
+title: "React v15.0"
+author: gaearon
+---
+
+We would like to thank the React community for reporting issues and regressions in the release candidates on our [issue tracker](https://github.com/facebook/react/issues/). Over the last few weeks we fixed those issues, and now, after two release candidates, we are excited to finally release the stable version of React 15.
+
+As a reminder, [we’re switching to major versions](/react/blog/2016/02/19/new-versioning-scheme.html) to indicate that we have been using React in production for a long time. This 15.0 release follows our previous 0.14 version and we’ll continue to follow semver like we’ve been doing since 2013. It’s also worth noting that [we no longer actively support Internet Explorer 8](/react/blog/2016/01/12/discontinuing-ie8-support.html). We believe React will work in its current form there but we will not be prioritizing any efforts to fix new issues that only affect IE8.
+
+React 15 brings significant improvements to how we interact with the DOM:
+
+* We are now using `document.createElement` instead of setting `innerHTML` when mounting components. This allows us to get rid of the `data-reactid` attribute on every node and make the DOM lighter. Using `document.createElement` is also faster in modern browsers and fixes a number of edge cases related to SVG elements and running multiple copies of React on the same page.
+
+* Historically our support for SVG has been incomplete, and many tags and attributes were missing. We heard you, and in React 15 we [added support for all the SVG attributes that are recognized by today’s browsers](https://github.com/facebook/react/pull/6243). If we missed any of the attributes you’d like to use, please [let us know](https://github.com/facebook/react/issues/1657). As a bonus, thanks to using `document.createElement`, we no longer need to maintain a list of SVG tags, so any SVG tags that were previously unsupported should work just fine in React 15.
+
+* We received some amazing contributions from the community in this release, and we would like to highlight [this pull request](https://github.com/facebook/react/pull/5753) by [Michael Wiencek](https://github.com/mwiencek) in particular. Thanks to Michael’s work, React 15 no longer emits extra `<span>` nodes around the text, making the DOM output much cleaner. This was a longstanding annoyance for React users so it’s exciting to accept this as an outside contribution.
+
+While this isn’t directly related to the release, we understand that in order to receive more community contributions like Michael’s, we need to communicate our goals and priorities more openly, and review pull requests more decisively. As a first step towards this, we started publishing [React core team weekly meeting notes](https://github.com/reactjs/core-notes) again. We also intend to introduce an RFC process inspired by [Ember RFCs](https://github.com/emberjs/rfcs) so external contributors can have more insight and influence in the future development of React. We will keep you updated about this on our blog.
+
+We are also experimenting with a new changelog format in this post. Every change now links to the corresponding pull request and mentions the author. Let us know whether you find this useful!
+
+## Upgrade Guide
+
+As usual with major releases, React 15 will remove support for some of the patterns deprecated nine months ago in React 0.14. We know changes can be painful (the Facebook codebase has over 20,000 React components, and that’s not even counting React Native), so we always try to make changes gradually in order to minimize the pain.
+
+If your code is free of warnings when running under React 0.14, upgrading should be easy. The bulk of changes in this release are actually behind the scenes, impacting the way that React interacts with the DOM. The other substantial change is that React now supports the full range of SVG elements and attributes. Beyond that we have a large number of incremental improvements and additional warnings aimed to aid developers. We’ve also laid some groundwork in the core to bring you some new capabilities in future releases.
+
+See the changelog below for more details.
+
+## Installation
+
+We recommend using React from `npm` and using a tool like browserify or webpack to build your code into a single bundle. To install the two packages:
+
+* `npm install --save react react-dom`
+
+Remember that by default, React runs extra checks and provides helpful warnings in development mode. When deploying your app, set the `NODE_ENV` environment variable to `production` to use the production build of React which does not include the development warnings and runs significantly faster.
+
+If you can’t use `npm` yet, we provide pre-built browser builds for your convenience, which are also available in the `react` package on bower.
+
+* **React**  
+  Dev build with warnings: <https://fb.me/react-15.0.0.js>  
+  Minified build for production: <https://fb.me/react-15.0.0.min.js>  
+* **React with Add-Ons**  
+  Dev build with warnings: <https://fb.me/react-with-addons-15.0.0.js>  
+  Minified build for production: <https://fb.me/react-with-addons-15.0.0.min.js>  
+* **React DOM** (include React in the page before React DOM)  
+  Dev build with warnings: <https://fb.me/react-dom-15.0.0.js>  
+  Minified build for production: <https://fb.me/react-dom-15.0.0.min.js>  
+
+## Changelog
+
+### Major changes
+
+- #### `document.createElement` is in and `data-reactid` is out
+
+    There were a number of large changes to our interactions with the DOM. One of the most noticeable changes is that we no longer set the `data-reactid` attribute for each DOM node. While this will make it more difficult to know if a website is using React, the advantage is that the DOM is much more lightweight. This change was made possible by us switching to use `document.createElement` on initial render. Previously we would generate a large string of HTML and then set `node.innerHTML`. At the time, this was decided to be faster than using `document.createElement` for the majority of cases and browsers that we supported. Browsers have continued to improve and so overwhelmingly this is no longer true. By using `createElement` we can make other parts of React faster. The ids were used to map back from events to the original React component, meaning we had to do a bunch of work on every event, even though we cached this data heavily. As we’ve all experienced, caching and in particularly invalidating caches, can be error prone and we saw many hard to reproduce issues over the years as a result. Now we can build up a direct mapping at render time since we already have a handle on the node.  
+
+    **Note:** `data-reactid` is still present for server-rendered content, however it is much smaller than before and is simply an auto-incrementing counter.  
+
+    <small>[@spicyj](https://github.com/spicyj) in [#5205](https://github.com/facebook/react/pull/5205)</small>
+
+- #### No more extra `<span>`s
+
+    Another big change with our DOM interaction is how we render text blocks. Previously you may have noticed that React rendered a lot of extra `<span>`s. For example, in our most basic example on the home page we render `<div>Hello {this.props.name}</div>`, resulting in markup that contained 2 `<span>`s. Now we’ll render plain text nodes interspersed with comment nodes that are used for demarcation. This gives us the same ability to update individual pieces of text, without creating extra nested nodes. Very few people have depended on the actual markup generated here so it’s likely you are not impacted. However if you were targeting these `<span>`s in your CSS, you will need to adjust accordingly. You can always render them explicitly in your components.  
+
+    <small>[@mwiencek](https://github.com/mwiencek) in [#5753](https://github.com/facebook/react/pull/5753)</small>
+
+- #### Rendering `null` now uses comment nodes
+
+    We’ve also made use of these comment nodes to change what `null` renders to. Rendering to `null` was a feature we added in React 0.11 and was implemented by rendering `<noscript>` elements. By rendering to comment nodes now, there’s a chance some of your CSS will be targeting the wrong thing, specifically if you are making use of `:nth-child` selectors. React’s use of the `<noscript>` tag has always been considered an implementation detail of how React targets the DOM. We believe they are safe changes to make without going through a release with warnings detailing the subtle differences as they are details that should not be depended upon. Additionally, we have seen that these changes have improved React performance for many typical applications.  
+
+    <small>[@spicyj](https://github.com/spicyj) in [#5451](https://github.com/facebook/react/pull/5451)</small>
+
+- #### Functional components can now return `null` too
+
+    We added support for [defining stateless components as functions](/react/blog/2015/09/10/react-v0.14-rc1.html#stateless-function-components) in React 0.14. However, React 0.14 still allowed you to define a class component without extending `React.Component` or using `React.createClass()`, so [we couldn’t reliably tell if your component is a function or a class](https://github.com/facebook/react/issues/5355), and did not allow returning `null` from it. This issue is solved in React 15, and you can now return `null` from any component, whether it is a class or a function.  
+
+    <small>[@jimfb](https://github.com/jimfb) in [#5884](https://github.com/facebook/react/pull/5884)</small>
+
+- #### Improved SVG support
+
+    All SVG tags are now fully supported. (Uncommon SVG tags are not present on the `React.DOM` element helper, but JSX and `React.createElement` work on all tag names.) All SVG attributes that are implemented by the browsers should be supported too. If you find any attributes that we have missed, please [let us know in this issue](https://github.com/facebook/react/issues/1657).  
+
+    <small>[@zpao](https://github.com/zpao) in [#6243](https://github.com/facebook/react/pull/6243)</small>
+
+### Breaking changes
+
+- #### No more extra `<span>`s
+
+    It’s worth calling out the DOM structure changes above again, in particular the change from `<span>`s. In the course of updating the Facebook codebase, we found a very small amount of code that was depending on the markup that React generated. Some of these cases were integration tests like WebDriver which were doing very specific XPath queries to target nodes. Others were simply tests using `ReactDOM.renderToStaticMarkup` and comparing markup. Again, there were a very small number of changes that had to be made, but we don’t want anybody to be blindsided. We encourage everybody to run their test suites when upgrading and consider alternative approaches when possible. One approach that will work for some cases is to explicitly use `<span>`s in your `render` method.  
+
+    <small>[@mwiencek](https://github.com/mwiencek) in [#5753](https://github.com/facebook/react/pull/5753)</small>
+
+- #### `React.cloneElement()` now resolves `defaultProps`
+
+    We fixed a bug in `React.cloneElement()` that some components may rely on. If some of the `props` received by `cloneElement()` are `undefined`, it used to return an element with `undefined` values for those props. In React 15, we’re changing it to be consistent with `createElement()`. Now any `undefined` props passed to `cloneElement()` are resolved to the corresponding component’s `defaultProps`. Only one of our 20,000 React components was negatively affected by this so we feel comfortable releasing this change without keeping the old behavior for another release cycle.  
+
+    <small>[@truongduy134](https://github.com/truongduy134) in [#5997](https://github.com/facebook/react/pull/5997)</small>
+
+- #### `ReactPerf.getLastMeasurements()` is opaque
+
+    This change won’t affect applications but may break some third-party tools. We are [revamping `ReactPerf` implementation](https://github.com/facebook/react/pull/6046) and plan to release it during the 15.x cycle. The internal performance measurement format is subject to change so, for the time being, we consider the return value of `ReactPerf.getLastMeasurements()` an opaque data structure that should not be relied upon.  
+
+    <small>[@gaearon](https://github.com/gaearon) in [#6286](https://github.com/facebook/react/pull/6286)</small>
+
+- #### Removed deprecations
+
+    These deprecations were introduced nine months ago in v0.14 with a warning and are removed:
+
+    - Deprecated APIs are removed from the `React` top-level export: `findDOMNode`, `render`, `renderToString`, `renderToStaticMarkup`, and `unmountComponentAtNode`. As a reminder, they are now available on `ReactDOM` and `ReactDOMServer`.  
+    <small>[@jimfb](https://github.com/jimfb) in [#5832](https://github.com/facebook/react/pull/5832)</small>
+
+    - Deprecated addons are removed: `batchedUpdates` and `cloneWithProps`.  
+    <small>[@jimfb](https://github.com/jimfb) in [#5859](https://github.com/facebook/react/pull/5859), [@zpao](https://github.com/zpao) in [#6016](https://github.com/facebook/react/pull/6016)</small>
+
+    - Deprecated component instance methods are removed: `setProps`, `replaceProps`, and `getDOMNode`.  
+    <small>[@jimfb](https://github.com/jimfb) in [#5570](https://github.com/facebook/react/pull/5570)</small>
+
+    - Deprecated CommonJS `react/addons` entry point is removed. As a reminder, you should use separate `react-addons-*` packages instead. This only applies if you use the CommonJS builds.  
+    <small>[@gaearon](https://github.com/gaearon) in [#6285](https://github.com/facebook/react/pull/6285)</small>
+
+    - Passing `children` to void elements like `<input>` was deprecated, and now throws an error.  
+    <small>[@jonhester](https://github.com/jonhester) in [#3372](https://github.com/facebook/react/pull/3372)</small>
+
+    - React-specific properties on DOM `refs` (e.g. `this.refs.div.props`) were deprecated, and are removed now.  
+    <small>[@jimfb](https://github.com/jimfb) in [#5495](https://github.com/facebook/react/pull/5495)</small>
+
+### New deprecations, introduced with a warning
+
+Each of these changes will continue to work as before with a new warning until the release of React 16 so you can upgrade your code gradually.
+
+- `LinkedStateMixin` and `valueLink` are now deprecated due to very low popularity. If you need this, you can use a wrapper component that implements the same behavior: [react-linked-input](https://www.npmjs.com/package/react-linked-input).  
+<small>[@jimfb](https://github.com/jimfb) in [#6127](https://github.com/facebook/react/pull/6127)</small>
+
+- Future versions of React will treat `<input value={null}>` as a request to clear the input. However, React 0.14 has been ignoring `value={null}`. React 15 warns you on a `null` input value and offers you to clarify your intention. To fix the warning, you may explicitly pass an empty string to clear a controlled input, or pass `undefined` to make the input uncontrolled.  
+<small>[@antoaravinth](https://github.com/antoaravinth) in [#5048](https://github.com/facebook/react/pull/5048)</small>
+
+- `ReactPerf.printDOM()` was renamed to `ReactPerf.printOperations()`, and `ReactPerf.getMeasurementsSummaryMap()` was renamed to `ReactPerf.getWasted()`.  
+<small>[@gaearon](https://github.com/gaearon) in [#6287](https://github.com/facebook/react/pull/6287)</small>
+
+### New helpful warnings
+
+- If you use a minified copy of the _development_ build, React DOM kindly encourages you to use the faster production build instead.  
+<small>[@spicyj](https://github.com/spicyj) in [#5083](https://github.com/facebook/react/pull/5083)</small>
+
+- React DOM: When specifying a unit-less CSS value as a string, a future version will not add `px` automatically. This version now warns in this case (ex: writing `style={{'{{'}}width: '300'}}`. Unitless *number* values like `width: 300` are unchanged.  
+<small>[@pluma](https://github.com/pluma) in [#5140](https://github.com/facebook/react/pull/5140)</small>
+
+- Synthetic Events will now warn when setting and accessing properties (which will not get cleared appropriately), as well as warn on access after an event has been returned to the pool.  
+<small>[@kentcdodds](https://github.com/kentcdodds) in [#5940](https://github.com/facebook/react/pull/5940) and [@koba04](https://github.com/koba04) in [#5947](https://github.com/facebook/react/pull/5947)</small>
+
+- Elements will now warn when attempting to read `ref` and `key` from the props.  
+<small>[@prometheansacrifice](https://github.com/prometheansacrifice) in [#5744](https://github.com/facebook/react/pull/5744)</small>
+
+- React will now warn if you pass a different `props` object to `super()` in the constructor.  
+<small>[@prometheansacrifice](https://github.com/prometheansacrifice) in [#5346](https://github.com/facebook/react/pull/5346)</small>
+
+- React will now warn if you call `setState()` inside `getChildContext()`.  
+<small>[@raineroviir](https://github.com/raineroviir) in [#6121](https://github.com/facebook/react/pull/6121)</small>
+
+- React DOM now attempts to warn for mistyped event handlers on DOM elements, such as `onclick` which should be `onClick`.  
+<small>[@ali](https://github.com/ali) in [#5361](https://github.com/facebook/react/pull/5361)</small>
+
+- React DOM now warns about `NaN` values in `style`.  
+<small>[@jontewks](https://github.com/jontewks) in [#5811](https://github.com/facebook/react/pull/5811)</small>
+
+- React DOM now warns if you specify both `value` and `defaultValue` for an input.  
+<small>[@mgmcdermott](https://github.com/mgmcdermott) in [#5823](https://github.com/facebook/react/pull/5823)</small>
+
+- React DOM now warns if an input switches between being controlled and uncontrolled.  
+<small>[@TheBlasfem](https://github.com/TheBlasfem) in [#5864](https://github.com/facebook/react/pull/5864)</small>
+
+- React DOM now warns if you specify `onFocusIn` or `onFocusOut` handlers as they are unnecessary in React.  
+<small>[@jontewks](https://github.com/jontewks) in [#6296](https://github.com/facebook/react/pull/6296)</small>
+
+- React now prints a descriptive error message when you pass an invalid callback as the last argument to `ReactDOM.render()`, `this.setState()`, or `this.forceUpdate()`.  
+<small>[@conorhastings](https://github.com/conorhastings) in [#5193](https://github.com/facebook/react/pull/5193) and [@gaearon](https://github.com/gaearon) in [#6310](https://github.com/facebook/react/pull/6310)</small>
+
+- Add-Ons: `TestUtils.Simulate()` now prints a helpful message if you attempt to use it with shallow rendering.  
+<small>[@conorhastings](https://github.com/conorhastings) in [#5358](https://github.com/facebook/react/pull/5358)</small>
+
+- PropTypes: `arrayOf()` and `objectOf()` provide better error messages for invalid arguments.  
+<small>[@chicoxyzzy](https://github.com/chicoxyzzy) in [#5390](https://github.com/facebook/react/pull/5390)</small>
+
+### Notable bug fixes
+
+- Fixed multiple small memory leaks.  
+<small>[@spicyj](https://github.com/spicyj) in [#4983](https://github.com/facebook/react/pull/4983) and [@victor-homyakov](https://github.com/victor-homyakov) in [#6309](https://github.com/facebook/react/pull/6309)</small>
+
+- Input events are handled more reliably in IE 10 and IE 11; spurious events no longer fire when using a placeholder.  
+<small>[@jquense](https://github.com/jquense) in [#4051](https://github.com/facebook/react/pull/4051)</small>
+
+- The `componentWillReceiveProps()` lifecycle method is now consistently called when `context` changes.  
+<small>[@milesj](https://github.com/milesj) in [#5787](https://github.com/facebook/react/pull/5787)</small>
+
+- `React.cloneElement()` doesn’t append slash to an existing `key` when used inside `React.Children.map()`.  
+<small>[@ianobermiller](https://github.com/ianobermiller) in [#5892](https://github.com/facebook/react/pull/5892)</small>
+
+- React DOM now supports the `cite` and `profile` HTML attributes.  
+<small>[@AprilArcus](https://github.com/AprilArcus) in [#6094](https://github.com/facebook/react/pull/6094) and [@saiichihashimoto](https://github.com/saiichihashimoto) in [#6032](https://github.com/facebook/react/pull/6032)</small>
+
+- React DOM now supports `cssFloat`, `gridRow` and `gridColumn` CSS properties.  
+<small>[@stevenvachon](https://github.com/stevenvachon) in [#6133](https://github.com/facebook/react/pull/6133) and  [@mnordick](https://github.com/mnordick) in [#4779](https://github.com/facebook/react/pull/4779)</small>
+
+- React DOM now correctly handles `borderImageOutset`, `borderImageWidth`, `borderImageSlice`, `floodOpacity`, `strokeDasharray`, and `strokeMiterlimit` as unitless CSS properties.  
+<small>[@rofrischmann](https://github.com/rofrischmann) in [#6210](https://github.com/facebook/react/pull/6210) and [#6270](https://github.com/facebook/react/pull/6270)</small>
+
+- React DOM now supports the `onAnimationStart`, `onAnimationEnd`, `onAnimationIteration`, `onTransitionEnd`, and `onInvalid` events. Support for `onLoad` has been added to `object` elements.  
+<small>[@tomduncalf](https://github.com/tomduncalf) in [#5187](https://github.com/facebook/react/pull/5187),  [@milesj](https://github.com/milesj) in [#6005](https://github.com/facebook/react/pull/6005), and [@ara4n](https://github.com/ara4n) in [#5781](https://github.com/facebook/react/pull/5781)</small>
+
+- React DOM now defaults to using DOM attributes instead of properties, which fixes a few edge case bugs. Additionally the nullification of values (ex: `href={null}`) now results in the forceful removal, no longer trying to set to the default value used by browsers in the absence of a value.  
+<small>[@syranide](https://github.com/syranide) in [#1510](https://github.com/facebook/react/pull/1510)</small>
+
+- React DOM does not mistakingly coerce `children` to strings for Web Components.  
+<small>[@jimfb](https://github.com/jimfb) in [#5093](https://github.com/facebook/react/pull/5093)</small>
+
+- React DOM now correctly normalizes SVG `<use>` events.  
+<small>[@edmellum](https://github.com/edmellum) in [#5720](https://github.com/facebook/react/pull/5720)</small>
+
+- React DOM does not throw if a `<select>` is unmounted while its `onChange` handler is executing.  
+<small>[@sambev](https://github.com/sambev) in [#6028](https://github.com/facebook/react/pull/6028)</small>
+
+- React DOM does not throw in Windows 8 apps.  
+<small>[@Andrew8xx8](https://github.com/Andrew8xx8) in [#6063](https://github.com/facebook/react/pull/6063)</small>
+
+- React DOM does not throw when asynchronously unmounting a child with a `ref`.  
+<small>[@yiminghe](https://github.com/yiminghe) in [#6095](https://github.com/facebook/react/pull/6095)</small>
+
+- React DOM no longer forces synchronous layout because of scroll position tracking.  
+<small>[@syranide](https://github.com/syranide) in [#2271](https://github.com/facebook/react/pull/2271)</small>
+
+- `Object.is` is used in a number of places to compare values, which leads to fewer false positives, especially involving `NaN`. In particular, this affects the `shallowCompare` add-on.  
+<small>[@chicoxyzzy](https://github.com/chicoxyzzy) in [#6132](https://github.com/facebook/react/pull/6132)</small>
+
+- Add-Ons: ReactPerf no longer instruments adding or removing an event listener because they don’t really touch the DOM due to event delegation.  
+<small>[@antoaravinth](https://github.com/antoaravinth) in [#5209](https://github.com/facebook/react/pull/5209)</small>
+
+### Other improvements
+
+- React now uses `loose-envify` instead of `envify` so it installs fewer transitive dependencies.  
+<small>[@qerub](https://github.com/qerub) in [#6303](https://github.com/facebook/react/pull/6303)</small>
+
+- Shallow renderer now exposes `getMountedInstance()`.  
+<small>[@glenjamin](https://github.com/glenjamin) in [#4918](https://github.com/facebook/react/pull/4918)</small>
+
+- Shallow renderer now returns the rendered output from `render()`.  
+<small>[@simonewebdesign](https://github.com/simonewebdesign) in [#5411](https://github.com/facebook/react/pull/5411)</small>
+
+- React no longer depends on ES5 *shams* for `Object.create` and `Object.freeze` in older environments. It still, however, requires ES5 *shims* in those environments.  
+<small>[@dgreensp](https://github.com/dgreensp) in [#4959](https://github.com/facebook/react/pull/4959)</small>
+
+- React DOM now allows `data-` attributes with names that start with numbers.  
+<small>[@nLight](https://github.com/nLight) in [#5216](https://github.com/facebook/react/pull/5216)</small>
+
+- React DOM adds a new `suppressContentEditableWarning` prop for components like [Draft.js](https://facebook.github.io/draft-js/) that intentionally manage `contentEditable` children with React.  
+<small>[@mxstbr](https://github.com/mxstbr) in [#6112](https://github.com/facebook/react/pull/6112)</small>
+
+- React improves the performance for `createClass()` on complex specs.  
+<small>[@spicyj](https://github.com/spicyj) in [#5550](https://github.com/facebook/react/pull/5550)</small>
diff --git a/docs/_posts/2016-04-08-react-v15.0.1.md b/docs/_posts/2016-04-08-react-v15.0.1.md
new file mode 100644
index 000000000000..671cb98dba32
--- /dev/null
+++ b/docs/_posts/2016-04-08-react-v15.0.1.md
@@ -0,0 +1,34 @@
+---
+title: "React v15.0.1"
+author: zpao
+---
+
+Yesterday afternoon we shipped v15.0.0 and quickly got some feedback about a couple of issues. We apologize for these problems and we've been working since then to make sure we get fixes into your hands as quickly as possible.
+
+The first of these issues is related to the removal of an undocumented API. This API was added to enable [JSX Spread Attributes](/react/docs/jsx-spread.html) in our JS compile tools (react-tools, JSXTransformer) before `Object.assign` was standard. When we stopped supporting these tools last year, we kept the API there to catch the longer tail of people using those tools. Meanwhile we moved to using Babel and encouraged others to do the same. Babel will typically compile the spread use to an `_extends` helper, which will use `Object.assign`. We did not properly research other compilation tools before deciding to remove the API in v15. Specifically, TypeScript and coffee-react are two popular packages using `React.__spread`, as well as reactify which still makes use react-tools. In order to make sure that code compiled with these tools is not broken, we will be restoring the `React.__spread` API and adding a warning. It will be removed in the future so if you maintain a project making using of it, we encourage you to compile to `Object.assign` directly or a similar helper function.
+
+The second issue resulted in cursor position being lost in controlled inputs. We merged a pull request earlier this week to fix a separate regression from v0.14. Our goal was to target `<option>` elements but we ended up targeting all interactions with `value` properties. Unfortunately we didn't test it as thoroughly as we thought. We backed out the offending change and fixed the issue in different way which doesn't have the same problem.
+
+We apologize if you installed 15.0.0 and have encountered these issues yourselves.
+
+As usual, you can get install the `react` package via npm or download a browser bundle.
+
+* **React**  
+  Dev build with warnings: <https://fb.me/react-15.0.1.js>  
+  Minified build for production: <https://fb.me/react-15.0.1.min.js>  
+* **React with Add-Ons**  
+  Dev build with warnings: <https://fb.me/react-with-addons-15.0.1.js>  
+  Minified build for production: <https://fb.me/react-with-addons-15.0.1.min.js>  
+* **React DOM** (include React in the page before React DOM)  
+  Dev build with warnings: <https://fb.me/react-dom-15.0.1.js>  
+  Minified build for production: <https://fb.me/react-dom-15.0.1.min.js>  
+
+## Changelog
+
+### React
+- Restore `React.__spread` API to unbreak code compiled with some tools making use of this undocumented API. It is now officially deprecated.  
+  <small>[@zpao](https://github.com/zpao) in [#6444](https://github.com/facebook/react/pull/6444)</small>
+
+### ReactDOM
+- Fixed issue resulting in loss of cursor position in controlled inputs.  
+  <small>[@spicyj](https://github.com/spicyj) in [#6449](https://github.com/facebook/react/pull/6449)</small>
diff --git a/docs/_posts/2016-07-11-introducing-reacts-error-code-system.md b/docs/_posts/2016-07-11-introducing-reacts-error-code-system.md
new file mode 100644
index 000000000000..6bce06833846
--- /dev/null
+++ b/docs/_posts/2016-07-11-introducing-reacts-error-code-system.md
@@ -0,0 +1,18 @@
+---
+title: "Introducing React's Error Code System"
+author: keyanzhang
+---
+
+Building a better developer experience has been one of the things that React deeply cares about, and a crucial part of it is to detect anti-patterns/potential errors early and provide helpful error messages when things (may) go wrong. However, most of these only exist in development mode; in production, we avoid having extra expensive assertions and sending down full error messages in order to reduce the number of bytes sent over the wire.
+
+Prior to this release, we stripped out error messages at build-time and this is why you might have seen this message in production:
+
+> Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.
+
+In order to make debugging in production easier, we're introducing an Error Code System in [15.2.0](https://github.com/facebook/react/releases/tag/v15.2.0). We developed a [gulp script](https://github.com/facebook/react/blob/master/scripts/error-codes/gulp-extract-errors.js) that collects all of our `invariant` error messages and folds them to a [JSON file](https://github.com/facebook/react/blob/master/scripts/error-codes/codes.json), and at build-time Babel uses the JSON to [rewrite](https://github.com/facebook/react/blob/master/scripts/error-codes/dev-expression-with-codes.js) our `invariant` calls in production to reference the corresponding error IDs. Now when things go wrong in production, the error that React throws will contain a URL with an error ID and relevant information. The URL will point you to a page in our documentation where the original error message gets reassembled.
+
+While we hope you don't see errors often, you can see how it works [here](/react/docs/error-decoder.html?invariant=109&args[]=Foo). This is what the same error from above will look like:
+
+> Minified React error #109; visit https://facebook.github.io/react/docs/error-decoder.html?invariant=109&args[]=Foo for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
+
+We do this so that the developer experience is as good as possible, while also keeping the production bundle size as small as possible. This feature shouldn't require any changes on your side — use the `min.js` files in production or bundle your application code with `process.env.NODE_ENV === 'production'` and you should be good to go!
diff --git a/docs/_posts/2016-07-13-mixins-considered-harmful.md b/docs/_posts/2016-07-13-mixins-considered-harmful.md
new file mode 100644
index 000000000000..ad9659260997
--- /dev/null
+++ b/docs/_posts/2016-07-13-mixins-considered-harmful.md
@@ -0,0 +1,614 @@
+---
+title: "Mixins Considered Harmful"
+author: gaearon
+---
+
+“How do I share the code between several components?” is one of the first questions that people ask when they learn React. Our answer has always been to use component composition for code reuse. You can define a component and use it in several other components.
+
+It is not always obvious how a certain pattern can be solved with composition. React is influenced by functional programming but it came into the field that was dominated by object-oriented libraries. It was hard for engineers both inside and outside of Facebook to give up on the patterns they were used to.
+
+To ease the initial adoption and learning, we included certain escape hatches into React. The mixin system was one of those escape hatches, and its goal was to give you a way to reuse code between components when you aren’t sure how to solve the same problem with composition.
+
+Three years passed since React was released. The landscape has changed. Multiple view libraries now adopt a component model similar to React. Using composition over inheritance to build declarative user interfaces is no longer a novelty. We are also more confident in the React component model, and we have seen many creative uses of it both internally and in the community.
+
+In this post, we will consider the problems commonly caused by mixins. Then we will suggest several alternative patterns for the same use cases. We have found those patterns to scale better with the complexity of the codebase than mixins.
+
+## Why Mixins are Broken
+
+At Facebook, React usage has grown from a few components to thousands of them. This gives us a window into how people use React. Thanks to declarative rendering and top-down data flow, many teams were able to fix a bunch of bugs while shipping new features as they adopted React.
+
+However it’s inevitable that some of our code using React gradually became incomprehensible. Occasionally, the React team would see groups of components in different projects that people were afraid to touch. These components were too easy to break accidentally, were confusing to new developers, and eventually became just as confusing to the people who wrote them in the first place. Much of this confusion was caused by mixins. At the time, I wasn’t working at Facebook but I came to the [same conclusions](https://medium.com/@dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750) after writing my fair share of terrible mixins.
+
+This doesn’t mean that mixins themselves are bad. People successfully employ them in different languages and paradigms, including some functional languages. At Facebook, we extensively use traits in Hack which are fairly similar to mixins. Nevertheless, we think that mixins are unnecessary and problematic in React codebases. Here’s why.
+
+### Mixins introduce implicit dependencies
+
+Sometimes a component relies on a certain method defined in the mixin, such as `getClassName()`. Sometimes it’s the other way around, and mixin calls a method like `renderHeader()` on the component. JavaScript is a dynamic language so it’s hard to enforce or document these dependencies.
+
+Mixins break the common and usually safe assumption that you can rename a state key or a method by searching for its occurrences in the component file. You might write a stateful component and then your coworker might add a mixin that reads this state. In a few months, you might want to move that state up to the parent component so it can be shared with a sibling. Will you remember to update the mixin to read a prop instead? What if, by now, other components also use this mixin?
+
+These implicit dependencies make it hard for new team members to contribute to a codebase. A component’s `render()` method might reference some method that isn’t defined on the class. Is it safe to remove? Perhaps it’s defined in one of the mixins. But which one of them? You need to scroll up to the mixin list, open each of those files, and look for this method. Worse, mixins can specify their own mixins, so the search can be deep.
+
+Often, mixins come to depend on other mixins, and removing one of them breaks the other. In these situations it is very tricky to tell how the data flows in and out of mixins, and what their dependency graph looks like. Unlike components, mixins don’t form a hierarchy: they are flattened and operate in the same namespace.
+
+### Mixins cause name clashes
+
+There is no guarantee that two particular mixins can be used together. For example, if `FluxListenerMixin` defines `handleChange()` and `WindowSizeMixin` defines `handleChange()`, you can’t use them together. You also can’t define a method with this name on your own component.
+
+It’s not a big deal if you control the mixin code. When you have a conflict, you can rename that method on one of the mixins. However it’s tricky because some components or other mixins may already be calling this method directly, and you need to find and fix those calls as well.
+
+If you have a name conflict with a mixin from a third party package, you can’t just rename a method on it. Instead, you have to use awkward method names on your component to avoid clashes.
+
+The situation is no better for mixin authors. Even adding a new method to a mixin is always a potentially breaking change because a method with the same name might already exist on some of the components using it, either directly or through another mixin. Once written, mixins are hard to remove or change. Bad ideas don’t get refactored away because refactoring is too risky.
+
+### Mixins cause snowballing complexity
+
+Even when mixins start out simple, they tend to become complex over time. The example below is based on a real scenario I’ve seen play out in a codebase.
+
+A component needs some state to track mouse hover. To keep this logic reusable, you might extract `handleMouseEnter()`, `handleMouseLeave()` and `isHovering()` into a `HoverMixin`. Next, somebody needs to implement a tooltip. They don’t want to duplicate the logic in `HoverMixin` so they create a `TooltipMixin` that uses `HoverMixin`. `TooltipMixin` reads `isHovering()` provided by `HoverMixin` in its `componentDidUpdate()` and either shows or hides the tooltip.
+
+A few months later, somebody wants to make the tooltip direction configurable. In an effort to avoid code duplication, they add support for a new optional method called `getTooltipOptions()` to `TooltipMixin`. By this time, components that show popovers also use `HoverMixin`. However popovers need a different hover delay. To solve this, somebody adds support for an optional `getHoverOptions()` method and implements it in `TooltipMixin`. Those mixins are now tightly coupled.
+
+This is fine while there are no new requirements. However this solution doesn’t scale well. What if you want to support displaying multiple tooltips in a single component? You can’t define the same mixin twice in a component. What if the tooltips need to be displayed automatically in a guided tour instead of on hover? Good luck decoupling `TooltipMixin` from `HoverMixin`. What if you need to support the case where the hover area and the tooltip anchor are located in different components? You can’t easily hoist the state used by mixin up into the parent component. Unlike components, mixins don’t lend themselves naturally to such changes.
+
+Every new requirement makes the mixins harder to understand. Components using the same mixin become increasingly coupled with time. Any new capability gets added to all of the components using that mixin. There is no way to split a “simpler” part of the mixin without either duplicating the code or introducing more dependencies and indirection between mixins. Gradually, the encapsulation boundaries erode, and since it’s hard to change or remove the existing mixins, they keep getting more abstract until nobody understands how they work.
+
+These are the same problems we faced building apps before React. We found that they are solved by declarative rendering, top-down data flow, and encapsulated components. At Facebook, we have been migrating our code to use alternative patterns to mixins, and we are generally happy with the results. You can read about those patterns below.
+
+## Migrating from Mixins
+
+Let’s make it clear that mixins are not technically deprecated. If you use `React.createClass()`, you may keep using them. We only say that they didn’t work well for us, and so we won’t recommend using them in the future.
+
+Every section below corresponds to a mixin usage pattern that we found in the Facebook codebase. For each of them, we describe the problem and a solution that we think works better than mixins. The examples are written in ES5 but once you don’t need mixins, you can switch to ES6 classes if you’d like.
+
+We hope that you find this list helpful. Please let us know if we missed important use cases so we can either amend the list or be proven wrong!
+
+### Performance Optimizations
+
+One of the most commonly used mixins is [`PureRenderMixin`](/react/docs/pure-render-mixin.html). You might be using it in some components to [prevent unnecessary re-renders](/react/docs/advanced-performance.html#shouldcomponentupdate-in-action) when the props and state are shallowly equal to the previous props and state:
+
+```javascript
+var PureRenderMixin = require('react-addons-pure-render-mixin');
+
+var Button = React.createClass({
+  mixins: [PureRenderMixin],
+
+  // ...
+
+});
+```
+
+#### Solution
+
+To express the same without mixins, you can use the [`shallowCompare`](/react/docs/shallow-compare.html) function directly instead:
+
+```js
+var shallowCompare = require('react-addons-shallow-compare');
+
+var Button = React.createClass({
+  shouldComponentUpdate: function(nextProps, nextState) {
+    return shallowCompare(this, nextProps, nextState);
+  },
+
+  // ...
+
+});
+```
+
+If you use a custom mixin implementing a `shouldComponentUpdate` function with different algorithm, we suggest exporting just that single function from a module and calling it directly from your components.
+
+We understand that more typing can be annoying. For the most common case, we plan to [introduce a new base class](https://github.com/facebook/react/pull/7195) called `React.PureComponent` in the next minor release. It uses the same shallow comparison as `PureRenderMixin` does today.
+
+### Subscriptions and Side Effects
+
+The second most common type of mixins that we encountered are mixins that subscribe a React component to a third-party data source. Whether this data source is a Flux Store, an Rx Observable, or something else, the pattern is very similar: the subscription is created in `componentDidMount`, destroyed in `componentWillUnmount`, and the change handler calls `this.setState()`.
+
+```javascript
+var SubscriptionMixin = {
+  getInitialState: function() {
+    return {
+      comments: DataSource.getComments()
+    };
+  },
+
+  componentDidMount: function() {
+    DataSource.addChangeListener(this.handleChange);
+  },
+
+  componentWillUnmount: function() {
+    DataSource.removeChangeListener(this.handleChange);
+  },
+
+  handleChange: function() {
+    this.setState({
+      comments: DataSource.getComments()
+    });
+  }
+};
+
+var CommentList = React.createClass({
+  mixins: [SubscriptionMixin],
+
+  render: function() {
+    // Reading comments from state managed by mixin.
+    var comments = this.state.comments;
+    return (
+      <div>
+        {comments.map(function(comment) {
+          return <Comment comment={comment} key={comment.id} />
+        })}
+      </div>
+    )
+  }
+});
+
+module.exports = CommentList;
+```
+
+#### Solution
+
+If there is just one component subscribed to this data source, it is fine to embed the subscription logic right into the component. Avoid premature abstractions.
+
+If several components used this mixin to subscribe to a data source, a nice way to avoid repetition is to use a pattern called [“higher-order components”](https://medium.com/@dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750). It can sound intimidating so we will take a closer look at how this pattern naturally emerges from the component model.
+
+#### Higher-Order Components Explained
+
+Let’s forget about React for a second. Consider these two functions that add and multiply numbers, logging the results as they do that:
+
+```js
+function addAndLog(x, y) {
+  var result = x + y;
+  console.log('result:', result);
+  return result;
+}
+
+function multiplyAndLog(x, y) {
+  var result = x * y;
+  console.log('result:', result);
+  return result;
+}
+```
+
+These two functions are not very useful but they help us demonstrate a pattern that we can later apply to components.
+
+Let’s say that we want to extract the logging logic out of these functions without changing their signatures. How can we do this? An elegant solution is to write a [higher-order function](https://en.wikipedia.org/wiki/Higher-order_function), that is, a function that takes a function as an argument and returns a function.
+
+Again, it sounds more intimidating than it really is:
+
+```js
+function withLogging(wrappedFunction) {
+  // Return a function with the same API...
+  return function(x, y) {
+    // ... that calls the original function
+    var result = wrappedFunction(x, y);
+    // ... but also logs its result!
+    console.log('result:', result);
+    return result;
+  };
+}
+```
+
+The `withLogging` higher-order function lets us write `add` and `multiply` without the logging statements, and later wrap them to get `addAndLog` and `multiplyAndLog` with exactly the same signatures as before:
+
+```js
+function add(x, y) {
+  return x + y;
+}
+
+function multiply(x, y) {
+  return x * y;
+}
+
+function withLogging(wrappedFunction) {
+  return function(x, y) {
+    var result = wrappedFunction(x, y);
+    console.log('result:', result);
+    return result;
+  };
+}
+
+// Equivalent to writing addAndLog by hand:
+var addAndLog = withLogging(add);
+
+// Equivalent to writing multiplyAndLog by hand:
+var multiplyAndLog = withLogging(multiply);
+```
+
+Higher-order components are a very similar pattern, but applied to components in React. We will apply this transformation from mixins in two steps.
+
+As a first step, we will split our `CommentList` component in two, a child and a parent. The child will be only concerned with rendering the comments. The parent will set up the subscription and pass the up-to-date data to the child via props.
+
+```js
+// This is a child component.
+// It only renders the comments it receives as props.
+var CommentList = React.createClass({
+  render: function() {
+    // Note: now reading from props rather than state.
+    var comments = this.props.comments;
+    return (
+      <div>
+        {comments.map(function(comment) {
+          return <Comment comment={comment} key={comment.id} />
+        })}
+      </div>
+    )
+  }
+});
+
+// This is a parent component.
+// It subscribes to the data source and renders <CommentList />.
+var CommentListWithSubscription = React.createClass({
+  getInitialState: function() {
+    return {
+      comments: DataSource.getComments()
+    };
+  },
+
+  componentDidMount: function() {
+    DataSource.addChangeListener(this.handleChange);
+  },
+
+  componentWillUnmount: function() {
+    DataSource.removeChangeListener(this.handleChange);
+  },
+
+  handleChange: function() {
+    this.setState({
+      comments: DataSource.getComments()
+    });
+  },
+
+  render: function() {
+    // We pass the current state as props to CommentList.
+    return <CommentList comments={this.state.comments} />;
+  }
+});
+
+module.exports = CommentListWithSubscription;
+```
+
+There is just one final step left to do.
+
+Remember how we made `withLogging()` take a function and return another function wrapping it? We can apply a similar pattern to React components.
+
+We will write a new function called `withSubscription(WrappedComponent)`. Its argument could be any React component. We will pass `CommentList` as `WrappedComponent`, but we could also apply `withSubscription()` to any other component in our codebase.
+
+This function would return another component. The returned component would manage the subscription and render `<WrappedComponent />` with the current data.
+
+We call this pattern a “higher-order component”.
+
+The composition happens at React rendering level rather than with a direct function call. This is why it doesn’t matter whether the wrapped component is defined with `createClass()`, as an ES6 class or a function. If `WrappedComponent` is a React component, the component created by `withSubscription()` can render it.
+
+```js
+// This function takes a component...
+function withSubscription(WrappedComponent) {
+  // ...and returns another component...
+  return React.createClass({
+    getInitialState: function() {
+      return {
+        comments: DataSource.getComments()
+      };
+    },
+
+    componentDidMount: function() {
+      // ... that takes care of the subscription...
+      DataSource.addChangeListener(this.handleChange);
+    },
+
+    componentWillUnmount: function() {
+      DataSource.removeChangeListener(this.handleChange);
+    },
+
+    handleChange: function() {
+      this.setState({
+        comments: DataSource.getComments()
+      });
+    },
+
+    render: function() {
+      // ... and renders the wrapped component with the fresh data!
+      return <WrappedComponent comments={this.state.comments} />;
+    }
+  });
+}
+```
+
+Now we can declare `CommentListWithSubscription` by applying `withSubscription` to `CommentList`:
+
+```js
+var CommentList = React.createClass({
+  render: function() {
+    var comments = this.props.comments;
+    return (
+      <div>
+        {comments.map(function(comment) {
+          return <Comment comment={comment} key={comment.id} />
+        })}
+      </div>
+    )
+  }
+});
+
+// withSubscription() returns a new component that
+// is subscribed to the data source and renders
+// <CommentList /> with up-to-date data.
+var CommentListWithSubscription = withSubscription(CommentList);
+
+// The rest of the app is interested in the subscribed component
+// so we export it instead of the original unwrapped CommentList.
+module.exports = CommentListWithSubscription;
+```
+
+#### Solution, Revisited
+
+Now that we understand higher-order components better, let’s take another look at the complete solution that doesn’t involve mixins. There are a few minor changes that are annotated with inline comments:
+
+```js
+function withSubscription(WrappedComponent) {
+  return React.createClass({
+    getInitialState: function() {
+      return {
+        comments: DataSource.getComments()
+      };
+    },
+
+    componentDidMount: function() {
+      DataSource.addChangeListener(this.handleChange);
+    },
+
+    componentWillUnmount: function() {
+      DataSource.removeChangeListener(this.handleChange);
+    },
+
+    handleChange: function() {
+      this.setState({
+        comments: DataSource.getComments()
+      });
+    },
+
+    render: function() {
+      // Use JSX spread syntax to pass all props and state down automatically.
+      return <WrappedComponent {...this.props} {...this.state} />;
+    }
+  });
+}
+
+// Optional change: convert CommentList to a functional component
+// because it doesn't use lifecycle hooks or state.
+function CommentList(props) {
+  var comments = props.comments;
+  return (
+    <div>
+      {comments.map(function(comment) {
+        return <Comment comment={comment} key={comment.id} />
+      })}
+    </div>
+  )
+}
+
+// Instead of declaring CommentListWithSubscription,
+// we export the wrapped component right away.
+module.exports = withSubscription(CommentList);
+```
+
+Higher-order components are a powerful pattern. You can pass additional arguments to them if you want to further customize their behavior. After all, they are not even a feature of React. They are just functions that receive components and return components that wrap them.
+
+Like any solution, higher-order components have their own pitfalls. For example, if you heavily use [refs](/react/docs/more-about-refs.html), you might notice that wrapping something into a higher-order component changes the ref to point to the wrapping component. In practice we discourage using refs for component communication so we don’t think it’s a big issue. In the future, we might consider adding [ref forwarding](https://github.com/facebook/react/issues/4213) to React to solve this annoyance.
+
+### Rendering Logic
+
+The next most common use case for mixins that we discovered in our codebase is sharing rendering logic between components.
+
+Here is a typical example of this pattern:
+
+```js
+var RowMixin = {
+  // Called by components from render()
+  renderHeader: function() {
+    return (
+      <div className='row-header'>
+        <h1>
+          {this.getHeaderText() /* Defined by components */}
+        </h1>
+      </div>
+    );
+  }
+};
+
+var UserRow = React.createClass({
+  mixins: [RowMixin],
+
+  // Called by RowMixin.renderHeader()
+  getHeaderText: function() {
+    return this.props.user.fullName;
+  },
+
+  render: function() {
+    return (
+      <div>
+        {this.renderHeader() /* Defined by RowMixin */}
+        <h2>{this.props.user.biography}</h2>
+      </div>
+    )
+  }
+});
+```
+
+Multiple components may be sharing `RowMixin` to render the header, and each of them would need to define `getHeaderText()`.
+
+#### Solution
+
+If you see rendering logic inside a mixin, it’s time to extract a component!
+
+Instead of `RowMixin`, we will define a `<RowHeader>` component. We will also replace the convention of defining a `getHeaderText()` method with the standard mechanism of top-data flow in React: passing props.
+
+Finally, since neither of those components currently need lifecycle hooks or state, we can declare them as simple functions:
+
+```js
+function RowHeader(props) {
+  return (
+    <div className='row-header'>
+      <h1>{props.text}</h1>
+    </div>
+  );
+}
+
+function UserRow(props) {
+  return (
+    <div>
+      <RowHeader text={props.user.fullName} />
+      <h2>{props.user.biography}</h2>
+    </div>
+  );
+}
+```
+
+Props keep component dependencies explicit, easy to replace, and enforceable with tools like [Flow](https://flowtype.org/) and [TypeScript](https://www.typescriptlang.org/).
+
+> **Note:**
+>
+> Defining components as functions is not required. There is also nothing wrong with using lifecycle hooks and state—they are first-class React features. We use functional components in this example because they are easier to read and we didn’t need those extra features, but classes would work just as fine.
+
+### Context
+
+Another group of mixins we discovered were helpers for providing and consuming [React context](/react/docs/context.html). Context is an experimental unstable feature, has [certain issues](https://github.com/facebook/react/issues/2517), and will likely change its API in the future. We don’t recommend using it unless you’re confident there is no other way of solving your problem.
+
+Nevertheless, if you already use context today, you might have been hiding its usage with mixins like this:
+
+```js
+var RouterMixin = {
+  contextTypes: {
+    router: React.PropTypes.object.isRequired
+  },
+
+  // The mixin provides a method so that components
+  // don't have to use the context API directly.
+  push: function(path) {
+    this.context.router.push(path)
+  }
+};
+
+var Link = React.createClass({
+  mixins: [RouterMixin],
+
+  handleClick: function(e) {
+    e.stopPropagation();
+
+    // This method is defined in RouterMixin.
+    this.push(this.props.to);
+  },
+
+  render: function() {
+    return (
+      <a onClick={this.handleClick}>
+        {this.props.children}
+      </a>
+    );
+  }
+});
+
+module.exports = Link;
+```
+
+#### Solution
+
+We agree that hiding context usage from consuming components is a good idea until the context API stabilizes. However, we recommend using higher-order components instead of mixins for this.
+
+Let the wrapping component grab something from the context, and pass it down with props to the wrapped component:
+
+```js
+function withRouter(WrappedComponent) {
+  return React.createClass({
+    contextTypes: {
+      router: React.PropTypes.object.isRequired
+    },
+
+    render: function() {
+      // The wrapper component reads something from the context
+      // and passes it down as a prop to the wrapped component.
+      var router = this.context.router;
+      return <WrappedComponent {...this.props} router={router} />;
+    }
+  });
+};
+
+var Link = React.createClass({
+  handleClick: function(e) {
+    e.stopPropagation();
+
+    // The wrapped component uses props instead of context.
+    this.props.router.push(this.props.to);
+  },
+
+  render: function() {
+    return (
+      <a onClick={this.handleClick}>
+        {this.props.children}
+      </a>
+    );
+  }
+});
+
+// Don't forget to wrap the component!
+module.exports = withRouter(Link);
+```
+
+If you’re using a third party library that only provides a mixin, we encourage you to file an issue with them linking to this post so that they can provide a higher-order component instead. In the meantime, you can create a higher-order component around it yourself in exactly the same way.
+
+### Utility Methods
+
+Sometimes, mixins are used solely to share utility functions between components:
+
+```js
+var ColorMixin = {
+  getLuminance(color) {
+    var c = parseInt(color, 16);
+    var r = (c & 0xFF0000) >> 16;
+    var g = (c & 0x00FF00) >> 8;
+    var b = (c & 0x0000FF);
+    return (0.299 * r + 0.587 * g + 0.114 * b);
+  }
+};
+
+var Button = React.createClass({
+  mixins: [ColorMixin],
+
+  render: function() {
+    var theme = this.getLuminance(this.props.color) > 160 ? 'dark' : 'light';
+    return (
+      <div className={theme}>
+        {this.props.children}
+      </div>
+    )
+  }
+});
+```
+
+#### Solution
+
+Put utility functions into regular JavaScript modules and import them. This also makes it easier to test them or use them outside of your components:
+
+```js
+var getLuminance = require('../utils/getLuminance');
+
+var Button = React.createClass({
+  render: function() {
+    var theme = getLuminance(this.props.color) > 160 ? 'dark' : 'light';
+    return (
+      <div className={theme}>
+        {this.props.children}
+      </div>
+    )
+  }
+});
+```
+
+### Other Use Cases
+
+Sometimes people use mixins to selectively add logging to lifecycle hooks in some components. In the future, we intend to provide an [official DevTools API](https://github.com/facebook/react/issues/5306) that would let you implement something similar without touching the components. However it’s still very much a work in progress. If you heavily depend on logging mixins for debugging, you might want to keep using those mixins for a little longer.
+
+If you can’t accomplish something with a component, a higher-order component, or a utility module, it could be mean that React should provide this out of the box. [File an issue](https://github.com/facebook/react/issues/new) to tell us about your use case for mixins, and we’ll help you consider alternatives or perhaps implement your feature request.
+
+Mixins are not deprecated in the traditional sense. You can keep using them with `React.createClass()`, as we won’t be changing it further. Eventually, as ES6 classes gain more adoption and their usability problems in React are solved, we might split `React.createClass()` into a separate package because most people wouldn’t need it. Even in that case, your old mixins would keep working.
+
+We believe that the alternatives above are better for the vast majority of cases, and we invite you to try writing React apps without using mixins.
diff --git a/docs/_posts/2016-07-22-create-apps-with-no-configuration.md b/docs/_posts/2016-07-22-create-apps-with-no-configuration.md
new file mode 100644
index 000000000000..91a91fda4653
--- /dev/null
+++ b/docs/_posts/2016-07-22-create-apps-with-no-configuration.md
@@ -0,0 +1,165 @@
+---
+title: "Create Apps with No Configuration"
+author: gaearon
+---
+
+**[Create React App](https://github.com/facebookincubator/create-react-app)** is a new officially supported way to create single-page React applications. It offers a modern build setup with no configuration.
+
+## Getting Started
+
+### Installation
+
+First, install the global package:
+
+```sh
+npm install -g create-react-app
+```
+
+Node.js 4.x or higher is required.
+
+### Creating an App
+
+Now you can use it to create a new app:
+
+```sh
+create-react-app hello-world
+```
+
+This will take a while as npm installs the transitive dependencies, but once it’s done, you will see a list of commands you can run in the created folder:
+
+![created folder](/react/img/blog/create-apps-with-no-configuration/created-folder.png)
+
+### Starting the Server
+
+Run `npm start` to launch the development server. The browser will open automatically with the created app’s URL.
+
+![compiled successfully](/react/img/blog/create-apps-with-no-configuration/compiled-successfully.png)
+
+Create React App uses both webpack and Babel under the hood.
+The console output is tuned to be minimal to help you focus on the problems:
+
+![failed to compile](/react/img/blog/create-apps-with-no-configuration/failed-to-compile.png)
+
+ESLint is also integrated so lint warnings are displayed right in the console:
+
+![compiled with warnings](/react/img/blog/create-apps-with-no-configuration/compiled-with-warnings.png)
+
+We only picked a small subset of lint rules that often lead to bugs.
+
+### Building for Production
+
+To build an optimized bundle, run `npm run build`:
+
+![npm run build](/react/img/blog/create-apps-with-no-configuration/npm-run-build.png)
+
+It is minified, correctly envified, and the assets include content hashes for caching.
+
+### One Dependency
+
+Your `package.json` contains only a single build dependency and a few scripts:
+
+```js
+{
+  "name": "hello-world",
+  "dependencies": {
+    "react": "^15.2.1",
+    "react-dom": "^15.2.1"
+  },
+  "devDependencies": {
+    "react-scripts": "0.1.0"
+  },
+  "scripts": {
+    "start": "react-scripts start",
+    "build": "react-scripts build",
+    "eject": "react-scripts eject"
+  }
+}
+```
+
+We take care of updating Babel, ESLint, and webpack to stable compatible versions so you can update a single dependency to get them all.
+
+### Zero Configuration
+
+It is worth repeating: there are no configuration files or complicated folder structures. The tool only generates the files you need to build your app.
+
+```
+hello-world/
+  README.md
+  index.html
+  favicon.ico
+  node_modules/
+  package.json
+  src/
+    App.css
+    App.js
+    index.css
+    index.js
+    logo.svg
+```
+
+All the build settings are preconfigured and can’t be changed. Some features, such as testing, are currently missing. This is an intentional limitation, and we recognize it might not work for everybody. And this brings us to the last point.
+
+### No Lock-In
+
+We first saw this feature in [Enclave](https://github.com/eanplatter/enclave), and we loved it. We talked to [Ean](https://twitter.com/EanPlatter), and he was excited to collaborate with us. He already sent a few pull requests!
+
+“Ejecting” lets you leave the comfort of Create React App setup at any time. You run a single command, and all the build dependencies, configs, and scripts are moved right into your project. At this point you can customize everything you want, but effectively you are forking our configuration and going your own way. If you’re experienced with build tooling and prefer to fine-tune everything to your taste, this lets you use Create React App as a boilerplate generator.
+
+We expect that at early stages, many people will “eject” for one reason or another, but as we learn from them, we will make the default setup more and more compelling while still providing no configuration.
+
+## Try It Out!
+
+You can find [**Create React App**](https://github.com/facebookincubator/create-react-app) with additional instructions on GitHub.
+
+This is an experiment, and only time will tell if it becomes a popular way of creating and building React apps, or fades into obscurity.
+
+We welcome you to participate in this experiment. Help us build the React tooling that more people can use. We are always [open to feedback](https://github.com/facebookincubator/create-react-app/issues/11).
+
+## The Backstory
+
+React was one of the first libraries to embrace transpiling JavaScript. As a result, even though you can [learn React without any tooling](https://github.com/facebook/react/blob/3fd582643ef3d222a00a0c756292c15b88f9f83c/examples/basic-jsx/index.html), the React ecosystem has commonly become associated with an overwhelming explosion of tools.
+
+Eric Clemmons called this phenomenon the “[JavaScript Fatigue](https://medium.com/@ericclemmons/javascript-fatigue-48d4011b6fc4)”:
+
+>Ultimately, the problem is that by choosing React (and inherently JSX), you’ve unwittingly opted into a confusing nest of build tools, boilerplate, linters, & time-sinks to deal with before you ever get to create anything.
+
+It is tempting to write code in ES2015 and JSX. It is sensible to use a bundler to keep the codebase modular, and a linter to catch the common mistakes. It is nice to have a development server with fast rebuilds, and a command to produce optimized bundles for production.
+
+Combining these tools requires some experience with each of them. Even so, it is far too easy to get dragged into fighting small incompatibilities, unsatisfied peerDependencies, and illegible configuration files.
+
+Many of those tools are plugin platforms and don’t directly acknowledge each other’s existence. They leave it up to the users to wire them together. The tools mature and change independently, and tutorials quickly get out of date.
+
+<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">Marc was almost ready to implement his &quot;hello world&quot; React app <a href="https://t.co/ptdg4yteF1">pic.twitter.com/ptdg4yteF1</a></p>&mdash; Thomas Fuchs (@thomasfuchs) <a href="https://twitter.com/thomasfuchs/status/708675139253174273">March 12, 2016</a></blockquote>
+<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
+
+This doesn’t mean those tools aren’t great. To many of us, they have become indispensable, and we very much appreciate the effort of their maintainers. They already have too much on their plates to worry about the state of the React ecosystem.
+
+Still, we knew it was frustrating to spend days setting up a project when all you wanted was to learn React. We wanted to fix this.
+
+## Could We Fix This?
+
+We found ourselves in an unusual dilemma.
+
+So far, [our strategy](/react/contributing/design-principles.html#dogfooding) has been to only release the code that we are using at Facebook. This helped us ensure that every project is battle-tested and has clearly defined scope and priorities.
+
+However, tooling at Facebook is different than at many smaller companies. Linting, transpilation, and packaging are all handled by powerful remote development servers, and product engineers don’t need to configure them. While we wish we could give a dedicated server to every user of React, even Facebook cannot scale that well!
+
+The React community is very important to us. We knew that we couldn’t fix the problem within the limits of our open source philosophy. This is why we decided to make an exception, and to ship something that we didn’t use ourselves, but that we thought would be useful to the community.
+
+## The Quest for a React <abbr title="Command Line Interface">CLI</abbr>
+
+Having just attended [EmberCamp](http://embercamp.com/) a week ago, I was excited about [Ember CLI](https://ember-cli.com/). Ember users have a great “getting started” experience thanks to a curated set of tools united under a single command-line interface. I have heard similar feedback about [Elm Reactor](https://github.com/elm-lang/elm-reactor).
+
+Providing a cohesive curated experience is valuable by itself, even if the user could in theory assemble those parts themselves. Kathy Sierra [explains it best](http://seriouspony.com/blog/2013/7/24/your-app-makes-me-fat):
+
+>If your UX asks the user to make *choices*, for example, even if those choices are both clear and useful, the act of *deciding* is a cognitive drain. And not just *while* they’re deciding... even *after* we choose, an unconscious cognitive background thread is slowly consuming/leaking resources, “Was *that* the right choice?”
+
+I never tried to write a command-line tool for React apps, and neither has [Christopher](https://twitter.com/vjeux). We were chatting on Messenger about this idea, and we decided to work together on it for a week as a hackathon project.
+
+We knew that such projects traditionally haven’t been very successful in the React ecosystem. Christopher told me that multiple “React CLI” projects have started and failed at Facebook. The community tools with similar goals also exist, but so far they have not yet gained enough traction.
+
+Still, we decided it was worth another shot. Christopher and I created a very rough proof of concept on the weekend, and [Kevin](https://twitter.com/lacker) soon joined us.
+
+We invited some of the community members to collaborate with us, and we have spent this week working on this tool. We hope that you’ll enjoy using it! [Let us know what you think.](https://github.com/facebookincubator/create-react-app/issues/11)
+
+We would like to express our gratitude to [Max Stoiber](https://twitter.com/mxstbr), [Jonny Buchanan](https://twitter.com/jbscript), [Ean Platter](https://twitter.com/eanplatter), [Tyler McGinnis](https://github.com/tylermcginnis), [Kent C. Dodds](https://github.com/kentcdodds), and [Eric Clemmons](https://twitter.com/ericclemmons) for their early feedback, ideas, and contributions.
diff --git a/docs/_posts/2016-08-05-relay-state-of-the-state.md b/docs/_posts/2016-08-05-relay-state-of-the-state.md
new file mode 100644
index 000000000000..741d35c236b7
--- /dev/null
+++ b/docs/_posts/2016-08-05-relay-state-of-the-state.md
@@ -0,0 +1,81 @@
+---
+title: "Relay: State of the State"
+author: josephsavona
+---
+
+This month marks a year since we released Relay and we'd like to share an update on the project and what's next.
+
+## A Year In Review
+
+A year after launch, we're incredibly excited to see an active community forming around Relay and that companies such as Twitter are [using Relay in production](https://fabric.io/blog/building-fabric-mission-control-with-graphql-and-relay):
+
+> For a project like mission control, GraphQL and Relay were a near-perfect solution, and the cost of building it any other way justified the investment.
+>
+> -- <cite>Fin Hopkins</cite>
+
+This kind of positive feedback is really encouraging (I'll admit to re-reading that post far too many times), and great motivation for us to keep going and make Relay even better.
+
+With the community's help we've already come a long way since the technical preview. Here are some highlights:
+
+- In March we added support for server-side rendering and for creating multiple instances of Relay on a single page. This was a coordinated effort over the course of several months by community members [Denis Nedelyaev](https://github.com/denvned) and [Gerald Monaco](https://github.com/devknoll) (now at Facebook).
+- Also in March we added support for React Native. While we use Relay and React Native together internally, they didn't quite work together in open-source out of the box. We owe a big thanks to [Adam Miskiewicz](https://github.com/skevy), [Tom Burns](https://github.com/boourns), [Gaëtan Renaudeau](https://github.com/gre), [David Aurelio](https://github.com/davidaurelio), [Martín Bigio](https://github.com/martinbigio), [Paul O’Shannessy](https://github.com/zpao), [Ben Alpert](https://github.com/spicyj), and many others who helped track down and resolve issues. Finally, thanks to [Steven Luscher](https://github.com/steveluscher) for coordinating this effort and building the first Relay/ReactNative example app.
+
+We've also seen some great open-source projects spring up around Relay:
+
+- [Denis Nedelyaev](https://github.com/denvned) created [isomorphic-relay](https://github.com/denvned/isomorphic-relay/), a package that helps developers build server-rendered Relay apps where data is prepared on the server and then used to bootstrap the app on the client.
+- [Jimmy Jia](https://github.com/taion) created [react-router-relay](https://github.com/relay-tools/react-router-relay) to integrate Relay data-fetching into React Router.
+- [Pavel Chertorogov](https://github.com/nodkz) released [relay-network-layer](https://github.com/nodkz/react-relay-network-layer), which adds features such as batching query requests, middleware, authentication, logging, and more.
+
+This is just a small sampling of the community's contributions. So far we've merged over 300 PRs - about 25% of our commits - from over 80 of you. These PRs have improved everything from the website and docs down the very core of the framework. We're humbled by these outstanding contributions and excited to keep working with each of you!
+
+# Retrospective & Roadmap
+
+Earlier this year we paused to reflect on the state of the project. What was working well? What could be improved? What features should we add, and what could we remove? A few themes emerged: performance on mobile, developer experience, and empowering the community.
+
+## Mobile Perf
+
+First, Relay was built to serve the needs of product developers at Facebook. In 2016, that means helping developers to build apps that work well on [mobile devices connecting on slower networks](https://newsroom.fb.com/news/2015/10/news-feed-fyi-building-for-all-connectivity/). For example, people in developing markets commonly use [2011 year-class phones](https://code.facebook.com/posts/307478339448736/year-class-a-classification-system-for-android/) and connect via [2G class networks](https://code.facebook.com/posts/952628711437136/classes-performance-and-network-segmentation-on-android/). These scenarios present their own challenges.
+
+Therefore, one of our primary goals this year is to optimize Relay for performance on low-end mobile devices *first*, knowing that this can translate to improved performance on high-end devices as well. In addition to standard approaches such as benchmarking, profiling, and optimizations, we're also working on big-picture changes.
+
+For example, in today's Relay, here's what happens when an app is opened. First, React Native starts initializing the JavaScript context (loading and parsing your code and then running it). When this finishes, the app executes and Relay sees that you need data. It constructs and prints the query, uploads the query text to the server, processes the response, and renders your app. (Note that this process applies on the web, except that the code has to be *downloaded* instead of loaded from the device.)
+
+Ideally, though, we could begin fetching data as soon as the native code had loaded - in parallel with the JS context initialization. By the time your JS code was ready to run, the data-fetching would already be under way. To do this we would need a way to determine *statically* - at build time - what query an application would send.
+
+The key is that GraphQL is already static - we just need to fully embrace this fact. More on this later.
+
+## Developer Experience
+
+Next, we've paid attention to the community's feedback and know that, to put it simply, Relay could be "easier" to use (and "simpler" too). This isn't entirely surprising to us - Relay was originally designed as a routing library and gradually morphed into a data-fetching library. Concepts like Relay "routes", for example, no longer serve as critical a role and are just one more concept that developers have to learn about. Another example is mutations: while writes *are* inherently more complex than reads, our API doesn't make the simple things simple enough.
+
+Alongside our focus on mobile performance, we've also kept the developer experience in mind as we evolve Relay core.
+
+## Empowering the Community
+
+Finally, we want to make it easier for people in the community to develop useful libraries that work with Relay. By comparison, React's small surface area - components - allows developers to build cool things like routing, higher-order components, or reusable text editors. For Relay, this would mean having the framework provide core primitives that users can build upon. We want it to be possible for the community to integrate Relay with view libraries other than React, or to build real-time subscriptions as a complementary library.
+
+# What's Next
+
+These were big goals, and also a bit scary; we knew that incremental improvements would only allow us to move so fast. So in April we started a project to build a new implementation of Relay core targeting low-end mobile devices from the start.
+
+As you can guess since we're writing this, the experiment was a success. The result is a new core that retains the best parts of Relay today - colocated components & data-dependencies, automatic data/view consistency, declarative data-fetching - while improving performance on mobile devices and addressing several common areas of confusion.
+
+We're currently focused on shipping the first applications using the new core: ironing out bugs, refining the API changes and developer experience, and adding any missing features. We're excited to bring these changes to open source, and will do so once we've proven them in production. We'll go into more detail in some upcoming talks - links below - but for now here's an overview:
+
+- **Static Queries**: By adding a couple of Relay-specific directives, we've been able to retain the expressivity of current Relay queries using static syntax (concretely: you know what query an app will execute just by looking at the source text, without having to run that code). For starters this will allow Relay apps to start fetching data in parallel with JavaScript initialization. But it also unlocks other possibilities: knowing the query ahead of time means that we can generate optimized code for handling query responses, for example, or for reading query data from an offline cache.
+- **Expressive Mutations**: We'll continue to support a higher-level mutation API for common cases, but will also provide a lower-level API that allows "raw" data access where necessary. If you need to order a list of cached elements, for example, there will be a way to `sort()` it.
+- **Route-less Relay**: Routes will be gone in open source. Instead of a route with multiple query definitions, you'll just provide a single query with as many root fields as you want.
+- **Cache Eviction/Garbage Collection**: The API and architecture is designed from the start to allow removing cached data that is no longer referenced by a mounted view.
+
+Stepping back, we recognize that any API changes will require an investment on your part. To make the transition easier, though, *we will continue to support the current API for the foreseeable future* (we're still using it too). And as much as possible we will open-source the tools that we use to migrate our own code. Ideas that we're exploring include codemods, an interoperability layer for the old/new APIs, and tutorials & guides to ease migration.
+
+Ultimately, we're making these changes because we believe they make Relay better all around: simpler for developers building apps and faster for the people using them.
+
+# Conclusion
+
+If you made it this far, congrats and thanks for reading! We'll be sharing more information about these changes in some upcoming talks:
+
+- [Greg Hurrell](https://github.com/wincent) will presenting a Relay "Deep Dive" at the [Silicon Valley ReactJS Meetup](http://www.meetup.com/Silicon-Valley-ReactJS-Meetup/events/232236845/) on August 17th.
+- I ([@josephsavona](https://github.com/josephsavona)) will be speaking about Relay at [React Rally](http://www.reactrally.com) on August 25th.
+
+We can't wait to share the new code with you and are working as fast as we can to do so!
diff --git a/docs/_posts/2016-09-28-our-first-50000-stars.md b/docs/_posts/2016-09-28-our-first-50000-stars.md
new file mode 100644
index 000000000000..289dd96a6ea5
--- /dev/null
+++ b/docs/_posts/2016-09-28-our-first-50000-stars.md
@@ -0,0 +1,229 @@
+---
+title: "Our First 50,000 Stars"
+author: vjeux
+---
+
+Just three and a half years ago we open sourced a little JavaScript library called React. The journey since that day has been incredibly exciting.
+
+## Commemorative T-Shirt
+
+In order to celebrate 50,000 GitHub stars, [Maggie Appleton](http://www.maggieappleton.com/) from [egghead.io](http://egghead.io/) has designed us a special T-shirt, which will be available for purchase from Teespring **only for a week** through Thursday, October 6. Maggie also wrote [a blog post](https://www.behance.net/gallery/43269677/Reacts-50000-Stars-Shirt) showing all the different concepts she came up with before settling on the final design.
+
+<a target="_blank" href="https://teespring.com/react-50000-stars"><img src="/react/img/blog/react-50k-tshirt.jpg" width="650" height="340" alt="React 50k Tshirt" /></a>
+
+The T-shirts are super soft using American Apparel's tri-blend fabric; we also have kids and toddler T-shirts and baby onesies available.
+
+* [Adult T-shirts (straight-cut and fitted)](https://teespring.com/react-50000-stars)
+* [Kids T-shirts](https://teespring.com/react-50000-stars-kids)
+* [Toddler T-Shirts](https://teespring.com/react-50000-stars-toddler)
+* [Baby Onesies](https://teespring.com/react-50000-stars-baby)
+
+Proceeds from the shirts will be donated to [CODE2040](http://www.code2040.org/), a nonprofit that creates access, awareness, and opportunities in technology for underrepresented minorities with a specific focus on Black and Latinx talent.
+
+## Archeology
+
+We've spent a lot of time trying to explain the concepts behind React and the problems it attempts to solve, but we haven't talked much about how React evolved before being open sourced. This milestone seemed like as good a time as any to dig through the earliest commits and share some of the more important moments and fun facts.
+
+The story begins in our ads org, where we were building incredibly sophisticated client side web apps using an internal MVC framework called [BoltJS](http://web.archive.org/web/20130608154901/http://shaneosullivan.github.io/boltjs/intro.html). Here's a sample of what some Bolt code looked like:
+
+```js
+var CarView = require('javelin/core').createClass({
+  name: 'CarView',
+  extend: require('container').Container,
+  properties: {
+    wheels: 4,
+  },
+  declare: function() {
+    return {
+      childViews: [
+        { content: 'I have ' },
+        { ref: 'wheelView' },
+        { content: ' wheels' }
+      ]
+    };
+  },
+  setWheels: function(wheels) {
+    this.findRef('wheelView').setContent(wheels);
+  },
+  getWheels: function() {
+    return this.findRef('wheelView').getContent();
+  },
+});
+
+var car = new CarView();
+car.setWheels(3);
+car.placeIn(document.body);
+//<div>
+//  <div>I have </div>
+//  <div>3</div>
+//  <div> wheels</div>
+//</div>
+```
+
+Bolt introduced a number of APIs and features that would eventually make their way into React including `render`, `createClass`, and `refs`. Bolt introduced the concept of `refs` as a way to create references to nodes that can be used imperatively. This was relevant for legacy interoperability and incremental adoption, and while React would eventually strive to be a lot more functional, `refs` proved to be a very useful way to break out of the functional paradigm when the need arose.
+
+But as our applications grew more and more sophisticated, our Bolt codebases got pretty complicated. Recognizing some of the framework's shortcomings, [Jordan Walke](https://twitter.com/jordwalke) started experimenting with a side-project called [FaxJS](https://github.com/jordwalke/FaxJs). His goal was to solve many of the same problems as Bolt, but in a very different way. This is actually where most of React's fundamentals were born, including props, state, re-evaluating large portions of the tree to “diff” the UI, server-side rendering, and a basic concept of components.
+
+```js
+TestProject.PersonDisplayer = {
+  structure : function() {
+    return Div({
+      classSet: { personDisplayerContainer: true },
+      titleDiv: Div({
+        classSet: { personNameTitle: true },
+        content: this.props.name
+      }),
+      nestedAgeDiv: Div({
+        content: 'Interests: ' + this.props.interests
+      })
+    });
+  }
+};
+```
+
+## FBolt is Born
+
+Through his FaxJS experiment, Jordan became convinced that functional APIs  — which discouraged mutation —  offered a better, more scalable way to build user interfaces. He imported his library into Facebook's codebase in March of 2012 and renamed it “FBolt”, signifying an extension of Bolt where components are written in a functional programming style. Or maybe “FBolt” was a nod to FaxJS – he didn't tell us! ;)
+
+The interoperability between FBolt and Bolt allowed us to experiment with replacing just one component at a time with more functional component APIs. We could test the waters of this new functional paradigm, without having to go all in. We started with the components that were clearly best expressed functionally and then we would later continue to push the boundaries of what we could express as functions.
+
+Realizing that FBolt wouldn't be a great name for the library when used on its own, Jordan Walke and [Tom Occhino](https://twitter.com/tomocchino) decided on a new name: “React.” After Tom sent out the diff to rename everything to React, Jordan commented:
+
+
+> Jordan Walke:
+I might add for the sake of discussion, that many systems advertise some kind of reactivity, but they usually require that you set up some kind of point-to-point listeners and won't work on structured data. This API reacts to any state or property changes, and works with data of any form (as deeply structured as the graph itself) so I think the name is fitting.
+
+
+Most of Tom's other commits at the time were on the first version of [GraphiQL](https://github.com/graphql/graphiql), a project which was recently open sourced.
+
+## Adding JSX
+
+Since about 2010 Facebook has been using an extension of PHP called [XHP](https://www.facebook.com/notes/facebook-engineering/xhp-a-new-way-to-write-php/294003943919/), which enables engineers to create UIs using XML literals right inside their PHP code. It was first introduced to help prevent XSS holes but ended up being an excellent way to structure applications with custom components.
+
+```js
+final class :a:post extends :x:element {
+  attribute :a;
+  protected function render(): XHPRoot {
+    $anchor = <a>{$this->getChildren()}</a>;
+    $form = (
+      <form
+        method="post"
+        action={$this->:href}
+        target={$this->:target}
+        class="postLink"
+      >{$anchor}</form>
+    );
+    $this->transferAllAttributes($anchor);
+    return $form;
+  }
+}
+```
+
+Before Jordan's work had even made its way into the Facebook codebase, Adam Hupp implemented an XHP-like concept for JavaScript, written in Haskell. This system enabled you to write the following inside a JavaScript file:
+
+```js
+function :example:hello(attrib, children) {
+  return (
+    <div class="special">
+      <h1>Hello, World!</h1>
+      {children}
+    </div>
+  );
+}
+```
+
+It would compile the above into the following normal ES3-compatible JavaScript:
+
+```js
+function jsx_example_hello(attrib, children) {
+  return (
+    S.create("div", {"class": "special"}, [
+      S.create("h1", {}, ["Hello, World!"]),
+      children
+    ]
+  );
+}
+```
+
+In this prototype, `S.create` would immediately create and return a DOM node. Most of the conversations on this prototype revolved around the performance characteristics of `innerHTML` versus creating DOM nodes directly. At the time, it would have been less than ideal to push developers universally in the direction of creating DOM nodes directly since it did not perform as well, especially in Firefox and IE. Facebook's then-CTO [Bret Taylor](https://twitter.com/btaylor) chimed in on the discussion at the time in favor of `innerHTML` over `document.createElement`:
+
+
+> Bret Taylor:
+If you are not convinced about innerHTML, here is a small microbenchmark. It is about the same in Chrome. innerHTML is about 30% faster in the latest version of Firefox (much more in previous versions), and about 90% faster in IE8.
+
+
+This work was eventually abandoned but was revived after React made its way into the codebase. Jordan sidelined the previous performance discussions by introducing the concept of a “Virtual DOM,” though its eventual name didn't exist yet.
+
+
+> Jordan Walke:
+> For the first step, I propose that we do the easiest, yet most general transformation possible. My suggestion is to simply map xml expressions to function call expressions.
+>
+> - `<x></x>` becomes `x( )`
+> - `<x height=12></x>` becomes `x( {height:12} )`
+> - `<x> <y> </y> </x>` becomes `x({ childList: [y( )] })`
+>
+> At this point, JSX doesn't need to know about React - it's just a convenient way to write function calls. Coincidentally, React's primary abstraction is the function. Okay maybe it's not so coincidental ;)
+
+
+Adam made a very insightful comment, which is now the default way we write lists in React with JSX.
+
+
+> Adam Hupp:
+> I think we should just treat arrays of elements as a frag. This is useful for constructs like:
+>
+> ```js
+<ul>{foo.map(function(i) { return <li>{i.data}</li>; })}</ul>
+```
+>
+> In this case the ul(..) will get a childList with a single child, which is itself a list.
+
+
+React didn't end up using Adam's implementation directly. Instead, we created JSX by forking [js-xml-literal](https://github.com/laverdet/js-xml-literal), a side project by XHP creator Marcel Laverdet. JSX took its name from js-xml-literal, which Jordan modified to just be syntactic sugar for deeply nested function calls.
+
+## API Churn
+
+During the first year of React, internal adoption was growing quickly but there was quite a lot of churn in the component APIs and naming conventions:
+
+* `project` was renamed to `declare` then to `structure` and finally to `render`.
+* `Componentize` was renamed to `createComponent` and finally to `createClass`.
+
+As the project was about to be open sourced, [Lee Byron](https://twitter.com/leeb) sat down with Jordan Walke, Tom Occhino and Sebastian Markbåge in order to refactor, reimplement, and rename one of React's most beloved features – the lifecycle API. Lee [came up with a well-designed API](https://gist.github.com/vjeux/f2b015d230cc1ab18ed1df30550495ed) that is still in place today.
+
+* Concepts
+    * component - a ReactComponent instance
+    * state - internal state to a component
+    * props - external state to a component
+    * markup - the stringy HTML-ish stuff components generate
+    * DOM - the document and elements within the document
+* Actions
+    * mount - to put a component into a DOM
+    * initialize - to prepare a component for rendering
+    * update - a transition of state (and props) resulting a render.
+    * render - a side-effect-free process to get the representation (markup) of a component.
+    * validate - make assertions about something created and provided
+    * destroy - opposite of initialize
+* Operands
+    * create - make a new thing
+    * get - get an existing thing
+    * set - merge into existing
+    * replace - replace existing
+    * receive - respond to new data
+    * force - skip checks to do action
+* Notifications
+    * shouldObjectAction
+    * objectWillAction
+    * objectDidAction
+
+## Instagram
+
+In 2012, Instagram got acquired by Facebook. [Pete Hunt](https://twitter.com/floydophone), who was working on Facebook photos and videos at the time, joined their newly formed web team. He wanted to build their website completely in React, which was in stark contrast with the incremental adoption model that had been used at Facebook.
+
+To make this happen, React had to be decoupled from Facebook's infrastructure, since Instagram didn't use any of it. This project acted as a forcing function to do the work needed to open source React. In the process, Pete also discovered and promoted a little project called webpack. He also implemented the `renderToString` primitive which was needed to do server-side rendering.
+
+As we started to prepare for the open source launch, [Maykel Loomans](https://twitter.com/miekd), a designer on Instagram, made a mock of what the website could look like. The header ended up defining the visual identity of React: its logo and the electric blue color!
+
+<center><a target="_blank" href="/react/img/blog/react-50k-mock-full.jpg"><img src="/react/img/blog/react-50k-mock.jpg" width="400" height="410" alt="React website mock" /></a></center>
+
+In its earliest days, React benefited tremendously from feedback, ideas, and technical contributions of early adopters and collaborators all over the company. While it might look like an overnight success in hindsight, the story of React is actually a great example of how new ideas often need to go through several rounds of refinement, iteration, and course correction over a long period of time before reaching their full potential.
+
+React's approach to building user interfaces with functional programming principles has changed the way we do things in just a few short years. It goes without saying, but React would be nothing without the amazing open source community that's built up around it!
diff --git a/docs/_posts/2016-11-16-react-v15.4.0.md b/docs/_posts/2016-11-16-react-v15.4.0.md
new file mode 100644
index 000000000000..d07691a04e83
--- /dev/null
+++ b/docs/_posts/2016-11-16-react-v15.4.0.md
@@ -0,0 +1,174 @@
+---
+title: "React v15.4.0"
+author: gaearon
+---
+
+Today we are releasing React 15.4.0.
+
+We didn't announce the [previous](https://github.com/facebook/react/blob/master/CHANGELOG.md#1510-may-20-2016) [minor](https://github.com/facebook/react/blob/master/CHANGELOG.md#1520-july-1-2016) [releases](https://github.com/facebook/react/blob/master/CHANGELOG.md#1530-july-29-2016) on the blog because most of the changes were bug fixes. However, 15.4.0 is a special release, and we would like to highlight a few notable changes in it.
+
+### Separating React and React DOM
+
+[More than a year ago](/react/blog/2015/09/10/react-v0.14-rc1.html#two-packages-react-and-react-dom), we started separating React and React DOM into separate packages. We deprecated `React.render()` in favor of `ReactDOM.render()` in React 0.14, and removed DOM-specific APIs from `React` completely in React 15. However, the React DOM implementation still [secretly lived inside the React package](https://www.reddit.com/r/javascript/comments/3m6wyu/found_this_line_in_the_react_codebase_made_me/cvcyo4a/).
+
+In React 15.4.0, we are finally moving React DOM implementation to the React DOM package. The React package will now contain only the renderer-agnostic code such as `React.Component` and `React.createElement()`.
+
+This solves a few long-standing issues, such as [errors](https://github.com/facebook/react/issues/7386) when you import React DOM in the same file as the [snapshot testing](https://facebook.github.io/jest/blog/2016/07/27/jest-14.html) renderer.
+
+**If you only use the official and documented React APIs you won't need to change anything in your application.**
+
+However, there is a possibility that you imported private APIs from `react/lib/*`, or that a package you rely on might use them. We would like to remind you that this was never supported, and that your apps should not rely on internal APIs. The React internals will keep changing as we work to make React better.
+
+Another thing to watch out for is that React DOM Server is now about the same size as React DOM since it contains its own copy of the React reconciler. We don't recommend using React DOM Server on the client in most cases.
+
+### Profiling Components with Chrome Timeline
+
+You can now visualize React components in the Chrome Timeline. This lets you see which components exactly get mounted, updated, and unmounted, how much time they take relative to each other.
+
+<center><img src="/react/img/blog/react-perf-chrome-timeline.png" width="651" height="228" alt="React components in Chrome timeline" /></center>
+
+To use it:
+
+1. Load your app with `?react_perf` in the query string (for example, `http://localhost:3000/?react_perf`).
+
+2. Open the Chrome DevTools **Timeline** tab and press **Record**.
+
+3. Perform the actions you want to profile. Don't record more than 20 seconds or Chrome might hang.
+
+4. Stop recording.
+
+5. React events will be grouped under the **User Timing** label.
+
+Note that the numbers are relative so components will render faster in production. Still, this should help you realize when unrelated UI gets updated by mistake, and how deep and how often your UI updates occur.
+
+Currently Chrome, Edge, and IE are the only browsers supporting this feature, but we use the standard [User Timing API](https://developer.mozilla.org/en-US/docs/Web/API/User_Timing_API) so we expect more browsers to add support for it.
+
+### Mocking Refs for Snapshot Testing
+
+If you're using Jest [snapshot testing](https://facebook.github.io/jest/blog/2016/07/27/jest-14.html), you might have had [issues](https://github.com/facebook/react/issues/7371) with components that rely on refs. With React 15.4.0, we introduce a way to provide mock refs to the test renderer. For example, consider this component using a ref in `componentDidMount`:
+
+```js{5,11}
+import React from 'react';
+
+export default class MyInput extends React.Component {
+  componentDidMount() {
+    this.input.focus();
+  }
+
+  render() {
+    return (
+      <input
+        ref={node => this.input = node}
+      />
+    );
+  }
+}
+```
+
+With snapshot renderer, `this.input` will be `null` because there is no DOM. React 15.4.0 lets us avoid such crashes by passing a custom `createNodeMock` function to the snapshot renderer in an `options` argument:
+
+```js{5-12,16}
+import React from 'react';
+import MyInput from './MyInput';
+import renderer from 'react-test-renderer';
+
+function createNodeMock(element) {
+  if (element.type === 'input') {
+    return {
+      focus() {},
+    };
+  }
+  return null;
+}
+
+it('renders correctly', () => {
+  const options = {createNodeMock};
+  const tree = renderer.create(<MyInput />, options);
+  expect(tree).toMatchSnapshot();
+});
+```
+
+We would like to thank [Brandon Dail](https://github.com/Aweary) for implementing this feature.
+
+You can learn more about snapshot testing in [this Jest blog post](https://facebook.github.io/jest/blog/2016/07/27/jest-14.html).
+
+---
+
+## Installation
+
+We recommend using [Yarn](https://yarnpkg.com/) or [npm](https://www.npmjs.com/) for managing front-end dependencies. If you're new to package managers, the [Yarn documentation](https://yarnpkg.com/en/docs/getting-started) is a good place to get started.
+
+To install React with Yarn, run:
+
+```bash
+yarn add react@15.4.0 react-dom@15.4.0
+```
+
+To install React with npm, run:
+
+```bash
+npm install --save react@15.4.0 react-dom@15.4.0
+```
+
+We recommend using a bundler like [webpack](https://webpack.js.org/) or [Browserify](http://browserify.org/) so you can write modular code and bundle it together into small packages to optimize load time.
+
+Remember that by default, React runs extra checks and provides helpful warnings in development mode. When deploying your app, make sure to [compile it in production mode](/react/docs/installation.html#development-and-production-versions).
+
+In case you don't use a bundler, we also provide pre-built bundles in the npm packages which you can [include as script tags](/react/docs/installation.html#using-a-cdn) on your page:
+
+* **React**  
+  Dev build with warnings: [react/dist/react.js](https://unpkg.com/react@15.4.0/dist/react.js)  
+  Minified build for production: [react/dist/react.min.js](https://unpkg.com/react@15.4.0/dist/react.min.js)  
+* **React with Add-Ons**  
+  Dev build with warnings: [react/dist/react-with-addons.js](https://unpkg.com/react@15.4.0/dist/react-with-addons.js)  
+  Minified build for production: [react/dist/react-with-addons.min.js](https://unpkg.com/react@15.4.0/dist/react-with-addons.min.js)  
+* **React DOM** (include React in the page before React DOM)  
+  Dev build with warnings: [react-dom/dist/react-dom.js](https://unpkg.com/react-dom@15.4.0/dist/react-dom.js)  
+  Minified build for production: [react-dom/dist/react-dom.min.js](https://unpkg.com/react-dom@15.4.0/dist/react-dom.min.js)  
+* **React DOM Server** (include React in the page before React DOM Server)  
+  Dev build with warnings: [react-dom/dist/react-dom-server.js](https://unpkg.com/react-dom@15.4.0/dist/react-dom-server.js)  
+  Minified build for production: [react-dom/dist/react-dom-server.min.js](https://unpkg.com/react-dom@15.4.0/dist/react-dom-server.min.js)
+
+We've also published version `15.4.0` of the `react`, `react-dom`, and addons packages on npm and the `react` package on bower.
+
+- - -
+
+## Changelog
+
+### React
+* React package and browser build no longer "secretly" includes React DOM.  
+  <small>([@sebmarkbage](https://github.com/sebmarkbage) in [#7164](https://github.com/facebook/react/pull/7164) and [#7168](https://github.com/facebook/react/pull/7168))</small>
+* Required PropTypes now fail with specific messages for null and undefined.  
+  <small>([@chenglou](https://github.com/chenglou) in [#7291](https://github.com/facebook/react/pull/7291))</small>
+* Improved development performance by freezing children instead of copying.  
+  <small>([@keyanzhang](https://github.com/keyanzhang) in [#7455](https://github.com/facebook/react/pull/7455))</small>
+
+### React DOM
+* Fixed occasional test failures when React DOM is used together with shallow renderer.  
+  <small>([@goatslacker](https://github.com/goatslacker) in [#8097](https://github.com/facebook/react/pull/8097))</small>
+* Added a warning for invalid `aria-` attributes.  
+  <small>([@jessebeach](https://github.com/jessebeach) in [#7744](https://github.com/facebook/react/pull/7744))</small>
+* Added a warning for using `autofocus` rather than `autoFocus`.  
+  <small>([@hkal](https://github.com/hkal) in [#7694](https://github.com/facebook/react/pull/7694))</small>
+* Removed an unnecessary warning about polyfilling `String.prototype.split`.  
+  <small>([@nhunzaker](https://github.com/nhunzaker) in [#7629](https://github.com/facebook/react/pull/7629))</small>
+* Clarified the warning about not calling PropTypes manually.  
+  <small>([@jedwards1211](https://github.com/jedwards1211) in [#7777](https://github.com/facebook/react/pull/7777))</small>
+* The unstable `batchedUpdates` API now passes the wrapped function's return value through.  
+  <small>([@bgnorlov](https://github.com/bgnorlov) in [#7444](https://github.com/facebook/react/pull/7444))</small>
+* Fixed a bug with updating text in IE 8.  
+  <small>([@mnpenner](https://github.com/mnpenner) in [#7832](https://github.com/facebook/react/pull/7832))</small>
+
+### React Perf
+* When ReactPerf is started, you can now view the relative time spent in components as a chart in Chrome Timeline.  
+  <small>([@gaearon](https://github.com/gaearon) in [#7549](https://github.com/facebook/react/pull/7549))</small>
+
+### React Test Utils
+* If you call `Simulate.click()` on a `<input disabled onClick={foo} />` then `foo` will get called whereas it didn't before.  
+  <small>([@nhunzaker](https://github.com/nhunzaker) in [#7642](https://github.com/facebook/react/pull/7642))</small>
+
+### React Test Renderer
+* Due to packaging changes, it no longer crashes when imported together with React DOM in the same file.  
+  <small>([@sebmarkbage](https://github.com/sebmarkbage) in [#7164](https://github.com/facebook/react/pull/7164) and [#7168](https://github.com/facebook/react/pull/7168))</small>
+* `ReactTestRenderer.create()` now accepts `{createNodeMock: element => mock}` as an optional argument so you can mock refs with snapshot testing.  
+  <small>([@Aweary](https://github.com/Aweary) in [#7649](https://github.com/facebook/react/pull/7649) and [#8261](https://github.com/facebook/react/pull/8261))</small>
diff --git a/docs/_posts/2017-04-07-react-v15.5.0.md b/docs/_posts/2017-04-07-react-v15.5.0.md
new file mode 100644
index 000000000000..7c38475c1a48
--- /dev/null
+++ b/docs/_posts/2017-04-07-react-v15.5.0.md
@@ -0,0 +1,227 @@
+---
+title: "React v15.5.0"
+author: acdlite
+---
+
+It's been exactly one year since the last breaking change to React. Our next major release, React 16, will include some exciting improvements, including a [complete rewrite](https://www.youtube.com/watch?v=ZCuYPiUIONs) of React's internals. [We take stability seriously](/react/contributing/design-principles.html#stability), and are committed to bringing those improvements to all of our users with minimal effort.
+
+To that end, today we're releasing React 15.5.0.
+
+### New Deprecation Warnings
+
+The biggest change is that we've extracted `React.PropTypes` and `React.createClass` into their own packages. Both are still accessible via the main `React` object, but using either will log a one-time deprecation warning to the console when in development mode. This will enable future code size optimizations.
+
+These warnings will not affect the behavior of your application. However, we realize they may cause some frustration, particularly if you use a testing framework that treats `console.error` as a failure.
+
+**Adding new warnings is not something we do lightly.** Warnings in React are not mere suggestions — they are integral to our strategy of keeping as many people as possible on the latest version of React. We never add warnings without providing an incremental path forward.
+
+So while the warnings may cause frustration in the short-term, we believe **prodding developers to migrate their codebases now prevents greater frustration in the future**. Proactively fixing warnings ensures you are prepared for the next major release. If your app produces zero warnings in 15.5, it should continue to work in 16 without any changes.
+
+For each of these new deprecations, we've provided a codemod to automatically migrate your code. They are available as part of the [react-codemod](https://github.com/reactjs/react-codemod) project.
+
+### Migrating from React.PropTypes
+
+Prop types are a feature for runtime validation of props during development. We've extracted the built-in prop types to a separate package to reflect the fact that not everybody uses them.
+
+In 15.5, instead of accessing `PropTypes` from the main `React` object, install the `prop-types` package and import them from there:
+
+```js{11,16,25}
+// Before (15.4 and below)
+import React from 'react';
+
+class Component extends React.Component {
+  render() {
+    return <div>{this.props.text}</div>;
+  }
+}
+
+Component.propTypes = {
+  text: React.PropTypes.string.isRequired,
+}
+
+// After (15.5)
+import React from 'react';
+import PropTypes from 'prop-types';
+
+class Component extends React.Component {
+  render() {
+    return <div>{this.props.text}</div>;
+  }
+}
+
+Component.propTypes = {
+  text: PropTypes.string.isRequired,
+};
+```
+
+The [codemod](https://github.com/reactjs/react-codemod#react-proptypes-to-prop-types) for this change performs this conversion automatically. Basic usage:
+
+```bash
+jscodeshift -t react-codemod/transforms/React-PropTypes-to-prop-types.js <path>
+```
+
+
+The `propTypes`, `contextTypes`, and `childContextTypes` APIs will work exactly as before. The only change is that the built-in validators now live in a separate package.
+
+You may also consider using [Flow](https://flow.org/) to statically type check your JavaScript code, including [React components](https://flow.org/en/docs/frameworks/react/#setup-flow-with-react-a-classtoc-idtoc-setup-flow-with-react-hreftoc-setup-flow-with-reacta).
+
+### Migrating from React.createClass
+
+When React was initially released, there was no idiomatic way to create classes in JavaScript, so we provided our own: `React.createClass`.
+
+Later, classes were added to the language as part of ES2015, so we added the ability to create React components using JavaScript classes. **Along with functional components, JavaScript classes are now the [preferred way to create components in React](/react/docs/components-and-props.html#functional-and-class-components).**
+
+For your existing `createClass` components, we recommend that you migrate them to JavaScript classes. However, if you have components that rely on mixins, converting to classes may not be immediately feasible. If so, `create-react-class` is available on npm as a drop-in replacement:
+
+```js{4,13,15}
+// Before (15.4 and below)
+var React = require('react');
+
+var Component = React.createClass({
+  mixins: [MixinA],
+  render() {
+    return <Child />;
+  }
+});
+
+// After (15.5)
+var React = require('react');
+var createReactClass = require('create-react-class');
+
+var Component = createReactClass({
+  mixins: [MixinA],
+  render() {
+    return <Child />;
+  }
+});
+```
+
+Your components will continue to work the same as they did before.
+
+The [codemod](https://github.com/reactjs/react-codemod#explanation-of-the-new-es2015-class-transform-with-property-initializers) for this change attempts to convert a `createClass` component to a JavaScript class, with a fallback to `create-react-class` if necessary. It has converted thousands of components internally at Facebook.
+
+Basic usage:
+
+```bash
+jscodeshift -t react-codemod/transforms/class.js path/to/components
+```
+
+### Discontinuing support for React Addons
+
+We're discontinuing active maintenance of React Addons packages. In truth, most of these packages haven't been actively maintained in a long time. They will continue to work indefinitely, but we recommend migrating away as soon as you can to prevent future breakages.
+
+- **react-addons-create-fragment** – React 16 will have first-class support for fragments, at which point this package won't be necessary. We recommend using arrays of keyed elements instead.
+- **react-addons-css-transition-group** - Use [react-transition-group/CSSTransitionGroup](https://github.com/reactjs/react-transition-group) instead. Version 1.1.1 provides a drop-in replacement.
+- **react-addons-linked-state-mixin** - Explicitly set the `value` and `onChange` handler instead.
+- **react-addons-pure-render-mixin** - Use [`React.PureComponent`](/react/docs/react-api.html#react.purecomponent) instead.
+- **react-addons-shallow-compare** - Use [`React.PureComponent`](/react/docs/react-api.html#react.purecomponent) instead.
+- **react-addons-transition-group** - Use [react-transition-group/TransitionGroup](https://github.com/reactjs/react-transition-group) instead. Version 1.1.1 provides a drop-in replacement.
+- **react-addons-update** - Use [immutability-helper](https://github.com/kolodny/immutability-helper) instead, a drop-in replacement.
+- **react-linked-input** - Explicitly set the `value` and `onChange` handler instead.
+
+We're also discontinuing support for the `react-with-addons` UMD build. It will be removed in React 16.
+
+### React Test Utils
+
+Currently, the React Test Utils live inside `react-addons-test-utils`. As of 15.5, we're deprecating that package and moving them to `react-dom/test-utils` instead:
+
+```js
+// Before (15.4 and below)
+import TestUtils from 'react-addons-test-utils';
+
+// After (15.5)
+import TestUtils from 'react-dom/test-utils';
+```
+
+This reflects the fact that what we call the Test Utils are really a set of APIs that wrap the DOM renderer.
+
+The exception is shallow rendering, which is not DOM-specific. The shallow renderer has been moved to `react-test-renderer/shallow`.
+
+```js{2,5}
+// Before (15.4 and below)
+import { createRenderer } from 'react-addons-test-utils';
+
+// After (15.5)
+import { createRenderer } from 'react-test-renderer/shallow';
+```
+
+---
+
+## Acknowledgements
+
+A special thank you to these folks for transferring ownership of npm package names:
+
+- [Jason Miller](https://github.com/developit)
+- [Aaron Ackerman](https://github.com/aackerman)
+- [Vinicius Marson](https://github.com/viniciusmarson)
+
+---
+
+## Installation
+
+We recommend using [Yarn](https://yarnpkg.com/) or [npm](https://www.npmjs.com/) for managing front-end dependencies. If you're new to package managers, the [Yarn documentation](https://yarnpkg.com/en/docs/getting-started) is a good place to get started.
+
+To install React with Yarn, run:
+
+```bash
+yarn add react@^15.5.0 react-dom@^15.5.0
+```
+
+To install React with npm, run:
+
+```bash
+npm install --save react@^15.5.0 react-dom@^15.5.0
+```
+
+We recommend using a bundler like [webpack](https://webpack.js.org/) or [Browserify](http://browserify.org/) so you can write modular code and bundle it together into small packages to optimize load time.
+
+Remember that by default, React runs extra checks and provides helpful warnings in development mode. When deploying your app, make sure to [compile it in production mode](/react/docs/installation.html#development-and-production-versions).
+
+In case you don't use a bundler, we also provide pre-built bundles in the npm packages which you can [include as script tags](/react/docs/installation.html#using-a-cdn) on your page:
+
+* **React**  
+  Dev build with warnings: [react/dist/react.js](https://unpkg.com/react@15.5.0/dist/react.js)  
+  Minified build for production: [react/dist/react.min.js](https://unpkg.com/react@15.5.0/dist/react.min.js)  
+* **React with Add-Ons**  
+  Dev build with warnings: [react/dist/react-with-addons.js](https://unpkg.com/react@15.5.0/dist/react-with-addons.js)  
+  Minified build for production: [react/dist/react-with-addons.min.js](https://unpkg.com/react@15.5.0/dist/react-with-addons.min.js)  
+* **React DOM** (include React in the page before React DOM)  
+  Dev build with warnings: [react-dom/dist/react-dom.js](https://unpkg.com/react-dom@15.5.0/dist/react-dom.js)  
+  Minified build for production: [react-dom/dist/react-dom.min.js](https://unpkg.com/react-dom@15.5.0/dist/react-dom.min.js)  
+* **React DOM Server** (include React in the page before React DOM Server)  
+  Dev build with warnings: [react-dom/dist/react-dom-server.js](https://unpkg.com/react-dom@15.5.0/dist/react-dom-server.js)  
+  Minified build for production: [react-dom/dist/react-dom-server.min.js](https://unpkg.com/react-dom@15.5.0/dist/react-dom-server.min.js)
+
+We've also published version `15.5.0` of the `react`, `react-dom`, and addons packages on npm and the `react` package on bower.
+
+---
+
+## Changelog
+
+## 15.5.0 (April 7, 2017)
+
+### React
+
+* Added a deprecation warning for `React.createClass`. Points users to create-react-class instead. ([@acdlite](https://github.com/acdlite) in [d9a4fa4](https://github.com/facebook/react/commit/d9a4fa4f51c6da895e1655f32255cf72c0fe620e))
+* Added a deprecation warning for `React.PropTypes`. Points users to prop-types instead. ([@acdlite](https://github.com/acdlite) in [043845c](https://github.com/facebook/react/commit/043845ce75ea0812286bbbd9d34994bb7e01eb28))
+* Fixed an issue when using `ReactDOM` together with `ReactDOMServer`. ([@wacii](https://github.com/wacii) in [#9005](https://github.com/facebook/react/pull/9005))
+* Fixed issue with Closure Compiler. ([@anmonteiro](https://github.com/anmonteiro) in [#8895](https://github.com/facebook/react/pull/8895))
+* Another fix for Closure Compiler. ([@Shastel](https://github.com/Shastel) in [#8882](https://github.com/facebook/react/pull/8882))
+* Added component stack info to invalid element type warning. ([@n3tr](https://github.com/n3tr) in [#8495](https://github.com/facebook/react/pull/8495))
+
+### React DOM
+
+* Fixed Chrome bug when backspacing in number inputs. ([@nhunzaker](https://github.com/nhunzaker) in [#7359](https://github.com/facebook/react/pull/7359))
+* Added `react-dom/test-utils`, which exports the React Test Utils. ([@bvaughn](https://github.com/bvaughn))
+
+### React Test Renderer
+
+* Fixed bug where `componentWillUnmount` was not called for children. ([@gre](https://github.com/gre) in [#8512](https://github.com/facebook/react/pull/8512))
+* Added `react-test-renderer/shallow`, which exports the shallow renderer. ([@bvaughn](https://github.com/bvaughn))
+
+### React Addons
+
+* Last release for addons; they will no longer be actively maintained.
+* Removed `peerDependencies` so that addons continue to work indefinitely. ([@acdlite](https://github.com/acdlite) and [@bvaughn](https://github.com/bvaughn) in [8a06cd7](https://github.com/facebook/react/commit/8a06cd7a786822fce229197cac8125a551e8abfa) and [67a8db3](https://github.com/facebook/react/commit/67a8db3650d724a51e70be130e9008806402678a))
+* Updated to remove references to `React.createClass` and `React.PropTypes` ([@acdlite](https://github.com/acdlite) in [12a96b9](https://github.com/facebook/react/commit/12a96b94823d6b6de6b1ac13bd576864abd50175))
+* `react-addons-test-utils` is deprecated. Use `react-dom/test-utils` and `react-test-renderer/shallow` instead. ([@bvaughn](https://github.com/bvaughn))
diff --git a/docs/_posts/2017-05-18-whats-new-in-create-react-app.md b/docs/_posts/2017-05-18-whats-new-in-create-react-app.md
new file mode 100644
index 000000000000..a8fbcbeaf4ff
--- /dev/null
+++ b/docs/_posts/2017-05-18-whats-new-in-create-react-app.md
@@ -0,0 +1,107 @@
+---
+title: "What's New in Create React App"
+author: gaearon
+---
+
+Less than a year ago, we introduced [Create React App](/react/blog/2016/07/22/create-apps-with-no-configuration.html) as an officially supported way to create apps with zero configuration. The project has since enjoyed tremendous growth, with over 950 commits by more than 250 contributors.
+
+Today, we are excited to announce that many features that have been in the pipeline for the last few months are finally released.
+
+As usual with Create React App, **you can enjoy these improvements in your existing non-ejected apps by updating a single dependency** and following our [migration instructions](https://github.com/facebookincubator/create-react-app/releases/tag/v1.0.0).
+
+Newly created apps will get these improvements automatically.
+
+### webpack 2
+
+>*This change was contributed by [@Timer](https://github.com/Timer) in [#1291](https://github.com/facebookincubator/create-react-app/pull/1291).*
+
+We have upgraded to webpack 2 which has been [officially released](https://medium.com/webpack/webpack-2-and-beyond-40520af9067f) a few months ago. It is a big upgrade with many bugfixes and general improvements. We have been testing it for a while, and now consider it stable enough to recommend it to everyone.
+
+While the Webpack configuration format has changed, Create React App users who didn't eject don't need to worry about it as we have updated the configuration on our side.
+
+If you had to eject your app for one reason or another, Webpack provides a [configuration migration guide](https://webpack.js.org/guides/migrating/) that you can follow to update your apps. Note that with each release of Create React App, we are working to support more use cases out of the box so that you don't have to eject in the future.
+
+The biggest notable webpack 2 feature is the ability to write and import [ES6 modules](http://2ality.com/2014/09/es6-modules-final.html) directly without compiling them to CommonJS. This shouldn’t affect how you write code since you likely already use `import` and `export` statements, but it will help catch more mistakes like missing named exports at compile time:
+
+<img src='/react/img/blog/cra-update-exports.gif' alt='Export validation' style="max-width:100%"> 
+
+In the future, as the ecosystem around ES6 modules matures, you can expect more improvements to your app's bundle size thanks to [tree shaking](https://webpack.js.org/guides/tree-shaking/).
+
+### Runtime Error Overlay
+
+>*This change was contributed by [@Timer](https://github.com/Timer) and [@nicinabox](https://github.com/nicinabox) in [#1101](https://github.com/facebookincubator/create-react-app/pull/1101), [@bvaughn](https://github.com/bvaughn) in [#2201](https://github.com/facebookincubator/create-react-app/pull/2201).*
+
+Have you ever made a mistake in code and only realized it after the console is flooded with cryptic errors? Or worse, have you ever shipped an app with crashes in production because you accidentally missed an error in development?
+
+To address these issues, we are introducing an overlay that pops up whenever there is an uncaught error in your application. It only appears in development, and you can dismiss it by pressing Escape. 
+
+A GIF is worth a thousand words:
+    
+<img src='/react/img/blog/cra-runtime-error.gif' alt='Runtime error overlay' style="max-width:100%"> 
+
+(Yes, it integrates with your editor!)
+
+In the future, we plan to teach the runtime error overlay to understand more about your React app. For example, after React 16 we plan to show React component stacks in addition to the JavaScript stacks when an error is thrown.
+
+
+### Progressive Web Apps by Default
+
+>*This change was contributed by [@jeffposnick](https://github.com/jeffposnick) in [#1728](https://github.com/facebookincubator/create-react-app/pull/1728).*
+
+Newly created projects are built as [Progressive Web Apps](https://developers.google.com/web/progressive-web-apps/) by default. This means that they employ [service workers](https://developers.google.com/web/fundamentals/getting-started/primers/service-workers) with an [offline-first caching strategy](https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/#cache-falling-back-to-network) to minimize the time it takes to serve the app to the users who visit it again. You can opt out of this behavior, but we recommend it both for new and existing apps, especially if you target mobile devices.
+
+<img src='/react/img/blog/cra-pwa.png' alt='Loading assets from service worker' style="max-width:100%"> 
+
+New apps automatically have these features, but you can easily convert an existing project to a Progressive Web App  by following [our migration guide](https://github.com/facebookincubator/create-react-app/releases/tag/v1.0.0).
+
+We will be adding [more documentation](https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md#making-a-progressive-web-app) on this topic in the coming weeks. Please feel free to [ask any questions](https://github.com/facebookincubator/create-react-app/issues/new) on the issue tracker!
+
+
+### Jest 20
+
+>*This change was contributed by [@rogeliog](https://github.com/rogeliog) in [#1614](https://github.com/facebookincubator/create-react-app/pull/1614) and [@gaearon](https://github.com/gaearon) in [#2171](https://github.com/facebookincubator/create-react-app/pull/2171).*
+   
+We are now using the latest version of Jest that includes numerous bugfixes and improvements. You can read more about the changes in [Jest 19](https://facebook.github.io/jest/blog/2017/02/21/jest-19-immersive-watch-mode-test-platform-improvements.html) and [Jest 20](http://facebook.github.io/jest/blog/2017/05/06/jest-20-delightful-testing-multi-project-runner.html) blog posts.
+
+Highlights include a new [immersive watch mode](https://facebook.github.io/jest/blog/2017/02/21/jest-19-immersive-watch-mode-test-platform-improvements.html#immersive-watch-mode), [a better snapshot format](https://facebook.github.io/jest/blog/2017/02/21/jest-19-immersive-watch-mode-test-platform-improvements.html#snapshot-updates), [improvements to printing skipped tests](https://facebook.github.io/jest/blog/2017/02/21/jest-19-immersive-watch-mode-test-platform-improvements.html#improved-printing-of-skipped-tests), and [new testing APIs](https://facebook.github.io/jest/blog/2017/05/06/jest-20-delightful-testing-multi-project-runner.html#new-improved-testing-apis).
+
+<img src='/react/img/blog/cra-jest-search.gif' alt='Immersive test watcher' style="max-width:100%"> 
+
+Additionally, Create React App now support configuring a few Jest options related to coverage reporting.
+
+### Code Splitting with Dynamic import()
+
+>*This change was contributed by [@Timer](https://github.com/Timer) in [#1538](https://github.com/facebookincubator/create-react-app/pull/1538) and [@tharakawj](https://github.com/tharakawj) in [#1801](https://github.com/facebookincubator/create-react-app/pull/1801).*
+   
+It is important to keep the initial JavaScript payload of web apps down to the minimum, and [load the rest of the code on demand](https://medium.com/@addyosmani/progressive-web-apps-with-react-js-part-2-page-load-performance-33b932d97cf2). Although Create React App supported [code splitting](https://webpack.js.org/guides/code-splitting-async/) using `require.ensure()` since the first release, it used a webpack-specific syntax that did not work in Jest or other environments.
+   
+In this release, we are adding support for the [dynamic `import()` proposal](http://2ality.com/2017/01/import-operator.html#loading-code-on-demand) which aligns with the future web standards. Unlike `require.ensure()`, it doesn't break Jest tests, and should eventually become a part of JavaScript. We encourage you to use `import()` to delay loading the code for non-critical component subtrees until you need to render them.
+
+<img src='/react/img/blog/cra-dynamic-import.gif' alt='Creating chunks with dynamic import' style="max-width:100%">
+
+### Better Console Output
+
+>*This change was contributed by [@gaearon](https://github.com/gaearon) in [#2120](https://github.com/facebookincubator/create-react-app/pull/2120), [#2125](https://github.com/facebookincubator/create-react-app/pull/2125), and [#2161](https://github.com/facebookincubator/create-react-app/pull/2161).*
+
+We have improved the console output across the board.
+
+For example, when you start the development server, we now display the LAN address in additional to the localhost address so that you can quickly access the app from a mobile device on the same network:
+
+<img src='/react/img/blog/cra-better-output.png' alt='Better console output' style="max-width:100%"> 
+
+When lint errors are reported, we no longer show the warnings so that you can concentrate on more critical issues. Errors and warnings in the production build output are better formatted, and the build error overlay font size now matches the browser font size more closely.
+
+### But Wait... There's More!
+
+You can only fit so much in a blog post, but there are other long-requested features in this release, such as [environment-specific and local `.env` files](https://github.com/facebookincubator/create-react-app/pull/1344), [a lint rule against confusingly named globals](https://github.com/facebookincubator/create-react-app/pull/2130), [support for multiple proxies in development](https://github.com/facebookincubator/create-react-app/pull/1790), [a customizable browser launch script](https://github.com/facebookincubator/create-react-app/pull/1590), and many bugfixes.
+
+You can read the full changelog and the migration guide in the [v1.0.0 release notes](https://github.com/facebookincubator/create-react-app/releases/tag/v1.0.0).
+
+### Acknowledgements
+
+This release is a result of months of work from many people in the React community. It is focused on improving both developer and end user experience, as we believe they are complementary and go hand in hand.
+
+We are grateful to [everyone who has offered their contributions](https://github.com/facebookincubator/create-react-app/graphs/contributors), whether in code, documentation, or by helping other people. We would like to specifically thank [Joe Haddad](https://github.com/timer) for his invaluable help maintaining the project.
+
+We are excited to bring these improvements to everybody using Create React App, and we are looking forward to more of your feedback and contributions.
+
diff --git a/docs/_posts/2017-06-13-react-v15.6.0.md b/docs/_posts/2017-06-13-react-v15.6.0.md
new file mode 100644
index 000000000000..7accc87e04c5
--- /dev/null
+++ b/docs/_posts/2017-06-13-react-v15.6.0.md
@@ -0,0 +1,95 @@
+---
+title: "React v15.6.0"
+author: flarnie
+---
+
+Today we are releasing React 15.6.0. As we prepare for React 16.0, we have been fixing and cleaning up many things. This release continues to pave the way.
+
+## Improving Inputs
+
+In React 15.6.0 the `onChange` event for inputs is a little bit more reliable and handles more edge cases, including the following:
+
+* not firing when radio button is clicked but not changed ([issue 1471](https://github.com/facebook/react/issues/1471))
+* changing an input of type `range` with the arrow keys ([issue 554](https://github.com/facebook/react/issues/554))
+* pasting text into a text area in IE11 ([issue 7211](https://github.com/facebook/react/issues/7211))
+* auto-fill in IE11 ([issue 6614](https://github.com/facebook/react/issues/6614))
+* clearing input with 'x' button or right-click 'delete' in IE11 ([issue 6822](https://github.com/facebook/react/issues/6822))
+* not firing when characters are present in the input on render in IE11 ([issue 2185](https://github.com/facebook/react/issues/2185))
+
+Thanks to [Jason Quense](https://github.com/jquense) and everyone who helped out on those issues and PRs.
+
+## Less Noisy Deprecation Warnings
+
+We are also including a couple of new warnings for upcoming deprecations. These should not affect most users, and for more details see the changelog below.
+
+After the last release, we got valuable community feedback that deprecation warnings were causing noise and failing tests. **In React 15.6, we have downgraded deprecation warnings to use `console.warn` instead of `console.error`.** Our other warnings will still use `console.error` because they surface urgent issues which could lead to bugs. Unlike our other warnings, deprecation warnings can be fixed over time and won't cause problems in your app if shipped. We believe that downgrading the urgency of deprecation warnings will make your next update easier. Thanks to everyone who was involved in the discussion of this change.
+
+---
+
+## Installation
+
+We recommend using [Yarn](https://yarnpkg.com/) or [npm](https://www.npmjs.com/) for managing front-end dependencies. If you're new to package managers, the [Yarn documentation](https://yarnpkg.com/en/docs/getting-started) is a good place to get started.
+
+To install React with Yarn, run:
+
+```bash
+yarn add react@^15.6.0 react-dom@^15.6.0
+```
+
+To install React with npm, run:
+
+```bash
+npm install --save react@^15.6.0 react-dom@^15.6.0
+```
+
+We recommend using a bundler like [webpack](https://webpack.js.org/) or [Browserify](http://browserify.org/) so you can write modular code and bundle it together into small packages to optimize load time.
+
+Remember that by default, React runs extra checks and provides helpful warnings in development mode. When deploying your app, make sure to [use the production build](/react/docs/optimizing-performance.html#use-the-production-build).
+
+In case you don't use a bundler, we also provide pre-built bundles in the npm packages which you can [include as script tags](/react/docs/installation.html#using-a-cdn) on your page:
+
+* **React**<br/>
+  Dev build with warnings: [react/dist/react.js](https://unpkg.com/react@15.6.0/dist/react.js)<br/>
+  Minified build for production: [react/dist/react.min.js](https://unpkg.com/react@15.6.0/dist/react.min.js)<br/>
+* **React with Add-Ons**<br/>
+  Dev build with warnings: [react/dist/react-with-addons.js](https://unpkg.com/react@15.6.0/dist/react-with-addons.js)<br/>
+  Minified build for production: [react/dist/react-with-addons.min.js](https://unpkg.com/react@15.5.0/dist/react-with-addons.min.js)<br/>
+* **React DOM** (include React in the page before React DOM)<br/>
+  Dev build with warnings: [react-dom/dist/react-dom.js](https://unpkg.com/react-dom@15.6.0/dist/react-dom.js)<br/>
+  Minified build for production: [react-dom/dist/react-dom.min.js](https://unpkg.com/react-dom@15.6.0/dist/react-dom.min.js)<br/>
+* **React DOM Server** (include React in the page before React DOM Server)<br/>
+  Dev build with warnings: [react-dom/dist/react-dom-server.js](https://unpkg.com/react-dom@15.6.0/dist/react-dom-server.js)<br/>
+  Minified build for production: [react-dom/dist/react-dom-server.min.js](https://unpkg.com/react-dom@15.6.0/dist/react-dom-server.min.js)<br/>
+
+We've also published version `15.6.0` of `react` and `react-dom` on npm, and the `react` package on bower.
+
+---
+
+## Changelog
+
+## 15.6.0 (June 13, 2017)
+
+### React
+
+* Downgrade deprecation warnings to use `console.warn` instead of `console.error`. ([@flarnie](https://github.com/flarnie) in [#9753](https://github.com/facebook/react/pull/9753))
+* Add a deprecation warning for `React.createClass`. Points users to `create-react-class` instead. ([@flarnie](https://github.com/flarnie) in [#9771](https://github.com/facebook/react/pull/9771))
+* Add deprecation warnings and separate module for `React.DOM` factory helpers. ([@nhunzaker](https://github.com/nhunzaker) in [#8356](https://github.com/facebook/react/pull/8356))
+* Warn for deprecation of `React.createMixin` helper, which was never used. ([@aweary](https://github.com/aweary) in [#8853](https://github.com/facebook/react/pull/8853))
+
+### React DOM
+
+* Add support for CSS variables in `style` attribute. ([@aweary](https://github.com/aweary) in [#9302](https://github.com/facebook/react/pull/9302))
+* Add support for CSS Grid style properties. ([@ericsakmar](https://github.com/ericsakmar) in [#9185](https://github.com/facebook/react/pull/9185))
+* Fix bug where inputs mutated value on type conversion. ([@nhunzaker](https://github.com/mhunzaker) in [#9806](https://github.com/facebook/react/pull/9806))
+* Fix issues with `onChange` not firing properly for some inputs. ([@jquense](https://github.com/jquense) in [#8575](https://github.com/facebook/react/pull/8575))
+* Fix bug where controlled number input mistakenly allowed period. ([@nhunzaker](https://github.com/nhunzaker) in [#9584](https://github.com/facebook/react/pull/9584))
+* Fix bug where performance entries were being cleared. ([@chrisui](https://github.com/chrisui) in [#9451](https://github.com/facebook/react/pull/9451))
+
+### React Addons
+
+* Fix AMD support for addons depending on `react`. ([@flarnie](https://github.com/flarnie) in [#9919](https://github.com/facebook/react/issues/9919))
+* Fix `isMounted()` to return `true` in `componentWillUnmount`. ([@mridgway](https://github.com/mridgway) in [#9638](https://github.com/facebook/react/issues/9638))
+* Fix `react-addons-update` to not depend on native `Object.assign`. ([@gaearon](https://github.com/gaearon) in [#9937](https://github.com/facebook/react/pull/9937))
+* Remove broken Google Closure Compiler annotation from `create-react-class`. ([@gaearon](https://github.com/gaearon) in [#9933](https://github.com/facebook/react/pull/9933))
+* Remove unnecessary dependency from `react-linked-input`. ([@gaearon](https://github.com/gaearon) in [#9766](https://github.com/facebook/react/pull/9766))
+* Point `react-addons-(css-)transition-group` to the new package. ([@gaearon](https://github.com/gaearon) in [#9937](https://github.com/facebook/react/pull/9937))
diff --git a/docs/acknowledgements.md b/docs/acknowledgements.md
index cb1cd3e6dff0..19894764be3e 100644
--- a/docs/acknowledgements.md
+++ b/docs/acknowledgements.md
@@ -2,6 +2,7 @@
 id: acknowledgements
 title: Acknowledgements
 layout: single
+permalink: acknowledgements.html
 ---
 
 We'd like to thank all of our contributors:
diff --git a/docs/circle.yml b/docs/circle.yml
new file mode 100644
index 000000000000..774c6cec668d
--- /dev/null
+++ b/docs/circle.yml
@@ -0,0 +1,5 @@
+---
+general:
+  branches:
+    ignore:
+      - gh-pages
diff --git a/docs/community/complementary-tools.it-IT.md b/docs/community/complementary-tools.it-IT.md
new file mode 100644
index 000000000000..def23d848277
--- /dev/null
+++ b/docs/community/complementary-tools.it-IT.md
@@ -0,0 +1,5 @@
+---
+permalink: docs/complementary-tools-it-IT.html
+layout: redirect
+dest_url: https://github.com/facebook/react/wiki/Complementary-Tools
+---
diff --git a/docs/community/complementary-tools.ko-KR.md b/docs/community/complementary-tools.ko-KR.md
new file mode 100644
index 000000000000..b41ef3fe7168
--- /dev/null
+++ b/docs/community/complementary-tools.ko-KR.md
@@ -0,0 +1,5 @@
+---
+permalink: docs/complementary-tools-ko-KR.html
+layout: redirect
+dest_url: https://github.com/facebook/react/wiki/Complementary-Tools
+---
diff --git a/docs/community/complementary-tools.md b/docs/community/complementary-tools.md
new file mode 100644
index 000000000000..d3dcf0406ad9
--- /dev/null
+++ b/docs/community/complementary-tools.md
@@ -0,0 +1,5 @@
+---
+permalink: docs/complementary-tools.html
+layout: redirect
+dest_url: https://github.com/facebook/react/wiki/Complementary-Tools
+---
diff --git a/docs/community/complementary-tools.zh-CN.md b/docs/community/complementary-tools.zh-CN.md
new file mode 100644
index 000000000000..e27a8bc5f1be
--- /dev/null
+++ b/docs/community/complementary-tools.zh-CN.md
@@ -0,0 +1,5 @@
+---
+permalink: docs/complementary-tools-zh-CN.html
+layout: redirect
+dest_url: https://github.com/facebook/react/wiki/Complementary-Tools
+---
diff --git a/docs/community/conferences.it-IT.md b/docs/community/conferences.it-IT.md
new file mode 100644
index 000000000000..3ab4ff5db42b
--- /dev/null
+++ b/docs/community/conferences.it-IT.md
@@ -0,0 +1,19 @@
+---
+id: conferences-it-IT
+title: Conferenze
+permalink: docs/conferences-it-IT.html
+prev: thinking-in-react-it-IT.html
+next: videos-it-IT.html
+---
+
+### React.js Conf 2015
+28 e 29 Gennaio
+
+[Sito web](http://conf.reactjs.com/) - [Agenda](http://conf.reactjs.com/schedule.html) - [Video](https://www.youtube-nocookie.com/playlist?list=PLb0IAmt7-GS1cbw4qonlQztYV1TAW0sCr)
+
+<iframe width="100%" height="315" src="//www.youtube-nocookie.com/embed/KVZ-P-ZI6W4?list=PLb0IAmt7-GS1cbw4qonlQztYV1TAW0sCr" frameborder="0" allowfullscreen></iframe>
+
+### ReactEurope 2015
+2 e 3 Luglio
+
+[Sito web](http://www.react-europe.org/) - [Agenda](http://www.react-europe.org/#schedule)
diff --git a/docs/community/conferences.ko-KR.md b/docs/community/conferences.ko-KR.md
new file mode 100644
index 000000000000..653d65d2521d
--- /dev/null
+++ b/docs/community/conferences.ko-KR.md
@@ -0,0 +1,19 @@
+---
+id: conferences-ko-KR
+title: 컨퍼런스들
+permalink: docs/conferences-ko-KR.html
+prev: thinking-in-react-ko-KR.html
+next: videos-ko-KR.html
+---
+
+### React.js Conf 2015
+1월 28일 & 29일
+
+[웹사이트](http://conf.reactjs.com/) - [스케줄](http://conf.reactjs.com/schedule.html) - [비디오들](https://www.youtube-nocookie.com/playlist?list=PLb0IAmt7-GS1cbw4qonlQztYV1TAW0sCr)
+
+<iframe width="100%" height="315" src="//www.youtube-nocookie.com/embed/KVZ-P-ZI6W4?list=PLb0IAmt7-GS1cbw4qonlQztYV1TAW0sCr" frameborder="0" allowfullscreen></iframe>
+
+### ReactEurope 2015
+7월 2일 & 3일
+
+[웹사이트](http://www.react-europe.org/) - [스케줄](http://www.react-europe.org/#schedule)
diff --git a/docs/community/conferences.md b/docs/community/conferences.md
new file mode 100644
index 000000000000..5db95be803a3
--- /dev/null
+++ b/docs/community/conferences.md
@@ -0,0 +1,136 @@
+---
+id: conferences
+title: Conferences
+layout: community
+sectionid: community
+permalink: community/conferences.html
+redirect_from: "docs/conferences.html"
+---
+
+## Upcoming Conferences
+
+### Chain React 2017
+July 10-11 in Portland, Oregon USA
+
+[Website](https://infinite.red/ChainReactConf) - [Twitter](https://twitter.com/chainreactconf)
+
+### React Rally
+August 24-25 in Salt Lake City, Utah USA
+
+[Website](http://www.reactrally.com) - [Twitter](https://twitter.com/reactrally)
+
+### React Native EU 2017
+September 6-7 in Wroclaw, Poland
+
+[Website](http://react-native.eu/)
+
+### React Alicante 2017
+September 28-30 in Alicante, Spain
+
+[Website](http://reactalicante.es) - [Twitter](https://twitter.com/ReactAlicante)
+
+### ReactJS Day 2017
+October 6 in Verona, Italy
+
+[Website](http://2017.reactjsday.it) - [Twitter](https://twitter.com/reactjsday)
+
+### React Conf Brasil 2017
+October 7 in Sao Paulo, Brazil
+
+[Website](http://reactconfbr.com.br) - [Twitter](https://twitter.com/reactconfbr) - [Facebook](https://www.facebook.com/reactconf/)
+
+### State.js Conference 2017
+October 13 in Stockholm, Sweden
+
+[Website](https://statejs.com/)
+
+### ReactiveConf 2017
+October 25–27, Bratislava, Slovakia
+
+[Website](https://reactiveconf.com)
+
+
+
+## Past Conferences
+
+### React.js Conf 2015
+January 28 & 29 in Facebook HQ, CA
+
+[Website](http://conf2015.reactjs.org/) - [Schedule](http://conf2015.reactjs.org/schedule.html) - [Videos](https://www.youtube.com/playlist?list=PLb0IAmt7-GS1cbw4qonlQztYV1TAW0sCr)
+
+<iframe width="100%" height="315" src="//www.youtube-nocookie.com/embed/KVZ-P-ZI6W4?list=PLb0IAmt7-GS1cbw4qonlQztYV1TAW0sCr" frameborder="0" allowfullscreen></iframe>
+
+### ReactEurope 2015
+July 2 & 3 in Paris, France
+
+[Website](http://www.react-europe.org/) - [Schedule](http://www.react-europe.org/#schedule) - [Videos](https://www.youtube.com/channel/UCorlLn2oZfgOJ-FUcF2eZ1A/playlists)
+
+### Reactive 2015
+November 2-4 in Bratislava, Slovakia
+
+[Website](https://reactive2015.com/) - [Schedule](https://reactive2015.com/schedule_speakers.html#schedule)
+
+### React.js Conf 2016
+February 22 & 23 in San Francisco, CA
+
+[Website](http://conf.reactjs.com/) - [Schedule](http://conf.reactjs.com/schedule.html) - [Videos](https://www.youtube.com/playlist?list=PLb0IAmt7-GS0M8Q95RIc2lOM6nc77q1IY)
+
+### React Amsterdam 2016
+April 16 in Amsterdam, The Netherlands
+
+[Website](https://react.amsterdam/2016) - [Videos](https://youtu.be/sXDZBxbRRag?list=PLNBNS7NRGKMG3uLrm5fgY02hJ87Wzb4IU)
+
+### ReactEurope 2016
+June 2 & 3 in Paris, France
+
+[Website](http://www.react-europe.org/) - [Schedule](http://www.react-europe.org/#schedule) - [Videos](https://www.youtube.com/channel/UCorlLn2oZfgOJ-FUcF2eZ1A/playlists)
+
+### ReactRally 2016
+August 25-26 in Salt Lake City, UT
+
+[Website](http://www.reactrally.com/) - [Schedule](http://www.reactrally.com/#/schedule) - [Videos](https://www.youtube.com/playlist?list=PLUD4kD-wL_zYSfU3tIYsb4WqfFQzO_EjQ)
+
+### ReactNext 2016
+September 15 in Tel Aviv, Israel
+
+[Website](http://react-next.com/) - [Schedule](http://react-next.com/#schedule) - [Videos](https://www.youtube.com/channel/UC3BT8hh3yTTYxbLQy_wbk2w)
+
+### ReactNL 2016
+October 13 in Amsterdam, The Netherlands - [Schedule](http://reactnl.org/#program)
+
+[Website](http://reactnl.org/)
+
+### Reactive 2016
+October 26-28 in Bratislava, Slovakia
+
+[Website](https://reactiveconf.com/)
+
+### React Remote Conf 2016
+October 26-28 online
+
+[Website](https://allremoteconfs.com/react-2016) - [Schedule](https://allremoteconfs.com/react-2016#schedule)
+
+### Agent Conference 2017
+January 20-21 in Dornbirn, Austria
+
+[Website](http://agent.sh/)
+
+### React Conf 2017
+March 13-14 in Santa Clara, CA
+
+[Website](http://conf.reactjs.org/)
+
+### React London 2017
+March 28th at the [QEII Centre, London](http://qeiicentre.london/)
+
+[Website](http://react.london/)
+
+### React Amsterdam 2017
+April 21st in Amsterdam, The Netherlands
+
+[Website](https://react.amsterdam) - [Twitter](https://twitter.com/reactamsterdam)
+
+### ReactEurope 2017
+May 18th & 19th in Paris, France
+
+[Website](http://www.react-europe.org/) - [Schedule](http://www.react-europe.org/#schedule) - [Videos](https://www.youtube.com/channel/UCorlLn2oZfgOJ-FUcF2eZ1A/playlists)
diff --git a/docs/docs/conferences.zh-CN.md b/docs/community/conferences.zh-CN.md
similarity index 77%
rename from docs/docs/conferences.zh-CN.md
rename to docs/community/conferences.zh-CN.md
index cc1666d92cb7..2e079391bb8d 100644
--- a/docs/docs/conferences.zh-CN.md
+++ b/docs/community/conferences.zh-CN.md
@@ -1,7 +1,7 @@
 ---
 id: conferences-zh-CN
 title: 会议
-permalink: conferences-zh-CN.html
+permalink: docs/conferences-zh-CN.html
 prev: thinking-in-react-zh-CN.html
 next: videos-zh-CN.html
 ---
@@ -11,7 +11,7 @@ next: videos-zh-CN.html
 
 [Website](http://conf.reactjs.com/) - [Schedule](http://conf.reactjs.com/schedule.html) - [Videos](https://www.youtube-nocookie.com/playlist?list=PLb0IAmt7-GS1cbw4qonlQztYV1TAW0sCr)
 
-<iframe width="650" height="315" src="//www.youtube-nocookie.com/embed/KVZ-P-ZI6W4?list=PLb0IAmt7-GS1cbw4qonlQztYV1TAW0sCr" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="315" src="//www.youtube-nocookie.com/embed/KVZ-P-ZI6W4?list=PLb0IAmt7-GS1cbw4qonlQztYV1TAW0sCr" frameborder="0" allowfullscreen></iframe>
 
 ### ReactEurope 2015
 七月 2 & 3
diff --git a/docs/community/examples.it-IT.md b/docs/community/examples.it-IT.md
new file mode 100644
index 000000000000..592429600313
--- /dev/null
+++ b/docs/community/examples.it-IT.md
@@ -0,0 +1,5 @@
+---
+permalink: docs/examples-it-IT.html
+layout: redirect
+dest_url: https://github.com/facebook/react/wiki/Examples
+---
diff --git a/docs/community/examples.ko-KR.md b/docs/community/examples.ko-KR.md
new file mode 100644
index 000000000000..709328358221
--- /dev/null
+++ b/docs/community/examples.ko-KR.md
@@ -0,0 +1,5 @@
+---
+permalink: docs/examples-ko-KR.html
+layout: redirect
+dest_url: https://github.com/facebook/react/wiki/Examples
+---
diff --git a/docs/community/examples.md b/docs/community/examples.md
new file mode 100644
index 000000000000..bccc3287a4cd
--- /dev/null
+++ b/docs/community/examples.md
@@ -0,0 +1,5 @@
+---
+permalink: docs/examples.html
+layout: redirect
+dest_url: https://github.com/facebook/react/wiki/Examples
+---
diff --git a/docs/community/examples.zh-CN.md b/docs/community/examples.zh-CN.md
new file mode 100644
index 000000000000..ac16cf1bbd03
--- /dev/null
+++ b/docs/community/examples.zh-CN.md
@@ -0,0 +1,5 @@
+---
+permalink: docs/examples-zh-CN.html
+layout: redirect
+dest_url: https://github.com/facebook/react/wiki/Examples
+---
diff --git a/docs/community/support.md b/docs/community/support.md
new file mode 100644
index 000000000000..1a98421b6c73
--- /dev/null
+++ b/docs/community/support.md
@@ -0,0 +1,34 @@
+---
+id: support
+title: Where To Get Support
+layout: community
+sectionid: community
+permalink: community/support.html
+redirect_from: "support.html"
+---
+
+**React** is worked on full-time by Facebook's product infrastructure and Instagram's user interface engineering teams. They're often around and available for questions.
+
+## Stack Overflow
+
+Many members of the community use Stack Overflow to ask questions. Read through the [existing questions](http://stackoverflow.com/questions/tagged/reactjs) tagged with **reactjs** or [ask your own](http://stackoverflow.com/questions/ask?tags=reactjs)!
+
+## Discussion forum
+
+For longer-form conversations about React, we've set up a [discussion forum at **discuss.reactjs.org**](https://discuss.reactjs.org/). This forum is a great place for discussion about best practices and application architecture as well as the future of React. If you have an answerable code-level question, please post it to Stack Overflow instead.
+
+In the forum there's also a category for job posts and a category for discussion of our weekly meeting notes.
+
+## Reactiflux Chat
+
+If you need an answer right away, check out the [Reactiflux Discord](https://discord.gg/0ZcbPKXt5bZjGY5n) community. There are usually a number of React experts there who can help out or point you to somewhere you might want to look.
+
+## Freenode IRC
+
+Many developers also hang out in [#reactjs on Freenode](http://irc.lc/freenode/reactjs).
+
+## Facebook and Twitter
+
+For the latest news about React, [like us on Facebook](https://facebook.com/react) and [follow **@reactjs** on Twitter](https://twitter.com/reactjs). In addition, you can use the [#reactjs](https://twitter.com/hashtag/reactjs) hashtag to see what others are saying or add to the conversation.
+
+<div><a class="twitter-timeline" data-dnt="true" data-chrome="nofooter noheader transparent" href="https://twitter.com/search?q=%23reactjs" data-widget-id="342522405270470656"></a></div>
diff --git a/docs/docs/videos.it-IT.md b/docs/community/videos.it-IT.md
similarity index 78%
rename from docs/docs/videos.it-IT.md
rename to docs/community/videos.it-IT.md
index e03707aefae0..099024506ea7 100644
--- a/docs/docs/videos.it-IT.md
+++ b/docs/community/videos.it-IT.md
@@ -1,14 +1,14 @@
 ---
 id: videos-it-IT
 title: Video
-permalink: videos-it-IT.html
+permalink: docs/videos-it-IT.html
 prev: conferences-it-IT.html
 next: complementary-tools-it-IT.html
 ---
 
 ### Riconsiderare le best practice - JSConf.eu
 
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/x7cQ3mrcKaY" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/x7cQ3mrcKaY" frameborder="0" allowfullscreen></iframe>
 
 "A Facebook e Instagram, con React stiamo provando a spingerci oltre i limiti di ciò che è possibile realizzare sul web. Il mio talk comincerà con una breve introduzione al framework, e poi approfondirà tre argomenti controversi: Gettare via la nozione dei template e costruire le viste con JavaScript, effettuare il “ri-rendering” dell'intera applicazione quando i dati cambiano, e un'implementazione leggera del DOM e degli eventi." -- [Pete Hunt](http://www.petehunt.net/)
 
@@ -23,7 +23,7 @@ Un video di [tagtree.tv](http://tagtree.tv/) che espone i principi di [Pensare i
 
 ### I Segreti del DOM Virtuale - MtnWest JS
 
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/h3KksH8gfcQ" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/h3KksH8gfcQ" frameborder="0" allowfullscreen></iframe>
 
 "In questo talk discuterò perché abbiamo costruito un DOM virtuale, i vantaggi rispetto ad altri sistemi, e la sua rilevanza per il futuro della tecnologia dei browser." -- [Pete Hunt](http://www.petehunt.net/)
 
@@ -31,7 +31,7 @@ Un video di [tagtree.tv](http://tagtree.tv/) che espone i principi di [Pensare i
 
 ### Pensare in grande con React
 
-"Sulla carta, tutti questi framework JS sembrano promettenti: implementazioni pulite, design veloce del codice, esecuzione perfetta. Ma che succede quando metti Javascript sotto stress? Che succede se gli dài in pasto 6 megabyte di codice? In questo talk investigheremo come si comporta React in situazioni di stress elevato, e come ha aiutato il nostro team a costruire codice sicuro ad una scala enorme."
+"Sulla carta, tutti questi framework JS sembrano promettenti: implementazioni pulite, design veloce del codice, esecuzione perfetta. Ma che succede quando metti JavaScript sotto stress? Che succede se gli dài in pasto 6 megabyte di codice? In questo talk investigheremo come si comporta React in situazioni di stress elevato, e come ha aiutato il nostro team a costruire codice sicuro ad una scala enorme."
 <figure>[![](https://i.vimeocdn.com/video/481670116_650.jpg)](https://skillsmatter.com/skillscasts/5429-going-big-with-react#video)</figure>
 
 * * *
@@ -99,14 +99,14 @@ Un video di [tagtree.tv](http://tagtree.tv/) che espone i principi di [Pensare i
 
 ### Introduzione a React.js - Facebook Seattle
 
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/XxVg_s8xAms" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/XxVg_s8xAms" frameborder="0" allowfullscreen></iframe>
 
 Di [Tom Occhino](http://tomocchino.com/) e [Jordan Walke](https://github.com/jordwalke)
 
 * * *
 
 ### Backbone + React + Middleman Screencast
-<iframe width="650" height="488" src="https://www.youtube-nocookie.com/embed/iul1fWHVU6A" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="488" src="https://www.youtube-nocookie.com/embed/iul1fWHVU6A" frameborder="0" allowfullscreen></iframe>
 
 Backbone è una grande maniera di interfacciare una API REST con React. Questo screencast mostra come integrare i due usando [Backbone-React-Component](https://github.com/magalhas/backbone-react-component). Middleman è il framework utilizzato in questo esempio, ma può essere facilmente sostituito con altri framework. Si può trovare un template supportato per questo esempio [qui](https://github.com/jbhatab/middleman-backbone-react-template). -- [Open Minded Innovations](http://www.openmindedinnovations.com/)
 
@@ -114,7 +114,7 @@ Backbone è una grande maniera di interfacciare una API REST con React. Questo s
 
 ### Sviluppare Interfacce Utente Con React - Super VanJS
 
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/1OeXsL5mr4g" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/1OeXsL5mr4g" frameborder="0" allowfullscreen></iframe>
 
 Di [Steven Luscher](https://github.com/steveluscher)
 
@@ -122,7 +122,7 @@ Di [Steven Luscher](https://github.com/steveluscher)
 
 ### Introduzione a React - LAWebSpeed meetup
 
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/SMMRJif5QW0" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/SMMRJif5QW0" frameborder="0" allowfullscreen></iframe>
 
 Di [Stoyan Stefanov](http://www.phpied.com/)
 
@@ -130,7 +130,7 @@ Di [Stoyan Stefanov](http://www.phpied.com/)
 
 ### React, o come rendere la vita più semplice - FrontEnd Dev Conf '14
 
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/YJNUK0EA_Jo" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/YJNUK0EA_Jo" frameborder="0" allowfullscreen></iframe>
 
 **In Russo** di [Alexander Solovyov](http://solovyov.net/)
 
@@ -138,19 +138,19 @@ Di [Stoyan Stefanov](http://www.phpied.com/)
 
 ### "Programmazione funzionale del DOM" - Meteor DevShop 11
 
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/qqVbr_LaCIo" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/qqVbr_LaCIo" frameborder="0" allowfullscreen></iframe>
 
 * * *
 
 ### "Ripensare lo Sviluppo di Applicazioni Web a Facebook" - Facebook F8 Conference 2014
 
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/nYkdrAPrdcw" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/nYkdrAPrdcw" frameborder="0" allowfullscreen></iframe>
 
 * * *
 
 ### React e Flux: Costruire Applicazioni con un Flusso Dati Unidirezionale - Forward JS 2014
 
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/i__969noyAM" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/i__969noyAM" frameborder="0" allowfullscreen></iframe>
 
 Gli ingegneri di Facebook [Bill Fisher](https://twitter.com/fisherwebdev) e [Jing Chen](https://twitter.com/jingc) parlano di Flux e React, e di come usare un'architettura dell'applicazione con un flusso di dati unidirezionale rende gran parte del loro codice più pulito.
 
@@ -158,7 +158,7 @@ Gli ingegneri di Facebook [Bill Fisher](https://twitter.com/fisherwebdev) e [Jin
 
 ### Rendering Lato Server di Applicazioni Isomorfiche a SoundCloud
 
-<iframe src="https://player.vimeo.com/video/108488724" width="650" height="365" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
+<iframe src="https://player.vimeo.com/video/108488724" width="100%" height="365" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
 
 [Andres Suarez](https://github.com/zertosh) ci accompagna alla scoperta di come [SoundCloud](https://developers.soundcloud.com/blog/) usa React e Flux per il rendering lato server.
 
@@ -168,6 +168,6 @@ Gli ingegneri di Facebook [Bill Fisher](https://twitter.com/fisherwebdev) e [Jin
 
 ### Introduzione a React Native (+Playlist) - React.js Conf 2015
 
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/KVZ-P-ZI6W4?list=PLb0IAmt7-GS1cbw4qonlQztYV1TAW0sCr" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/KVZ-P-ZI6W4?list=PLb0IAmt7-GS1cbw4qonlQztYV1TAW0sCr" frameborder="0" allowfullscreen></iframe>
 
 [Tom Occhino](https://twitter.com/tomocchino) ripercorre il passato e il presente di React nel 2015, e ci mostra dove è diretto nell'immediato futuro.
diff --git a/docs/docs/videos.ko-KR.md b/docs/community/videos.ko-KR.md
similarity index 80%
rename from docs/docs/videos.ko-KR.md
rename to docs/community/videos.ko-KR.md
index b2270f608f66..3f0c1672bcf4 100644
--- a/docs/docs/videos.ko-KR.md
+++ b/docs/community/videos.ko-KR.md
@@ -1,14 +1,14 @@
 ---
 id: videos-ko-KR
 title: 비디오들
-permalink: videos-ko-KR.html
+permalink: docs/videos-ko-KR.html
 prev: conferences-ko-KR.html
 next: complementary-tools-ko-KR.html
 ---
 
 ### Rethinking best practices - JSConf.eu
 
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/x7cQ3mrcKaY" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/x7cQ3mrcKaY" frameborder="0" allowfullscreen></iframe>
 
 "페이스북과 인스타그램에서, 우리는 React 를 이용해 웹에서 벌어질 수 있는 한계를 뛰어넘으려 노력하고 있습니다. 저는 프레임워크에 대한 짤막한 소개로 시작해서, 논쟁이 벌어질 수 있는 다음의 세가지 주제로 넘어갈겁니다. 템플릿의 개념을 버리고 JavaScript 를 이용해 View 를 구축하기, 자료가 변할때 전체 어플리케이션을 다시 그리기(“re-rendering”), 그리고 DOM과 events의 경량화된 구현 입니다." -- [Pete Hunt](http://www.petehunt.net/)
 
@@ -23,7 +23,7 @@ next: complementary-tools-ko-KR.html
 
 ### Secrets of the Virtual DOM - MtnWest JS
 
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/h3KksH8gfcQ" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/h3KksH8gfcQ" frameborder="0" allowfullscreen></iframe>
 
 "이번에는 왜 우리가 virtual DOM을 만들었는지, 이것이 다른 시스템들과는 어떻게 다른지, 그리고 브라우져 기술들의 미래와 어떻게 관련이 있는지에 대해서 이야기 해 볼 겁니다." -- [Pete Hunt](http://www.petehunt.net/)
 
@@ -101,14 +101,14 @@ JavaScript Jabber 73에서 [Pete Hunt](http://www.petehunt.net/)와 [Jordan Walk
 
 ### Introduction to React.js - Facebook Seattle
 
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/XxVg_s8xAms" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/XxVg_s8xAms" frameborder="0" allowfullscreen></iframe>
 
 By [Tom Occhino](http://tomocchino.com/), [Jordan Walke](https://github.com/jordwalke)
 
 * * *
 
 ### Backbone + React + Middleman Screencast
-<iframe width="650" height="488" src="https://www.youtube-nocookie.com/embed/iul1fWHVU6A" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="488" src="https://www.youtube-nocookie.com/embed/iul1fWHVU6A" frameborder="0" allowfullscreen></iframe>
 
 Backbone은 React로 REST API를 제공하기 위한 아주 좋은 방법입니다. 이 화면중개는 [Backbone-React-Component](https://github.com/magalhas/backbone-react-component)을 이용해서 어떻게 이 두가지를 연동하는지 보여줍니다. Middleman은 이 예제에서 사용되는 프레임워크이지만, 쉽게 다른 프레임워크로 대체하실 수 있습니다. 지원되는 템플릿은 [이곳](https://github.com/jbhatab/middleman-backbone-react-template)에서 찾으실 수 있습니다. -- [열린 마음의 혁명들](http://www.openmindedinnovations.com/)
 
@@ -116,7 +116,7 @@ Backbone은 React로 REST API를 제공하기 위한 아주 좋은 방법입니
 
 ### Developing User Interfaces With React - Super VanJS
 
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/1OeXsL5mr4g" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/1OeXsL5mr4g" frameborder="0" allowfullscreen></iframe>
 
 By [Steven Luscher](https://github.com/steveluscher)
 
@@ -124,7 +124,7 @@ By [Steven Luscher](https://github.com/steveluscher)
 
 ### Introduction to React - LAWebSpeed meetup
 
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/SMMRJif5QW0" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/SMMRJif5QW0" frameborder="0" allowfullscreen></iframe>
 
 by [Stoyan Stefanov](http://www.phpied.com/)
 
@@ -132,7 +132,7 @@ by [Stoyan Stefanov](http://www.phpied.com/)
 
 ### React, or how to make life simpler - FrontEnd Dev Conf '14
 
-<iframe width="560" height="366" src="https://www.youtube-nocookie.com/embed/YJNUK0EA_Jo" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/YJNUK0EA_Jo" frameborder="0" allowfullscreen></iframe>
 
 **러시아어** by [Alexander Solovyov](http://solovyov.net/)
 
@@ -140,19 +140,19 @@ by [Stoyan Stefanov](http://www.phpied.com/)
 
 ### "Functional DOM programming" - Meteor DevShop 11
 
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/qqVbr_LaCIo" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/qqVbr_LaCIo" frameborder="0" allowfullscreen></iframe>
 
 * * *
 
 ### "Rethinking Web App Development at Facebook" - Facebook F8 Conference 2014
 
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/nYkdrAPrdcw" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/nYkdrAPrdcw" frameborder="0" allowfullscreen></iframe>
 
 * * *
 
 ### React and Flux: Building Applications with a Unidirectional Data Flow - Forward JS 2014
 
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/i__969noyAM" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/i__969noyAM" frameborder="0" allowfullscreen></iframe>
 
 Facebook 개발자 [Bill Fisher](https://twitter.com/fisherwebdev)와 [Jing Chen](https://twitter.com/jingc)가 Flux 와 React 에 대해서 이야기합니다. 그리고 어떻게 단일 방향의 자료흐름을 사용하는 어플리케이션 구조가 방대한 코드를 정리하는지에 대해서 이야기합니다."
 
@@ -160,7 +160,7 @@ Facebook 개발자 [Bill Fisher](https://twitter.com/fisherwebdev)와 [Jing Chen
 
 ### Server-Side Rendering of Isomorphic Apps at SoundCloud
 
-<iframe src="https://player.vimeo.com/video/108488724" width="650" height="365" frameborder="0" allowfullscreen></iframe>
+<iframe src="https://player.vimeo.com/video/108488724" width="100%" height="365" frameborder="0" allowfullscreen></iframe>
 
 Server-side rendering을 위해 [SoundCloud](https://developers.soundcloud.com/blog/)가 React 와 Flux를 사용하는지 by [Andres Suarez](https://github.com/zertosh)
 [발표 자료와 예제 코드](https://github.com/zertosh/ssr-demo-kit)
@@ -169,6 +169,6 @@ Server-side rendering을 위해 [SoundCloud](https://developers.soundcloud.com/b
 
 ### Introducing React Native (+Playlist) - React.js Conf 2015
 
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/v/KVZ-P-ZI6W4&index=1&list=PLb0IAmt7-GS1cbw4qonlQztYV1TAW0sCr" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/v/KVZ-P-ZI6W4&index=1&list=PLb0IAmt7-GS1cbw4qonlQztYV1TAW0sCr" frameborder="0" allowfullscreen></iframe>
 
 2015년에 [Tom Occhino](https://twitter.com/tomocchino)님이 React의 과거와 현재를 리뷰하고 나아갈 방향을 제시했습니다.
diff --git a/docs/community/videos.md b/docs/community/videos.md
new file mode 100644
index 000000000000..513a32da99e5
--- /dev/null
+++ b/docs/community/videos.md
@@ -0,0 +1,174 @@
+---
+id: videos
+title: Videos
+layout: community
+sectionid: community
+permalink: community/videos.html
+redirect_from: "docs/videos.html"
+---
+
+### Introduction to React
+
+[Tom Occhino](http://tomocchino.com/) and [Jordan Walke](https://github.com/jordwalke) introduce React at Facebook Seattle.
+
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/XxVg_s8xAms" frameborder="0" allowfullscreen></iframe>
+
+### Introducing React Native
+
+[Tom Occhino](https://twitter.com/tomocchino) reviews the past and present of React in 2015, and teases where it's going next.
+
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/KVZ-P-ZI6W4?list=PLb0IAmt7-GS1cbw4qonlQztYV1TAW0sCr" frameborder="0" allowfullscreen></iframe>
+
+### Rethinking Web App Development at Facebook
+
+Delivering reliable, high-performance web experiences at Facebook's scale has required us to challenge some long-held assumptions about software development. Watch this Facebook F8 2014 talk to learn how we abandoned the traditional MVC paradigm in favor of a more functional application architecture.
+
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/nYkdrAPrdcw" frameborder="0" allowfullscreen></iframe>
+
+### Secrets of the Virtual DOM
+
+[Pete Hunt](http://www.petehunt.net/) at Mountain West JavaScript 2014 discusses why a virtual DOM was built for React, how it compares to other systems, and its relevance to the future of browser technologies.
+
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/h3KksH8gfcQ" frameborder="0" allowfullscreen></iframe>
+
+### Rethinking Best Practices
+
+[Pete Hunt](http://www.petehunt.net/)'s talk at JSConf EU 2013 covers three topics: throwing out the notion of templates and building views with JavaScript, “re-rendering” your entire application when your data changes, and a lightweight implementation of the DOM and events.
+
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/x7cQ3mrcKaY" frameborder="0" allowfullscreen></iframe>
+
+
+### High performance functional DOM programming
+
+Tech Talk by [Pete Hunt](http://www.petehunt.net/) at Meteor DevShop 11.
+
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/qqVbr_LaCIo" frameborder="0" allowfullscreen></iframe>
+
+
+### Developing User Interfaces With React
+
+[Steven Luscher](https://github.com/steveluscher) at Super VanJS 2013.
+
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/1OeXsL5mr4g" frameborder="0" allowfullscreen></iframe>
+
+
+### Introduction to React
+
+[Stoyan Stefanov](http://www.phpied.com/) at LAWebSpeed meetup.
+
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/SMMRJif5QW0" frameborder="0" allowfullscreen></iframe>
+
+### Going big with React
+
+Areeb Malik investigates how React performs in a high stress situation, and how it helped his team build safe code on a massive scale.
+
+[![](https://i.vimeocdn.com/video/481670116_650.jpg)](https://skillsmatter.com/skillscasts/5429-going-big-with-react#video)
+
+### Backbone + React + Middleman Screencast
+
+This screencast shows how to integrate Backbone with React using [Backbone-React-Component](https://github.com/magalhas/backbone-react-component).
+
+<iframe width="100%" height="488" src="https://www.youtube-nocookie.com/embed/iul1fWHVU6A" frameborder="0" allowfullscreen></iframe>
+
+### React, or how to make life simpler
+
+Tech talk by [Alexander Solovyov](http://solovyov.net/) at FrontEnd Dev Conf '14 (Russian).
+
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/YJNUK0EA_Jo" frameborder="0" allowfullscreen></iframe>
+
+
+### React and Flux: Building Applications with a Unidirectional Data Flow
+
+Facebook engineers [Bill Fisher](https://twitter.com/fisherwebdev) and [Jing Chen](https://twitter.com/jingc) talk about Flux and React at Forward JS 2014, and how using an application architecture with a unidirectional data flow cleans up a lot of their code.
+
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/i__969noyAM" frameborder="0" allowfullscreen></iframe>
+
+> [Slides and sample code](https://github.com/zertosh/ssr-demo-kit)
+
+### CodeWinds Podcast
+
+[Pete Hunt](http://www.petehunt.net/) talked with [Jeff Barczewski](http://jeff.barczewski.com/) about React in [CodeWinds Episode 4](http://codewinds.com/podcast/004.html).
+<figure>[![](/react/img/docs/codewinds-004.png)](http://codewinds.com/4)</figure>
+
+<table width="100%">
+<tr>
+<th>02:08</th><td>What is React and why use it?</td>
+<th>27:17</th><td>Rendering HTML on the server with Node.js. Rendering backends</td>
+</tr>
+<tr>
+<th>03:08</th><td>The symbiotic relationship of ClojureScript and React</td>
+<th>29:20</th><td>React evolved through survival of the fittest at Facebook</td>
+</tr>
+<tr>
+<th>04:54</th><td>The history of React and why it was created</td>
+<th>30:15</th><td>Ideas for having state on server and client, using web sockets.</td>
+</tr>
+<tr>
+<th>09:43</th><td>Updating web page with React without using data binding</td>
+<th>32:05</th><td>React-multiuser - distributed shared mutable state using Firebase</td>
+</tr>
+<tr>
+<th>13:11</th><td>Using the virtual DOM to change the browser DOM</td>
+<th>33:03</th><td>Better debugging with React using the state transitions, replaying events</td>
+</tr>
+<tr>
+<th>13:57</th><td>Programming with React, render targets HTML, canvas, other</td>
+<th>34:08</th><td>Differences from Web Components</td>
+</tr>
+<tr>
+<th>16:45</th><td>Working with designers. Contrasted with Ember and AngularJS</td>
+<th>34:25</th><td>Notable companies using React</td>
+</tr>
+<tr>
+<th>21:45</th><td>JSX Compiler bridging HTML and React javascript</td>
+<th>35:16</th><td>Could a React backend plugin be created to target PDF?</td>
+</tr>
+<tr>
+<th>23:50</th><td>Autobuilding JSX and in browser tools for React</td>
+<th>36:30</th><td>Future of React, what's next?</td>
+</tr>
+<tr>
+<th>24:50</th><td>Tips and tricks to working with React, getting started</td>
+<th>39:38</th><td>Contributing and getting help</td>
+</tr>
+</table>
+
+### JavaScript Jabber Podcast
+
+[Pete Hunt](http://www.petehunt.net/) and [Jordan Walke](https://github.com/jordwalke) talked about React in [JavaScript Jabber 73](https://devchat.tv/js-jabber/073-jsj-react-with-pete-hunt-and-jordan-walke).
+<figure>[![](/react/img/docs/javascript-jabber.png)](http://javascriptjabber.com/073-jsj-react-with-pete-hunt-and-jordan-walke/#content)</figure>
+
+<table width="100%">
+  <tr>
+    <th>01:34</th><td>Pete Hunt Introduction</td>
+    <th>23:06</th><td>Supporting Node.js</td>
+  </tr>
+  <tr>
+    <th>02:45</th><td>Jordan Walke Introduction</td>
+    <th>24:03</th><td>rendr</td>
+  </tr>
+  <tr>
+    <th>04:15</th><td>React</td>
+    <th>26:02</th><td>JSX</td>
+  </tr>
+  <tr>
+    <th>06:38</th><td>60 Frames Per Second</td>
+    <th>30:31</th><td>requestAnimationFrame</td>
+  </tr>
+  <tr>
+    <th>09:34</th><td>Data Binding</td>
+    <th>34:15</th><td>React and Applications</td>
+  </tr>
+  <tr>
+    <th>12:31</th><td>Performance</td>
+    <th>38:12</th><td>React Users Khan Academy</td>
+  </tr>
+  <tr>
+    <th>17:39</th><td>Diffing Algorithm</td>
+    <th>39:53</th><td>Making it work</td>
+  </tr>
+  <tr>
+    <th>19:36</th><td>DOM Manipulation</td>
+    <th></th><td></td>
+  </tr>
+</table>
diff --git a/docs/docs/videos.zh-CN.md b/docs/community/videos.zh-CN.md
similarity index 77%
rename from docs/docs/videos.zh-CN.md
rename to docs/community/videos.zh-CN.md
index 60f92881307b..8e571e52dc9b 100644
--- a/docs/docs/videos.zh-CN.md
+++ b/docs/community/videos.zh-CN.md
@@ -1,14 +1,14 @@
 ---
 id: videos-zh-CN
 title: 视频
-permalink: videos-zh-CN.html
+permalink: docs/videos-zh-CN.html
 prev: conferences-zh-CN.html
 next: complementary-tools-zh-CN.html
 ---
 
 ### Rethinking best practices - JSConf.eu
 
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/x7cQ3mrcKaY" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/x7cQ3mrcKaY" frameborder="0" allowfullscreen></iframe>
 
 "在 Facebook 和 Instagram, 我们正在努力挑战React在web上能达到的极限。我的讲话会从对框架的简单介绍开始，然后深入三个有争议的话题：扔掉模板的概念并用JavaScript构建views, 当数据改变 “re-rendering” 你的整个应用，以及一个DOM和events的轻量级实现。" -- [Pete Hunt](http://www.petehunt.net/)
 
@@ -23,7 +23,7 @@ next: complementary-tools-zh-CN.html
 
 ### Secrets of the Virtual DOM - MtnWest JS
 
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/h3KksH8gfcQ" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/h3KksH8gfcQ" frameborder="0" allowfullscreen></iframe>
 
 "在这次讲座里，我会讨论为什么我们构建了一个虚拟 DOM，它比起其他系统如何，以及它与未来浏览器技术的关系。" -- [Pete Hunt](http://www.petehunt.net/)
 
@@ -99,14 +99,14 @@ next: complementary-tools-zh-CN.html
 
 ### Introduction to React.js - Facebook Seattle
 
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/XxVg_s8xAms" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/XxVg_s8xAms" frameborder="0" allowfullscreen></iframe>
 
 由 [Tom Occhino](http://tomocchino.com/) 和 [Jordan Walke](https://github.com/jordwalke)
 
 * * *
 
 ### Backbone + React + Middleman Screencast
-<iframe width="650" height="488" src="https://www.youtube-nocookie.com/embed/iul1fWHVU6A" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="488" src="https://www.youtube-nocookie.com/embed/iul1fWHVU6A" frameborder="0" allowfullscreen></iframe>
 
 Backbone 是一个在用React实现 REST API 接口的极好方法。这个屏博展示了用 [Backbone-React-Component](https://github.com/magalhas/backbone-react-component)如何整合两者. Middleman 是在本例中使用的框架但很容易被替换成其他框架。对此可支持的template可以在[这里](https://github.com/jbhatab/middleman-backbone-react-template) 找到. -- [Open Minded Innovations](http://www.openmindedinnovations.com/)
 
@@ -114,7 +114,7 @@ Backbone 是一个在用React实现 REST API 接口的极好方法。这个屏
 
 ### Developing User Interfaces With React - Super VanJS
 
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/1OeXsL5mr4g" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/1OeXsL5mr4g" frameborder="0" allowfullscreen></iframe>
 
 来自 [Steven Luscher](https://github.com/steveluscher)
 
@@ -122,7 +122,7 @@ Backbone 是一个在用React实现 REST API 接口的极好方法。这个屏
 
 ### Introduction to React - LAWebSpeed meetup
 
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/SMMRJif5QW0" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/SMMRJif5QW0" frameborder="0" allowfullscreen></iframe>
 
 来自 [Stoyan Stefanov](http://www.phpied.com/)
 
@@ -130,7 +130,7 @@ Backbone 是一个在用React实现 REST API 接口的极好方法。这个屏
 
 ### React, or how to make life simpler - FrontEnd Dev Conf '14
 
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/YJNUK0EA_Jo" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/YJNUK0EA_Jo" frameborder="0" allowfullscreen></iframe>
 
 **俄语** by [Alexander Solovyov](http://solovyov.net/)
 
@@ -138,19 +138,19 @@ Backbone 是一个在用React实现 REST API 接口的极好方法。这个屏
 
 ### "Functional DOM programming" - Meteor DevShop 11
 
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/qqVbr_LaCIo" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/qqVbr_LaCIo" frameborder="0" allowfullscreen></iframe>
 
 * * *
 
 ### "Rethinking Web App Development at Facebook" - Facebook F8 Conference 2014
 
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/nYkdrAPrdcw" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/nYkdrAPrdcw" frameborder="0" allowfullscreen></iframe>
 
 * * *
 
 ### React and Flux: Building Applications with a Unidirectional Data Flow - Forward JS 2014
 
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/i__969noyAM" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/i__969noyAM" frameborder="0" allowfullscreen></iframe>
 
 Facebook 工程师 [Bill Fisher](https://twitter.com/fisherwebdev) 和 [Jing Chen](https://twitter.com/jingc) 谈论 Flux 和 React, 以及如何使用单向数据流的程序架构清理他们的代码 .
 
@@ -158,7 +158,7 @@ Facebook 工程师 [Bill Fisher](https://twitter.com/fisherwebdev) 和 [Jing Che
 
 ### Server-Side Rendering of Isomorphic Apps at SoundCloud
 
-<iframe src="https://player.vimeo.com/video/108488724" width="650" height="365" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
+<iframe src="https://player.vimeo.com/video/108488724" width="100%" height="365" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
 
 来自 [Andres Suarez](https://github.com/zertosh) 的演练，关于 [SoundCloud](https://developers.soundcloud.com/blog/) 如何使用 React 和 Flux 在服务器端渲染.
 
@@ -168,6 +168,6 @@ Facebook 工程师 [Bill Fisher](https://twitter.com/fisherwebdev) 和 [Jing Che
 
 ### Introducing React Native (+Playlist) - React.js Conf 2015
 
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/KVZ-P-ZI6W4?list=PLb0IAmt7-GS1cbw4qonlQztYV1TAW0sCr" frameborder="0" allowfullscreen></iframe>
+<iframe width="100%" height="366" src="https://www.youtube-nocookie.com/embed/KVZ-P-ZI6W4?list=PLb0IAmt7-GS1cbw4qonlQztYV1TAW0sCr" frameborder="0" allowfullscreen></iframe>
 
 [Tom Occhino](https://twitter.com/tomocchino) 回顾了React的过去和现在，在2015年。梳理了下一步要做什么。
diff --git a/docs/contributing/codebase-overview.md b/docs/contributing/codebase-overview.md
new file mode 100644
index 000000000000..f0978e5bca04
--- /dev/null
+++ b/docs/contributing/codebase-overview.md
@@ -0,0 +1,404 @@
+---
+id: codebase-overview
+title: Codebase Overview
+layout: contributing
+permalink: contributing/codebase-overview.html
+prev: how-to-contribute.html
+next: implementation-notes.html
+---
+
+This section will give you an overview of the React codebase organization, its conventions, and the implementation.
+
+If you want to [contribute to React](/react/contributing/how-to-contribute.html) we hope that this guide will help you feel more comfortable making changes.
+
+We don't necessarily recommend any of these conventions in React apps. Many of them exist for historical reasons and might change with time.
+
+### Custom Module System
+
+At Facebook, internally we use a custom module system called "Haste". It is similar to [CommonJS](https://nodejs.org/docs/latest/api/modules.html) and also uses `require()` but has a few important differences that often confuse outside contributors.
+
+In CommonJS, when you import a module, you need to specify its relative path:
+
+```js
+// Importing from the same folder:
+var setInnerHTML = require('./setInnerHTML');
+
+// Importing from a different folder:
+var setInnerHTML = require('../utils/setInnerHTML');
+
+// Importing from a deeply nested folder:
+var setInnerHTML = require('../client/utils/setInnerHTML');
+```
+
+However, with Haste **all filenames are globally unique.** In the React codebase, you can import any module from any other module by its name alone:
+
+```js
+var setInnerHTML = require('setInnerHTML');
+```
+
+Haste was originally developed for giant apps like Facebook. It's easy to move files to different folders and import them without worrying about relative paths. The fuzzy file search in any editor always takes you to the correct place thanks to globally unique names.
+
+React itself was extracted from Facebook's codebase and uses Haste for historical reasons. In the future, we will probably [migrate React to use CommonJS or ES Modules](https://github.com/facebook/react/issues/6336) to be more aligned with the community. However, this requires changes in Facebook's internal infrastructure so it is unlikely to happen very soon.
+
+**Haste will make more sense to you if you remember a few rules:**
+
+* All filenames in the React source code are unique. This is why they're sometimes verbose.
+* When you add a new file, make sure you include a [license header](https://github.com/facebook/react/blob/87724bd87506325fcaf2648c70fc1f43411a87be/src/renderers/dom/client/utils/setInnerHTML.js#L1-L10). You can copy it from any existing file. A license header always includes [a line like this](https://github.com/facebook/react/blob/87724bd87506325fcaf2648c70fc1f43411a87be/src/renderers/dom/client/utils/setInnerHTML.js#L9). Change it to match the name of the file you created.
+* Don’t use relative paths when importing. Instead of `require('./setInnerHTML')`, write `require('setInnerHTML')`.
+
+When we compile React for npm, a script copies all the modules into [a single flat directory called `lib`](https://unpkg.com/react@15/lib/) and prepends all `require()` paths with `./`. This way Node, Browserify, webpack, and other tools can understand React build output without being aware of Haste.
+
+**If you're reading React source on GitHub and want to jump to a file, press "t".**
+
+This is a GitHub shortcut for searching the current repo for fuzzy filename matches. Start typing the name of the file you are looking for, and it will show up as the first match.
+
+### External Dependencies
+
+React has almost no external dependencies. Usually, a `require()` points to a file in React's own codebase. However, there are a few relatively rare exceptions.
+
+If you see a `require()` that does not correspond to a file in the React repository, you can look in a special repository called [fbjs](https://github.com/facebook/fbjs). For example, `require('warning')` will resolve to the [`warning` module from fbjs](https://github.com/facebook/fbjs/blob/df9047fec0bbd1e64635ae369c045975777cba7c/packages/fbjs/src/__forks__/warning.js).
+
+The [fbjs repository](https://github.com/facebook/fbjs) exists because React shares some small utilities with libraries like [Relay](https://github.com/facebook/relay), and we keep them in sync. We don't depend on equivalent small modules in the Node ecosystem because we want Facebook engineers to be able to make changes to them whenever necessary. None of the utilities inside fbjs are considered to be public API, and they are only intended for use by Facebook projects such as React.
+
+### Top-Level Folders
+
+After cloning the [React repository](https://github.com/facebook/react), you will see a few top-level folders in it:
+
+* [`src`](https://github.com/facebook/react/tree/master/src) is the source code of React. **If your change is related to the code, `src` is where you'll spend most of your time.**
+* [`docs`](https://github.com/facebook/react/tree/master/docs) is the React documentation website. When you change APIs, make sure to update the relevant Markdown files.
+* [`fixtures`](https://github.com/facebook/react/tree/master/fixtures) contains a few small React test applications for contributors.
+* [`packages`](https://github.com/facebook/react/tree/master/packages) contains metadata (such as `package.json`) for all packages in the React repository. Nevertheless, their source code is still located inside [`src`](https://github.com/facebook/react/tree/master/src).
+* `build` is the build output of React. It is not in the repository but it will appear in your React clone after you [build it](/react/contributing/how-to-contribute.html#development-workflow) for the first time.
+
+There are a few other top-level folders but they are mostly used for the tooling and you likely won't ever encounter them when contributing.
+
+### Colocated Tests
+
+We don't have a top-level directory for unit tests. Instead, we put them into a directory called `__tests__` relative to the files that they test.
+
+For example, a test for [`setInnerHTML.js`](https://github.com/facebook/react/blob/87724bd87506325fcaf2648c70fc1f43411a87be/src/renderers/dom/client/utils/setInnerHTML.js) is located in [`__tests__/setInnerHTML-test.js`](https://github.com/facebook/react/blob/87724bd87506325fcaf2648c70fc1f43411a87be/src/renderers/dom/client/utils/__tests__/setInnerHTML-test.js) right next to it.
+
+### Shared Code
+
+Even though Haste allows us to import any module from anywhere in the repository, we follow a convention to avoid cyclic dependencies and other unpleasant surprises. By convention, a file may only import files in the same folder or in subfolders below.
+
+For example, files inside [`src/renderers/dom/stack/client`](https://github.com/facebook/react/blob/f53854424b33692907234fe7a1f80b888fd80751/src/renderers/dom/stack/client) may import other files in the same folder or any folder below.
+
+However they can't import modules from [`src/renderers/dom/stack/server`](https://github.com/facebook/react/blob/f53854424b33692907234fe7a1f80b888fd80751/src/renderers/dom/stack/server) because it is not a child directory of [`src/renderers/dom/stack/client`](https://github.com/facebook/react/blob/f53854424b33692907234fe7a1f80b888fd80751/src/renderers/dom/stack/client).
+
+There is an exception to this rule. Sometimes we *do* need to share functionality between two groups of modules. In this case, we hoist the shared module up to a folder called `shared` inside the closest common ancestor folder of the modules that need to rely on it.
+
+For example, code shared between [`src/renderers/dom/stack/client`](https://github.com/facebook/react/blob/f53854424b33692907234fe7a1f80b888fd80751/src/renderers/dom/stack/client) and [`src/renderers/dom/stack/server`](https://github.com/facebook/react/blob/f53854424b33692907234fe7a1f80b888fd80751/src/renderers/dom/stack/server) lives in [`src/renderers/dom/shared`](https://github.com/facebook/react/blob/f53854424b33692907234fe7a1f80b888fd80751/src/renderers/dom/shared).
+
+By the same logic, if [`src/renderers/dom/stack/client`](https://github.com/facebook/react/blob/f53854424b33692907234fe7a1f80b888fd80751/src/renderers/dom/stack/client) needs to share a utility with something in [`src/renderers/native`](https://github.com/facebook/react/blob/f53854424b33692907234fe7a1f80b888fd80751/src/renderers/native), this utility would be in [`src/renderers/shared`](https://github.com/facebook/react/blob/f53854424b33692907234fe7a1f80b888fd80751/src/renderers/shared).
+
+This convention is not enforced but we check for it during a pull request review.
+
+### Warnings and Invariants
+
+The React codebase uses the `warning` module to display warnings:
+
+```js
+var warning = require('warning');
+
+warning(
+  2 + 2 === 4,
+  'Math is not working today.'
+);
+```
+
+**The warning is shown when the `warning` condition is `false`.**
+
+One way to think about it is that the condition should reflect the normal situation rather than the exceptional one.
+
+It is a good idea to avoid spamming the console with duplicate warnings:
+
+```js
+var warning = require('warning');
+
+var didWarnAboutMath = false;
+if (!didWarnAboutMath) {
+  warning(
+    2 + 2 === 4,
+    'Math is not working today.'
+  );
+  didWarnAboutMath = true;
+}
+```
+
+Warnings are only enabled in development. In production, they are completely stripped out. If you need to forbid some code path from executing, use `invariant` module instead:
+
+```js
+var invariant = require('invariant');
+
+invariant(
+  2 + 2 === 4,
+  'You shall not pass!'
+);
+```
+
+**The invariant is thrown when the `invariant` condition is `false`.**
+
+"Invariant" is just a way of saying "this condition always holds true". You can think about it as making an assertion.
+
+It is important to keep development and production behavior similar, so `invariant` throws both in development and in production. The error messages are automatically replaced with error codes in production to avoid negatively affecting the byte size.
+
+### Development and Production
+
+You can use `__DEV__` pseudo-global variable in the codebase to guard development-only blocks of code.
+
+It is inlined during the compile step, and turns into `process.env.NODE_ENV !== 'production'` checks in the CommonJS builds.
+
+For standalone builds, it becomes `true` in the unminified build, and gets completely stripped out with the `if` blocks it guards in the minified build.
+
+```js
+if (__DEV__) {
+  // This code will only run in development.
+}
+```
+
+### JSDoc
+
+Some of the internal and public methods are annotated with [JSDoc annotations](http://usejsdoc.org/):
+
+```js
+/**
+  * Updates this component by updating the text content.
+  *
+  * @param {ReactText} nextText The next text content
+  * @param {ReactReconcileTransaction} transaction
+  * @internal
+  */
+receiveComponent: function(nextText, transaction) {
+  // ...
+},
+```
+
+We try to keep existing annotations up-to-date but we don't enforce them. We don't use JSDoc in the newly written code, and instead use Flow to document and enforce types.
+
+### Flow
+
+We recently started introducing [Flow](https://flowtype.org/) checks to the codebase. Files marked with the `@flow` annotation in the license header comment are being typechecked.
+
+We accept pull requests [adding Flow annotations to existing code](https://github.com/facebook/react/pull/7600/files). Flow annotations look like this:
+
+```js
+ReactRef.detachRefs = function(
+  instance: ReactInstance,
+  element: ReactElement | string | number | null | false,
+): void {
+  // ...
+}
+```
+
+When possible, new code should use Flow annotations.
+You can run `npm run flow` locally to check your code with Flow.
+
+### Classes and Mixins
+
+React was originally written in ES5. We have since enabled ES6 features with [Babel](http://babeljs.io/), including classes. However, most of React code is still written in ES5.
+
+In particular, you might see the following pattern quite often:
+
+```js
+// Constructor
+function ReactDOMComponent(element) {
+  this._currentElement = element;
+}
+
+// Methods
+ReactDOMComponent.Mixin = {
+  mountComponent: function() {
+    // ...
+  }
+};
+
+// Put methods on the prototype
+Object.assign(
+  ReactDOMComponent.prototype,
+  ReactDOMComponent.Mixin
+);
+
+module.exports = ReactDOMComponent;
+```
+
+The `Mixin` in this code has no relation to React `mixins` feature. It is just a way of grouping a few methods under an object. Those methods may later get attached to some other class. We use this pattern in a few places although we try to avoid it in the new code.
+
+The equivalent code in ES6 would look like this:
+
+```js
+class ReactDOMComponent {
+  constructor(element) {
+    this._currentElement = element;
+  }
+
+  mountComponent() {
+    // ...
+  }
+}
+
+module.exports = ReactDOMComponent;
+```
+
+Sometimes we [convert old code to ES6 classes](https://github.com/facebook/react/pull/7647/files). However, this is not very important to us because there is an [ongoing effort](#fiber-reconciler) to replace the React reconciler implementation with a less object-oriented approach which wouldn't use classes at all.
+
+### Dynamic Injection
+
+React uses dynamic injection in some modules. While it is always explicit, it is still unfortunate because it hinders understanding of the code. The main reason it exists is because React originally only supported DOM as a target. React Native started as a React fork. We had to add dynamic injection to let React Native override some behaviors.
+
+You may see modules declaring their dynamic dependencies like this:
+
+```js
+// Dynamically injected
+var textComponentClass = null;
+
+// Relies on dynamically injected value
+function createInstanceForText(text) {
+  return new textComponentClass(text);
+}
+
+var ReactHostComponent = {
+  createInstanceForText,
+
+  // Provides an opportunity for dynamic injection
+  injection: {
+    injectTextComponentClass: function(componentClass) {
+      textComponentClass = componentClass;
+    },
+  },
+};
+
+module.exports = ReactHostComponent;
+```
+
+The `injection` field is not handled specially in any way. But by convention, it means that this module wants to have some (presumably platform-specific) dependencies injected into it at runtime.
+
+In React DOM, [`ReactDefaultInjection`](https://github.com/facebook/react/blob/4f345e021a6bd9105f09f3aee6d8762eaa9db3ec/src/renderers/dom/shared/ReactDefaultInjection.js) injects a DOM-specific implementation:
+
+```js
+ReactHostComponent.injection.injectTextComponentClass(ReactDOMTextComponent);
+```
+
+In React Native, [`ReactNativeDefaultInjection`](https://github.com/facebook/react/blob/4f345e021a6bd9105f09f3aee6d8762eaa9db3ec/src/renderers/native/ReactNativeDefaultInjection.js) injects its own implementation:
+
+```js
+ReactHostComponent.injection.injectTextComponentClass(ReactNativeTextComponent);
+```
+
+There are multiple injection points in the codebase. In the future, we intend to get rid of the dynamic injection mechanism and wire up all the pieces statically during the build.
+
+### Multiple Packages
+
+React is a [monorepo](http://danluu.com/monorepo/). Its repository contains multiple separate packages so that their changes can be coordinated together, and documentation and issues live in one place.
+
+The npm metadata such as `package.json` files is located in the [`packages`](https://github.com/facebook/react/tree/master/packages) top-level folder. However, there is almost no real code in it.
+
+For example, [`packages/react/react.js`](https://github.com/facebook/react/blob/87724bd87506325fcaf2648c70fc1f43411a87be/packages/react/react.js) re-exports [`src/isomorphic/React.js`](https://github.com/facebook/react/blob/87724bd87506325fcaf2648c70fc1f43411a87be/src/isomorphic/React.js), the real npm entry point. Other packages mostly repeat this pattern. All the important code lives in [`src`](https://github.com/facebook/react/tree/master/src).
+
+While the code is separated in the source tree, the exact package boundaries are slightly different for npm packages and standalone browser builds.
+
+### React Core
+
+The "core" of React includes all the [top-level `React` APIs](/react/docs/top-level-api.html#react), for example:
+
+* `React.createElement()`
+* `React.Component`
+* `React.Children`
+
+**React core only includes the APIs necessary to define components.** It does not include the [reconciliation](/react/docs/reconciliation.html) algorithm or any platform-specific code. It is used both by React DOM and React Native components.
+
+The code for React core is located in [`src/isomorphic`](https://github.com/facebook/react/tree/master/src/isomorphic) in the source tree. It is available on npm as the [`react`](https://www.npmjs.com/package/react) package. The corresponding standalone browser build is called `react.js`, and it exports a global called `React`.
+
+>**Note:**
+>
+>Until very recently, `react` npm package and `react.js` standalone build contained all React code (including React DOM) rather than just the core. This was done for backward compatibility and historical reasons. Since React 15.4.0, the core is better separated in the build output.
+>
+>There is also an additional standalone browser build called `react-with-addons.js` which we will consider separately further below.
+
+### Renderers
+
+React was originally created for the DOM but it was later adapted to also support native platforms with [React Native](http://facebook.github.io/react-native/). This introduced the concept of "renderers" to React internals.
+
+**Renderers manage how a React tree turns into the underlying platform calls.**
+
+Renderers are located in [`src/renderers`](https://github.com/facebook/react/tree/master/src/renderers/):
+
+* [React DOM Renderer](https://github.com/facebook/react/tree/master/src/renderers/dom) renders React components to the DOM. It implements [top-level `ReactDOM` APIs](/react/docs/top-level-api.html#reactdom) and is available as [`react-dom`](https://www.npmjs.com/package/react-dom) npm package. It can also be used as standalone browser bundle called `react-dom.js` that exports a `ReactDOM` global.
+* [React Native Renderer](https://github.com/facebook/react/tree/master/src/renderers/native) renders React components to native views. It is used internally by React Native via [`react-native-renderer`](https://www.npmjs.com/package/react-native-renderer) npm package. In the future a copy of it may get checked into the React Native [repository](https://github.com/facebook/react-native) so that React Native can update React at its own pace.
+* [React Test Renderer](https://github.com/facebook/react/tree/master/src/renderers/testing) renders React components to JSON trees. It is used by the [Snapshot Testing](https://facebook.github.io/jest/blog/2016/07/27/jest-14.html) feature of [Jest](https://facebook.github.io/jest) and is available as [react-test-renderer](https://www.npmjs.com/package/react-test-renderer) npm package.
+
+The only other officially supported renderer is [`react-art`](https://github.com/reactjs/react-art). To avoid accidentally breaking it as we make changes to React, we checked it in as [`src/renderers/art`](https://github.com/facebook/react/tree/master/src/renderers/art) and run its test suite. Nevertheless, its [GitHub repository](https://github.com/reactjs/react-art) still acts as the source of truth.
+
+While it is [technically possible](https://github.com/iamdustan/tiny-react-renderer) to create custom React renderers, this is currently not officially supported. There is no stable public contract for custom renderers yet which is another reason why we keep them all in a single place.
+
+>**Note:**
+>
+>Technically the [`native`](https://github.com/facebook/react/tree/master/src/renderers/native) renderer is a very thin layer that teaches React to interact with React Native implementation. The real platform-specific code managing the native views lives in the [React Native repository](https://github.com/facebook/react-native) together with its components.
+
+### Reconcilers
+
+Even vastly different renderers like React DOM and React Native need to share a lot of logic. In particular, the [reconciliation](/react/docs/reconciliation.html) algorithm should be as similar as possible so that declarative rendering, custom components, state, lifecycle methods, and refs work consistently across platforms.
+
+To solve this, different renderers share some code between them. We call this part of React a "reconciler". When an update such as `setState()` is scheduled, the reconciler calls `render()` on components in the tree and mounts, updates, or unmounts them.
+
+Reconcilers are not packaged separately because they currently have no public API. Instead, they are exclusively used by renderers such as React DOM and React Native.
+
+### Stack Reconciler
+
+The "stack" reconciler is the one powering all React production code today. It is located in [`src/renderers/shared/stack/reconciler`](https://github.com/facebook/react/tree/master/src/renderers/shared/stack) and is used by both React DOM and React Native.
+
+It is written in an [object-oriented way](https://en.wikipedia.org/wiki/Composite_pattern) and maintains a separate tree of "internal instances" for all React components. The internal instances exist both for user-defined ("composite") and platform-specific ("host") components. The internal instances are inaccessible directly to the user, and their tree is never exposed.
+
+When a component mounts, updates, or unmounts, the stack reconciler calls a method on that internal instance. The methods are called `mountComponent(element)`, `receiveComponent(nextElement)`, and `unmountComponent(element)`.
+
+#### Host Components
+
+Platform-specific ("host") components, such as `<div>` or a `<View>`, run platform-specific code. For example, React DOM instructs the stack reconciler to use [`ReactDOMComponent`](https://github.com/facebook/react/blob/87724bd87506325fcaf2648c70fc1f43411a87be/src/renderers/dom/shared/ReactDOMComponent.js) to handle [mounting](https://github.com/facebook/react/blob/87724bd87506325fcaf2648c70fc1f43411a87be/src/renderers/dom/shared/ReactDOMComponent.js#L517), [updates](https://github.com/facebook/react/blob/87724bd87506325fcaf2648c70fc1f43411a87be/src/renderers/dom/shared/ReactDOMComponent.js#L865), and [unmounting](https://github.com/facebook/react/blob/87724bd87506325fcaf2648c70fc1f43411a87be/src/renderers/dom/shared/ReactDOMComponent.js#L1140) of DOM components.
+
+Regardless of the platform, both `<div>` and `<View>` handle managing multiple children in a similar way. For convenience, the stack reconciler provides a helper called [`ReactMultiChild`](https://github.com/facebook/react/blob/87724bd87506325fcaf2648c70fc1f43411a87be/src/renderers/shared/stack/reconciler/ReactMultiChild.js) that both DOM and Native renderers [use](https://github.com/facebook/react/blob/87724bd87506325fcaf2648c70fc1f43411a87be/src/renderers/dom/shared/ReactDOMComponent.js#L1203).
+
+#### Composite Components
+
+User-defined ("composite") components should behave the same way with all renderers. This is why the stack reconciler provides a shared implementation in [`ReactCompositeComponent`](https://github.com/facebook/react/blob/87724bd87506325fcaf2648c70fc1f43411a87be/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js). It is always the same regardless of the renderer.
+
+Composite components also implement [mounting](https://github.com/facebook/react/blob/87724bd87506325fcaf2648c70fc1f43411a87be/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js#L181), [updating](https://github.com/facebook/react/blob/87724bd87506325fcaf2648c70fc1f43411a87be/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js#L703), and [unmounting](https://github.com/facebook/react/blob/87724bd87506325fcaf2648c70fc1f43411a87be/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js#L524). However, unlike host components, `ReactCompositeComponent` needs to behave differently depending on the user's code. This is why it calls methods, such as `render()` and `componentDidMount()`, on the user-supplied class.
+
+During an update, `ReactCompositeComponent` checks whether the `render()` output has a different `type` or `key` than the last time. If neither `type` nor `key` has changed, it delegates the update to the existing child internal instance. Otherwise, it unmounts the old child instance and mounts a new one. This is described in the [reconciliation algorithm](/react/docs/reconciliation.html).
+
+#### Recursion
+
+During an update, the stack reconciler "drills down" through composite components, runs their `render()` methods, and decides whether to update or replace their single child instance. It executes platform-specific code as it passes through the host components like `<div>` and `<View>`. Host components may have multiple children which are also processed recursively.
+
+It is important to understand that the stack reconciler always processes the component tree synchronously in a single pass. While individual tree branches may [bail out of reconciliation](/react/docs/advanced-performance.html#avoiding-reconciling-the-dom), the stack reconciler can't pause, and so it is suboptimal when the updates are deep and the available CPU time is limited.
+
+#### Learn More
+
+**The [next section](/react/contributing/implementation-notes.html) describes the current implementation in more details.**
+
+### Fiber Reconciler
+
+The "fiber" reconciler is a new effort aiming to resolve the problems inherent in the stack reconciler and fix a few long-standing issues.
+
+It is a complete rewrite of the reconciler and is currently [in active development](https://github.com/facebook/react/pulls?utf8=%E2%9C%93&q=is%3Apr%20is%3Aopen%20fiber).
+
+Its main goals are:
+
+* Ability to split interruptible work in chunks.
+* Ability to prioritize, rebase and reuse work in progress.
+* Ability to yield back and forth between parents and children to support layout in React.
+* Ability to return multiple elements from `render()`.
+* Better support for error boundaries.
+
+You can read more about it in [React Fiber Architecture](https://github.com/acdlite/react-fiber-architecture). At this moment, it is still very experimental, and far from feature parity with the stack reconciler.
+
+Its source code is located in [`src/renderers/shared/fiber`](https://github.com/facebook/react/tree/master/src/renderers/shared/fiber).
+
+### Event System
+
+React implements a synthetic event system which is agnostic of the renderers and works both with React DOM and React Native. Its source code is located in [`src/renderers/shared/shared/event`](https://github.com/facebook/react/tree/master/src/renderers/shared/shared/event).
+
+There is a [video with a deep code dive into it](https://www.youtube.com/watch?v=dRo_egw7tBc) (66 mins).
+
+### What Next?
+
+Read the [next section](/react/contributing/implementation-notes.html) to learn about the current implementation of reconciler in more detail.
diff --git a/docs/contributing/design-principles.md b/docs/contributing/design-principles.md
new file mode 100644
index 000000000000..20bc3dd7b0c2
--- /dev/null
+++ b/docs/contributing/design-principles.md
@@ -0,0 +1,161 @@
+---
+id: design-principles
+title: Design Principles
+layout: contributing
+permalink: contributing/design-principles.html
+prev: implementation-notes.html
+---
+
+We wrote this document so that you have a better idea of how we decide what React does and what React doesn't do, and what our development philosophy is like. While we are excited to see community contributions, we are not likely to choose a path that violates one or more of these principles.
+
+>**Note:**
+>
+>This document assumes a strong understanding of React. It describes the design principles of *React itself*, not React components or applications.
+>
+>For an introduction to React, check out [Thinking in React](/react/docs/thinking-in-react.html) instead.
+
+### Composition
+
+The key feature of React is composition of components. Components written by different people should work well together. It is important to us that you can add functionality to a component without causing rippling changes throughout the codebase.
+
+For example, it should be possible to introduce some local state into a component without changing any of the components using it. Similarly, it should be possible to add some initialization and teardown code to any component when necessary.
+
+There is nothing "bad" about using state or lifecycle hooks in components. Like any powerful feature, they should be used in moderation, but we have no intention to remove them. On the contrary, we think they are integral parts of what makes React useful. We might enable [more functional patterns](https://github.com/reactjs/react-future/tree/master/07%20-%20Returning%20State) in the future, but both local state and lifecycle hooks will be a part of that model.
+
+Components are often described as "just functions" but in our view they need to be more than that to be useful. In React, components describe any composable behavior, and this includes rendering, lifecycle, and state. Some external libraries like [Relay](http://facebook.github.io/relay/) augment components with other responsibilities such as describing data dependencies. It is possible that those ideas might make it back into React too in some form.
+
+### Common Abstraction
+
+In general we [resist adding features](https://www.youtube.com/watch?v=4anAwXYqLG8) that can be implemented in userland. We don't want to bloat your apps with useless library code. However, there are exceptions to this.
+
+For example, if React didn't provide support for local state or lifecycle hooks, people would create custom abstractions for them. When there are multiple abstractions competing, React can't enforce or take advantage of the properties of either of them. It has to work with the lowest common denominator.
+
+This is why sometimes we add features to React itself. If we notice that many components implement a certain feature in incompatible or inefficient ways, we might prefer to bake it into React. We don't do it lightly. When we do it, it's because we are confident that raising the abstraction level benefits the whole ecosystem. State, lifecycle hooks, cross-browser event normalization are good examples of this.
+
+We always discuss such improvement proposals with the community. You can find some of those discussions by the [“big picture”](https://github.com/facebook/react/issues?q=is%3Aopen+is%3Aissue+label%3A%22big+picture%22) label on the React issue tracker.
+
+### Escape Hatches
+
+React is pragmatic. It is driven by the needs of the products written at Facebook. While it is influenced by some paradigms that are not yet fully mainstream such as functional programming, staying accessible to a wide range of developers with different skills and experience levels is an explicit goal of the project.
+
+If we want to deprecate a pattern that we don't like, it is our responsibility to consider all existing use cases for it and [educate the community about the alternatives](/react/blog/2016/07/13/mixins-considered-harmful.html) before we deprecate it. If some pattern that is useful for building apps is hard to express in a declarative way, we will [provide an imperative API](/react/docs/more-about-refs.html) for it. If we can't figure out a perfect API for something that we found necessary in many apps, we will [provide a temporary subpar working API](/react/docs/context.html) as long as it is possible to get rid of it later and it leaves the door open for future improvements.
+
+### Stability
+
+We value API stability. At Facebook, we have more than 20 thousand components using React. Many other companies, including [Twitter](https://twitter.com/) and [Airbnb](https://www.airbnb.com/), are also heavy users of React. This is why we are usually reluctant to change public APIs or behavior.
+
+However we think stability in the sense of "nothing changes" is overrated. It quickly turns into stagnation. Instead, we prefer the stability in the sense of "It is heavily used in production, and when something changes, there is a clear (and preferably automated) migration path."
+
+When we deprecate a pattern, we study its internal usage at Facebook and add deprecation warnings. They let us assess the impact of the change. Sometimes we back out if we see that it is too early, and we need to think more strategically about getting the codebases to the point where they are ready for this change.
+
+If we are confident that the change is not too disruptive and the migration strategy is viable for all use cases, we release the deprecation warning to the open source community. We are closely in touch with many users of React outside of Facebook, and we monitor popular open source projects and guide them in fixing those deprecations.
+
+Given the sheer size of the Facebook React codebase, successful internal migration is often a good indicator that other companies won't have problems either. Nevertheless sometimes people point out additional use cases we haven't thought of, and we add escape hatches for them or rethink our approach.
+
+We don't deprecate anything without a good reason. We recognize that sometimes deprecations warnings cause frustration but we add them because deprecations clean up the road for the improvements and new features that we and many people in the community consider valuable.
+
+For example, we added a [warning about unknown DOM props](/react/warnings/unknown-prop.html) in React 15.2.0. Many projects were affected by this. However fixing this warning is important so that we can introduce the support for [custom attributes](https://github.com/facebook/react/issues/140) to React. There is a reason like this behind every deprecation that we add.
+
+When we add a deprecation warning, we keep it for the rest of the current major version, and [change the behavior in the next major version](/react/blog/2016/02/19/new-versioning-scheme.html). If there is a lot of repetitive manual work involved, we release a [codemod](https://www.youtube.com/watch?v=d0pOgY8__JM) script that automates most of the change. Codemods enable us to move forward without stagnation in a massive codebase, and we encourage you to use them as well.
+
+You can find the codemods that we released in the [react-codemod](https://github.com/reactjs/react-codemod) repository.
+
+### Interoperability
+
+We place high value in interoperability with existing systems and gradual adoption. Facebook has a massive non-React codebase. Its website uses a mix of a server-side component system called XHP, internal UI libraries that came before React, and React itself. It is important to us that any product team can [start using React for a small feature](https://www.youtube.com/watch?v=BF58ZJ1ZQxY) rather than rewrite their code to bet on it.
+
+This is why React provides escape hatches to work with mutable models, and tries to work well together with other UI libraries. You can wrap an existing imperative UI into a declarative component, and vice versa. This is crucial for gradual adoption.
+
+### Scheduling
+
+Even when your components are described as functions, when you use React you don't call them directly. Every component returns a [description of what needs to be rendered](/react/blog/2015/12/18/react-components-elements-and-instances.html#elements-describe-the-tree), and that description may include both user-written components like `<LikeButton>` and platform-specific components like `<div>`. It is up to React to "unroll" `<LikeButton>` at some point in the future and actually apply changes to the UI tree according to the render results of the components recursively.
+
+This is a subtle distinction but a powerful one. Since you don't call that component function but let React call it, it means React has the power to delay calling it if necessary. In its current implementation React walks the tree recursively and calls render functions of the whole updated tree during a single tick. However in the future it might start [delaying some updates to avoid dropping frames](https://github.com/facebook/react/issues/6170).
+
+This is a common theme in React design. Some popular libraries implement the "push" approach where computations are performed when the new data is available. React, however, sticks to the "pull" approach where computations can be delayed until necessary.
+
+React is not a generic data processing library. It is a library for building user interfaces. We think that it is uniquely positioned in an app to know which computations are relevant right now and which are not.
+
+If something is offscreen, we can delay any logic related to it. If data is arriving faster than the frame rate, we can coalesce and batch updates. We can prioritize work coming from user interactions (such as an animation caused by a button click) over less important background work (such as rendering new content just loaded from the network) to avoid dropping frames.
+
+To be clear, we are not taking advantage of this right now. However the freedom to do something like this is why we prefer to have control over scheduling, and why `setState()` is asynchronous. Conceptually, we think of it as "scheduling an update".
+
+The control over scheduling would be harder for us to gain if we let the user directly compose views with a "push" based paradigm common in some variations of [Functional Reactive Programming](https://en.wikipedia.org/wiki/Functional_reactive_programming). We want to own the "glue" code.
+
+It is a key goal for React that the amount of the user code that executes before yielding back into React is minimal. This ensures that React retains the capability to schedule and split work in chunks according to what it knows about the UI.
+
+There is an internal joke in the team that React should have been called "Schedule" because React does not want to be fully "reactive".
+
+### Developer Experience
+
+Providing a good developer experience is important to us.
+
+For example, we maintain [React DevTools](https://github.com/facebook/react-devtools) which let you inspect the React component tree in Chrome and Firefox. We have heard that it brings a big productivity boost both to the Facebook engineers and to the community.
+
+We also try to go an extra mile to provide helpful developer warnings. For example, React warns you in development if you nest tags in a way that the browser doesn't understand, or if you make a common typo in the API. Developer warnings and the related checks are the main reason why the development version of React is slower than the production version.
+
+The usage patterns that we see internally at Facebook help us understand what the common mistakes are, and how to prevent them early. When we add new features, we try to anticipate the common mistakes and warn about them.
+
+We are always looking out for ways to improve the developer experience. We love to hear your suggestions and accept your contributions to make it even better.
+
+### Debugging
+
+When something goes wrong, it is important that you have breadcrumbs to trace the mistake to its source in the codebase. In React, props and state are those breadcrumbs.
+
+If you see something wrong on the screen, you can open React DevTools, find the component responsible for rendering, and then see if the props and state are correct. If they are, you know that the problem is in the component’s `render()` function, or some function that is called by `render()`. The problem is isolated.
+
+If the state is wrong, you know that the problem is caused by one of the `setState()` calls in this file. This, too, is relatively simple to locate and fix because usually there are only a few `setState()` calls in a single file.
+
+If the props are wrong, you can traverse the tree up in the inspector, looking for the component that first "poisoned the well" by passing bad props down.
+
+This ability to trace any UI to the data that produced it in the form of current props and state is very important to React. It is an explicit design goal that state is not "trapped" in closures and combinators, and is available to React directly.
+
+While the UI is dynamic, we believe that synchronous `render()` functions of props and state turn debugging from guesswork into a boring but finite procedure. We would like to preserve this constraint in React even though it makes some use cases, like complex animations, harder.
+
+### Configuration
+
+We find global runtime configuration options to be problematic.
+
+For example, it is occasionally requested that we implement a function like `React.configure(options)` or `React.register(component)`. However this poses multiple problems, and we are not aware of good solutions to them.
+
+What if somebody calls such a function from a third-party component library? What if one React app embeds another React app, and their desired configurations are incompatible? How can a third-party component specify that it requires a particular configuration? We think that global configuration doesn't work well with composition. Since composition is central to React, we don't provide global configuration in code.
+
+We do, however, provide some global configuration on the build level. For example, we provide separate development and production builds. We may also [add a profiling build](https://github.com/facebook/react/issues/6627) in the future, and we are open to considering other build flags.
+
+### Beyond the DOM
+
+We see the value of React in the way it allows us to write components that have fewer bugs and compose together well. DOM is the original rendering target for React but [React Native](http://facebook.github.io/react-native/) is just as important both to Facebook and the community.
+
+Being renderer-agnostic is an important design constraint of React. It adds some overhead in the internal representations. On the other hand, any improvements to the core translate across platforms.
+
+Having a single programming model lets us form engineering teams around products instead of platforms. So far the tradeoff has been worth it for us.
+
+### Implementation
+
+We try to provide elegant APIs where possible. We are much less concerned with the implementation being elegant. The real world is far from perfect, and to a reasonable extent we prefer to put the ugly code into the library if it means the user does not have to write it. When we evaluate new code, we are looking for an implementation that is correct, performant and affords a good developer experience. Elegance is secondary.
+
+We prefer boring code to clever code. Code is disposable and often changes. So it is important that it [doesn't introduce new internal abstractions unless absolutely necessary](https://youtu.be/4anAwXYqLG8?t=13m9s). Verbose code that is easy to move around, change and remove is preferred to elegant code that is prematurely abstracted and hard to change.
+
+### Optimized for Tooling
+
+Some commonly used APIs have verbose names. For example, we use `componentDidMount()` instead of `didMount()` or `onMount()`. This is [intentional](https://github.com/reactjs/react-future/issues/40#issuecomment-142442124). The goal is to make the points of interaction with the library highly visible.
+
+In a massive codebase like Facebook, being able to search for uses of specific APIs is very important. We value distinct verbose names, and especially for the features that should be used sparingly. For example, `dangerouslySetInnerHTML` is hard to miss in a code review.
+
+Optimizing for search is also important because of our reliance on [codemods](https://www.youtube.com/watch?v=d0pOgY8__JM) to make breaking changes. We want it to be easy and safe to apply vast automated changes across the codebase, and unique verbose names help us achieve this. Similarly, distinctive names make it easy to write custom [lint rules](https://github.com/yannickcr/eslint-plugin-react) about using React without worrying about potential false positives.
+
+[JSX](/react/docs/displaying-data.html#jsx-syntax) plays a similar role. While it is not required with React, we use it extensively at Facebook both for aesthetic and pragmatic reasons.
+
+In our codebase, JSX provides an unambiguous hint to the tools that they are dealing with a React element tree. This makes it possible to add build-time optimizations such as [hoisting constant elements](http://babeljs.io/docs/plugins/transform-react-constant-elements/), safely lint and codemod internal component usage, and [include JSX source location](https://github.com/facebook/react/pull/6771) into the warnings.
+
+### Dogfooding
+
+We try our best to address the problems raised by the community. However we are likely to prioritize the issues that people are *also* experiencing internally at Facebook. Perhaps counter-intuitively, we think this is the main reason why the community can bet on React.
+
+Heavy internal usage gives us the confidence that React won't disappear tomorrow. React was created at Facebook to solve its problems. It brings tangible business value to the company and is used in many of its products. [Dogfooding](https://en.wikipedia.org/wiki/Eating_your_own_dog_food) it means that our vision stays sharp and we have a focused direction going forward.
+
+This doesn't mean that we ignore the issues raised by the community. For example, we added support for [web components](/react/docs/webcomponents.html) and [SVG](https://github.com/facebook/react/pull/6243) to React even though we don't rely on either of them internally. We are actively [listening to your pain points](https://github.com/facebook/react/issues/2686) and [address them](/react/blog/2016/07/11/introducing-reacts-error-code-system.html) to the best of our ability. The community is what makes React special to us, and we are honored to contribute back.
+
+After releasing many open source projects at Facebook, we have learned that trying to make everyone happy at the same time produced projects with poor focus that didn't grow well. Instead, we found that picking a small audience and focusing on making them happy brings a positive net effect. That's exactly what we did with React, and so far solving the problems encountered by Facebook product teams has translated well to the open source community.
+
+The downside of this approach is that sometimes we fail to give enough focus to the things that Facebook teams don't have to deal with, such as the "getting started" experience. We are acutely aware of this, and we are thinking of how to improve in a way that would benefit everyone in the community without making the same mistakes we did with open source projects before.
diff --git a/docs/contributing/how-to-contribute.md b/docs/contributing/how-to-contribute.md
new file mode 100644
index 000000000000..3403ca379e40
--- /dev/null
+++ b/docs/contributing/how-to-contribute.md
@@ -0,0 +1,164 @@
+---
+id: how-to-contribute
+title: How to Contribute
+layout: contributing
+permalink: contributing/how-to-contribute.html
+next: codebase-overview.html
+redirect_from: "tips/introduction.html"
+---
+
+React is one of Facebook's first open source projects that is both under very active development and is also being used to ship code to everybody on [facebook.com](https://www.facebook.com). We're still working out the kinks to make contributing to this project as easy and transparent as possible, but we're not quite there yet. Hopefully this document makes the process for contributing clear and answers some questions that you may have.
+
+### [Code of Conduct](https://code.facebook.com/codeofconduct)
+
+Facebook has adopted a Code of Conduct that we expect project participants to adhere to. Please read [the full text](https://code.facebook.com/codeofconduct) so that you can understand what actions will and will not be tolerated.
+
+### Open Development
+
+All work on React happens directly on [GitHub](https://github.com/facebook/react). Both core team members and external contributors send pull requests which go through the same review process.
+
+### Branch Organization
+
+We will do our best to keep the [`master` branch](https://github.com/facebook/react/tree/master) in good shape, with tests passing at all times. But in order to move fast, we will make API changes that your application might not be compatible with. We recommend that you use [the latest stable version of React](/react/downloads.html).
+
+If you send a pull request, please do it against the `master` branch. We maintain stable branches for major versions separately but we don't accept pull requests to them directly. Instead, we cherry-pick non-breaking changes from master to the latest stable major version.
+
+### Semantic Versioning
+
+React follows [semantic versioning](http://semver.org/). We release patch versions for bugfixes, minor versions for new features, and major versions for any breaking changes. When we make breaking changes, we also introduce deprecation warnings in a minor version so that our users learn about the upcoming changes and migrate their code in advance.
+
+We tag every pull request with a label marking whether the change should go in the next [patch](https://github.com/facebook/react/pulls?q=is%3Aopen+is%3Apr+label%3Asemver-patch), [minor](https://github.com/facebook/react/pulls?q=is%3Aopen+is%3Apr+label%3Asemver-minor), or a [major](https://github.com/facebook/react/pulls?q=is%3Aopen+is%3Apr+label%3Asemver-major) version. We release new patch versions every few weeks, minor versions every few months, and major versions one or two times a year.
+
+Every significant change is documented in the [changelog file](https://github.com/facebook/react/blob/master/CHANGELOG.md).
+
+### Bugs
+
+#### Where to Find Known Issues
+
+We are using [GitHub Issues](https://github.com/facebook/react/issues) for our public bugs. We keep a close eye on this and try to make it clear when we have an internal fix in progress. Before filing a new task, try to make sure your problem doesn't already exist.
+
+#### Reporting New Issues
+
+The best way to get your bug fixed is to provide a reduced test case. This [JSFiddle template](https://jsfiddle.net/84v837e9/) is a great starting point.
+
+#### Security Bugs
+
+Facebook has a [bounty program](https://www.facebook.com/whitehat/) for the safe disclosure of security bugs. With that in mind, please do not file public issues; go through the process outlined on that page.
+
+### How to Get in Touch
+
+* IRC: [#reactjs on freenode](https://webchat.freenode.net/?channels=reactjs)
+* Discussion forum: [discuss.reactjs.org](https://discuss.reactjs.org/)
+
+There is also [an active community of React users on the Discord chat platform](http://www.reactiflux.com/) in case you need help with React.
+
+### Proposing a Change
+
+If you intend to change the public API, or make any non-trivial changes to the implementation, we recommend [filing an issue](https://github.com/facebook/react/issues/new). This lets us reach an agreement on your proposal before you put significant effort into it.
+
+If you're only fixing a bug, it's fine to submit a pull request right away but we still recommend to file an issue detailing what you're fixing. This is helpful in case we don't accept that specific fix but want to keep track of the issue.
+
+### Your First Pull Request
+
+Working on your first Pull Request? You can learn how from this free video series:
+
+**[How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github)**
+
+To help you get your feet wet and get you familiar with our contribution process, we have a list of **[beginner friendly issues](https://github.com/facebook/react/issues?q=is%3Aopen+is%3Aissue+label%3A%22Difficulty%3A+beginner%22)** that contain bugs which are fairly easy to fix. This is a great place to get started.
+
+If you decide to fix an issue, please be sure to check the comment thread in case somebody is already working on a fix. If nobody is working on it at the moment, please leave a comment stating that you intend to work on it so other people don't accidentally duplicate your effort.
+
+If somebody claims an issue but doesn't follow up for more than two weeks, it's fine to take over it but you should still leave a comment.
+
+### Sending a Pull Request
+
+The core team is monitoring for pull requests. We will review your pull request and either merge it, request changes to it, or close it with an explanation. For API changes we may need to fix our internal uses at Facebook.com, which could cause some delay. We'll do our best to provide updates and feedback throughout the process.
+
+**Before submitting a pull request,** please make sure the following is done:
+
+1. Fork [the repository](https://github.com/facebook/react) and create your branch from `master`.
+2. If you've added code that should be tested, add tests!
+3. If you've changed APIs, update the documentation.
+4. Ensure the test suite passes (`npm test`).
+5. Make sure your code lints (`npm run lint`).
+6. Format your code with [prettier](https://github.com/prettier/prettier) (`npm run prettier`).
+7. Run the [Flow](https://flowtype.org/) typechecks (`npm run flow`).
+8. If you added or removed any tests, run `./scripts/fiber/record-tests` before submitting the pull request, and commit the resulting changes.
+9. If you haven't already, complete the CLA.
+
+### Contributor License Agreement (CLA)
+
+In order to accept your pull request, we need you to submit a CLA. You only need to do this once, so if you've done this for another Facebook open source project, you're good to go. If you are submitting a pull request for the first time, just let us know that you have completed the CLA and we can cross-check with your GitHub username.
+
+**[Complete your CLA here.](https://code.facebook.com/cla)**
+
+### Contribution Prerequisites
+
+* You have `node` installed at v4.0.0+ and `npm` at v2.0.0+.
+* You have `gcc` installed or are comfortable installing a compiler if needed. Some of our `npm` dependencies may require a compilation step. On OS X, the Xcode Command Line Tools will cover this. On Ubuntu, `apt-get install build-essential` will install the required packages. Similar commands should work on other Linux distros. Windows will require some additional steps, see the [`node-gyp` installation instructions](https://github.com/nodejs/node-gyp#installation) for details.
+* You are familiar with `npm` and know whether or not you need to use `sudo` when installing packages globally.
+* You are familiar with `git`.
+
+### Development Workflow
+
+After cloning React, run `npm install` to fetch its dependencies.
+Then, you can run several commands:
+
+* `npm run lint` checks the code style.
+* `npm test` runs the complete test suite.
+* `npm test -- --watch` runs an interactive test watcher.
+* `npm test <pattern>` runs tests with matching filenames.
+* `npm run flow` runs the [Flow](https://flowtype.org/) typechecks.
+* `npm run build` creates a `build` folder with all the packages.
+
+We recommend running `npm test` (or its variations above) to make sure you don't introduce any regressions as you work on your change. However it can be handy to try your build of React in a real project.
+
+First, run `npm run build`. This will produce pre-built bundles in `build` folder, as well as prepare npm packages inside `build/packages`.
+
+The easiest way to try your changes is to run `npm run build` and then open `fixtures/packaging/babel-standalone/dev.html`. This file already uses `react.js` from the `build` folder so it will pick up your changes.
+
+If you want to try your changes in your existing React project, you may copy `build/dist/react.development.js`, `build/dist/react-dom.development.js`, or any other build products into your app and use them instead of the stable version. If your project uses React from npm, you may delete `react` and `react-dom` in its dependencies and use `npm link` to point them to your local `build` folder:
+
+```sh
+cd your_project
+npm link ~/path_to_your_react_clone/build/packages/react
+npm link ~/path_to_your_react_clone/build/packages/react-dom
+```
+
+Every time you run `npm run build` in the React folder, the updated versions will appear in your project's `node_modules`. You can then rebuild your project to try your changes.
+
+We still require that your pull request contains unit tests for any new functionality. This way we can ensure that we don't break your code in the future.
+
+### Style Guide
+
+Our linter will catch most styling issues that may exist in your code.
+You can check the status of your code styling by simply running `npm run lint`.
+
+However, there are still some styles that the linter cannot pick up. If you are unsure about something, looking at [Airbnb's Style Guide](https://github.com/airbnb/javascript) will guide you in the right direction.
+
+### Code Conventions
+
+* Use semicolons `;`
+* Commas last `,`
+* 2 spaces for indentation (no tabs)
+* Prefer `'` over `"`
+* `'use strict';`
+* 120 character line length (**except documentation**)
+* Write "attractive" code
+* Do not use the optional parameters of `setTimeout` and `setInterval`
+
+### Introductory Video
+
+You may be interested in watching [this short video](https://www.youtube.com/watch?v=wUpPsEcGsg8) (26 mins) which gives an introduction on how to contribute to React.
+
+### Meeting Notes
+
+React team meets once a week to discuss the development of React, future plans, and priorities. You can find the meeting notes in a [dedicated repository](https://github.com/reactjs/core-notes/).
+
+### License
+
+By contributing to React, you agree that your contributions will be licensed under its BSD license.
+
+### What Next?
+
+Read the [next section](/react/contributing/codebase-overview.html) to learn how the codebase is organized.
diff --git a/docs/contributing/implementation-notes.md b/docs/contributing/implementation-notes.md
new file mode 100644
index 000000000000..2309dd721cc1
--- /dev/null
+++ b/docs/contributing/implementation-notes.md
@@ -0,0 +1,896 @@
+---
+id: implementation-notes
+title: Implementation Notes
+layout: contributing
+permalink: contributing/implementation-notes.html
+prev: codebase-overview.html
+next: design-principles.html
+---
+
+This section is a collection of implementation notes for the [stack reconciler](/react/contributing/codebase-overview.html#stack-reconciler).
+
+It is very technical and assumes a strong understanding of React public API as well as how it's divided into core, renderers, and the reconciler. If you're not very familiar with the React codebase, read [the codebase overview](/react/contributing/codebase-overview.html) first.
+
+It also assumes an understanding of the [differences between React components, their instances, and elements](/react/blog/2015/12/18/react-components-elements-and-instances.html).
+
+The stack reconciler is powering all the React production code today. It is located in [`src/renderers/shared/stack/reconciler`](https://github.com/facebook/react/tree/master/src/renderers/shared/stack) and is used by both React DOM and React Native.
+
+### Video: Building React from Scratch
+
+[Paul O'Shannessy](https://twitter.com/zpao) gave a talk about [building React from scratch](https://www.youtube.com/watch?v=_MAD4Oly9yg) that largely inspired this document.
+
+Both this document and his talk are simplifications of the real codebase so you might get a better understanding by getting familiar with both of them.
+
+### Overview
+
+The reconciler itself doesn't have a public API. [Renderers](/react/contributing/codebase-overview.html#stack-renderers) like React DOM and React Native use it to efficiently update the user interface according to the React components written by the user.
+
+### Mounting as a Recursive Process
+
+Let's consider the first time you mount a component:
+
+```js
+ReactDOM.render(<App />, rootEl);
+```
+
+React DOM will pass `<App />` along to the reconciler. Remember that `<App />` is a React element, that is, a description of *what* to render. You can think about it as a plain object:
+
+```js
+console.log(<App />);
+// { type: App, props: {} }
+```
+
+The reconciler will check if `App` is a class or a function.
+
+If `App` is a function, the reconciler will call `App(props)` to get the rendered element.
+
+If `App` is a class, the reconciler will instantiate an `App` with `new App(props)`, call the `componentWillMount()` lifecycle method, and then will call the `render()` method to get the rendered element.
+
+Either way, the reconciler will learn the element `App` "rendered to".
+
+This process is recursive. `App` may render to a `<Greeting />`, `Greeting` may render to a `<Button />`, and so on. The reconciler will "drill down" through user-defined components recursively as it learns what each component renders to.
+
+You can imagine this process as a pseudocode:
+
+```js
+function isClass(type) {
+  // React.Component subclasses have this flag
+  return (
+    Boolean(type.prototype) &&
+    Boolean(type.prototype.isReactComponent)
+  );
+}
+
+// This function takes a React element (e.g. <App />)
+// and returns a DOM or Native node representing the mounted tree.
+function mount(element) {
+  var type = element.type;
+  var props = element.props;
+
+  // We will determine the rendered element
+  // by either running the type as function
+  // or creating an instance and calling render().
+  var renderedElement;
+  if (isClass(type)) {
+    // Component class
+    var publicInstance = new type(props);
+    // Set the props
+    publicInstance.props = props;
+    // Call the lifecycle if necessary
+    if (publicInstance.componentWillMount) {
+      publicInstance.componentWillMount();
+    }
+    // Get the rendered element by calling render()
+    renderedElement = publicInstance.render();
+  } else {
+    // Component function
+    renderedElement = type(props);
+  }
+
+  // This process is recursive because a component may
+  // return an element with a type of another component.
+  return mount(renderedElement);
+
+  // Note: this implementation is incomplete and recurses infinitely!
+  // It only handles elements like <App /> or <Button />.
+  // It doesn't handle elements like <div /> or <p /> yet.
+}
+
+var rootEl = document.getElementById('root');
+var node = mount(<App />);
+rootEl.appendChild(node);
+```
+
+>**Note:**
+>
+>This really *is* a pseudo-code. It isn't similar to the real implementation. It will also cause a stack overflow because we haven't discussed when to stop the recursion.
+
+Let's recap a few key ideas in the example above:
+
+* React elements are plain objects representing the component type (e.g. `App`) and the props.
+* User-defined components (e.g. `App`) can be classes or functions but they all "render to" elements.
+* "Mounting" is a recursive process that creates a DOM or Native tree given the top-level React element (e.g. `<App />`).
+
+### Mounting Host Elements
+
+This process would be useless if we didn't render something to the screen as a result.
+
+In addition to user-defined ("composite") components, React elements may also represent platform-specific ("host") components. For example, `Button` might return a `<div />` from its render method.
+
+If element's `type` property is a string, we are dealing with a host element:
+
+```js
+console.log(<div />);
+// { type: 'div', props: {} }
+```
+
+There is no user-defined code associated with host elements.
+
+When the reconciler encounters a host element, it lets the renderer take care of mounting it. For example, React DOM would create a DOM node.
+
+If the host element has children, the reconciler recursively mounts them following the same algorithm as above. It doesn't matter whether children are host (like `<div><hr /></div>`), composite (like `<div><Button /></div>`), or both.
+
+The DOM nodes produced by the child components will be appended to the parent DOM node, and recursively, the complete DOM structure will be assembled.
+
+>**Note:**
+>
+>The reconciler itself is not tied to the DOM. The exact result of mounting (sometimes called "mount image" in the source code) depends on the renderer, and can be a DOM node (React DOM), a string (React DOM Server), or a number representing a native view (React Native).
+
+If we were to extend the code to handle host elements, it would look like this:
+
+```js
+function isClass(type) {
+  // React.Component subclasses have this flag
+  return (
+    Boolean(type.prototype) &&
+    Boolean(type.prototype.isReactComponent)
+  );
+}
+
+// This function only handles elements with a composite type.
+// For example, it handles <App /> and <Button />, but not a <div />.
+function mountComposite(element) {
+  var type = element.type;
+  var props = element.props;
+
+  var renderedElement;
+  if (isClass(type)) {
+    // Component class
+    var publicInstance = new type(props);
+    // Set the props
+    publicInstance.props = props;
+    // Call the lifecycle if necessary
+    if (publicInstance.componentWillMount) {
+      publicInstance.componentWillMount();
+    }
+    renderedElement = publicInstance.render();
+  } else if (typeof type === 'function') {
+    // Component function
+    renderedElement = type(props);
+  }
+
+  // This is recursive but we'll eventually reach the bottom of recursion when
+  // the element is host (e.g. <div />) rather than composite (e.g. <App />):
+  return mount(renderedElement);
+}
+
+// This function only handles elements with a host type.
+// For example, it handles <div /> and <p /> but not an <App />.
+function mountHost(element) {
+  var type = element.type;
+  var props = element.props;
+  var children = props.children || [];
+  if (!Array.isArray(children)) {
+    children = [children];
+  }
+  children = children.filter(Boolean);
+
+  // This block of code shouldn't be in the reconciler.
+  // Different renderers might initialize nodes differently.
+  // For example, React Native would create iOS or Android views.
+  var node = document.createElement(type);
+  Object.keys(props).forEach(propName => {
+    if (propName !== 'children') {
+      node.setAttribute(propName, props[propName]);
+    }
+  });
+
+  // Mount the children
+  children.forEach(childElement => {
+    // Children may be host (e.g. <div />) or composite (e.g. <Button />).
+    // We will also mount them recursively:
+    var childNode = mount(childElement);
+
+    // This line of code is also renderer-specific.
+    // It would be different depending on the renderer:
+    node.appendChild(childNode);
+  });
+
+  // Return the DOM node as mount result.
+  // This is where the recursion ends.
+  return node;
+}
+
+function mount(element) {
+  var type = element.type;
+  if (typeof type === 'function') {
+    // User-defined components
+    return mountComposite(element);
+  } else if (typeof type === 'string') {
+    // Platform-specific components
+    return mountHost(element);
+  }
+}
+
+var rootEl = document.getElementById('root');
+var node = mount(<App />);
+rootEl.appendChild(node);
+```
+
+This is working but still far from how the reconciler is really implemented. The key missing ingredient is support for updates.
+
+### Introducing Internal Instances
+
+The key feature of React is that you can re-render everything, and it won't recreate the DOM or reset the state:
+
+```js
+ReactDOM.render(<App />, rootEl);
+// Should reuse the existing DOM:
+ReactDOM.render(<App />, rootEl);
+```
+
+However, our implementation above only knows how to mount the initial tree. It can't perform updates on it because it doesn't store all the necessary information, such as all the `publicInstance`s, or which DOM `node`s correspond to which components.
+
+The stack reconciler codebase solves this by making the `mount()` function a method and putting it on a class. There are drawbacks to this approach, and we are going in the opposite direction in the [ongoing rewrite of the reconciler](/react/contributing/codebase-overview.html#fiber-reconciler). Nevertheless this is how it works now.
+
+Instead of separate `mountHost` and `mountComposite` functions, we will create two classes: `DOMComponent` and `CompositeComponent`.
+
+Both classes have a constructor accepting the `element`, as well as a `mount()` method returning the mounted node. We will replace a top-level `mount()` function with a factory that instantiates the correct class:
+
+```js
+function instantiateComponent(element) {
+  var type = element.type;
+  if (typeof type === 'function') {
+    // User-defined components
+    return new CompositeComponent(element);
+  } else if (typeof type === 'string') {
+    // Platform-specific components
+    return new DOMComponent(element);
+  }  
+}
+```
+
+First, let's consider the implementation of `CompositeComponent`:
+
+```js
+class CompositeComponent {
+  constructor(element) {
+    this.currentElement = element;
+    this.renderedComponent = null;
+    this.publicInstance = null;
+  }
+
+  getPublicInstance() {
+    // For composite components, expose the class instance.
+    return this.publicInstance;
+  }
+
+  mount() {
+    var element = this.currentElement;
+    var type = element.type;
+    var props = element.props;
+
+    var publicInstance;
+    var renderedElement;
+    if (isClass(type)) {
+      // Component class
+      publicInstance = new type(props);
+      // Set the props
+      publicInstance.props = props;
+      // Call the lifecycle if necessary
+      if (publicInstance.componentWillMount) {
+        publicInstance.componentWillMount();
+      }
+      renderedElement = publicInstance.render();
+    } else if (typeof type === 'function') {
+      // Component function
+      publicInstance = null;
+      renderedElement = type(props);
+    }
+
+    // Save the public instance
+    this.publicInstance = publicInstance;
+
+    // Instantiate the child internal instance according to the element.
+    // It would be a DOMComponent for <div /> or <p />,
+    // and a CompositeComponent for <App /> or <Button />:
+    var renderedComponent = instantiateComponent(renderedElement);
+    this.renderedComponent = renderedComponent;
+
+    // Mount the rendered output
+    return renderedComponent.mount();
+  }
+}
+```
+
+This is not much different from our previous `mountComposite()` implementation, but now we can save some information, such as `this.currentElement`, `this.renderedComponent`, and `this.publicInstance`, for use during updates.
+
+Note that an instance of `CompositeComponent` is not the same thing as an instance of the user-supplied `element.type`. `CompositeComponent` is an implementation detail of our reconciler, and is never exposed to the user. The user-defined class is the one we read from `element.type`, and `CompositeComponent` creates an instance of it.
+
+To avoid the confusion, we will call instances of `CompositeComponent` and `DOMComponent` "internal instances". They exist so we can associate some long-lived data with them. Only the renderer and the reconciler are aware that they exist.
+
+In contrast, we call an instance of the user-defined class a "public instance". The public instance is what you see as `this` in the `render()` and other methods of your custom components.
+
+The `mountHost()` function, refactored to be a `mount()` method on `DOMComponent` class, also looks familiar:
+
+```js
+class DOMComponent {
+  constructor(element) {
+    this.currentElement = element;
+    this.renderedChildren = [];
+    this.node = null;
+  }
+
+  getPublicInstance() {
+    // For DOM components, only expose the DOM node.
+    return this.node;
+  }
+
+  mount() {
+    var element = this.currentElement;
+    var type = element.type;
+    var props = element.props;
+    var children = props.children || [];
+    if (!Array.isArray(children)) {
+      children = [children];
+    }
+
+    // Create and save the node
+    var node = document.createElement(type);
+    this.node = node;
+
+    // Set the attributes
+    Object.keys(props).forEach(propName => {
+      if (propName !== 'children') {
+        node.setAttribute(propName, props[propName]);
+      }
+    });
+
+    // Create and save the contained children.
+    // Each of them can be a DOMComponent or a CompositeComponent,
+    // depending on whether the element type is a string or a function.
+    var renderedChildren = children.map(instantiateComponent);
+    this.renderedChildren = renderedChildren;
+
+    // Collect DOM nodes they return on mount
+    var childNodes = renderedChildren.map(child => child.mount());
+    childNodes.forEach(childNode => node.appendChild(childNode));
+
+    // Return the DOM node as mount result
+    return node;
+  }
+}
+```
+
+The main difference after refactoring from `mountHost()` is that we now keep `this.node` and `this.renderedChildren` associated with the internal DOM component instance. We will also use them for applying non-destructive updates in the future.
+
+As a result, each internal instance, composite or host, now points to its child internal instances. To help visualize this, if a functional `<App>` component renders a `<Button>` class component, and `Button` class renders a `<div>`, the internal instance tree would look like this:
+
+```js
+[object CompositeComponent] {
+  currentElement: <App />,
+  publicInstance: null,
+  renderedComponent: [object CompositeComponent] {
+    currentElement: <Button />,
+    publicInstance: [object Button],
+    renderedComponent: [object DOMComponent] {
+      currentElement: <div />,
+      node: [object HTMLDivElement],
+      renderedChildren: []
+    }
+  }
+}
+```
+
+In the DOM you would only see the `<div>`. However the internal instance tree contains both composite and host internal instances.
+
+The composite internal instances need to store:
+
+* The current element.
+* The public instance if element type is a class.
+* The single rendered internal instance. It can be either a `DOMComponent` or a `CompositeComponent`.
+
+The host internal instances need to store:
+
+* The current element.
+* The DOM node.
+* All the child internal instances. Each of them can be either a `DOMComponent` or a `CompositeComponent`.
+
+If you're struggling to imagine how an internal instance tree is structured in more complex applications, [React DevTools](https://github.com/facebook/react-devtools) can give you a close approximation, as it highlights host instances with grey, and composite instances with purple:
+
+ <img src="/react/img/docs/implementation-notes-tree.png" width="500" style="max-width: 100%" alt="React DevTools tree" />
+
+To complete this refactoring, we will introduce a function that mounts a complete tree into a container node, just like `ReactDOM.render()`. It returns a public instance, also like `ReactDOM.render()`:
+
+```js
+function mountTree(element, containerNode) {
+  // Create the top-level internal instance
+  var rootComponent = instantiateComponent(element);
+
+  // Mount the top-level component into the container
+  var node = rootComponent.mount();
+  containerNode.appendChild(node);
+
+  // Return the public instance it provides
+  var publicInstance = rootComponent.getPublicInstance();
+  return publicInstance;
+}
+
+var rootEl = document.getElementById('root');
+mountTree(<App />, rootEl);
+```
+
+### Unmounting
+
+Now that we have internal instances that hold onto their children and the DOM nodes, we can implement unmounting. For a composite component, unmounting calls a lifecycle hook and recurses.
+
+```js
+class CompositeComponent {
+
+  // ...
+
+  unmount() {
+    // Call the lifecycle hook if necessary
+    var publicInstance = this.publicInstance;
+    if (publicInstance) {
+      if (publicInstance.componentWillUnmount) {
+        publicInstance.componentWillUnmount();
+      }
+    }
+
+    // Unmount the single rendered component
+    var renderedComponent = this.renderedComponent;
+    renderedComponent.unmount();
+  }
+}
+```
+
+For `DOMComponent`, unmounting tells each child to unmount:
+
+```js
+class DOMComponent {
+
+  // ...
+
+  unmount() {
+    // Unmount all the children
+    var renderedChildren = this.renderedChildren;
+    renderedChildren.forEach(child => child.unmount());
+  }
+}
+```
+
+In practice, unmounting DOM components also removes the event listeners and clears some caches, but we will skip those details.
+
+We can now add a new top-level function called `unmountTree(containerNode)` that is similar to `ReactDOM.unmountComponentAtNode()`:
+
+```js
+function unmountTree(containerNode) {
+  // Read the internal instance from a DOM node:
+  // (This doesn't work yet, we will need to change mountTree() to store it.)
+  var node = containerNode.firstChild;
+  var rootComponent = node._internalInstance;
+
+  // Unmount the tree and clear the container
+  rootComponent.unmount();
+  containerNode.innerHTML = '';
+}
+```
+
+In order for this to work, we need to read an internal root instance from a DOM node. We will modify `mountTree()` to add the `_internalInstance` property to the root DOM node. We will also teach `mountTree()` to destroy any existing tree so it can be called multiple times:
+
+```js
+function mountTree(element, containerNode) {
+  // Destroy any existing tree
+  if (containerNode.firstChild) {
+    unmountTree(containerNode);
+  }
+
+  // Create the top-level internal instance
+  var rootComponent = instantiateComponent(element);
+
+  // Mount the top-level component into the container
+  var node = rootComponent.mount();
+  containerNode.appendChild(node);
+
+  // Save a reference to the internal instance
+  node._internalInstance = rootComponent;
+
+  // Return the public instance it provides
+  var publicInstance = rootComponent.getPublicInstance();
+  return publicInstance;
+}
+```
+
+Now, running `unmountTree()`, or running `mountTree()` repeatedly, removes the old tree and runs the `componentWillUnmount()` lifecycle hook on components.
+
+### Updating
+
+In the previous section, we implemented unmounting. However React wouldn't be very useful if each prop change unmounted and mounted the whole tree. The goal of the reconciler is to reuse existing instances where possible to preserve the DOM and the state:
+
+```js
+var rootEl = document.getElementById('root');
+
+mountTree(<App />, rootEl);
+// Should reuse the existing DOM:
+mountTree(<App />, rootEl);
+```
+
+We will extend our internal instance contract with one more method. In addition to `mount()` and `unmount()`, both `DOMComponent` and `CompositeComponent` will implement a new method called `receive(nextElement)`:
+
+```js
+class CompositeComponent {
+  // ...
+
+  receive(nextElement) {
+    // ...
+  }
+}
+
+class DOMComponent {
+  // ...
+
+  receive(nextElement) {
+    // ...
+  }
+}
+```
+
+Its job is to do whatever is necessary to bring the component (and any of its children) up to date with the description provided by the `nextElement`.
+
+This is the part that is often described as "virtual DOM diffing" although what really happens is that we walk the internal tree recursively and let each internal instance receive an update.
+
+### Updating Composite Components
+
+When a composite component receives a new element, we run the `componentWillUpdate()` lifecycle hook.
+
+Then we re-render the component with the new props, and get the next rendered element:
+
+```js
+class CompositeComponent {
+
+  // ...
+
+  receive(nextElement) {
+    var prevProps = this.currentElement.props;
+    var publicInstance = this.publicInstance;
+    var prevRenderedComponent = this.renderedComponent;
+    var prevRenderedElement = prevRenderedComponent.currentElement;
+
+    // Update *own* element
+    this.currentElement = nextElement;
+    var type = nextElement.type;
+    var nextProps = nextElement.props;
+
+    // Figure out what the next render() output is
+    var nextRenderedElement;
+    if (isClass(type)) {
+      // Component class
+      // Call the lifecycle if necessary
+      if (publicInstance.componentWillUpdate) {
+        publicInstance.componentWillUpdate(nextProps);
+      }
+      // Update the props
+      publicInstance.props = nextProps;
+      // Re-render
+      nextRenderedElement = publicInstance.render();
+    } else if (typeof type === 'function') {
+      // Component function
+      nextRenderedElement = type(nextProps);
+    }
+
+    // ...
+```
+
+Next, we can look at the rendered element's `type`. If the `type` has not changed since the last render, the component below can also be updated in place.
+
+For example, if it returned `<Button color="red" />` the first time, and `<Button color="blue" />` the second time, we can just tell the corresponding internal instance to `receive()` the next element:
+
+```js
+    // ...
+
+    // If the rendered element type has not changed,
+    // reuse the existing component instance and exit.
+    if (prevRenderedElement.type === nextRenderedElement.type) {
+      prevRenderedComponent.receive(nextRenderedElement);
+      return;
+    }
+
+    // ...
+```
+
+However, if the next rendered element has a different `type` than the previously rendered element, we can't update the internal instance. A `<button>` can't "become" an `<input>`.
+
+Instead, we have to unmount the existing internal instance and mount the new one corresponding to the rendered element type. For example, this is what happens when a component that previously rendered a `<button />` renders an `<input />`:
+
+```js
+    // ...
+
+    // If we reached this point, we need to unmount the previously
+    // mounted component, mount the new one, and swap their nodes.
+
+    // Find the old node because it will need to be replaced
+    var prevNode = prevRenderedComponent.getHostNode();
+
+    // Unmount the old child and mount a new child
+    prevRenderedComponent.unmount();
+    var nextRenderedComponent = instantiateComponent(nextRenderedElement);
+    var nextNode = nextRenderedComponent.mount();
+
+    // Replace the reference to the child
+    this.renderedComponent = nextRenderedComponent;
+
+    // Replace the old node with the new one
+    // Note: this is renderer-specific code and
+    // ideally should live outside of CompositeComponent:
+    prevNode.parentNode.replaceChild(nextNode, prevNode);
+  }
+}
+```
+
+To sum this up, when a composite component receives a new element, it may either delegate the update to its rendered internal instance, or unmount it and mount a new one in its place.
+
+There is another condition under which a component will re-mount rather than receive an element, and that is when the element's `key` has changed. We don't discuss `key` handling in this document because it adds more complexity to an already complex tutorial.
+
+Note that we needed to add a method called `getHostNode()` to the internal instance contract so that it's possible to locate the platform-specific node and replace it during the update. Its implementation is straightforward for both classes:
+
+```js
+class CompositeComponent {
+  // ...
+
+  getHostNode() {
+    // Ask the rendered component to provide it.
+    // This will recursively drill down any composites.
+    return this.renderedComponent.getHostNode();
+  }
+}
+
+class DOMComponent {
+  // ...
+
+  getHostNode() {
+    return this.node;
+  }  
+}
+```
+
+### Updating Host Components
+
+Host component implementations, such as `DOMComponent`, update differently. When they receive an element, they need to update the underlying platform-specific view. In case of React DOM, this means updating the DOM attributes:
+
+```js
+class DOMComponent {
+  // ...
+
+  receive(nextElement) {
+    var node = this.node;
+    var prevElement = this.currentElement;
+    var prevProps = prevElement.props;
+    var nextProps = nextElement.props;    
+    this.currentElement = nextElement;
+
+    // Remove old attributes.
+    Object.keys(prevProps).forEach(propName => {
+      if (propName !== 'children' && !nextProps.hasOwnProperty(propName)) {
+        node.removeAttribute(propName);
+      }
+    });
+    // Set next attributes.
+    Object.keys(nextProps).forEach(propName => {
+      if (propName !== 'children') {
+        node.setAttribute(propName, nextProps[propName]);
+      }
+    });
+
+    // ...
+```
+
+Then, host components need to update their children. Unlike composite components, they might contain more than a single child.
+
+In this simplified example, we use an array of internal instances and iterate over it, either updating or replacing the internal instances depending on whether the received `type` matches their previous `type`. The real reconciler also takes element's `key` in the account and track moves in addition to insertions and deletions, but we will omit this logic.
+
+We collect DOM operations on children in a list so we can execute them in batch:
+
+```js
+    // ...
+
+    // These are arrays of React elements:
+    var prevChildren = prevProps.children || [];
+    if (!Array.isArray(prevChildren)) {
+      prevChildren = [prevChildren];
+    }
+    var nextChildren = nextProps.children || [];
+    if (!Array.isArray(nextChildren)) {
+      nextChildren = [nextChildren];
+    }
+    // These are arrays of internal instances:
+    var prevRenderedChildren = this.renderedChildren;
+    var nextRenderedChildren = [];
+
+    // As we iterate over children, we will add operations to the array.
+    var operationQueue = [];
+
+    // Note: the section below is extremely simplified!
+    // It doesn't handle reorders, children with holes, or keys.
+    // It only exists to illustrate the overall flow, not the specifics.
+
+    for (var i = 0; i < nextChildren.length; i++) {
+      // Try to get an existing internal instance for this child
+      var prevChild = prevRenderedChildren[i];
+
+      // If there is no internal instance under this index,
+      // a child has been appended to the end. Create a new
+      // internal instance, mount it, and use its node.
+      if (!prevChild) {
+        var nextChild = instantiateComponent(nextChildren[i]);
+        var node = nextChild.mount();
+
+        // Record that we need to append a node
+        operationQueue.push({type: 'ADD', node});
+        nextRenderedChildren.push(nextChild);
+        continue;
+      }
+
+      // We can only update the instance if its element's type matches.
+      // For example, <Button size="small" /> can be updated to
+      // <Button size="large" /> but not to an <App />.
+      var canUpdate = prevChildren[i].type === nextChildren[i].type;
+
+      // If we can't update an existing instance, we have to unmount it
+      // and mount a new one instead of it.
+      if (!canUpdate) {
+        var prevNode = prevChild.node;
+        prevChild.unmount();
+
+        var nextChild = instantiateComponent(nextChildren[i]);
+        var nextNode = nextChild.mount();
+
+        // Record that we need to swap the nodes
+        operationQueue.push({type: 'REPLACE', prevNode, nextNode});
+        nextRenderedChildren.push(nextChild);
+        continue;
+      }
+
+      // If we can update an existing internal instance,
+      // just let it receive the next element and handle its own update.
+      prevChild.receive(nextChildren[i]);
+      nextRenderedChildren.push(prevChild);
+    }
+
+    // Finally, unmount any children that don't exist:
+    for (var j = nextChildren.length; j < prevChildren.length; j++) {
+     var prevChild = prevRenderedChildren[j];
+     var node = prevChild.node;
+     prevChild.unmount();
+
+     // Record that we need to remove the node
+     operationQueue.push({type: 'REMOVE', node});
+    }
+
+    // Point the list of rendered children to the updated version.
+    this.renderedChildren = nextRenderedChildren;
+
+    // ...
+```
+
+As the last step, we execute the DOM operations. Again, the real reconciler code is more complex because it also handles moves:
+
+```js
+    // ...
+
+    // Process the operation queue.
+    while (operationQueue.length > 0) {
+      var operation = operationQueue.shift();
+      switch (operation.type) {
+      case 'ADD':
+        this.node.appendChild(operation.node);
+        break;
+      case 'REPLACE':
+        this.node.replaceChild(operation.nextNode, operation.prevNode);
+        break;
+      case 'REMOVE':
+        this.node.removeChild(operation.node);
+        break;
+      }
+    }
+  }
+}
+```
+
+And that is it for updating host components.
+
+### Top-Level Updates
+
+Now that both `CompositeComponent` and `DOMComponent` implement the `receive(nextElement)` method, we can change the top-level `mountTree()` function to use it when the element `type` is the same as it was the last time:
+
+```js
+function mountTree(element, containerNode) {
+  // Check for an existing tree
+  if (containerNode.firstChild) {
+    var prevNode = containerNode.firstChild;
+    var prevRootComponent = prevNode._internalInstance;
+    var prevElement = prevRootComponent.currentElement;
+
+    // If we can, reuse the existing root component
+    if (prevElement.type === element.type) {
+      prevRootComponent.receive(element);
+      return;
+    }
+
+    // Otherwise, unmount the existing tree
+    unmountTree(containerNode);
+  }
+
+  // ...
+
+}
+```
+
+Now calling `mountTree()` two times with the same type isn't destructive:
+
+```js
+var rootEl = document.getElementById('root');
+
+mountTree(<App />, rootEl);
+// Reuses the existing DOM:
+mountTree(<App />, rootEl);
+```
+
+These are the basics of how React works internally.
+
+### What We Left Out
+
+This document is simplified compared to the real codebase. There are a few important aspects we didn't address:
+
+* Components can render `null`, and the reconciler can handle "empty slots" in arrays and rendered output.
+
+* The reconciler also reads `key` from the elements, and uses it to establish which internal instance corresponds to which element in an array. A bulk of complexity in the actual React implementation is related to that.
+
+* In addition to composite and host internal instance classes, there are also classes for "text" and "empty" components. They represent text nodes and the "empty slots" you get by rendering `null`.
+
+* Renderers use [injection](/react/contributing/codebase-overview.html#dynamic-injection) to pass the host internal class to the reconciler. For example, React DOM tells the reconciler to use `ReactDOMComponent` as the host internal instance implementation.
+
+* The logic for updating the list of children is extracted into a mixin called `ReactMultiChild` which is used by the host internal instance class implementations both in React DOM and React Native.
+
+* The reconciler also implements support for `setState()` in composite components. Multiple updates inside event handlers get batched into a single update.
+
+* The reconciler also takes care of attaching and detaching refs to composite components and host nodes.
+
+* Lifecycle hooks that are called after the DOM is ready, such as `componentDidMount()` and `componentDidUpdate()`, get collected into "callback queues" and are executed in a single batch.
+
+* React puts information about the current update into an internal object called "transaction". Transactions are useful for keeping track of the queue of pending lifecycle hooks, the current DOM nesting for the warnings, and anything else that is "global" to a specific update. Transactions also ensure React "cleans everything up" after updates. For example, the transaction class provided by React DOM restores the input selection after any update.
+
+### Jumping into the Code
+
+* [`ReactMount`](https://github.com/facebook/react/blob/83381c1673d14cd16cf747e34c945291e5518a86/src/renderers/dom/client/ReactMount.js) is where the code like `mountTree()` and `unmountTree()` from this tutorial lives. It takes care of mounting and unmounting top-level components. [`ReactNativeMount`](https://github.com/facebook/react/blob/83381c1673d14cd16cf747e34c945291e5518a86/src/renderers/native/ReactNativeMount.js) is its React Native analog.
+* [`ReactDOMComponent`](https://github.com/facebook/react/blob/83381c1673d14cd16cf747e34c945291e5518a86/src/renderers/dom/shared/ReactDOMComponent.js) is the equivalent of `DOMComponent` in this tutorial. It implements the host component class for React DOM renderer. [`ReactNativeBaseComponent`](https://github.com/facebook/react/blob/83381c1673d14cd16cf747e34c945291e5518a86/src/renderers/native/ReactNativeBaseComponent.js) is its React Native analog.
+* [`ReactCompositeComponent`](https://github.com/facebook/react/blob/83381c1673d14cd16cf747e34c945291e5518a86/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js) is the equivalent of `CompositeComponent` in this tutorial. It handles calling user-defined components and maintaining their state.
+* [`instantiateReactComponent`](https://github.com/facebook/react/blob/83381c1673d14cd16cf747e34c945291e5518a86/src/renderers/shared/stack/reconciler/instantiateReactComponent.js) contains the switch that picks the right internal instance class to construct for an element. It is equivalent to `instantiateComponent()` in this tutorial.
+
+* [`ReactReconciler`](https://github.com/facebook/react/blob/83381c1673d14cd16cf747e34c945291e5518a86/src/renderers/shared/stack/reconciler/ReactReconciler.js) is a wrapper with `mountComponent()`, `receiveComponent()`, and `unmountComponent()` methods. It calls the underlying implementations on the internal instances, but also includes some code around them that is shared by all internal instance implementations.
+
+* [`ReactChildReconciler`](https://github.com/facebook/react/blob/83381c1673d14cd16cf747e34c945291e5518a86/src/renderers/shared/stack/reconciler/ReactChildReconciler.js) implements the logic for mounting, updating, and unmounting children according to the `key` of their elements.
+
+* [`ReactMultiChild`](https://github.com/facebook/react/blob/83381c1673d14cd16cf747e34c945291e5518a86/src/renderers/shared/stack/reconciler/ReactMultiChild.js) implements processing the operation queue for child insertions, deletions, and moves independently of the renderer.
+
+* `mount()`, `receive()`, and `unmount()` are really called `mountComponent()`, `receiveComponent()`, and `unmountComponent()` in React codebase for legacy reasons, but they receive elements.
+
+* Properties on the internal instances start with an underscore, e.g. `_currentElement`. They are considered to be read-only public fields throughout the codebase.
+
+### Future Directions
+
+Stack reconciler has inherent limitations such as being synchronous and unable to interrupt the work or split it in chunks. There is a work in progress on the [new Fiber reconciler](/react/contributing/codebase-overview.html#fiber-reconciler) with a [completely different architecture](https://github.com/acdlite/react-fiber-architecture). In the future, we intend to replace stack reconciler with it, but at the moment it is far from feature parity.
+
+### Next Steps
+
+Read the [next section](/react/contributing/design-principles.html) to learn about the guiding principles we use for React development.
diff --git a/docs/css/codemirror.css b/docs/css/codemirror.css
index 86eda77ec105..00a153279323 100644
--- a/docs/css/codemirror.css
+++ b/docs/css/codemirror.css
@@ -18,7 +18,7 @@
   padding: 0 14px; /* Horizontal padding of content */
 }
 
-.CodeMirror-scrollbar-filler {
+.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
   background-color: white; /* The little square between H and V scrollbars */
 }
 
@@ -27,6 +27,7 @@
 .CodeMirror-gutters {
   border-right: 1px solid #ddd;
   background-color: #f7f7f7;
+  white-space: nowrap;
 }
 .CodeMirror-linenumbers {}
 .CodeMirror-linenumber {
@@ -34,68 +35,110 @@
   min-width: 20px;
   text-align: right;
   color: #999;
+  white-space: nowrap;
 }
 
+.CodeMirror-guttermarker { color: black; }
+.CodeMirror-guttermarker-subtle { color: #999; }
+
 /* CURSOR */
 
-.CodeMirror div.CodeMirror-cursor {
+.CodeMirror-cursor {
   border-left: 1px solid black;
+  border-right: none;
+  width: 0;
 }
 /* Shown when moving in bi-directional text */
 .CodeMirror div.CodeMirror-secondarycursor {
   border-left: 1px solid silver;
 }
-.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor {
+.cm-fat-cursor .CodeMirror-cursor {
   width: auto;
-  border: 0;
-  background: transparent;
-  background: rgba(0, 200, 0, .4);
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#6600c800, endColorstr=#4c00c800);
+  border: 0 !important;
+  background: #7e7;
 }
-/* Kludge to turn off filter in ie9+, which also accepts rgba */
-.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor:not(#nonsense_id) {
-  filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
+.cm-fat-cursor div.CodeMirror-cursors {
+  z-index: 1;
+}
+
+.cm-animate-fat-cursor {
+  width: auto;
+  border: 0;
+  -webkit-animation: blink 1.06s steps(1) infinite;
+  -moz-animation: blink 1.06s steps(1) infinite;
+  animation: blink 1.06s steps(1) infinite;
+  background-color: #7e7;
+}
+@-moz-keyframes blink {
+  0% {}
+  50% { background-color: transparent; }
+  100% {}
+}
+@-webkit-keyframes blink {
+  0% {}
+  50% { background-color: transparent; }
+  100% {}
+}
+@keyframes blink {
+  0% {}
+  50% { background-color: transparent; }
+  100% {}
 }
+
 /* Can style cursor different in overwrite (non-insert) mode */
-.CodeMirror div.CodeMirror-cursor.CodeMirror-overwrite {}
+.CodeMirror-overwrite .CodeMirror-cursor {}
+
+.cm-tab { display: inline-block; text-decoration: inherit; }
+
+.CodeMirror-ruler {
+  border-left: 1px solid #ccc;
+  position: absolute;
+}
 
 /* DEFAULT THEME */
 
+.cm-s-default .cm-header {color: blue;}
+.cm-s-default .cm-quote {color: #090;}
+.cm-negative {color: #d44;}
+.cm-positive {color: #292;}
+.cm-header, .cm-strong {font-weight: bold;}
+.cm-em {font-style: italic;}
+.cm-link {text-decoration: underline;}
+.cm-strikethrough {text-decoration: line-through;}
+
 .cm-s-default .cm-keyword {color: #708;}
 .cm-s-default .cm-atom {color: #219;}
 .cm-s-default .cm-number {color: #164;}
 .cm-s-default .cm-def {color: #00f;}
-.cm-s-default .cm-variable {color: black;}
+.cm-s-default .cm-variable,
+.cm-s-default .cm-punctuation,
+.cm-s-default .cm-property,
+.cm-s-default .cm-operator {}
 .cm-s-default .cm-variable-2 {color: #05a;}
 .cm-s-default .cm-variable-3 {color: #085;}
-.cm-s-default .cm-property {color: black;}
-.cm-s-default .cm-operator {color: black;}
 .cm-s-default .cm-comment {color: #a50;}
 .cm-s-default .cm-string {color: #a11;}
 .cm-s-default .cm-string-2 {color: #f50;}
 .cm-s-default .cm-meta {color: #555;}
-.cm-s-default .cm-error {color: #f00;}
 .cm-s-default .cm-qualifier {color: #555;}
 .cm-s-default .cm-builtin {color: #30a;}
 .cm-s-default .cm-bracket {color: #997;}
 .cm-s-default .cm-tag {color: #170;}
 .cm-s-default .cm-attribute {color: #00c;}
-.cm-s-default .cm-header {color: blue;}
-.cm-s-default .cm-quote {color: #090;}
 .cm-s-default .cm-hr {color: #999;}
 .cm-s-default .cm-link {color: #00c;}
 
-.cm-negative {color: #d44;}
-.cm-positive {color: #292;}
-.cm-header, .cm-strong {font-weight: bold;}
-.cm-em {font-style: italic;}
-.cm-emstrong {font-style: italic; font-weight: bold;}
-.cm-link {text-decoration: underline;}
-
+.cm-s-default .cm-error {color: #f00;}
 .cm-invalidchar {color: #f00;}
 
+.CodeMirror-composing { border-bottom: 2px solid; }
+
+/* Default styles for common addons */
+
 div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
 div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
+.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
+.CodeMirror-activeline-background {background: #e8f2ff;}
 
 /* STOP */
 
@@ -103,28 +146,30 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
    the editor. You probably shouldn't touch them. */
 
 .CodeMirror {
-  line-height: 1;
   position: relative;
   overflow: hidden;
+  background: white;
 }
 
 .CodeMirror-scroll {
+  overflow: scroll !important; /* Things will break if this is overridden */
   /* 30px is the magic margin used to hide the element's real scrollbars */
-  /* See overflow: hidden in .CodeMirror, and the paddings in .CodeMirror-sizer */
+  /* See overflow: hidden in .CodeMirror */
   margin-bottom: -30px; margin-right: -30px;
-  padding-bottom: 30px; padding-right: 30px;
+  padding-bottom: 30px;
   height: 100%;
   outline: none; /* Prevent dragging from highlighting the element */
   position: relative;
 }
 .CodeMirror-sizer {
   position: relative;
+  border-right: 30px solid transparent;
 }
 
 /* The fake, visible scrollbars. Used to force redraw during scrolling
    before actual scrolling happens, thus preventing shaking and
    flickering artifacts. */
-.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler {
+.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
   position: absolute;
   z-index: 6;
   display: none;
@@ -141,33 +186,55 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
 }
 .CodeMirror-scrollbar-filler {
   right: 0; bottom: 0;
-  z-index: 6;
+}
+.CodeMirror-gutter-filler {
+  left: 0; bottom: 0;
 }
 
 .CodeMirror-gutters {
   position: absolute; left: 0; top: 0;
-  height: 100%;
+  min-height: 100%;
   z-index: 3;
 }
 .CodeMirror-gutter {
+  white-space: normal;
   height: 100%;
   display: inline-block;
+  vertical-align: top;
+  margin-bottom: -30px;
   /* Hack to make IE7 behave */
   *zoom:1;
   *display:inline;
 }
+.CodeMirror-gutter-wrapper {
+  position: absolute;
+  z-index: 4;
+  background: none !important;
+  border: none !important;
+}
+.CodeMirror-gutter-background {
+  position: absolute;
+  top: 0; bottom: 0;
+  z-index: 4;
+}
 .CodeMirror-gutter-elt {
   position: absolute;
   cursor: default;
   z-index: 4;
 }
+.CodeMirror-gutter-wrapper {
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  user-select: none;
+}
 
 .CodeMirror-lines {
   cursor: text;
+  min-height: 1px; /* prevents collapsing before first draw */
 }
 .CodeMirror pre {
   /* Reset some styles that the rest of the page might have set */
-  -moz-border-radius: 0; -webkit-border-radius: 0; -o-border-radius: 0; border-radius: 0;
+  -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
   border-width: 0;
   background: transparent;
   font-family: inherit;
@@ -180,12 +247,16 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
   z-index: 2;
   position: relative;
   overflow: visible;
+  -webkit-tap-highlight-color: transparent;
+  -webkit-font-variant-ligatures: none;
+  font-variant-ligatures: none;
 }
 .CodeMirror-wrap pre {
   word-wrap: break-word;
   white-space: pre-wrap;
   word-break: normal;
 }
+
 .CodeMirror-linebackground {
   position: absolute;
   left: 0; right: 0; top: 0; bottom: 0;
@@ -198,30 +269,51 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
   overflow: auto;
 }
 
-.CodeMirror-wrap .CodeMirror-scroll {
-  overflow-x: hidden;
+.CodeMirror-widget {}
+
+.CodeMirror-code {
+  outline: none;
+}
+
+/* Force content-box sizing for the elements where we expect it */
+.CodeMirror-scroll,
+.CodeMirror-sizer,
+.CodeMirror-gutter,
+.CodeMirror-gutters,
+.CodeMirror-linenumber {
+  -moz-box-sizing: content-box;
+  box-sizing: content-box;
 }
 
 .CodeMirror-measure {
   position: absolute;
-  width: 100%; height: 0px;
+  width: 100%;
+  height: 0;
   overflow: hidden;
   visibility: hidden;
 }
+
+.CodeMirror-cursor { position: absolute; }
 .CodeMirror-measure pre { position: static; }
 
-.CodeMirror div.CodeMirror-cursor {
-  position: absolute;
+div.CodeMirror-cursors {
   visibility: hidden;
-  border-right: none;
-  width: 0;
+  position: relative;
+  z-index: 3;
+}
+div.CodeMirror-dragcursors {
+  visibility: visible;
 }
-.CodeMirror-focused div.CodeMirror-cursor {
+
+.CodeMirror-focused div.CodeMirror-cursors {
   visibility: visible;
 }
 
 .CodeMirror-selected { background: #d9d9d9; }
 .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
+.CodeMirror-crosshair { cursor: crosshair; }
+.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
+.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
 
 .cm-searching {
   background: #ffa;
@@ -231,9 +323,18 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
 /* IE7 hack to prevent it from returning funny offsetTops on the spans */
 .CodeMirror span { *vertical-align: text-bottom; }
 
+/* Used to force a border model for a node */
+.cm-force-border { padding-right: .1px; }
+
 @media print {
   /* Hide the cursor when printing */
-  .CodeMirror div.CodeMirror-cursor {
+  .CodeMirror div.CodeMirror-cursors {
     visibility: hidden;
   }
 }
+
+/* See issue #2901 */
+.cm-tab-wrap-hack:after { content: ''; }
+
+/* Help users use markselection to safely style text background */
+span.CodeMirror-selectedtext { background: none; }
diff --git a/docs/css/react.scss b/docs/css/react.scss
index 0513b15eea56..3201a9df3346 100644
--- a/docs/css/react.scss
+++ b/docs/css/react.scss
@@ -7,8 +7,9 @@
 
 @mixin code-typography {
   font-family: 'source-code-pro', Menlo, Consolas, 'Courier New', monospace;
-  font-size: 13px;
   line-height: 1.5;
+  font-size: 13px;
+  -webkit-text-size-adjust: none;
 }
 
 $skinnyContentWidth: 650px;
@@ -19,7 +20,28 @@ $columnGutter: 40px;
 $twoColumnWidth: 2 * $columnWidth + $columnGutter;
 $navHeight: 50px;
 
+// Breakpoints
+$bp-large: 960px;
+$bp-medium: 640px;
+$bp-small: 480px;
 
+@mixin bp-small {
+  @media (max-width: $bp-small) {
+    @content;
+  }
+}
+
+@mixin bp-medium {
+  @media (max-width: $bp-medium) {
+    @content;
+  }
+}
+
+@mixin bp-large {
+  @media (max-width: $bp-large) {
+    @content;
+  }
+}
 
 // basic reset
 * {
@@ -46,15 +68,20 @@ html {
 
 .container {
   padding-top: $navHeight;
-  min-width: $contentWidth + (2 * $contentPadding);
+  width: 100%;
 }
 
 .wrap {
-  width: $contentWidth + (2 * $contentPadding);
+  max-width: $contentWidth + (2 * $contentPadding);
   margin-left: auto;
   margin-right: auto;
   padding-left: 20px;
   padding-right: 20px;
+
+  @include bp-large {
+    padding-left: 10px;
+    padding-right: 10px;
+  }
 }
 
 .skinnyWrap {
@@ -95,6 +122,7 @@ h1, h2, h3, h4, h5, h6 {
 .hash-link {
   color: $mediumTextColor;
   display: none;
+  padding-left: 8px;
 }
 
 // Main Nav
@@ -110,21 +138,21 @@ h1, h2, h3, h4, h5, h6 {
   width: 100%;
   z-index: 100;
 
+  @include bp-large {
+    height: auto;
+  }
+
   a {
     color: $lightColor;
     text-decoration: none;
   }
 
-  .nav-site-internal {
-    margin: 0 0 0 20px;
-  }
-
-  .nav-site-external {
-    float: right;
-    margin: 0;
-  }
-
   .nav-site {
+    display: inline-flex;
+    display: -ms-flexbox;
+    flex: 1;
+    -ms-flex: 1;
+
     li {
       margin: 0;
     }
@@ -136,17 +164,82 @@ h1, h2, h3, h4, h5, h6 {
       display: inline-block;
       height: $navHeight;
       color: #ddd;
+      white-space: nowrap;
+
+      @include bp-large {
+        display: flex;
+        display: -ms-flex;
+        justify-content: center;
+        align-items: center;
+        padding: 0 5px;
+        line-height: inherit;
+      }
 
       &:hover {
         color: #fff;
       }
 
       &.active {
+        position: relative;
         color: $lightTextColor;
-        border-bottom: 3px solid $primary;
         background: #333;
+
+        &:after {
+          content: "";
+          position: absolute;
+          bottom: 0;
+          left: 0;
+          right: 0;
+          border-bottom: 3px solid $primary;
+        }
+
+        @include bp-large {
+          background: inherit;
+        }
       }
     }
+
+    .nav-site-item {
+      &--hidden-sm {
+        @include bp-large {
+          display: none;
+        }
+      }
+    }
+
+    .nav-site-search {
+      @include bp-large {
+        position: absolute;
+        z-index: 1;
+        right: 0;
+        top: 0;
+        margin: 0 10px;
+
+        &:focus {
+          width: 170px;
+        }
+      }
+    }
+  }
+
+  .nav-site-internal {
+    margin: 0 0 0 20px;
+
+    @include bp-large {
+      margin: 0;
+    }
+  }
+
+  .nav-site-external {
+    float: right;
+    margin: 0;
+
+    @include bp-large {
+      position: absolute;
+      top: 0;
+      right: 55px;
+      float: none;
+    }
   }
 
   .nav-home {
@@ -155,11 +248,20 @@ h1, h2, h3, h4, h5, h6 {
     line-height: $navHeight;
     height: $navHeight;
     display: inline-block;
+
+    @include bp-large {
+      font-size: 20px;
+    }
   }
 
   .nav-logo {
     vertical-align: middle;
     display: inline-block;
+
+    @include bp-large {
+      height: 30px;
+      width: auto;
+    }
   }
 
   ul {
@@ -172,10 +274,37 @@ h1, h2, h3, h4, h5, h6 {
   }
 }
 
+.nav-lists {
+  display: inline-block;
+  vertical-align: top;
+  width: calc(100% - 120px);
+
+  @include bp-large {
+    display: flex;
+    display: -ms-flex;
+    width: calc(100% + 20px);
+    margin: 0 -10px;
+    font-size: 0.9em;
+
+    li {
+      display: flex;
+      display: -ms-flex;
+      -ms-flex: 1 0 auto;
+      align-items: center;
+
+      a {
+        -ms-flex: 1;
+        text-align: center;
+        line-height: 1.2;
+      }
+    }
+  }
+}
+
 // Hero!
 
 .hero {
-  height: 300px;
+  min-height: 300px;
   // background: $darkColor url(../img/header.png) no-repeat center;
   background: $darkColor;
   padding-top: 50px;
@@ -200,8 +329,13 @@ h1, h2, h3, h4, h5, h6 {
 }
 
 .buttons-unit {
+  display: flex;
+  display: flex;
+  justify-content: center;
+  flex-wrap: wrap;
   margin-top: 60px;
   text-align: center;
+  font-size: 1em;
 
   a {
     color: $blueColor;
@@ -215,6 +349,11 @@ h1, h2, h3, h4, h5, h6 {
     &:active {
       background: darken($primary, 5%);
     }
+
+    @include bp-large {
+      margin: 5px;
+      font-size: 1em;
+    }
   }
 }
 
@@ -233,12 +372,17 @@ h1, h2, h3, h4, h5, h6 {
   float: left;
   width: 210px;
 
+  @include bp-medium {
+    width: 100%;
+    padding-bottom: 40px;
+  }
+
   ul {
     list-style: none;
     margin: 0;
   }
   ul ul {
-    margin: 6px 0 0 20px;
+    margin: 0 0 6px 20px;
   }
   li {
     line-height: 16px;
@@ -292,6 +436,25 @@ h1, h2, h3, h4, h5, h6 {
       padding-bottom: 0;
       border-bottom: 0;
     }
+
+    > ul {
+      @include bp-medium {
+        columns: 2
+      }
+
+      @include bp-small {
+        columns: 1;
+      }
+
+      li {
+        margin: 0;
+
+        a {
+          padding: 0;
+          line-height: 1.6;
+        }
+      }
+    }
   }
 
 }
@@ -311,7 +474,8 @@ h1, h2, h3, h4, h5, h6 {
 .home-divider {
   border-top-color: #bbb;
   margin: 0 auto;
-  width: 400px;
+  width: 100%;
+  max-width: 400px;
 }
 
 .skinny-row {
@@ -337,11 +501,16 @@ h1, h2, h3, h4, h5, h6 {
   margin-left: 40px;
   width: $columnWidth;
 
+  @include bp-large {
+    margin: 0;
+    width: 100%;
+  }
+
   h3 {
     color: $darkColor;
     font-size: 24px;
+    line-height: 28px;
     font-weight: normal;
-    text-transform: uppercase;
   }
   p {
     font-size: 16px;
@@ -447,14 +616,6 @@ h1, h2, h3, h4, h5, h6 {
   float: right;
 }
 
-footer {
-  font-size: 13px;
-  font-weight: 600;
-  margin-top: 36px;
-  margin-bottom: 18px;
-  overflow: auto;
-}
-
 section.black content {
   padding-bottom: 18px;
 }
@@ -467,6 +628,10 @@ section.black content {
   @include clearfix;
 
   padding-top: 20px;
+  padding-bottom: 80px;
+  @include bp-medium {
+    padding-bottom: 0;
+  }
 
   blockquote {
     padding: 5px 15px;
@@ -501,13 +666,17 @@ section.black content {
   }
 
   padding-top: 20px;
+  padding-bottom: 80px;
+  @include bp-medium {
+    padding-bottom: 0;
+  }
 
   // Make a notice box out of blockquotes in the documentation:
   blockquote {
       padding: 15px 30px 15px 15px;
       margin: 20px 0;
-      background-color: rgba(204, 122, 111, 0.09999999999999998);
-      border-left: 5px solid rgba(191, 87, 73, 0.19999999999999996);
+      background-color: rgba(248, 245, 236, 0.5);
+      border-left: 5px solid rgba(191, 87, 73, 0.2);
     h4 {
       margin-top: 0;
     }
@@ -608,7 +777,17 @@ figure {
 
 .inner-content {
   float: right;
-  width: $skinnyContentWidth;
+  width: 100%;
+  max-width: $skinnyContentWidth;
+
+  @include bp-large {
+    width: calc(100% - 240px);
+    max-width: 100%;
+  }
+
+  @include bp-medium {
+    width: 100%;
+  }
 }
 
 .nosidebar .inner-content {
@@ -627,8 +806,48 @@ h1 {
   font-weight: normal;
   line-height: 20px;
   margin-top: 17px;
+
+  @include bp-medium {
+    float: left;
+    width: 100%;
+  }
+}
+
+/**
+ * Community
+ */
+
+.communityContent {
+  @include clearfix;
+
+  h3 {
+    margin-top: 30px;
+  }
+
+  padding-top: 20px;
+
+  blockquote {
+    padding: 5px 15px;
+    margin: 20px 0;
+    background-color: #f8f5ec;
+    border-left: 5px solid #f7ebc6;
+  }
+
+  th {
+    padding-right: 6px;
+    text-align: right;
+    vertical-align: top;
+    font-weight: normal;
+    @include code-typography;
+  }
+
+  td {
+    vertical-align: top;
+    text-align: left;
+  }
 }
 
+
 /* Blog */
 
 .post-list-item + .post-list-item {
@@ -702,7 +921,8 @@ p a code {
   border-radius: 0 3px 3px 3px;
   float: left;
   overflow: hidden;
-  width: $twoColumnWidth;
+  width: 100%;
+  max-width: $twoColumnWidth;
 }
 
 .playgroundPreview {
@@ -711,6 +931,7 @@ p a code {
   float: right;
   padding: 15px 20px;
   width: $columnWidth;
+  word-wrap: break-word;
 }
 
 .playgroundError {
@@ -725,6 +946,7 @@ p a code {
 
 .MarkdownEditor .content {
   white-space: pre-wrap;
+  word-break: break-word;
 }
 
 .hll {
@@ -806,9 +1028,9 @@ p a code {
   text-decoration: none !important;
 }
 
-@media screen and (max-width: 960px) {
+@include bp-large {
   .nav-main {
-    position: static;
+    position: relative;
   }
   .container {
     padding-top: 0;
@@ -821,6 +1043,7 @@ p a code {
 
 .post img {
   max-width: 100%;
+  height: auto;
 }
 
 .pagination {
@@ -841,6 +1064,20 @@ div[data-twttr-id] iframe {
   width: 100% !important;
 }
 
+.fb_iframe_widget {
+  max-width: 100%;
+
+  * {
+    max-width: 100%;
+  }
+}
+
+#twitter-widget-0 {
+  @include bp-large {
+    display: none !important; // Need !important because they inline display on the iframe.
+  }
+}
+
 /* Acknowledgements */
 
 .three-column {
@@ -860,12 +1097,6 @@ div[data-twttr-id] iframe {
 
 /* Algolia Doc Search */
 
-@media screen and (max-width: 960px) {
-  #algolia-doc-search {
-    display: none;
-  }
-}
-
 input#algolia-doc-search {
   background: transparent url('/react/img/search.png') no-repeat 10px center;
   background-size: 16px 16px;
@@ -886,10 +1117,21 @@ input#algolia-doc-search {
   width: 170px;
 
   transition: width .2s ease;
-}
 
-input#algolia-doc-search:focus {
-  width: 240px;
+  &:focus {
+    width: 240px;
+  }
+
+  @include bp-large {
+    background-color: transparent;
+    width: 0;
+    cursor: pointer;
+
+    &:focus {
+      width: 200px;
+      background-color: #333;
+    }
+  }
 }
 
 .algolia-autocomplete .aa-dropdown-menu {
@@ -925,3 +1167,96 @@ input#algolia-doc-search:focus {
 .aa-cursor .algolia-docsearch-suggestion {
   background: #f1f3f5;
 }
+
+/**
+ * Footer
+ */
+
+footer.nav-footer {
+  box-sizing: border-box;
+  border: none;
+  font-weight: 300;
+  color: #202020;
+  font-size: 15px;
+  line-height: 24px;
+  background: #2D2D2D;
+  box-shadow: inset 0 10px 10px -5px #0d1116;
+  padding-top: 2em;
+  padding-bottom: 2em;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+footer .sitemap {
+  display: flex;
+  display: -ms-flexbox;
+  justify-content: space-between;
+  max-width: 1080px;
+  margin: 0 auto 3em;
+}
+footer .sitemap div {
+  flex: 1;
+  -ms-flex: 1;
+}
+footer .sitemap .nav-home {
+  display: table;
+  margin: -12px 20px 0 0;
+  padding: 10px;
+  width: 60px;
+  height: 60px;
+  transition: opacity 0.15s ease-in-out;
+  background: url("../img/logo_small_gray.png") no-repeat content-box;
+}
+footer .sitemap .nav-home:hover,
+footer .sitemap .nav-home:focus {
+  background-image: url("../img/logo_small.png");
+}
+@media screen and (max-width: 740px) {
+  footer .sitemap {
+    display: none;
+  }
+}
+
+footer .sitemap a {
+  color: white;
+  display: table;
+  margin: 2px -10px;
+  padding: 3px 10px;
+}
+footer .sitemap a:hover,
+footer .sitemap a:focus {
+  color: #61dafb;
+  text-decoration: none;
+}
+footer .sitemap h6 > a:hover,
+footer .sitemap h6 > a:focus {
+  color: #61dafb;
+  text-decoration: none;
+}
+footer .sitemap h5,
+footer .sitemap h6 {
+  margin: 0 0 10px;
+}
+footer .sitemap h5,
+footer .sitemap h6,
+footer .sitemap h5 > a,
+footer .sitemap h6 > a {
+  color: white;
+}
+footer .sitemap h5 > a,
+footer .sitemap h6 > a {
+  margin: 0 -10px;
+}
+footer .fbOpenSource {
+  display: block;
+  margin: 1em auto;
+  opacity: 0.4;
+  transition: opacity 0.15s ease-in-out;
+  width: 170px;
+}
+footer .fbOpenSource:hover {
+  opacity: 1.0;
+}
+footer .copyright {
+  color: rgba(255, 255, 255, 0.4);
+  text-align: center;
+}
diff --git a/docs/docs/01-why-react.de-DE.md b/docs/docs/01-why-react.de-DE.md
deleted file mode 100644
index 93bd91217c6e..000000000000
--- a/docs/docs/01-why-react.de-DE.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-id: why-react-de-DE
-title: Warum React?
-permalink: why-react-de-DE.html
----
-React ist eine JavaScript-Bibliothek von Facebook und Instagram für Benutzeroberflächen. Man kann sich React als das **V** in **[MVC](https://de.wikipedia.org/wiki/Model_View_Controller)** vorstellen.
-
-Wir haben React für folgende Aufgabe entwickelt: **umfangreiche Anwendungen zu bauen, deren Daten sich zeitlich ändern**.
-
-## Einfach
-
-Beschreibe, wie sich Deine App zu jedem gewünschten Zeitpunkt präsentieren soll und React kümmert sich um alle Benutzeroberflächen-Änderungen sobald sich die zugrundeliegenden Daten ändern.
-
-## Deklarativ
-
-Bei Datenveränderungen drückt React bildlich die "Aktualisieren"-Taste und versteht sich darauf, nur die veränderten Elemente zu erneuern.
-
-## Baue zusammensetzbare Komponenten
-
-React unterstützt die Entwicklung wiederverwendbarer Komponenten. Tatsächlich machst Du in React nichts anderes, als Komponenten zu bauen. Dank ihrer Kapselung erleichtern Komponenten die Wiederverwendung und das Testen von Code sowie die Trennung der Belange. 
-
-## Gib' ihnen fünf Minuten
-
-React hinterfragt eine ganze Reihe konventioneller Standpunkte. Auf den ersten Blick mögen einige Ideen verrückt klingen. [Gib' ihnen fünf Minuten](https://signalvnoise.com/posts/3124-give-it-five-minutes) während Du diese Anleitung liest; diese verrückten Ideen halfen dabei, tausende von Komponenten innerhalb und außerhalb von Facebook und Instagram zu entwickeln.
-
-## Erfahre mehr
-
-Erfahre mehr über unsere Motivation zur Entwicklung von React in [diesem Blogeintrag](/react/blog/2013/06/05/why-react.html).
diff --git a/docs/docs/01-why-react.it-IT.md b/docs/docs/01-why-react.it-IT.md
deleted file mode 100644
index 2fc2f5c0d853..000000000000
--- a/docs/docs/01-why-react.it-IT.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-id: why-react-it-IT
-title: Perché React?
-permalink: why-react-it-IT.html
-next: displaying-data-it-IT.html
----
-React è una libreria JavaScript per creare interfacce utente scritta da Facebook e Instagram. A molti piace pensare a React come alla **V** di **[MVC](https://it.wikipedia.org/wiki/Model-View-Controller)**.
-
-Abbiamo costruito React per risolvere un problema: **costruire applicazioni di grandi dimensioni con dati che cambiano nel tempo**.
-
-## Semplice
-
-Dichiara semplicemente come la tua app debba apparire in ogni istante, e React gestirà automaticamente tutti gli aggiornamenti della UI quando i dati sottostanti cambiano.
-
-## Dichiarativo
-
-Quando i dati cambiano, React preme idealmente il bottone "aggiorna", e sa come aggiornare soltanto le parti che sono cambiate.
-
-## Costruisci Componenti Componibili
-
-React è basato interamente sulla costruzione di componenti riutilizzabili. Infatti, con React l'*unica* cosa che fai è costruire componenti. Dal momento che sono così incapsulati, i componenti facilitano il riutilizzo del codice, la verifica e la separazione dei concetti.
-
-## Dagli Cinque Minuti
-
-React sfida molte convenzioni, e a prima vista alcune delle idee potrebbero sembrare folli. [Dagli cinque minuti](https://signalvnoise.com/posts/3124-give-it-five-minutes) mentre leggi questa guida; quelle idee folli hanno funzionato per costruire migliaia di componenti sia dentro che fuori da Facebook e Instagram.
-
-## Per Approfondire
-
-Puoi approfondire le nostre motivazioni per la costruzione di React leggendo [questo articolo del blog](/react/blog/2013/06/05/why-react.html).
diff --git a/docs/docs/01-why-react.ja-JP.md b/docs/docs/01-why-react.ja-JP.md
deleted file mode 100644
index e9f37b29ab29..000000000000
--- a/docs/docs/01-why-react.ja-JP.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-id: why-react-ja-JP
-title: なぜReactを使うのでしょうか？
-permalink: why-react-ja-JP.html
-next: displaying-data-ja-JP.html
-
----
-ReactはFacebookとInstagramによって作られたユーザーインターフェイスを構築するためのJavaScriptのライブラリです。
-多くの人がReactを **[MVC](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller)** の **V** だと考えています。
-私たちはReactをある1つの問題を解決するために使います。それは、 **絶えず変化していくデータとともに大きなアプリケーションを構築する** ことです。それを行うために、Reactは2つの主要な考えを持っています。
-
-## 単純さ
-
-どのタイミングにおいても、アプリケーションがどのように見えるべきかを単純に表現し、Reactは根底にあるデータの変更があった場合に自動的に全てのUIを管理します。
-
-## 叙述的
-
-データが変わった時、Reactは概念的に「リフレッシュ」ボタンを押し、変わった箇所のみを検知します。
-
-## コンポーザブルなコンポーネントの構築
-Reactは再利用可能なコンポーネントを構築するものです。実際、Reactを用いてあなたがする *ただ1つの* ことは、コンポーネントを構築することです。Reactは無駄な部分を省いてあるので、コンポーネントはコードの再利用、テスト、関心の分離を可能にします。
-
-## 5分ください
-
-Reactは型にはまった知識にも挑戦し、ちらっと見ただけではおかしく見えるアイディアもあるでしょう。このガイドを読むのに[5分ください](https://signalvnoise.com/posts/3124-give-it-five-minutes) 。それらのおかしく見えるアイディアはFacebookやInstagramの中と外の両方で何千ものコンポーネントを構築するために動いています。
-
-## 更なる学習
-
-[このブログの投稿](/react/blog/2013/06/05/why-react.html)で、私たちがReactを構築するモチベーションについて更に学習することができます。
diff --git a/docs/docs/01-why-react.ko-KR.md b/docs/docs/01-why-react.ko-KR.md
deleted file mode 100644
index 93b41993fb49..000000000000
--- a/docs/docs/01-why-react.ko-KR.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-id: why-react-ko-KR
-title: 왜 React인가?
-permalink: why-react-ko-KR.html
-next: displaying-data-ko-KR.html
----
-
-React는 페이스북과 인스타그램에서 사용자 인터페이스를 구성하기 위해 만들어진 라이브러리입니다. 많은 사람들은 React를 **[MVC](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller)** 에서의 **V** 로 생각하는 경향이 있습니다.
-
-우리는 단 하나의 문제를 해결하기 위해 React를 만들었습니다: **지속해서 데이터가 변화하는 대규모 애플리케이션을 구축하기.** 이 문제를 해결하기 위해, React는 두가지 컨셉을 도입했습니다.
-
-## 단순함
-
-당신의 애플리케이션이 특정 시점에 어떻게 보여야 할지를 단순히 표현하는 것만으로, 데이터가 변할 때 React는 자동으로 모든 UI 업데이트를 관리해줍니다.
-
-## 선언적 문법
-
-데이터가 변할 때 React는 "새로 고침" 버튼을 누르듯이 작동하며, 데이터의 바뀐 부분만을 업데이트할 수 있습니다.
-
-## 구성적인 컴포넌트를 만드세요
-
-React는 재사용 가능한 컴포넌트들을 만드는 데에 도움이 됩니다. 사실, React를 사용하면 *단지* 컴포넌트를 만드는 일만 하게 됩니다. 컴포넌트들은 잘 캡슐화되어 되어 있기 때문에, 컴포넌트들은 코드의 재사용성을 높이고, 테스트를 쉽게 해 주며, 관심 분리의 원칙(separation of concerns)을 지키게 해 줍니다.
-
-## 5분만 투자하세요
-
-React는 많은 관습적인 사고에 도전하며, 첫눈에 볼 때는 이상한 아이디어들의 모음이라고 생각할 수도 있습니다. 이 가이드를 읽기 위해 [5분만 투자하세요](https://signalvnoise.com/posts/3124-give-it-five-minutes); 그 이상한 아이디어들은 페이스북과 인스타그램 안팎의 수천 개의 컴포넌트들을 만드는 데에 사용되었기 때문입니다.
-
-## 더 알아보기
-
-[이 블로그 포스트](/react/blog/2013/06/05/why-react.html)에서 React를 만든 우리의 동기에 대해 알아볼 수 있습니다.
diff --git a/docs/docs/01-why-react.md b/docs/docs/01-why-react.md
deleted file mode 100644
index fd94b2f04d0c..000000000000
--- a/docs/docs/01-why-react.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-id: why-react
-title: Why React?
-permalink: why-react.html
-next: displaying-data.html
----
-React is a JavaScript library for creating user interfaces by Facebook and Instagram. Many people choose to think of React as the **V** in **[MVC](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller)**.
-
-We built React to solve one problem: **building large applications with data that changes over time**.
-
-## Simple
-
-Simply express how your app should look at any given point in time, and React will automatically manage all UI updates when your underlying data changes.
-
-## Declarative
-
-When the data changes, React conceptually hits the "refresh" button, and knows to only update the changed parts.
-
-## Build Composable Components
-
-React is all about building reusable components. In fact, with React the *only* thing you do is build components. Since they're so encapsulated, components make code reuse, testing, and separation of concerns easy.
-
-## Give It Five Minutes
-
-React challenges a lot of conventional wisdom, and at first glance some of the ideas may seem crazy. [Give it five minutes](https://signalvnoise.com/posts/3124-give-it-five-minutes) while reading this guide; those crazy ideas have worked for building thousands of components both inside and outside of Facebook and Instagram.
-
-## Learn More
-
-You can learn more about our motivations behind building React in [this blog post](/react/blog/2013/06/05/why-react.html).
diff --git a/docs/docs/01-why-react.zh-CN.md b/docs/docs/01-why-react.zh-CN.md
deleted file mode 100644
index ca1ae0a0f95c..000000000000
--- a/docs/docs/01-why-react.zh-CN.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-id: why-react-zh-CN
-title: 为什么使用 React?
-permalink: why-react-zh-CN.html
-next: displaying-data-zh-CN.html
----
-React 是一个 Facebook 和 Instagram 用来创建用户界面的 JavaScript 库。很多人选择将 React 认为是 **[MVC](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller)** 中的 **V**（视图）。
-
-我们创造 React 是为了解决一个问题：**构建随着时间数据不断变化的大规模应用程序**。
-
-### 简单
-
-仅仅只要表达出你的应用程序在任一个时间点应该呈现的样子，然后当底层的数据变了，React 会自动处理所有用户界面的更新。
-
-### 声明式 (Declarative)
-
-数据变化后，React 概念上与点击“刷新”按钮类似，但仅会更新变化的部分。
-
-## 构建可组合的组件
-
-React 都是关于构建可复用的组件。事实上，通过 React 你*唯一*要做的事情就是构建组件。得益于其良好的封装性，组件使代码复用、测试和关注分离（separation of concerns）更加简单。
-
-## 给它5分钟的时间
-
-React挑战了很多传统的知识，第一眼看上去可能很多想法有点疯狂。当你阅读这篇指南，请[给它5分钟的时间](https://signalvnoise.com/posts/3124-give-it-five-minutes)；那些疯狂的想法已经帮助 Facebook 和 Instagram 从里到外创建了上千的组件了。
-
-## 了解更多
-
-你可以从这篇[博客](/react/blog/2013/06/05/why-react.html)了解更多我们创造 React 的动机。
diff --git a/docs/docs/02-displaying-data.it-IT.md b/docs/docs/02-displaying-data.it-IT.md
deleted file mode 100644
index d2fd2f27b42f..000000000000
--- a/docs/docs/02-displaying-data.it-IT.md
+++ /dev/null
@@ -1,128 +0,0 @@
----
-id: displaying-data-it-IT
-title: Visualizzare Dati
-permalink: displaying-data-it-IT.html
-prev: why-react-it-IT.html
-next: jsx-in-depth-it-IT.html
----
-
-L'attività più basilare che puoi effettuare con una UI è mostrare dei dati. React rende visualizzare dati semplice e mantiene automaticamente l'interfaccia aggiornata quando i dati cambiano.
-
-
-## Per Cominciare
-
-Diamo un'occhiata ad un esempio davvero semplice. Creiamo un file dal nome `hello-react.html` con il codice seguente:
-
-```html
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="UTF-8" />
-    <title>Hello React</title>
-    <script src="https://fb.me/react-{{site.react_version}}.js"></script>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
-  </head>
-  <body>
-    <div id="example"></div>
-    <script type="text/babel">
-
-      // ** Il tuo codice va qui! **
-
-    </script>
-  </body>
-</html>
-```
-
-Nel resto della documentazione, ci concentreremo soltanto sul codice JavaScript e assumeremo che sia inserito in un modello come quello qui sopra. Sostituisci il commento segnaposto qui sopra con il seguente codice JSX:
-
-```javascript
-var HelloWorld = React.createClass({
-  render: function() {
-    return (
-      <p>
-        Ciao, <input type="text" placeholder="Scrivi il tuo nome" />!
-        È il {this.props.date.toTimeString()}
-      </p>
-    );
-  }
-});
-
-setInterval(function() {
-  ReactDOM.render(
-    <HelloWorld date={new Date()} />,
-    document.getElementById('example')
-  );
-}, 500);
-```
-
-
-## Aggiornamenti Reattivi
-
-Apri `hello-react.html` in un browser web e scrivi il tuo nome nel campo di testo. Osserva che React cambia soltanto la stringa di testo dell'ora nella UI — ogni input che inserisci nel campo di testo rimane, anche se non hai scritto alcun codice che gestisce questo comportamento. React lo capisce da solo al tuo posto e fa la cosa giusta.
-
-La maniera in cui siamo in grado di capirlo è che React non manipola il DOM a meno che non sia necessario. **Utilizza un DOM interno fittizio e veloce per effettuare confronti ed effettuare le mutazioni del DOM più efficienti al tuo posto.**
-
-Gli input di questo componente sono chiamati `props` — breve per "properties". Sono passati come attributi nella sintassi JSX. Puoi pensare ad essi come immutabili nel contesto del componente, ovvero, **non assegnare mai `this.props`**.
-
-
-## I Componenti Sono Come Funzioni
-
-I componenti React sono molto semplici. Puoi immaginarli come semplici funzioni che ricevono in ingresso `props` e `state` (discusso in seguito) e rendono HTML. Fatta questa premessa, i componenti sono molto semplici da descrivere.
-
-> Nota:
->
-> **Una limitazione**: i componenti React possono rendere soltanto un singolo nodo radice. Se desideri restituire nodi multipli, essi *devono* essere avvolti in un singolo nodo radice.
-
-
-## Sintassi JSX
-
-Crediamo fermamente che i componenti sono la maniera corretta di separare i concetti anziché i "modelli" e la "logica di presentazione." Pensiamo che il markup e il codice che lo genera siano intimamente collegati. Inoltre, la logica di presentazione è solitamente molto complessa e usare un linguaggio di modello per esprimerla risulta dispendioso.
-
-Abbiamo scoperto che la migliore soluzione a questo problema è generare HTML e un albero di componenti direttamente dal codice JavaScript in maniera da poter utilizzare tutta la potenza espressiva di un vero linguaggio di programmazione per costruire UI.
-
-Per rendere il compito più facile, abbiamo aggiunto una semplice e **opzionale** sintassi simile all'HTML per creare questi nodi di albero React.
-
-**JSX ti permette di creare oggetti JavaScript usando una sintassi HTML.** Per generare un collegamento in React usando puro JavaScript puoi scrivere:
-
-`React.createElement('a', {href: 'https://facebook.github.io/react/'}, 'Ciao!')`
-
-Con JSX ciò diventa:
-
-`<a href="https://facebook.github.io/react/">Ciao!</a>`
-
-Abbiamo scoperto che questo ha reso la costruzione di applicazioni React più semplice e i designer tendono a preferire la sintassi, ma ciascuno ha un diverso flusso di lavoro, quindi **JSX non è richiesto per utilizzare React.**
-
-JSX è di dimensioni contenute. Per maggiori informazioni, consulta [JSX in profondità](/react/docs/jsx-in-depth-it-IT.html). Oppure osserva la trasformazione in tempo reale sulla [REPL di Babel](https://babeljs.io/repl/).
-
-JSX è simile all'HTML, ma non proprio identico. Consulta la guida [JSX gotchas](/react/docs/jsx-gotchas-it-IT.html) per alcune differenze fondamentali.
-
-[Babel offre una varietà di strumenti per cominciare a usare JSX](http://babeljs.io/docs/setup/), dagli strumenti a riga di comando alle integrazioni in Ruby on Rails. Scegli lo strumento che funziona meglio per te.
-
-
-## React senza JSX
-
-JSX è completamente opzionale; non è necessario utilizzare JSX con React. Puoi creare elementi React in puro JavaScript usando `React.createElement`, che richiede un nome di tag o di componente, un oggetto di proprietà e un numero variabile di argomenti che rappresentano nodi figli opzionali.
-
-```javascript
-var child1 = React.createElement('li', null, 'Primo Contenuto di Testo');
-var child2 = React.createElement('li', null, 'Secondo Contenuto di Testo');
-var root = React.createElement('ul', { className: 'my-list' }, child1, child2);
-ReactDOM.render(root, document.getElementById('example'));
-```
-
-Per comodità, puoi creare funzioni factory scorciatoia per costruire elementi da componenti personalizzati.
-
-```javascript
-var Factory = React.createFactory(ComponentClass);
-...
-var root = Factory({ custom: 'prop' });
-ReactDOM.render(root, document.getElementById('example'));
-```
-
-React possiede già delle factory predefinite per i tag HTML comuni:
-
-```javascript
-var root = React.DOM.ul({ className: 'my-list' },
-             React.DOM.li(null, 'Contenuto di Testo')
-           );
-```
diff --git a/docs/docs/02-displaying-data.ja-JP.md b/docs/docs/02-displaying-data.ja-JP.md
deleted file mode 100644
index da5ad25ac163..000000000000
--- a/docs/docs/02-displaying-data.ja-JP.md
+++ /dev/null
@@ -1,124 +0,0 @@
----
-id: displaying-data-ja-JP
-title: データを表示する
-permalink: displaying-data-ja-JP.html
-prev: why-react-ja-JP.html
-next: jsx-in-depth-ja-JP.html
-
----
-
-UIについて、最も基本的なことは、いくつかのデータを表示することです。Reactはデータを表示し、変更された時にはインターフェースを最新の状態に自動的に保つことが簡単にできるようになっています。
-
-## はじめに
-
-本当に単純な例を見てみましょう。`hello-react.html` ファイルを以下のようなコードで作成してください。
-
-```html
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="UTF-8" />
-    <title>Hello React</title>
-    <script src="https://fb.me/react-{{site.react_version}}.js"></script>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
-  </head>
-  <body>
-    <div id="example"></div>
-    <script type="text/babel">
-
-      // ** コードをここに書きます！ **
-
-    </script>
-  </body>
-</html>
-```
-
-このドキュメントの中では、JavaScriptのコードにのみフォーカスします。そして、それが上のようなテンプレートに挿入されていると考えます。
-
-```javascript
-var HelloWorld = React.createClass({
-  render: function() {
-    return (
-      <p>
-        Hello, <input type="text" placeholder="Your name here" />!
-        It is {this.props.date.toTimeString()}
-      </p>
-    );
-  }
-});
-
-setInterval(function() {
-  ReactDOM.render(
-    <HelloWorld date={new Date()} />,
-    document.getElementById('example')
-  );
-}, 500);
-```
-
-
-## リアクティブなアップデート
-
-`hello-react.html` をウェブブラウザで開き、テキストフィールドにあなたの名前を入力してください。ReactはUIのうち、時間の文字列しか変更しないことに注意してください。あなたがテキストフィールドに入力したものは残っています。あなたはそういったコードを書いていないのにも関わらずです。Reactはあなたのことを理解しており、正しいことを行います。
-
-このことについて私たちが理解できる方法は、Reactは必要になるまで、DOMの操作を行わないということです。 **Reactは、DOMの変化を表現し、あなたにもっとも効率的なDOMの変化を見積もるために早い、内部のモックのDOMを使っています。**
-
-このコンポーネントのインプットは `props` と呼ばれるものです。"properties" の省略形です。それらはJSXシンタックスの中でアトリビュートとして渡されます。それらはコンポーネントの中で不変と考えるべきで、 **`this.props` には書き込まないようにしてください**
-
-## コンポーネントは関数のようなものです。
-
-Reactのコンポーネントはとても単純です。それらは `props` や `state`　（後述します）を取り、HTMLをレンダリングする単純な関数だと考えることができます。この考えの元、コンポーネントは簡単に理解することができます。
-
-> 注意:
->
-> **1つの制限**: Reactのコンポーネントは単一の最上位のノードだけをレンダリングします。複数のノードをリターンしたい場合は、単一の最上位のもので *ラップする必要があります* 。
-
-## JSXシンタックス
-
-私たちは関心を分離する正しい方法は「テンプレート」と「ディスプレイロジック」ではなくコンポーネントであると強く考えています。ビューを生成するマークアップとコードは密接につながっていると考えています。加えて、ディスプレイロジックはとても複雑になりえますし、ビューを表現するのにテンプレート言語を使うことはとてもややこしくなりえます。
-
-私たちは、この問題の最適解は、UIを構築するのにリアルなプログラミング言語の表現力の全てを使うことができるように、JavaScriptのコードからHTMLやコンポーネントのツリーを直接生成することだと発見しました。
-
-上記のことを簡単に行うために、私たちはReactのツリーノードを構築するためのとても単純で、 **オプショナルな** HTMLに似たシンタックスを加えました。
-
-**JSXはHTMLのシンタックスを使ってJavaScriptのオブジェクトを構築するのを可能にします。** 純粋にJavaScriptを使ってReactでリンクを構築するには、以下のように書きます。
-
-`React.createElement('a', {href: 'https://facebook.github.io/react/'}, 'Hello!')`
-
-JSXでは、以下のように変換されます。
-
-`<a href="https://facebook.github.io/react/">Hello!</a>`
-
-以上のようなことで、Reactのアプリを作成するのは簡単になりましたし、デザイナーはこのシンタックスを好むようになると発見しました。しかし、人は自分自身のワークフローを持っているものです。 **JSXはReactを使う際に必ずしも必要ではありません。**
-
-JSXはとても小さいです。さらに学ぶためには、[JSXの深層](/react/docs/jsx-in-depth-ja-JP.html)を参照ください。または、[ライブJSXコンパイラー](/react/jsx-compiler.html)で変換の動作を確認してください。
-
-JSXはHTMLに似ていますが、正確に同じではありません。いくつかのキーの違いについては[JSXの理解](/react/docs/jsx-gotchas.html) をご覧ください。
-
-JSXを初めて使う際に最も簡単なのは、ブラウザで `JSXTransformer` を使う方法です。これはプロダクションでは使わないことを強くお勧めします。コードは、コマンドラインの[react-tools](https://www.npmjs.com/package/react-tools)パッケージを使うことでプリコンパイルできます。
-
-## JSXを使わないReact
-
-JSXは完全にオプションです。Reactと一緒にJSXを使う必要はありません。`React.createElement` を使って、ただのJavaScriptでReactの要素を作ることもできます。それは、タグの名前やコンポーネント、プロパティのオブジェクト、いくつかのオプションの子要素をとります。
-
-```javascript
-var child1 = React.createElement('li', null, 'First Text Content');
-var child2 = React.createElement('li', null, 'Second Text Content');
-var root = React.createElement('ul', { className: 'my-list' }, child1, child2);
-ReactDOM.render(root, document.getElementById('example'));
-```
-便利に書くために、カスタムコンポーネントで要素を作るために簡略した記法でファクトリー関数を作ることができます。
-
-```javascript
-var Factory = React.createFactory(ComponentClass);
-...
-var root = Factory({ custom: 'prop' });
-ReactDOM.render(root, document.getElementById('example'));
-```
-
-Reactはすでに、共通なHTMLのタグについてはビルトインの関数を持っています。
-
-```javascript
-var root = React.DOM.ul({ className: 'my-list' },
-             React.DOM.li(null, 'Text Content')
-           );
-```
diff --git a/docs/docs/02-displaying-data.ko-KR.md b/docs/docs/02-displaying-data.ko-KR.md
deleted file mode 100644
index df801d1556c8..000000000000
--- a/docs/docs/02-displaying-data.ko-KR.md
+++ /dev/null
@@ -1,124 +0,0 @@
----
-id: displaying-data-ko-KR
-title: 데이터를 표시하기
-permalink: displaying-data-ko-KR.html
-prev: why-react-ko-KR.html
-next: jsx-in-depth-ko-KR.html
----
-
-UI를 가지고 할 수 있는 가장 기초적인 것은 데이터를 표시하는 것입니다. React는 데이터를 표시하고 데이터가 변할 때마다 인터페이스를 최신의 상태로 자동으로 유지하기 쉽게 해 줍니다.
-
-## 시작하기
-
-정말 간단한 예제를 보도록 하죠. 다음과 같은 코드의 `hello-react.html` 파일을 만듭시다.
-
-```html
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="UTF-8" />
-    <title>Hello React</title>
-    <script src="https://fb.me/react-{{site.react_version}}.js"></script>
-    <script src="https://fb.me/react-dom-{{site.react_version}}.js"></script>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
-  </head>
-  <body>
-    <div id="example"></div>
-    <script type="text/babel">
-
-      // ** 코드는 여기에 작성하면 됩니다! **
-
-    </script>
-  </body>
-</html>
-```
-
-문서의 나머지에서, 코드가 위와 같은 HTML 템플릿에 들어갔다고 가정하고 JavaScript 코드에만 집중할 것입니다. 위의 주석 부분을 다음과 같은 JSX 코드로 바꿔 보세요:
-
-```javascript
-var HelloWorld = React.createClass({
-  render: function() {
-    return (
-      <p>
-        안녕, <input type="text" placeholder="이름을 여기에 작성하세요" />!
-        지금 시간은 {this.props.date.toTimeString()} 입니다.
-      </p>
-    );
-  }
-});
-
-setInterval(function() {
-  ReactDOM.render(
-    <HelloWorld date={new Date()} />,
-    document.getElementById('example')
-  );
-}, 500);
-```
-
-## 반응 적(Reactive) 업데이트
-
-`hello-react.html` 파일을 웹 브라우저에서 열어 당신의 이름을 텍스트 필드에 써 보세요. React는 단지 시간을 표시하는 부분만을 바꿉니다 — 텍스트 필드 안에 입력한 것은 그대로 남아 있구요, 당신이 이 동작을 관리하는 그 어떤 코드도 쓰지 않았음에도 불구하고 말이죠. React는 그걸 올바른 방법으로 알아서 해줍니다.
-
-우리가 이걸 할 수 있었던 건, React는 필요한 경우에만 DOM을 조작하기 때문입니다. **React는 빠른 React 내부의 DOM 모형을 이용하여 변경된 부분을 측정하고, 가장 효율적인 DOM 조작 방법을 계산해 줍니다.**
-
-이 컴포넌트에 대한 입력은 `props` 라고 불립니다 — "properties" 를 줄인 것이죠. 그들은 JSX 문법에서는 어트리뷰트로서 전달됩니다. 당신은 `props` 를 컴포넌트 안에서 불변의(immutable) 엘리먼트로서 생각해야 하고, `this.props` 를 덮어씌우려고 해서는 안됩니다.
-
-## 컴포넌트들은 함수와 같습니다
-
-React 컴포넌트들은 매우 단순합니다. 당신은 그것들을 `props` 와 `state` (이것들은 나중에 언급할 것입니다) 를 받고 HTML을 렌더링하는 단순한 함수들로 생각해도 됩니다. 이걸 염두하면, 컴포넌트의 작동을 이해하는 것도 쉽습니다.
-
-> 주의:
->
-> **한가지 제약이 있습니다**: React 컴포넌트들은 단 하나의 루트 노드(root node)만을 렌더할 수 있습니다. 만약 여러개의 노드들을 리턴하고 싶다면, 그것들은 단 하나의 루트 노드로 싸여져 있어야만 합니다.
-
-## JSX 문법
-
-우리는 컴포넌트를 사용하는 것이 "템플릿"과 "디스플레이 로직(display logic)"을 이용하는 것보다 관심을 분리(separate concerns)하는 데에 올바른 방법이라고 강하게 믿고 있습니다. 우리는 마크업과 그것을 만들어내는 코드는 친밀하게 함께 결합되어있다고 생각합니다. 또한, 디스플레이 로직은 종종 매우 복잡하고, 그것을 템플릿 언어를 이용해 표현하는 것은 점점 사용하기 어렵게 됩니다.
-
-우리는 이 문제를 해결하는 최고의 해결책은, UI를 만드는 진짜 프로그래밍 언어의 표현력을 모두 사용할 수 있는 JavaScript 코드로부터 HTML과 컴포넌트 트리들을 생성하는 것임을 발견했습니다.
-
-이것을 더 쉽게 하기 위해서, 우리는 매우 간단하고, **선택적인** HTML과 비슷한 문법을 추가하여 이 React 트리 노드들을 만들 수 있게 했습니다.
-
-**JSX는 당신으로 하여금 HTML 문법을 이용해 JavaScript 객체를 만들게 해줍니다.** React를 이용해 순수한 JavaScript 문법으로 링크를 만드려고 한다면, 코드는 다음과 같습니다:
-
-`React.createElement('a', {href: 'https://facebook.github.io/react/'}, '안녕하세요!')`
-
-JSX를 이용하면:
-
-`<a href="https://facebook.github.io/react/">안녕하세요!</a>`
-
-우리는 이것이 React 앱들을 만들기 쉽게 하고, 디자이너들이 이 문법을 더 선호하는 것을 발견했습니다, 하지만 모든 사람은 그들만의 선호하는 워크플로우가 있기 마련이므로, **JSX는 React를 사용하기 위해 필수적이지는 않습니다.**
-
-JSX는 매우 작은 언어입니다. 그것을 배우고 싶다면, [JSX 깊게 살펴보기](/react/docs/jsx-in-depth-ko-KR.html)를 살펴 보시기 바랍니다. 또는, [바벨 REPL](https://babeljs.io/repl/)를 통해 문법이 변환되는 것을 살펴 보시기 바랍니다.
-
-JSX는 HTML과 비슷하지만, 완전히 똑같지는 않습니다. [JSX의 실수하기 쉬운 부분들](/react/docs/jsx-gotchas-ko-KR.html)에 중요한 차이점들에 대해 설명되어 있습니다.
-
-[바벨에서 JSX를 시작하는 여러 방법을 제공합니다](http://babeljs.io/docs/setup/). 여기에는 커맨드 라인 툴부터 루비 온 레일스 연동까지 다양한 방법이 있습니다. 가장 편한 툴을 사용하세요.
-
-## JSX 없이 React 사용하기
-
-JSX는 완전히 선택적입니다. 당신은 React와 JSX를 함께 사용하지 않아도 상관없습니다. 그냥 JavaScript에서 React 엘리먼트를 `React.createElement`로 만들 수 있습니다. 여기에 태그 이름이나 컴포넌트, 속성 객체, 자식 엘리먼트들을 전달하면 됩니다.
-
-```javascript
-var child1 = React.createElement('li', null, 'First Text Content');
-var child2 = React.createElement('li', null, 'Second Text Content');
-var root = React.createElement('ul', { className: 'my-list' }, child1, child2);
-ReactDOM.render(root, document.getElementById('example'));
-```
-
-편의를 위하여, 당신은 팩토리 함수 헬퍼들을 이용해 커스텀 컴포넌트로부터 엘리먼트들을 만들 수 있습니다.
-
-```javascript
-var Factory = React.createFactory(ComponentClass);
-...
-var root = Factory({ custom: 'prop' });
-ReactDOM.render(root, document.getElementById('example'));
-```
-
-React는 이미 일반적인 HTML 태그에 대한 빌트인 팩토리를 가지고 있습니다.
-
-```javascript
-var root = React.DOM.ul({ className: 'my-list' },
-             React.DOM.li(null, '텍스트')
-           );
-```
diff --git a/docs/docs/02-displaying-data.md b/docs/docs/02-displaying-data.md
deleted file mode 100644
index 719bb7500c9f..000000000000
--- a/docs/docs/02-displaying-data.md
+++ /dev/null
@@ -1,124 +0,0 @@
----
-id: displaying-data
-title: Displaying Data
-permalink: displaying-data.html
-prev: why-react.html
-next: jsx-in-depth.html
----
-
-The most basic thing you can do with a UI is display some data. React makes it easy to display data and automatically keeps the interface up-to-date when the data changes.
-
-## Getting Started
-
-Let's look at a really simple example. Create a `hello-react.html` file with the following code:
-
-```html
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="UTF-8" />
-    <title>Hello React</title>
-    <script src="https://fb.me/react-{{site.react_version}}.js"></script>
-    <script src="https://fb.me/react-dom-{{site.react_version}}.js"></script>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
-  </head>
-  <body>
-    <div id="example"></div>
-    <script type="text/babel">
-
-      // ** Your code goes here! **
-
-    </script>
-  </body>
-</html>
-```
-
-For the rest of the documentation, we'll just focus on the JavaScript code and assume it's inserted into a template like the one above. Replace the placeholder comment above with the following JSX:
-
-```javascript
-var HelloWorld = React.createClass({
-  render: function() {
-    return (
-      <p>
-        Hello, <input type="text" placeholder="Your name here" />!
-        It is {this.props.date.toTimeString()}
-      </p>
-    );
-  }
-});
-
-setInterval(function() {
-  ReactDOM.render(
-    <HelloWorld date={new Date()} />,
-    document.getElementById('example')
-  );
-}, 500);
-```
-
-## Reactive Updates
-
-Open `hello-react.html` in a web browser and type your name into the text field. Notice that React is only changing the time string in the UI — any input you put in the text field remains, even though you haven't written any code to manage this behavior. React figures it out for you and does the right thing.
-
-The way we are able to figure this out is that React does not manipulate the DOM unless it needs to. **It uses a fast, internal mock DOM to perform diffs and computes the most efficient DOM mutation for you.**
-
-The inputs to this component are called `props` — short for "properties". They're passed as attributes in JSX syntax. You should think of these as immutable within the component, that is, **never write to `this.props`**.
-
-## Components are Just Like Functions
-
-React components are very simple. You can think of them as simple functions that take in `props` and `state` (discussed later) and render HTML. With this in mind, components are easy to reason about.
-
-> Note:
->
-> **One limitation**: React components can only render a single root node. If you want to return multiple nodes they *must* be wrapped in a single root.
-
-## JSX Syntax
-
-We strongly believe that components are the right way to separate concerns rather than "templates" and "display logic." We think that markup and the code that generates it are intimately tied together. Additionally, display logic is often very complex and using template languages to express it becomes cumbersome.
-
-We've found that the best solution for this problem is to generate HTML and component trees directly from the JavaScript code such that you can use all of the expressive power of a real programming language to build UIs.
-
-In order to make this easier, we've added a very simple, **optional** HTML-like syntax to create these React tree nodes.
-
-**JSX lets you create JavaScript objects using HTML syntax.** To generate a link in React using pure JavaScript you'd write:
-
-`React.createElement('a', {href: 'https://facebook.github.io/react/'}, 'Hello!')`
-
-With JSX this becomes:
-
-`<a href="https://facebook.github.io/react/">Hello!</a>`
-
-We've found this has made building React apps easier and designers tend to prefer the syntax, but everyone has their own workflow, so **JSX is not required to use React.**
-
-JSX is very small. To learn more about it, see [JSX in depth](/react/docs/jsx-in-depth.html). Or see the transform in action in [the Babel REPL](https://babeljs.io/repl/).
-
-JSX is similar to HTML, but not exactly the same. See [JSX gotchas](/react/docs/jsx-gotchas.html) for some key differences.
-
-[Babel exposes a number of ways to get started using JSX](http://babeljs.io/docs/setup/), ranging from command line tools to Ruby on Rails integrations. Choose the tool that works best for you.
-
-## React without JSX
-
-JSX is completely optional; you don't have to use JSX with React. You can create React elements in plain JavaScript using `React.createElement`, which takes a tag name or component, a properties object, and variable number of optional child arguments.
-
-```javascript
-var child1 = React.createElement('li', null, 'First Text Content');
-var child2 = React.createElement('li', null, 'Second Text Content');
-var root = React.createElement('ul', { className: 'my-list' }, child1, child2);
-ReactDOM.render(root, document.getElementById('example'));
-```
-
-For convenience, you can create short-hand factory functions to create elements from custom components.
-
-```javascript
-var Factory = React.createFactory(ComponentClass);
-...
-var root = Factory({ custom: 'prop' });
-ReactDOM.render(root, document.getElementById('example'));
-```
-
-React already has built-in factories for common HTML tags:
-
-```javascript
-var root = React.DOM.ul({ className: 'my-list' },
-             React.DOM.li(null, 'Text Content')
-           );
-```
diff --git a/docs/docs/02-displaying-data.zh-CN.md b/docs/docs/02-displaying-data.zh-CN.md
deleted file mode 100644
index 8991c63baac3..000000000000
--- a/docs/docs/02-displaying-data.zh-CN.md
+++ /dev/null
@@ -1,124 +0,0 @@
----
-id: displaying-data-zh-CN
-title: 显示数据
-permalink: displaying-data-zh-CN.html
-prev: why-react-zh-CN.html
-next: jsx-in-depth-zh-CN.html
----
-
-用户界面能做的最基础的事就是显示一些数据。React 让显示数据变得简单，当数据变化的时候，用户界面会自动同步更新。
-
-## 开始
-
-让我们看一个非常简单的例子。新建一个名为 `hello-react.html` 的文件，代码内容如下：
-
-```html
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="UTF-8" />
-    <title>Hello React</title>
-    <script src="https://fb.me/react-{{site.react_version}}.js"></script>
-    <script src="https://fb.me/react-dom-{{site.react_version}}.js"></script>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
-  </head>
-  <body>
-    <div id="example"></div>
-    <script type="text/babel">
-
-      // ** 在这里替换成你的代码 **
-
-    </script>
-  </body>
-</html>
-```
-
-在接下去的文档中，我们只关注 JavaScript 代码，假设我们把代码插入到上面那个模板中。用下面的代码替换掉上面用来占位的注释。
-
-```javascript
-var HelloWorld = React.createClass({
-  render: function() {
-    return (
-      <p>
-        Hello, <input type="text" placeholder="Your name here" />!
-        It is {this.props.date.toTimeString()}
-      </p>
-    );
-  }
-});
-
-setInterval(function() {
-  ReactDOM.render(
-    <HelloWorld date={new Date()} />,
-    document.getElementById('example')
-  );
-}, 500);
-```
-
-## 被动更新 (Reactive Updates)
-
-在浏览器中打开 `hello-react.html` ，在输入框输入你的名字。你会发现 React 在用户界面中只改变了时间， 任何你在输入框输入的内容一直保留着，即使你没有写任何代码来完成这个功能。React 为你解决了这个问题，做了正确的事。
-
-我们想到的方法是除非不得不操作 DOM ，React 是不会去操作 DOM 的。**它用一种更快的内置仿造的 DOM 来操作差异，为你计算出出效率最高的 DOM 改变**。
-
-对这个组件的输入称为 `props` - "properties"的缩写。得益于 JSX 语法，它们通过参数传递。你必须知道在组件里，这些属性是不可改变的，也就是说 **`this.props` 是只读的**。
-
-## 组件就像是函数
-
-React 组件非常简单。你可以认为它们就是简单的函数，接受 `props` 和 `state` (后面会讨论) 作为参数，然后渲染出 HTML。正是应为它们是这么的简单，这使得它们非常容易理解。
-
-> 注意:
->
-> **只有一个限制**: React 组件只能渲染单个根节点。如果你想要返回多个节点，它们*必须*被包含在同一个节点里。
-
-## JSX 语法
-
-我们坚信组件是正确方法去做关注分离，而不是通过“模板”和“展示逻辑”。我们认为标签和生成它的代码是紧密相连的。此外，展示逻辑通常是很复杂的，通过模板语言实现这些逻辑会产生大量代码。
-
-我们得出解决这个问题最好的方案是通过 JavaScript 直接生成模板，这样你就可以用一个真正语言的所有表达能力去构建用户界面。
-
-为了使这变得更简单，我们做了一个非常简单、**可选**类似 HTML 语法 ，通过函数调用即可生成模板的编译器，称为 JSX。
-
-**JSX 让你可以用 HTML 语法去写 JavaScript 函数调用** 为了在 React 生成一个链接，通过纯 JavaScript 你可以这么写：
-
-`React.createElement('a', {href: 'https://facebook.github.io/react/'}, 'Hello React!')`。
-
-通过 JSX 这就变成了
-
-`<a href="https://facebook.github.io/react/">Hello React!</a>`。
-
-我们发现这会使搭建 React 应用更加简单，设计师也偏向用这用语法，但是每个人可以有它们自己的工作流，所以**JSX 不是必须用的。**
-
-JSX 非常小；上面“hello, world”的例子使用了 JSX 所有的特性。想要了解更多，请看 [深入理解 JSX](/react/docs/jsx-in-depth-zh-CN.html)。或者直接使用[在线 JSX 编译器](/react/jsx-compiler.html)观察变化过程。
-
-JSX 类似于 HTML，但不是完全一样。参考 [JSX 陷阱](/react/docs/jsx-gotchas-zh-CN.html) 学习关键区别。
-
-[Babel 公开了一些使用 JSX 的方式],从命令行工具到 Ruby on Rails 集成。选择一个对你来说最合适的工具。
-
-## 没有 JSX 的 React
-
-JSX完全是可选的；你无需在 React 中必须使用 JSX。你可以通过 `React.createElement` 来创建一个树。第一个参数是标签，第二个参数是一个属性对象，第三个是子节点。
-
-```javascript
-var child1 = React.createElement('li', null, 'First Text Content');
-var child2 = React.createElement('li', null, 'Second Text Content');
-var root = React.createElement('ul', { className: 'my-list' }, child1, child2);
-ReactDOM.render(root, document.getElementById('example'));
-```
-
-方便起见，你可以创建基于自定义组件的速记工厂方法。
-
-```javascript
-var Factory = React.createFactory(ComponentClass);
-...
-var root = Factory({ custom: 'prop' });
-ReactDOM.render(root, document.getElementById('example'));
-```
-
-React 已经为 HTML 标签提供内置工厂方法。
-
-```javascript
-var root = React.DOM.ul({ className: 'my-list' },
-             React.DOM.li(null, 'Text Content')
-           );
-```
diff --git a/docs/docs/02.1-jsx-in-depth.it-IT.md b/docs/docs/02.1-jsx-in-depth.it-IT.md
deleted file mode 100644
index 0da7a60387b6..000000000000
--- a/docs/docs/02.1-jsx-in-depth.it-IT.md
+++ /dev/null
@@ -1,228 +0,0 @@
----
-id: jsx-in-depth-it-IT
-title: JSX in Profondità
-permalink: jsx-in-depth-it-IT.html
-prev: displaying-data-it-IT.html
-next: jsx-spread-it-IT.html
----
-
-[JSX](https://facebook.github.io/jsx/) è un'estensione della sintassi JavaScript che somiglia all'XML. Puoi usare una semplice trasformazione sintattica di JSX con React.
-
-## Perché JSX?
-
-Non devi per forza utilizzare JSX con React. Puoi anche usare semplice JS. Tuttavia, raccomandiamo di utilizzare JSX perché usa una sintassi concisa e familiare per definire strutture ad albero dotate di attributi.
-
-È più familiare a sviluppatori occasionali come i designer.
-
-L'XML ha i benefici di tag di apertura e chiusura bilanciati. Ciò rende la lettura di grandi strutture ad albero più semplice di chiamate a funzione o oggetti letterali.
-
-Non altera la semantica di JavaScript.
-
-## Tag HTML o Componenti React
-
-React può sia rendere tag HTML (stringhe) che componenti React (classi).
-
-Per rendere untag HTML, usa nomi di tag minuscoli in JSX:
-
-```javascript
-var myDivElement = <div className="foo" />;
-ReactDOM.render(myDivElement, document.getElementById('example'));
-```
-
-Per rendere un componente React, definisci una variabile locale che comincia con una lettera maiuscola:
-
-```javascript
-var MyComponent = React.createClass({/*...*/});
-var myElement = <MyComponent someProperty={true} />;
-ReactDOM.render(myElement, document.getElementById('example'));
-```
-
-Il JSX di React utilizza la convenzione maiuscolo o minuscolo per distinguere tra classi di componenti locali e tag HTML.
-
-> Nota:
->
-> Poiché JSX è JavaScript, gli identificatori come `class` e `for` sono sconsigliati
-> come nomi di attributi XML. Invece, i componenti DOM React si aspettano nomi di proprietà
-> come `className` e `htmlFor` rispettivamente.
-
-## La Trasformazione
-
-Il JSX di React viene trasformato da una sintassi XML a JavaScript nativo. Gli elementi XML, gli attributi e i figli sono trasformati in argomenti passati a `React.createElement`.
-
-```javascript
-var Nav;
-// Input (JSX):
-var app = <Nav color="blue" />;
-// Output (JS):
-var app = React.createElement(Nav, {color:"blue"});
-```
-
-Osserva che per utilizzare `<Nav />`, la variabile `Nav` deve essere visibile.
-
-JSX permette anche di specificare i figli usando una sintassi XML:
-
-```javascript
-var Nav, Profile;
-// Input (JSX):
-var app = <Nav color="blue"><Profile>click</Profile></Nav>;
-// Output (JS):
-var app = React.createElement(
-  Nav,
-  {color:"blue"},
-  React.createElement(Profile, null, "click")
-);
-```
-
-JSX inferirà il [displayName](/react/docs/component-specs-it-IT.html#displayname) della classe dall'assegnazione delle variabile, quando il valore di displayName è indefinito:
-
-```javascript
-// Input (JSX):
-var Nav = React.createClass({ });
-// Output (JS):
-var Nav = React.createClass({displayName: "Nav", });
-```
-
-Usa la [REPL di Babel](https://babeljs.io/repl/) per provare il JSX e vedere come viene trasformato
-in JavaScript nativo, e il
-[convertitore da HTML a JSX](/react/html-jsx.html) per convertire il tuo HTML esistente a
-JSX.
-
-Se desideri utilizzare JSX, la guida [Primi Passi](/react/docs/getting-started-it-IT.html) ti mostra come impostare la compilazione.
-
-> Nota:
->
-> L'espressione JSX viene sempre valutata come un ReactElement. Le implementazioni
-> attuali potrebbero differire. Un modo ottimizzato potrebbe porre il
-> ReactElement in linea come un oggetto letterale per evitare il codice di validazione in
-> `React.createElement`.
-
-## Namespace dei Componenti
-
-Se stai costruendo un componente che ha parecchi figli, come ad esempio un modulo, potresti facilmente trovarti con una quantità di dichiarazioni di variabili:
-
-```javascript
-// Imbarazzante blocco di dichiarazioni di variabili
-var Form = MyFormComponent;
-var FormRow = Form.Row;
-var FormLabel = Form.Label;
-var FormInput = Form.Input;
-
-var App = (
-  <Form>
-    <FormRow>
-      <FormLabel />
-      <FormInput />
-    </FormRow>
-  </Form>
-);
-```
-
-Per rendere tutto ciò più semplice e leggibile, *i componenti con un namespace* ti permettono di usare un componente che dispone di altri componenti come proprietà:
-
-```javascript
-var Form = MyFormComponent;
-
-var App = (
-  <Form>
-    <Form.Row>
-      <Form.Label />
-      <Form.Input />
-    </Form.Row>
-  </Form>
-);
-```
-
-Per fare ciò, devi semplicemente creare i tuoi *"sub-componenti"* come proprietà del componente principale:
-
-```javascript
-var MyFormComponent = React.createClass({ ... });
-
-MyFormComponent.Row = React.createClass({ ... });
-MyFormComponent.Label = React.createClass({ ... });
-MyFormComponent.Input = React.createClass({ ... });
-```
-
-JSX gestirà il tutto correttamente al momento di compilare il tuo codice.
-
-```javascript
-var App = (
-  React.createElement(Form, null,
-    React.createElement(Form.Row, null,
-      React.createElement(Form.Label, null),
-      React.createElement(Form.Input, null)
-    )
-  )
-);
-```
-
-> Nota:
->
-> Questa funzionalità è disponibile nella [v0.11](/react/blog/2014/07/17/react-v0.11.html#jsx) e successive.
-
-## Espressioni JavaScript
-
-### Expressioni come Attributi
-
-Per usare un'espressione JavaScript come valore di un attributo, racchiudi l'espressione in un paio
-di parentesi graffe (`{}`) anziché doppi apici (`""`).
-
-```javascript
-// Input (JSX):
-var person = <Person name={window.isLoggedIn ? window.name : ''} />;
-// Output (JS):
-var person = React.createElement(
-  Person,
-  {name: window.isLoggedIn ? window.name : ''}
-);
-```
-
-### Attributi Booleani
-
-Omettere il valore di un attributo fa in modo che JSX lo tratti come `true`. Per passare `false` occorre utilizzare un'espressione come attributo. Ciò capita spesso quando si usano elementi di moduli HTML, con attributi come `disabled`, `required`, `checked` e `readOnly`.
-
-```javascript
-// Queste due forme sono equivalenti in JSX per disabilitare un bottone
-<input type="button" disabled />;
-<input type="button" disabled={true} />;
-
-// E queste due forme sono equivalenti in JSX per non disabilitare un bottone
-<input type="button" />;
-<input type="button" disabled={false} />;
-```
-
-### Expressioni per Figli
-
-Similmente, espressioni JavaScript possono essere utilizzate per rappresentare figli:
-
-```javascript
-// Input (JSX):
-var content = <Container>{window.isLoggedIn ? <Nav /> : <Login />}</Container>;
-// Output (JS):
-var content = React.createElement(
-  Container,
-  null,
-  window.isLoggedIn ? React.createElement(Nav) : React.createElement(Login)
-);
-```
-
-### Commenti
-
-È facile aggiungere commenti al tuo codice JSX; sono semplici espressioni JS. Devi soltanto prestare attenzione a porre `{}` attorno ai commenti quando ti trovi dentro la sezione figli di un tag.
-
-```javascript
-var content = (
-  <Nav>
-    {/* commento figlio, racchiuso in {} */}
-    <Person
-      /* commento
-         su più
-         righe */
-      name={window.isLoggedIn ? window.name : ''} // fine del commento su una riga
-    />
-  </Nav>
-);
-```
-
-> NOTA:
->
-> JSX è simile all'HTML, ma non esattamente identico. Consulta la guida [JSX gotchas](/react/docs/jsx-gotchas-it-IT.html) per le differenze fondamentali.
diff --git a/docs/docs/02.1-jsx-in-depth.ja-JP.md b/docs/docs/02.1-jsx-in-depth.ja-JP.md
deleted file mode 100644
index dcbd5210e8f5..000000000000
--- a/docs/docs/02.1-jsx-in-depth.ja-JP.md
+++ /dev/null
@@ -1,219 +0,0 @@
----
-id: jsx-in-depth
-title: JSXの深層
-permalink: jsx-in-depth-ja-JP.html
-prev: displaying-data-ja-JP.html
-next: jsx-spread-ja_JP.html
----
-
-[JSX](https://facebook.github.io/jsx/)はXMLに似たJavaScriptのシンタックスの拡張です。Reactでは、単純なJSXのシンタックスの変換を使うことができます。
-
-## なぜJSXを使うのでしょうか？
-
-ReactでJSXの使用を強制されるわけではありません。生のJSを使うこともできます。しかし、JSXは簡潔で、木構造とReactの特性を定義しやすいシンタックスであるため、JSXを使うことをお勧めします。
-
-デザイナーのようなカジュアルな開発者にとってはさらに馴染みやすいでしょう。
-
-XMLにはバランスの取れた開始タグと終了タグという利益があります。このことで、関数がオブジェクトリテラルを呼んでいるのを読むよりも簡単に大きな木構造を作ることができます。
-
-これはJavaScriptのセマンティックスを代替するものではありません。
-
-## HTMLタグ対Reactコンポーネント
-
-ReactはHTMLタグ（文字列）とReactコンポーネント（クラス）の両方をレンダリングすることができます。
-
-以下のようにJSXで小文字のタグ名を使用するだけで、HTMLタグをレンダリングできます。
-
-```javascript
-var myDivElement = <div className="foo" />;
-ReactDOM.render(myDivElement, document.getElementById('example'));
-```
-
-以下のように大文字から始まるローカル変数を作成するだけで、Reactのコンポーネントをレンダリングできます。
-
-```javascript
-var MyComponent = React.createClass({/*...*/});
-var myElement = <MyComponent someProperty={true} />;
-ReactDOM.render(myElement, document.getElementById('example'));
-```
-
-ReactのJSXは大文字と小文字を使うことで、ローカルのコンポーネントクラスとHTMLタグを識別する習慣があります。
-
-> 注意:
->
-> JSXはJavaScriptなので、 `class` や `for` といった識別子はXMLの属性名としては使用しません。代わりに、 ReactのDOMコンポーネントはDOMのプロパティ名がそれぞれ `className` や `htmlFor` といったものであることを期待します。
-
-## The Transform
-
-ReactのJSXはXMLに似たシンタックスをネイティブなJavaScriptに変換します。XML要素や属性や子要素は `React.createElement` で渡される引数に変換されます。
-
-```javascript
-var Nav;
-// 入力 (JSX):
-var app = <Nav color="blue" />;
-// 出力 (JS):
-var app = React.createElement(Nav, {color:"blue"});
-```
-
-`<Nav />` を使うためには、 `Nav` 変数がスコープの中にないといけないことに注意してください。
-
-以下のように、JSXはXMLシンタックスを使うことで、細かな子要素の使用も許可します。
-
-```javascript
-var Nav, Profile;
-// 入力 (JSX):
-var app = <Nav color="blue"><Profile>click</Profile></Nav>;
-// 出力 (JS):
-var app = React.createElement(
-  Nav,
-  {color:"blue"},
-  React.createElement(Profile, null, "click")
-);
-```
-
-以下のように、displayNameがundefinedの時には、JSXはクラスの[displayName](/react/docs/component-specs.html#displayname)を変数の割り当てから予測します。
-
-```javascript
-// 入力 (JSX):
-var Nav = React.createClass({ });
-// 出力 (JS):
-var Nav = React.createClass({displayName: "Nav", });
-```
-
-JSXを試し、どのようにネイティブなJavaScriptに変換されるか見るには、[JSX Compiler](/react/jsx-compiler.html)を、すでに存在するHTMLをJSXに変換するには[HTMLからJSXへのコンバーター](/react/html-jsx.html)を使ってください。
-
-JSXを使いたい場合は、[始めてみましょう](/react/docs/getting-started-ja-JP.html)というガイドがどのようにコンパイルを設定するか示してくれます。
-
-> 注意:
->
-> JSXという表現は常にReactElementを評価します。実際に実行する際の詳細はおそらく異なっているでしょう。最適化されたモードでは `React.createElement` のコードのバリデーションを避けるためにReactElementをオブジェクトリテラルとして配置するでしょう。
-
-
-## ネームスペース化されたコンポーネント
-
-formのように、たくさんの子要素を持つコンポーネントを構築する際には、以下のように多くの変数を宣言しなければいけないでしょう。
-
-```javascript
-// 変数宣言のあまりよくない部分
-var Form = MyFormComponent;
-var FormRow = Form.Row;
-var FormLabel = Form.Label;
-var FormInput = Form.Input;
-
-var App = (
-  <Form>
-    <FormRow>
-      <FormLabel />
-      <FormInput />
-    </FormRow>
-  </Form>
-);
-```
-
-これを単純で簡単にするために、 *ネームスペース化されたコンポーネント* では、以下のように他のコンポーネントを付属物として持つ1つのコンポーネントを使うことができます。
-
-```javascript
-var Form = MyFormComponent;
-
-var App = (
-  <Form>
-    <Form.Row>
-      <Form.Label />
-      <Form.Input />
-    </Form.Row>
-  </Form>
-);
-```
-
-これを行うためには、以下のようにメインコンポーネントの付属物として、「サブコンポーネント」を作るだけで大丈夫です。
-
-```javascript
-var MyFormComponent = React.createClass({ ... });
-
-MyFormComponent.Row = React.createClass({ ... });
-MyFormComponent.Label = React.createClass({ ... });
-MyFormComponent.Input = React.createClass({ ... });
-```
-
-JSXはコードをコンパイルする際にこのプロパティをハンドルします。
-
-```javascript
-var App = (
-  React.createElement(Form, null,
-    React.createElement(Form.Row, null,
-      React.createElement(Form.Label, null),
-      React.createElement(Form.Input, null)
-    )
-  )
-);
-```
-
-> 注意:
-> この特徴は [v0.11](/react/blog/2014/07/17/react-v0.11.html#jsx) 以上で使用できます。
-
-## JavaScriptの表現
-
-### アトリビュートの表現
-
-JavaScriptで書いたものをアトリビュートの値として使うためには、その表現を引用(`""`)ではなく波括弧(`{}`)で囲ってください。
-
-```javascript
-// 入力 (JSX):
-var person = <Person name={window.isLoggedIn ? window.name : ''} />;
-// 出力 (JS):
-var person = React.createElement(
-  Person,
-  {name: window.isLoggedIn ? window.name : ''}
-);
-```
-
-### Booleanのアトリビュート
-
-アトリビュートの値を記述しないと、JSXはそれを `true` として扱ってしまいます。`false` を渡すためには、アトリビュートが使われる必要があります。これらはHTMLのform要素の `disabled` 、 `required` 、 `checked` 、 `readOnly` といったアトリビュートを使う際によく見かけられます。
-
-
-```javascript
-// 以下の2つはボタンを使用不能にするという意味でJSXでは同義です。
-<input type="button" disabled />;
-<input type="button" disabled={true} />;
-
-// 以下の2つはボタンを使用不能にしないという意味でJSXでは同義です。
-<input type="button" />;
-<input type="button" disabled={false} />;
-```
-
-### 子要素の表現
-
-同様に、JavaScriptは子要素を表現するのに使われることもあります。
-
-```javascript
-// 入力 (JSX):
-var content = <Container>{window.isLoggedIn ? <Nav /> : <Login />}</Container>;
-// 出力 (JS):
-var content = React.createElement(
-  Container,
-  null,
-  window.isLoggedIn ? React.createElement(Nav) : React.createElement(Login)
-);
-```
-
-### コメント
-
-JSXにコメントを加えるのは簡単です。ただのJSの書き方です。タグの内側にコメントを書く時には、 `{}` で囲うことに注意してください。
-
-```javascript
-var content = (
-  <Nav>
-    {/* 子要素にコメントを書く時には、 {} で囲う */}
-    <Person
-      /* 複数
-         行
-         コメント */
-      name={window.isLoggedIn ? window.name : ''} // 行末コメント
-    />
-  </Nav>
-);
-```
-
-> 注意:
-> JSXはHTMLに似ていますが、全く同じではありません。いくつかのキーの違いについては[JSXの理解](/react/docs/jsx-gotchas.html) をご覧ください。
diff --git a/docs/docs/02.1-jsx-in-depth.ko-KR.md b/docs/docs/02.1-jsx-in-depth.ko-KR.md
deleted file mode 100644
index cbcdea803403..000000000000
--- a/docs/docs/02.1-jsx-in-depth.ko-KR.md
+++ /dev/null
@@ -1,224 +0,0 @@
----
-id: jsx-in-depth-ko-KR
-title: JSX 깊이보기
-permalink: jsx-in-depth-ko-KR.html
-prev: displaying-data-ko-KR.html
-next: jsx-spread-ko-KR.html
----
-
-[JSX](https://facebook.github.io/jsx/)는 XML과 비슷한 JavaScript문법 확장입니다. React에서 변환되는 간단한 JSX 구문을 사용하실 수 있습니다.
-
-## 왜 JSX인가?
-
-React를 위해 꼭 JSX를 사용할 필요는 없고, 그냥 일반 JS를 사용할 수도 있습니만 JSX를 사용하기를 추천합니다. 왜냐하면, 어트리뷰트를 가진 트리 구조로 정의할 수 있는 간결하고 익숙한 문법이기 때문입니다.
-
-이것은 디자이너 같은 케쥬얼 개발자에게 더 익숙합니다.
-
-XML에는 여닫는 태그의 장점이 있습니다. 태그는 큰 트리일 때 함수 호출이나 객체 리터럴보다 읽기 쉬워 집니다.
-
-JSX는 JavaScript의 시맨틱을 변경하지 않습니다.
-
-## HTML 태그 vs. React 컴포넌트
-
-React는 렌더 HTML 태그(문자열)이나 React 컴포넌트(클래스)일 수 있습니다.
-
-HTML 태그를 렌더하려면, 그냥 JSX에 소문자 태그를 사용하세요.
-
-```javascript
-var myDivElement = <div className="foo" />;
-ReactDOM.render(myDivElement, document.getElementById('example'));
-```
-
-React 컴포넌트를 렌더하려면, 대문자로 시작하는 로컬 변수를 만드세요.
-
-```javascript
-var MyComponent = React.createClass({/*...*/});
-var myElement = <MyComponent someProperty={true} />;
-ReactDOM.render(myElement, document.getElementById('example'));
-```
-
-React JSX는 대소문자를 로컬 컴포넌트 클래스와 HTML 태그를 구별하는 컨벤션으로 사용합니다.
-
-> 주의:
->
-> JSX가 JavaScript기 때문에, `class`, `for`같은 식별자는 XML 어트리뷰트 이름으로
-> 권장하지 않습니다. 대신, React DOM 컴포넌트는 각각 `className`, `htmlFor`같은
-> DOM 프로퍼티 이름을 기대합니다.
-
-<a name="the-transform"></a>
-## 변환
-
-React JSX는 XML같은 문법에서 네이티브 JavaScript로 변환됩니다. XML 엘리먼트, 어트리뷰트, 자식은 `React.createElement`에 넘겨지는 인자로 변환됩니다.
-
-```javascript
-var Nav;
-// 입력 (JSX):
-var app = <Nav color="blue" />;
-// 출력 (JS):
-var app = React.createElement(Nav, {color:"blue"});
-```
-
-`<Nav />`를 사용하려면, `Nav`변수는 스코프에 있어야 합니다.
-
-JSX에서는 XML 구문으로 자식을 지정할 수도 있습니다.
-
-```javascript
-var Nav, Profile;
-// 입력 (JSX):
-var app = <Nav color="blue"><Profile>click</Profile></Nav>;
-// 출력 (JS):
-var app = React.createElement(
-  Nav,
-  {color:"blue"},
-  React.createElement(Profile, null, "click")
-);
-```
-
-클래스에 [displayName](/react/docs/component-specs-ko-KR.html#displayName)이 정의되어 있지 않으면 JSX는 변수명을 displayName으로 간주할 것입니다:
-
-```javascript
-// 입력 (JSX):
-var Nav = React.createClass({ });
-// 출력 (JS):
-var Nav = React.createClass({displayName: "Nav", });
-```
-
-[바벨 REPL](https://babeljs.io/repl/)를 보면 JSX에서 어떻게 네이티브 JavaScript로 변환(desugars)하는지 볼 수 있고, [HTML-JSX 변환기](/react/html-jsx.html)는 이미 있는 HTML을 JSX로 변환해 줍니다.
-
-JSX를 사용 하시려면, [시작하기](/react/docs/getting-started-ko-KR.html) 가이드에서 어떻게 컴파일을 하기 위해 설정하는지 보실 수 있습니다.
-
-> 주의:
->
-> JSX 표현식은 언제나 ReactElement로 변환됩니다. 실제 구현의 세부사항은 많이
-> 다를 수 있습니다. 최적화 모드는 ReactElement를 `React.createElement`에서 검증
-> 코드를 우회하는 객체 리터럴로 ReactElement를 인라인으로 만들 수 있습니다.
-
-## 네임스페이스를 사용한 컴포넌트
-
-폼같은 자식을 많이 가지는 컴포넌트를 만든다면, 많은 변수 선언을 하게 될 것입니다.
-
-```javascript
-// 변수 선언의 어색한 블록
-var Form = MyFormComponent;
-var FormRow = Form.Row;
-var FormLabel = Form.Label;
-var FormInput = Form.Input;
-
-var App = (
-  <Form>
-    <FormRow>
-      <FormLabel />
-      <FormInput />
-    </FormRow>
-  </Form>
-);
-```
-
-더 간단하고 쉽게 *네임스페이스를 사용한 컴포넌트*를 사용해서, 다른 컴포넌트를 어트리뷰트로 가지는 하나의 컴포넌트만 쓸 수 있습니다.
-
-```javascript
-var Form = MyFormComponent;
-
-var App = (
-  <Form>
-    <Form.Row>
-      <Form.Label />
-      <Form.Input />
-    </Form.Row>
-  </Form>
-);
-```
-
-이렇게 하려면, *"sub-components"*를 메인 컴포넌트의 어트리뷰트로 만들 필요가 있습니다.
-
-```javascript
-var MyFormComponent = React.createClass({ ... });
-
-MyFormComponent.Row = React.createClass({ ... });
-MyFormComponent.Label = React.createClass({ ... });
-MyFormComponent.Input = React.createClass({ ... });
-```
-
-코드를 컴파일할 때 JSX는 이것을 제대로 처리해 줍니다.
-
-```javascript
-var App = (
-  React.createElement(Form, null,
-    React.createElement(Form.Row, null,
-      React.createElement(Form.Label, null),
-      React.createElement(Form.Input, null)
-    )
-  )
-);
-```
-
-> 주의:
->
-> 이 기능은 [v0.11](/react/blog/2014/07/17/react-v0.11.html#jsx) 이상에만 있습니다.
-
-## JavaScript 표현식
-
-### 어트리뷰트 표현식
-
-JavaScript 표현식을 어트리뷰트 값으로 사용하려면, 표현식을 쌍따옴표(`""`)대신 중괄호(`{}`)로 감싸야 합니다.
-
-```javascript
-// 입력 (JSX):
-var person = <Person name={window.isLoggedIn ? window.name : ''} />;
-// 출력 (JS):
-var person = React.createElement(
-  Person,
-  {name: window.isLoggedIn ? window.name : ''}
-);
-```
-
-### 불린 어트리뷰트
-
-어트리뷰트의 값을 생략하면 JSX는 값을 `true`로 취급합니다. 어트리뷰트 표현식에 `false`를 넘기려면 사용해야만 합니다. HTML 폼 엘리먼트에 `disabled`, `required`, `checked`, `readOnly`같은 어트리뷰트를 사용할 일이 자주 있습니다.
-
-```javascript
-// JSX에서 이 두 줄은 똑같이 버튼을 비활성화합니다.
-<input type="button" disabled />;
-<input type="button" disabled={true} />;
-
-// 그리고 JSX에서 이 두 줄은 똑같이 버튼을 비활성화하지 않습니다.
-<input type="button" />;
-<input type="button" disabled={false} />;
-```
-
-### 자식 표현식
-
-비슷하게, JavaScript 표현식을 자식을 표현하는 데 사용할 수 있습니다.
-
-```javascript
-// 입력 (JSX):
-var content = <Container>{window.isLoggedIn ? <Nav /> : <Login />}</Container>;
-// 출력 (JS):
-var content = React.createElement(
-  Container,
-  null,
-  window.isLoggedIn ? React.createElement(Nav) : React.createElement(Login)
-);
-```
-
-### 주석
-
-JSX에 주석을 넣기는 쉽습니다. 그냥 JS 표현식과 같습니다. 그냥 태그의 자식 섹션에서만 조심하시면 됩니다. 이럴 땐 주석 주변에 `{}`를 감싸야 합니다.
-
-```javascript
-var content = (
-  <Nav>
-    {/* 자식 주석, {}로 감싼다 */}
-    <Person
-      /* 여러
-         줄
-         주석 */
-      name={window.isLoggedIn ? window.name : ''} // 줄 끝부분 주석
-    />
-  </Nav>
-);
-```
-
-> 주의:
->
-> JSX 는 HTML과 비슷하지만 완전히 같지는 않습니다. 중요한 차이점을 보시려면 [JSX gotchas](/react/docs/jsx-gotchas-ko-KR.html)를 보세요.
diff --git a/docs/docs/02.1-jsx-in-depth.md b/docs/docs/02.1-jsx-in-depth.md
deleted file mode 100644
index 8397e5048cf4..000000000000
--- a/docs/docs/02.1-jsx-in-depth.md
+++ /dev/null
@@ -1,224 +0,0 @@
----
-id: jsx-in-depth
-title: JSX in Depth
-permalink: jsx-in-depth.html
-prev: displaying-data.html
-next: jsx-spread.html
----
-
-[JSX](https://facebook.github.io/jsx/) is a JavaScript syntax extension that looks similar to XML. You can use a simple JSX syntactic transform with React.
-
-## Why JSX?
-
-You don't have to use JSX with React. You can just use plain JS. However, we recommend using JSX because it is a concise and familiar syntax for defining tree structures with attributes.
-
-It's more familiar for casual developers such as designers.
-
-XML has the benefit of balanced opening and closing tags. This helps make large trees easier to read than function calls or object literals.
-
-It doesn't alter the semantics of JavaScript.
-
-## HTML Tags vs. React Components
-
-React can either render HTML tags (strings) or React components (classes).
-
-To render an HTML tag, just use lower-case tag names in JSX:
-
-```javascript
-var myDivElement = <div className="foo" />;
-ReactDOM.render(myDivElement, document.getElementById('example'));
-```
-
-To render a React Component, just create a local variable that starts with an upper-case letter:
-
-```javascript
-var MyComponent = React.createClass({/*...*/});
-var myElement = <MyComponent someProperty={true} />;
-ReactDOM.render(myElement, document.getElementById('example'));
-```
-
-React's JSX uses the upper vs. lower case convention to distinguish between local component classes and HTML tags.
-
-> Note:
->
-> Since JSX is JavaScript, identifiers such as `class` and `for` are discouraged
-> as XML attribute names. Instead, React DOM components expect DOM property
-> names like `className` and `htmlFor`, respectively.
-
-## The Transform
-
-React JSX transforms from an XML-like syntax into native JavaScript. XML elements, attributes and children are transformed into arguments that are passed to `React.createElement`.
-
-```javascript
-var Nav;
-// Input (JSX):
-var app = <Nav color="blue" />;
-// Output (JS):
-var app = React.createElement(Nav, {color:"blue"});
-```
-
-Notice that in order to use `<Nav />`, the `Nav` variable must be in scope.
-
-JSX also allows specifying children using XML syntax:
-
-```javascript
-var Nav, Profile;
-// Input (JSX):
-var app = <Nav color="blue"><Profile>click</Profile></Nav>;
-// Output (JS):
-var app = React.createElement(
-  Nav,
-  {color:"blue"},
-  React.createElement(Profile, null, "click")
-);
-```
-
-JSX will infer the class's [displayName](/react/docs/component-specs.html#displayname) from the variable assignment when the displayName is undefined:
-
-```javascript
-// Input (JSX):
-var Nav = React.createClass({ });
-// Output (JS):
-var Nav = React.createClass({displayName: "Nav", });
-```
-
-Use the [Babel REPL](https://babeljs.io/repl/) to try out JSX and see how it desugars into native JavaScript, and the [HTML to JSX converter](/react/html-jsx.html) to convert your existing HTML to JSX.
-
-If you want to use JSX, the [Getting Started](/react/docs/getting-started.html) guide shows how to set up compilation.
-
-> Note:
->
-> The JSX expression always evaluates to a ReactElement. The actual
-> implementation details may vary. An optimized mode could inline the
-> ReactElement as an object literal to bypass the validation code in
-> `React.createElement`.
-
-## Namespaced Components
-
-If you are building a component that has many children, like a form, you might end up with something with a lot of variable declarations:
-
-```javascript
-// Awkward block of variable declarations
-var Form = MyFormComponent;
-var FormRow = Form.Row;
-var FormLabel = Form.Label;
-var FormInput = Form.Input;
-
-var App = (
-  <Form>
-    <FormRow>
-      <FormLabel />
-      <FormInput />
-    </FormRow>
-  </Form>
-);
-```
-
-To make it simpler and easier, *namespaced components* let you use one component that has other components as attributes:
-
-```javascript
-var Form = MyFormComponent;
-
-var App = (
-  <Form>
-    <Form.Row>
-      <Form.Label />
-      <Form.Input />
-    </Form.Row>
-  </Form>
-);
-```
-
-To do this, you just need to create your *"sub-components"* as attributes of the main component:
-
-```javascript
-var MyFormComponent = React.createClass({ ... });
-
-MyFormComponent.Row = React.createClass({ ... });
-MyFormComponent.Label = React.createClass({ ... });
-MyFormComponent.Input = React.createClass({ ... });
-```
-
-JSX will handle this properly when compiling your code.
-
-```javascript
-var App = (
-  React.createElement(Form, null,
-    React.createElement(Form.Row, null,
-      React.createElement(Form.Label, null),
-      React.createElement(Form.Input, null)
-    )
-  )
-);
-```
-
-> Note:
->
-> This feature is available in [v0.11](/react/blog/2014/07/17/react-v0.11.html#jsx) and above.
-
-## JavaScript Expressions
-
-### Attribute Expressions
-
-To use a JavaScript expression as an attribute value, wrap the expression in a pair of curly braces (`{}`) instead of quotes (`""`).
-
-```javascript
-// Input (JSX):
-var person = <Person name={window.isLoggedIn ? window.name : ''} />;
-// Output (JS):
-var person = React.createElement(
-  Person,
-  {name: window.isLoggedIn ? window.name : ''}
-);
-```
-
-### Boolean Attributes
-
-Omitting the value of an attribute causes JSX to treat it as `true`. To pass `false` an attribute expression must be used. This often comes up when using HTML form elements, with attributes like `disabled`, `required`, `checked` and `readOnly`.
-
-```javascript
-// These two are equivalent in JSX for disabling a button
-<input type="button" disabled />;
-<input type="button" disabled={true} />;
-
-// And these two are equivalent in JSX for not disabling a button
-<input type="button" />;
-<input type="button" disabled={false} />;
-```
-
-### Child Expressions
-
-Likewise, JavaScript expressions may be used to express children:
-
-```javascript
-// Input (JSX):
-var content = <Container>{window.isLoggedIn ? <Nav /> : <Login />}</Container>;
-// Output (JS):
-var content = React.createElement(
-  Container,
-  null,
-  window.isLoggedIn ? React.createElement(Nav) : React.createElement(Login)
-);
-```
-
-### Comments
-
-It's easy to add comments within your JSX; they're just JS expressions. You just need to be careful to put `{}` around the comments when you are within the children section of a tag.
-
-```javascript
-var content = (
-  <Nav>
-    {/* child comment, put {} around */}
-    <Person
-      /* multi
-         line
-         comment */
-      name={window.isLoggedIn ? window.name : ''} // end of line comment
-    />
-  </Nav>
-);
-```
-
-> NOTE:
->
-> JSX is similar to HTML, but not exactly the same. See [JSX gotchas](/react/docs/jsx-gotchas.html) for some key differences.
diff --git a/docs/docs/02.1-jsx-in-depth.zh-CN.md b/docs/docs/02.1-jsx-in-depth.zh-CN.md
deleted file mode 100644
index 2a499698f22a..000000000000
--- a/docs/docs/02.1-jsx-in-depth.zh-CN.md
+++ /dev/null
@@ -1,224 +0,0 @@
----
-id: jsx-in-depth-zh-CN
-title: 深入 JSX
-permalink: jsx-in-depth-zh-CN.html
-prev: displaying-data-zh-CN.html
-next: jsx-spread-zh-CN.html
----
-
-[JSX](https://facebook.github.io/jsx/) 是一个看起来很像 XML 的 JavaScript 语法扩展。React 可以用来做简单的 JSX 句法转换。
-
-## 为什么要用 JSX？
-
-你不需要为了 React 使用 JSX，可以直接使用原生 JS。但是，我们建议使用 JSX 是因为它能精确，也是常用的定义包含属性的树状结构的语法。
-
-它对于非专职开发者比如设计师也比较熟悉。
-
-XML 有固定的标签开启和闭合的优点。这能让复杂的树更易于阅读，优于方法调用和对象字面量的形式。
-
-它没有修改 JavaScript 语义。
-
-
-## HTML 标签对比 React 组件
-
-React 可以渲染 HTML 标签 (strings) 或 React 组件 (classes)。
-
-要渲染 HTML 标签，只需在 JSX 里使用小写字母的标签名。
-
-```javascript
-var myDivElement = <div className="foo" />;
-ReactDOM.render(myDivElement, document.getElementById('example'));
-```
-
-要渲染 React 组件，只需创建一个大写字母开头的本地变量。
-
-```javascript
-var MyComponent = React.createClass({/*...*/});
-var myElement = <MyComponent someProperty={true} />;
-ReactDOM.render(myElement, document.getElementById('example'));
-```
-
-React 的 JSX 使用大、小写的约定来区分本地组件的类和 HTML 标签。
-
-> 注意:
->
-> 由于 JSX 就是 JavaScript，一些标识符像 `class` 和 `for` 不建议作为 XML
-> 属性名。作为替代，React DOM 使用 `className` 和 `htmlFor` 来做对应的属性。
-
-## 转换（Transform）
-
-JSX 把类 XML 的语法转成原生 JavaScript，XML 元素、属性和子节点被转换成 `React.createElement` 的参数。
-
-```javascript
-var Nav;
-// 输入 (JSX):
-var app = <Nav color="blue" />;
-// 输出 (JS):
-var app = React.createElement(Nav, {color:"blue"});
-```
-
-注意，要想使用 `<Nav />`，`Nav` 变量一定要在作用区间内。
-
-JSX 也支持使用 XML 语法定义子结点：
-
-```javascript
-var Nav, Profile;
-// 输入 (JSX):
-var app = <Nav color="blue"><Profile>click</Profile></Nav>;
-// 输出 (JS):
-var app = React.createElement(
-  Nav,
-  {color:"blue"},
-  React.createElement(Profile, null, "click")
-);
-```
-
-当显示名称没有定义时，JSX 会根据变量赋值来推断类的 [显示名称](/react/docs/component-specs.html#displayname) :
-
-```javascript
-// 输入 (JSX):
-var Nav = React.createClass({ });
-// 输出 (JS):
-var Nav = React.createClass({displayName: "Nav", });
-```
-
-使用 [JSX 编译器](/react/jsx-compiler.html) 来试用 JSX 并理解它是如何转换到原生 JavaScript，还有 [HTML 到 JSX 转换器](/react/html-jsx.html) 来把现有 HTML 转成 JSX。
-
-如果你要使用 JSX，这篇 [新手入门](/react/docs/getting-started.html) 教程来教你如何搭建环境。
-
-> 注意:
->
->
-> JSX 表达式总是会当作 ReactElement 执行。具体的实际细节可能不同。一种优化
-> 的模式是把 ReactElement 当作一个行内的对象字面量形式来绕过
-> `React.createElement` 里的校验代码。
-
-## 命名组件（Namespaced Components）
-
-如果你正在构建一个有很多子组件的组件，比如表单，你也许会最终得到许多的变量声明。
-
-```javascript
-// 尴尬的变量声明块
-var Form = MyFormComponent;
-var FormRow = Form.Row;
-var FormLabel = Form.Label;
-var FormInput = Form.Input;
-
-var App = (
-  <Form>
-    <FormRow>
-      <FormLabel />
-      <FormInput />
-    </FormRow>
-  </Form>
-);
-```
-
-为了使其更简单和容易，*命名组件*令你使用包含其他组件作为属性的单一的组件。
-
-```javascript
-var Form = MyFormComponent;
-
-var App = (
-  <Form>
-    <Form.Row>
-      <Form.Label />
-      <Form.Input />
-    </Form.Row>
-  </Form>
-);
-```
-
-要做到这一点，你只需要把你的*"子组件"*创建为主组件的属性。
-
-```javascript
-var MyFormComponent = React.createClass({ ... });
-
-MyFormComponent.Row = React.createClass({ ... });
-MyFormComponent.Label = React.createClass({ ... });
-MyFormComponent.Input = React.createClass({ ... });
-```
-
-当编译你的代码时，JSX会恰当的进行处理。
-
-```javascript
-var App = (
-  React.createElement(Form, null,
-    React.createElement(Form.Row, null,
-      React.createElement(Form.Label, null),
-      React.createElement(Form.Input, null)
-    )
-  )
-);
-```
-
-> 注意:
->
-> 此特性在 [v0.11](/react/blog/2014/07/17/react-v0.11.html#jsx) 及以上可用.
-
-## JavaScript 表达式
-
-### 属性表达式
-
-要使用 JavaScript 表达式作为属性值，只需把这个表达式用一对大括号 (`{}`) 包起来，不要用引号 (`""`)。
-
-```javascript
-// 输入 (JSX):
-var person = <Person name={window.isLoggedIn ? window.name : ''} />;
-// 输出 (JS):
-var person = React.createElement(
-  Person,
-  {name: window.isLoggedIn ? window.name : ''}
-);
-```
-
-### Boolean 属性
-
-省略一个属性的值会导致JSX把它当做 `true`。要传值 `false`必须使用属性表达式。这常出现于使用HTML表单元素，含有属性如`disabled`, `required`, `checked` 和 `readOnly`。
-
-```javascript
-// 在JSX中，对于禁用按钮这二者是相同的。
-<input type="button" disabled />;
-<input type="button" disabled={true} />;
-
-// 在JSX中，对于不禁用按钮这二者是相同的。
-<input type="button" />;
-<input type="button" disabled={false} />;
-```
-
-### 子节点表达式
-
-同样地，JavaScript 表达式可用于描述子结点：
-
-```javascript
-// 输入 (JSX):
-var content = <Container>{window.isLoggedIn ? <Nav /> : <Login />}</Container>;
-// 输出 (JS):
-var content = React.createElement(
-  Container,
-  null,
-  window.isLoggedIn ? React.createElement(Nav) : React.createElement(Login)
-);
-```
-
-### 注释
-
-JSX 里添加注释很容易；它们只是 JS 表达式而已。你仅仅需要小心的是当你在一个标签的子节点块时，要用 `{}` 包围要注释的部分。
-
-```javascript
-var content = (
-  <Nav>
-    {/* child comment, 用 {} 包围 */}
-    <Person
-      /* 多
-         行
-         注释 */
-      name={window.isLoggedIn ? window.name : ''} // 行尾注释
-    />
-  </Nav>
-);
-```
-
-> 注意:
->
-> JSX 类似于 HTML，但不完全一样。参考 [JSX 陷阱](/react/docs/jsx-gotchas-zh-CN.html) 了解主要不同。
diff --git a/docs/docs/02.2-jsx-spread.it-IT.md b/docs/docs/02.2-jsx-spread.it-IT.md
deleted file mode 100644
index bad3e38d70d5..000000000000
--- a/docs/docs/02.2-jsx-spread.it-IT.md
+++ /dev/null
@@ -1,52 +0,0 @@
----
-id: jsx-spread-it-IT
-title: Attributi Spread JSX
-permalink: jsx-spread-it-IT.html
-prev: jsx-in-depth-it-IT.html
-next: jsx-gotchas-it-IT.html
----
-
-Se sai in anticipo che tutte le proprietà che desideri assegnare ad un componente, usare JSX è facile:
-
-```javascript
-  var component = <Component foo={x} bar={y} />;
-```
-
-## Le Props Mutevoli sono il Male
-
-Se non sai quali proprietà desideri impostare, potresti essere tentato di aggiungerle all'oggetto in seguito:
-
-```javascript
-  var component = <Component />;
-  component.props.foo = x; // male
-  component.props.bar = y; // altrettanto male
-```
-
-Questo è un anti-pattern perché significa che non possiamo aiutarti a verificare i propTypes per tempo. Ciò significa che i tuoi errori di propTypes finiscono per avere uno stack trace indecifrabile.
-
-Le props dovrebbero essere considerate immutabili. Mutare l'oggetto props altrove potrebbe causare conseguenze inattese, quindi a questo punto dovrebbe essere idealmente considerato un oggetto congelato.
-
-## Attributi Spread
-
-Adesso puoi utilizzare una nuova caratteristica di JSX chiamata attributi spread:
-
-```javascript
-  var props = {};
-  props.foo = x;
-  props.bar = y;
-  var component = <Component {...props} />;
-```
-
-Le proprietà dell'oggetto che passi al componente sono copiate nelle sue props.
-
-Puoi usarlo più volte o combinarlo con altri attributi. L'ordine in cui sono specificati è rilevante. Attributi successivi ridefiniscono quelli precedentemente impostati.
-
-```javascript
-  var props = { foo: 'default' };
-  var component = <Component {...props} foo={'override'} />;
-  console.log(component.props.foo); // 'override'
-```
-
-## Cos'è la strana notazione `...`?
-
-L'operatore `...` (o operatore spread) è già supportato per gli [array in ES6](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator). Esiste anche una proposta per ES7 per le proprietà [Spread e Rest di Object](https://github.com/sebmarkbage/ecmascript-rest-spread). Stiamo prendendo spunto da questi standard supportati o in corso di sviluppo per fornire una sintassi più pulita a JSX.
diff --git a/docs/docs/02.2-jsx-spread.ja-JP.md b/docs/docs/02.2-jsx-spread.ja-JP.md
deleted file mode 100644
index 42f0c8edc0c1..000000000000
--- a/docs/docs/02.2-jsx-spread.ja-JP.md
+++ /dev/null
@@ -1,52 +0,0 @@
----
-id: jsx-spread
-title: JSXの拡張属性
-permalink: jsx-spread-ja-JP.html
-prev: jsx-in-depth-ja-JP.html
-next: jsx-gotchas-ja-JP.html
----
-
-以下のように、コンポーネントにどのようなプロパティを配置したいか前もって全て分かっている場合は、JSXを使うことは簡単です。
-
-```javascript
-  var component = <Component foo={x} bar={y} />;
-```
-
-## Propsを変更してはいけない
-
-セットしたいプロパティが分からない場合は、以下のように後からオブジェクトに追加したいと思うでしょう。
-
-```javascript
-  var component = <Component />;
-  component.props.foo = x; // だめ
-  component.props.bar = y; // 同様にだめ
-```
-
-これはアンチパターンです。なぜなら、後々まで正しいpropTypesであるかどうかチェックすることを助けることができないことを意味するからです。これは、propTypesのエラーが隠されたスタックトレースに出力されて終わってしまうことを意味します。
-
-propsは変更不可と考えられるべきです。propsのオブジェクトをどこかで変更することは予期せぬ結果を発生させる可能性があるので、理想的には、この時点ではpropsは固定のオブジェクトであるべきです。
-
-## 拡張属性
-
-以下のように、拡張属性というJSXの新しい特徴を使うことができます。
-
-```javascript
-  var props = {};
-  props.foo = x;
-  props.bar = y;
-  var component = <Component {...props} />;
-```
-
-あなたが渡したオブジェクトのプロパティはコンポーネントのpropsにコピーされます。
-
-これを複数回使用したり、他の属性と組み合わせたりすることもできます。仕様書では、順序が重要となっています。後の属性は前の属性をオーバーライドします。
-
-```javascript
-  var props = { foo: 'default' };
-  var component = <Component {...props} foo={'override'} />;
-  console.log(component.props.foo); // 'override'
-```
-
-## 奇妙な `...` という表現は何でしょうか？
-
-`...` 操作（拡張操作）は既に[ES6のarrays](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator)でサポートされています。[Object Rest と Spread Properties](https://github.com/sebmarkbage/ecmascript-rest-spread)のES7のプロポーザルもあります。JSXのきれいなシンタックスを供給するために、それらのサポートや開発中の標準使用を利用しています。
diff --git a/docs/docs/02.2-jsx-spread.ko-KR.md b/docs/docs/02.2-jsx-spread.ko-KR.md
deleted file mode 100644
index 4c2a5d0cd52e..000000000000
--- a/docs/docs/02.2-jsx-spread.ko-KR.md
+++ /dev/null
@@ -1,52 +0,0 @@
----
-id: jsx-spread-ko-KR
-title: JSX 스프레드 어트리뷰트
-permalink: jsx-spread-ko-KR.html
-prev: jsx-in-depth-ko-KR.html
-next: jsx-gotchas-ko-KR.html
----
-
-미리 컴포넌트에 넣을 모든 프로퍼티를 알게 된다면, JSX를 사용하기 쉬워집니다.
-
-```javascript
-  var component = <Component foo={x} bar={y} />;
-```
-
-## Props의 변경은 나빠요
-
-하지만 어떤 프로퍼티를 설정하고 싶은지 모른다면, 객체 레이어에 넣고 싶어질 수도 있습니다.
-
-```javascript
-  var component = <Component />;
-  component.props.foo = x; // 나쁨
-  component.props.bar = y; // 역시 나쁨
-```
-
-이것은 안티 패턴입니다. 왜냐하면 한참 뒤까지 정확한 propTypes을 체크할 수 없다는 뜻이기 때문입니다. 이것은 propTypes 에러는 알기 힘든 스택 트레이스로 끝난다는 의미입니다.
-
-props는 변하지 않는 것으로 간주해야 합니다. props 객체를 변경하는 것은 다른 곳에서 예기치 못한 결과가 생길 수 있기 때문에 이상적으로는 이 시점에서 frozen 객체가 되어야 합니다.
-
-## 스프레드 어트리뷰트
-
-이제 JSX의 새로운 기능인 스프레드 어트리뷰트를 사용하실 수 있습니다.
-
-```javascript
-  var props = {};
-  props.foo = x;
-  props.bar = y;
-  var component = <Component {...props} />;
-```
-
-전달한 객체의 프로퍼티가 컴포넌트의 props에 복사됩니다.
-
-이렇게 여러 번 사용하거나 다른 어트리뷰트와 조합해서 사용할 수 있습니다. 명세의 순서는 중요합니다. 나중의 어트리뷰트가 이전 것보다 우선되기 때문입니다.
-
-```javascript
-  var props = { foo: 'default' };
-  var component = <Component {...props} foo={'override'} />;
-  console.log(component.props.foo); // 'override'
-```
-
-## 이상한 `...` 표기법은 무엇인가요?
-
-`...` 연산자(스프레드 연산자)는 이미 [ES6의 배열](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator)에서 지원합니다. [객체 rest와 스프레드 프로퍼티](https://github.com/sebmarkbage/ecmascript-rest-spread)에 대한 ES7의 제안도 있습니다. JSX의 구문을 더 깔끔하게 하기 위해 지원되고 개발중인 표준을 활용하고 있습니다.
diff --git a/docs/docs/02.2-jsx-spread.md b/docs/docs/02.2-jsx-spread.md
deleted file mode 100644
index a4b267824206..000000000000
--- a/docs/docs/02.2-jsx-spread.md
+++ /dev/null
@@ -1,52 +0,0 @@
----
-id: jsx-spread
-title: JSX Spread Attributes
-permalink: jsx-spread.html
-prev: jsx-in-depth.html
-next: jsx-gotchas.html
----
-
-If you know all the properties that you want to place on a component ahead of time, it is easy to use JSX:
-
-```javascript
-  var component = <Component foo={x} bar={y} />;
-```
-
-## Mutating Props is Bad
-
-If you don't know which properties you want to set, you might be tempted to add them onto the object later:
-
-```javascript
-  var component = <Component />;
-  component.props.foo = x; // bad
-  component.props.bar = y; // also bad
-```
-
-This is an anti-pattern because it means that we can't help you check the right propTypes until way later. This means that your propTypes errors end up with a cryptic stack trace.
-
-The props should be considered immutable. Mutating the props object somewhere else could cause unexpected consequences so ideally it would be a frozen object at this point.
-
-## Spread Attributes
-
-Now you can use a new feature of JSX called spread attributes:
-
-```javascript
-  var props = {};
-  props.foo = x;
-  props.bar = y;
-  var component = <Component {...props} />;
-```
-
-The properties of the object that you pass in are copied onto the component's props.
-
-You can use this multiple times or combine it with other attributes. The specification order is important. Later attributes override previous ones.
-
-```javascript
-  var props = { foo: 'default' };
-  var component = <Component {...props} foo={'override'} />;
-  console.log(component.props.foo); // 'override'
-```
-
-## What's with the weird `...` notation?
-
-The `...` operator (or spread operator) is already supported for [arrays in ES6](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator). There is also an ECMAScript proposal for [Object Rest and Spread Properties](https://github.com/sebmarkbage/ecmascript-rest-spread). We're taking advantage of these supported and developing standards in order to provide a cleaner syntax in JSX.
diff --git a/docs/docs/02.2-jsx-spread.zh-CN.md b/docs/docs/02.2-jsx-spread.zh-CN.md
deleted file mode 100644
index a7386d2013d2..000000000000
--- a/docs/docs/02.2-jsx-spread.zh-CN.md
+++ /dev/null
@@ -1,52 +0,0 @@
----
-id: jsx-spread-zh-CN
-title: JSX 展开属性
-permalink: jsx-spread-zh-CN.html
-prev: jsx-in-depth-zh-CN.html
-next: jsx-gotchas-zh-CN.html
----
-
-如果你事先知道组件需要的全部 Props（属性），JSX 很容易地这样写：
-
-```javascript
-  var component = <Component foo={x} bar={y} />;
-```
-
-## 修改 Props 是不好的，明白吗
-
-如果你不知道要设置哪些 Props，那么现在最好不要设置它：
-
-```javascript
-  var component = <Component />;
-  component.props.foo = x; // 不好
-  component.props.bar = y; // 同样不好
-```
-
-这样是反模式，因为 React 不能帮你检查属性类型（propTypes）。这样即使你的 属性类型有错误也不能得到清晰的错误提示。
-
-Props 应该被认为是不可变的。在别处修改 props 对象可能会导致预料之外的结果，所以原则上这将是一个冻结的对象。
-
-## 展开属性（Spread Attributes）
-
-现在你可以使用 JSX 的新特性 - 展开属性：
-
-```javascript
-  var props = {};
-  props.foo = x;
-  props.bar = y;
-  var component = <Component {...props} />;
-```
-
-传入对象的属性会被复制到组件内。
-
-它能被多次使用，也可以和其它属性一起用。注意顺序很重要，后面的会覆盖掉前面的。
-
-```javascript
-  var props = { foo: 'default' };
-  var component = <Component {...props} foo={'override'} />;
-  console.log(component.props.foo); // 'override'
-```
-
-## 这个奇怪的 `...` 标记是什么？
-
-这个 `...` 操作符（增强的操作符）已经被 [ES6 数组](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator) 支持。相关的还有 ECMAScript 规范草案中的 [Object 剩余和展开属性（Rest and Spread Properties）](https://github.com/sebmarkbage/ecmascript-rest-spread)。我们利用了这些还在制定中标准中已经被支持的特性来使 JSX 拥有更优雅的语法。
diff --git a/docs/docs/02.3-jsx-gotchas.it-IT.md b/docs/docs/02.3-jsx-gotchas.it-IT.md
deleted file mode 100644
index e6c3d5354cdd..000000000000
--- a/docs/docs/02.3-jsx-gotchas.it-IT.md
+++ /dev/null
@@ -1,68 +0,0 @@
----
-id: jsx-gotchas-it-IT
-title: JSX Gotchas
-permalink: jsx-gotchas-it-IT.html
-prev: jsx-spread-it-IT.html
-next: interactivity-and-dynamic-uis-it-IT.html
----
-
-JSX somiglia all'HTML ma ci sono delle differenze importanti da tenere in considerazione.
-
-> Nota:
->
-> Per le differenze del DOM, come l'attributo `style` in linea, consulta [here](/react/docs/dom-differences-it-IT.html).
-
-## Entità HTML
-
-Puoi inserire entità HTML nel testo letterale in JSX:
-
-```javascript
-<div>Primo &middot; Secondo</div>
-```
-
-Se desideri visualizzare un'entità HTML all'interno di un contenuto dinamico, avrai problemi con il doppio escape, poiché React effettua in maniera predefinita l'escape di tutte le stringhe visualizzate per prevenire un'ampia gamma di attacchi XSS.
-
-```javascript
-// Male: Mostra "Primo &middot; Secondo"
-<div>{'Primo &middot; Secondo'}</div>
-```
-
-Esistono molte maniere di aggirare questo problema. La più facile è scrivere i caratteri Unicode direttamente in JavaScript. Dovrai assicurarti che il file sia salvato come UTF-8 e che le appropriate direttive UTF-8 siano impostate in modo che il browser li visualizzi correttamente.
-
-```javascript
-<div>{'Primo · Secondo'}</div>
-```
-
-Un'alternativa più sicura consiste nel trovare il [codice Unicode corrispondente all'entità](http://www.fileformat.info/info/unicode/char/b7/index.htm) e usarlo all'interno di una stringa JavaScript.
-
-```javascript
-<div>{'Primo \u00b7 Secondo'}</div>
-<div>{'Primo ' + String.fromCharCode(183) + ' Secondo'}</div>
-```
-
-Puoi usare array misti con stringhe ed elementi JSX.
-
-```javascript
-<div>{['Primo ', <span>&middot;</span>, ' Secondo']}</div>
-```
-
-Come ultima risorsa, puoi sempre [inserire HTML nativo](/react/tips/dangerously-set-inner-html.html).
-
-```javascript
-<div dangerouslySetInnerHTML={{'{{'}}__html: 'Primo &middot; Secondo'}} />
-```
-
-
-## Attributi HTML Personalizzati
-
-Se passi proprietà che non esistono nella specifica HTML ad elementi HTML nativi, React li ignorerà. Se vuoi usare un attributo personalizzato, devi prefiggerlo con `data-`.
-
-```javascript
-<div data-custom-attribute="foo" />
-```
-
-Gli attributi per [l'Accessibilità del Web](http://www.w3.org/WAI/intro/aria) che iniziano per `aria-` saranno gestiti correttamente.
-
-```javascript
-<div aria-hidden={true} />
-```
diff --git a/docs/docs/02.3-jsx-gotchas.ja-JP.md b/docs/docs/02.3-jsx-gotchas.ja-JP.md
deleted file mode 100644
index f3ee5f4203a2..000000000000
--- a/docs/docs/02.3-jsx-gotchas.ja-JP.md
+++ /dev/null
@@ -1,68 +0,0 @@
----
-id: jsx-gotchas
-title: JSXの理解
-permalink: jsx-gotchas-ja-JP.html
-prev: jsx-spread-ja-JP.html
-next: interactivity-and-dynamic-uis-ja-JP.html
-
----
-
-JSXはHTMLに似ていますが、重要な違いがいくつかあります。
-
-> 注意:
-> インラインの `style` 属性のようなDOMの違いについては、[こちら](/react/docs/dom-differences.html)を確認してください。
-
-## HTMLのエンティティ
-
-以下のように、JSXの文字のテキストの中にHTMLのエンティティを挿入することができます。
-
-```javascript
-<div>First &middot; Second</div>
-```
-
-動的なコンテンツとしてHTMLのエンティティを表示する際に、ダブルエスケープを書いてしまうことがあるかと思いますが、Reactはデフォルトで広い範囲のXSS攻撃を防ぐために表示しようとしている全ての文字列をエスケープします。
-
-```javascript
-// 悪い例: 以下は "First &middot; Second" を表示します。
-<div>{'First &middot; Second'}</div>
-```
-
-この問題を防止するためにはいくつかの方法があります。最も簡単な方法は、unicodeの文字を直でJavaScriptに記述する方法です。その際には、ファイルがUTF-8で保存されていることと、ブラウザが正しく表示できるように、UTF-8で表示する命令が正しくセットされていることを確認してください。
-
-```javascript
-<div>{'First · Second'}</div>
-```
-
-さらに安全な代替の方法は、[エンティティに対応するunicodeの数値](http://www.fileformat.info/info/unicode/char/b7/index.htm)を見つけて、JavaScriptの文字列の中でそれを使うことです。
-
-```javascript
-<div>{'First \u00b7 Second'}</div>
-<div>{'First ' + String.fromCharCode(183) + ' Second'}</div>
-```
-
-配列と文字列とJSXの要素を混ぜて使うこともできます。
-
-```javascript
-<div>{['First ', <span>&middot;</span>, ' Second']}</div>
-```
-
-最後の手段として、常に[生のHTMLを挿入](/react/tips/dangerously-set-inner-html.html)することもできます。
-
-```javascript
-<div dangerouslySetInnerHTML={{'{{'}}__html: 'First &middot; Second'}} />
-```
-
-
-## カスタムされたHTMLの属性
-
-HTMLの仕様書に存在しない要素をネイティブなHTML要素に渡した場合は、Reactはそれらをレンダリングしません。カスタムした属性を使う場合は、 `data-` を頭につけてください。
-
-```javascript
-<div data-custom-attribute="foo" />
-```
-
-`aria-` から始まる[Webアクセシビリティ](http://www.w3.org/WAI/intro/aria)属性はプロパティをレンダリングします。
-
-```javascript
-<div aria-hidden={true} />
-```
diff --git a/docs/docs/02.3-jsx-gotchas.ko-KR.md b/docs/docs/02.3-jsx-gotchas.ko-KR.md
deleted file mode 100644
index 3dd72770e870..000000000000
--- a/docs/docs/02.3-jsx-gotchas.ko-KR.md
+++ /dev/null
@@ -1,68 +0,0 @@
----
-id: jsx-gotchas-ko-KR
-title: JSX Gotchas
-permalink: jsx-gotchas-ko-KR.html
-prev: jsx-spread-ko-KR.html
-next: interactivity-and-dynamic-uis-ko-KR.html
----
-
-JSX는 HTML처럼 보이지만, 작업하다 보면 마주치게 될 몇 가지 중요한 차이점이 있습니다.
-
-> 주의:
->
-> 인라인 `style` 어트리뷰트 같은 DOM과의 차이점은 [여기](/react/tips/dangerously-set-inner-html-ko-KR.html)를 보세요.
-
-## HTML 엔티티
-
-JSX의 리터럴 텍스트에 HTML 엔티티를 넣을 수 있습니다.
-
-```javascript
-<div>First &middot; Second</div>
-```
-
-동적 콘텐츠 안에 HTML 엔티티를 표시하려 할 때, React에서는 XSS 공격을 광범위하게 막기 위해서 기본적으로 모든 표시하는 문자열을 이스케이프 하기 때문에 더블 이스케이프 문제에 부딪히게 됩니다.
-
-```javascript
-// 나쁨: "First &middot; Second"를 표시
-<div>{'First &middot; Second'}</div>
-```
-
-이 이슈를 피해 갈 방법은 여럿 있지만, 가장 쉬운 방법은 유니코드 문자를 JavaScript에 직접 쓰는 것입니다. 브라우저가 올바르게 표시하도록 파일이 UTF-8으로 저장되어 있고 올바른 UTF-8 지시자를 사용하고 있는지 확인해야 합니다.
-
-```javascript
-<div>{'First · Second'}</div>
-```
-
-더 안전한 대안으로 [엔티티에 대응하는 유니코드 숫자](http://www.fileformat.info/info/unicode/char/b7/index.htm)를 찾아 JavaScript 문자열 안에서 사용하는 방법도 있습니다.
-
-```javascript
-<div>{'First \u00b7 Second'}</div>
-<div>{'First ' + String.fromCharCode(183) + ' Second'}</div>
-```
-
-문자열과 JSX 엘리먼트를 혼합한 배열을 사용할 수도 있습니다.
-
-```javascript
-<div>{['First ', <span>&middot;</span>, ' Second']}</div>
-```
-
-최후의 수단으로, 항상 [생 HTML을 삽입](/react/docs/dom-differences-ko-KR.html)할 수 있습니다.
-
-```javascript
-<div dangerouslySetInnerHTML={{'{{'}}__html: 'First &middot; Second'}} />
-```
-
-
-## 커스텀 HTML 어트리뷰트
-
-프로퍼티를 HTML 사양에는 없는 네이티브 HTML 엘리먼트에 넘기면, React는 그 프로퍼티를 렌더하지 않습니다. 커스텀 어트리뷰트를 사용하고 싶다면, 접두사로 `data-`를 붙이셔야 합니다.
-
-```javascript
-<div data-custom-attribute="foo" />
-```
-
-`aria-`로 시작하는 [Web 접근성](http://www.w3.org/WAI/intro/aria) 어트리뷰트는 제대로 렌더될 것입니다.
-
-```javascript
-<div aria-hidden={true} />
-```
diff --git a/docs/docs/02.3-jsx-gotchas.md b/docs/docs/02.3-jsx-gotchas.md
deleted file mode 100644
index 10ae6bcf0cac..000000000000
--- a/docs/docs/02.3-jsx-gotchas.md
+++ /dev/null
@@ -1,74 +0,0 @@
----
-id: jsx-gotchas
-title: JSX Gotchas
-permalink: jsx-gotchas.html
-prev: jsx-spread.html
-next: interactivity-and-dynamic-uis.html
----
-
-JSX looks like HTML but there are some important differences you may run into.
-
-> Note:
->
-> For DOM differences, such as the inline `style` attribute, check [here](/react/docs/dom-differences.html).
-
-## HTML Entities
-
-You can insert HTML entities within literal text in JSX:
-
-```javascript
-<div>First &middot; Second</div>
-```
-
-If you want to display an HTML entity within dynamic content, you will run into double escaping issues as React escapes all the strings you are displaying in order to prevent a wide range of XSS attacks by default.
-
-```javascript
-// Bad: It displays "First &middot; Second"
-<div>{'First &middot; Second'}</div>
-```
-
-There are various ways to work-around this issue. The easiest one is to write Unicode characters directly in JavaScript. You need to make sure that the file is saved as UTF-8 and that the proper UTF-8 directives are set so the browser will display it correctly.
-
-```javascript
-<div>{'First · Second'}</div>
-```
-
-A safer alternative is to find the [unicode number corresponding to the entity](http://www.fileformat.info/info/unicode/char/b7/index.htm) and use it inside of a JavaScript string.
-
-```javascript
-<div>{'First \u00b7 Second'}</div>
-<div>{'First ' + String.fromCharCode(183) + ' Second'}</div>
-```
-
-You can use mixed arrays with strings and JSX elements.
-
-```javascript
-<div>{['First ', <span>&middot;</span>, ' Second']}</div>
-```
-
-As a last resort, you always have the ability to [insert raw HTML](/react/tips/dangerously-set-inner-html.html).
-
-```javascript
-<div dangerouslySetInnerHTML={{'{{'}}__html: 'First &middot; Second'}} />
-```
-
-
-## Custom HTML Attributes
-
-If you pass properties to native HTML elements that do not exist in the HTML specification, React will not render them. If you want to use a custom attribute, you should prefix it with `data-`.
-
-```javascript
-<div data-custom-attribute="foo" />
-```
-
-However, arbitrary attributes are supported on custom elements (those with a hyphen in the tag name or an `is="..."` attribute).
-
-```javascript
-<x-my-component custom-attribute="foo" />
-```
-
-[Web Accessibility](http://www.w3.org/WAI/intro/aria) attributes starting with `aria-` will be rendered properly.
-
-```javascript
-<div aria-hidden={true} />
-```
diff --git a/docs/docs/02.3-jsx-gotchas.zh-CN.md b/docs/docs/02.3-jsx-gotchas.zh-CN.md
deleted file mode 100644
index 695e68adf731..000000000000
--- a/docs/docs/02.3-jsx-gotchas.zh-CN.md
+++ /dev/null
@@ -1,74 +0,0 @@
----
-id: jsx-gotchas-zh-CN
-title: JSX 陷阱
-permalink: jsx-gotchas-zh-CN.html
-prev: jsx-spread-zh-CN.html
-next: interactivity-and-dynamic-uis-zh-CN.html
----
-
-JSX 与 HTML 非常相似，但是有些关键区别要注意。
-
-> 注意:
->
-> 关于 DOM 的区别，如行内样式属性 `style`，参考 [DOM 区别](/react/docs/dom-differences.html)
-
-## HTML 实体
-
-HTML 实体可以插入到 JSX 的文本中。
-
-```javascript
-<div>First &middot; Second</div>
-```
-
-如果想在 JSX 表达式中显示 HTML 实体，可以会遇到二次转义的问题，因为 React 默认会转义所有字符串，为了防止各种 XSS 攻击。
-
-```javascript
-// 错误: 会显示 “First &middot; Second”
-<div>{'First &middot; Second'}</div>
-```
-
-有多种绕过的方法。最简单的是直接用 Unicode 字符。这时要确保文件是 UTF-8 编码且网页也指定为 UTF-8 编码。
-
-```javascript
-<div>{'First · Second'}</div>
-```
-
-安全的做法是先找到 [实体的 Unicode 编号](http://www.fileformat.info/info/unicode/char/b7/index.htm) ，然后在 JavaScript 字符串里使用。
-
-```javascript
-<div>{'First \u00b7 Second'}</div>
-<div>{'First ' + String.fromCharCode(183) + ' Second'}</div>
-```
-
-可以在数组里混合使用字符串和 JSX 元素。
-
-```javascript
-<div>{['First ', <span>&middot;</span>, ' Second']}</div>
-```
-
-万不得已，可以直接[插入原始HTML](/react/tips/dangerously-set-inner-html.html)。
-
-```javascript
-<div dangerouslySetInnerHTML={{'{{'}}__html: 'First &middot; Second'}} />
-```
-
-
-## 自定义 HTML 属性
-
-如果往原生 HTML 元素里传入 HTML 规范里不存在的属性，React 不会显示它们。如果需要使用自定义属性，要加 `data-` 前缀。
-
-```javascript
-<div data-custom-attribute="foo" />
-```
-
-然而，在自定义元素中任意的属性都是被支持的 （那些在tag名里带有连接符或者 `is="..."` 属性的）
-
-```javascript
-<x-my-component custom-attribute="foo" />
-```
-
-以 `aria-` 开头的 [网络无障碍](http://www.w3.org/WAI/intro/aria) 属性可以正常使用。
-
-```javascript
-<div aria-hidden={true} />
-```
diff --git a/docs/docs/03-interactivity-and-dynamic-uis.it-IT.md b/docs/docs/03-interactivity-and-dynamic-uis.it-IT.md
deleted file mode 100644
index 0bfbbdb397f7..000000000000
--- a/docs/docs/03-interactivity-and-dynamic-uis.it-IT.md
+++ /dev/null
@@ -1,84 +0,0 @@
----
-id: interactivity-and-dynamic-uis-it-IT
-title: Interattività e UI Dinamiche
-permalink: interactivity-and-dynamic-uis-it-IT.html
-prev: jsx-gotchas-it-IT.html
-next: multiple-components-it-IT.html
----
-
-Hai già [imparato a mostrare dati](/react/docs/displaying-data-it-IT.html) con React. Adesso vediamo come rendere le nostre UI interattive.
-
-
-## Un Esempio Semplice
-
-```javascript
-var LikeButton = React.createClass({
-  getInitialState: function() {
-    return {liked: false};
-  },
-  handleClick: function(event) {
-    this.setState({liked: !this.state.liked});
-  },
-  render: function() {
-    var text = this.state.liked ? 'mi piace' : 'non mi piace';
-    return (
-      <p onClick={this.handleClick}>
-        You {text} this. Click to toggle.
-      </p>
-    );
-  }
-});
-
-ReactDOM.render(
-  <LikeButton />,
-  document.getElementById('example')
-);
-```
-
-
-## Gestione degli Eventi ed Eventi Sintetici
-
-Con React devi semplicemente passare il tuo gestore di eventi come una proprietà camelCased in modo simile a come faresti nel normale HTML. React si assicura che tutti gli eventi si comportano in maniera identica in IE8 e successivi implementando un sistema di eventi sintetici. Ovvero, React sa come propagare e catturare eventi secondo la specifica, e garantisce che gli eventi passati ai tuoi gestori di eventi siano consistenti con la [specifica W3C](http://www.w3.org/TR/DOM-Level-3-Events/), qualunque browser tu stia utilizzando.
-
-
-## Dietro le Quinte: Binding Automatico e Delega degli Eventi
-
-Dietro le quinte, React esegue alcune operazioni per mantenere il tuo codice ad alte prestazioni e facile da comprendere.
-
-**Binding automatico:** Quando crei le callback in JavaScript, solitamente devi fare il binding esplicito del metodo alla sua istanza, in modo che il valore di `this` sia corretto. Con React, ogni metodo è automaticamente legato alla propria istanza del componente (eccetto quando si usa la sintassi delle classi ES6). React immagazzina il metodo legato in maniera tale da essere estremamente efficiente in termini di CPU e memoria. Ti permette anche di scrivere meno codice!
-
-**Delega degli eventi:** React non associa realmente i gestori di eventi ai nodi stessi. Quando React si avvia, comincia ad ascoltare tutti gli eventi a livello globale usando un singolo event listener. Quando un componente viene montato o smontato, i gestori di eventi sono semplicemente aggiunti o rimossi da un mapping interno. Quando si verifica un evento, React sa come inoltrarlo utilizzando questo mapping. Quando non ci sono più gestori di eventi rimasti nel mapping, i gestori di eventi di React sono semplici operazioni fittizie. Per saperne di più sul perché questo approccio è veloce, leggi [l'eccellente articolo sul blog di David Walsh](http://davidwalsh.name/event-delegate).
-
-
-## I Componenti Sono Macchine a Stati Finiti
-
-React considera le UI come semplici macchine a stati finiti. Pensando alla UI come in uno di tanti stati diversi e visualizzando questi stati, è facile mantenere la UI consistente.
-
-In React, aggiorni semplicemente lo stato di un componente, e quindi visualizzi una nuova UI basata su questo nuovo stato. React si occupa di aggiornare il DOM al tuo posto nella maniera più efficiente.
-
-
-## Come Funziona lo Stato
-
-Una maniera comune di informare React di un cambiamento nei dati è chiamare `setState(data, callback)`. Questo metodo effettua il merge di `data` in `this.state` e ridisegna il componente. Quando il componente ha terminato la fase di ri-rendering, la `callback` opzionale viene invocata. Nella maggior parte dei casi non avrai bisogno di fornire una `callback` dal momento che React si occuperà di mantenere la UI aggiornata per te.
-
-
-## Quali Componenti Devono Avere uno Stato?
-
-La maggior parte dei tuoi componenti dovrebbero semplicemente ricevere dei dati da `props` e visualizzarli. Tuttavia, a volte hai bisogno di reagire all'input dell'utente, una richiesta al server o il trascorrere del tempo. In questi casi utilizzi lo stato.
-
-**Prova a mantenere il maggior numero possibile dei tuoi componenti privi di stato.** Facendo ciò, isolerai lo stato nel suo luogo logicamente corretto e minimizzerai la ridondanza, rendendo più semplice ragionare sulla tua applicazione.
-
-Un pattern comune è quello di creare diversi componenti privi di stato che mostrano semplicemente dati, e di avere un componente dotato di stato al di sopra di essi nella gerarchia, che passa il proprio stato ai suoi figli tramite le `props`. Il componente dotato di stato incapsula tutta la logica di interazione, mentre i componenti privi di stato si occupano della visualizzazione dei dati in maniera dichiarativa.
-
-
-## Cosa *Dovrebbe* Contenere lo Stato?
-
-**Lo stato dovrebbe contenere dati che i gestori di eventi del componente possono modificare per scatenare un aggiornamento della UI.** In applicazioni reali, questi dati tendono ad essere molto limitati e serializzabili come JSON. Quando costruisci un componente dotato di stato, pensa alla minima rappresentazione possibile del suo stato, e conserva solo quelle proprietà in `this.state`. All'interno di `render()` calcola quindi ogni altra informazione necessaria basandoti sullo stato. Ti accorgerai che pensare e scrivere applicazioni in questo modo porta alla scrittura dell'applicazione più corretta, dal momento che aggiungere valori ridondanti o calcolati allo stato significherebbe doverli mantenere sincronizzati esplicitamente, anziché affidarti a React perché li calcoli al tuo posto.
-
-## Cosa *Non Dovrebbe* Contenere lo Stato?
-
-`this.state` dovrebbe contenere soltanto la quantità minima di dati indispensabile a rappresentare lo stato della tua UI. In quanto tale, non dovrebbe contenere:
-
-* **Dati calcolati:** Non preoccuparti di precalcolare valori basati sullo stato — è più semplice assicurarti che la tua UI sia consistente se effettui tutti i calcoli all'interno di `render()`. Per esempio, se lo stato contiene un array di elementi di una lista, e vuoi mostrare il numero di elementi come stringa, mostra semplicemente `this.state.listItems.length + ' elementi nella lista'` nel tuo metodo `render()` anziché conservarlo nello stato.
-* **Componenti React:** Costruiscili in `render()` basandoti sulle proprietà e sullo stato del componente.
-* **Dati duplicati dalle proprietà:** Prova ad utilizzare le proprietà come fonte di verità ove possibile. Un uso valido dello stato per i valori delle proprietà è conservarne il valore precedente quando le proprietà cambiano nel tempo.
diff --git a/docs/docs/03-interactivity-and-dynamic-uis.ja-JP.md b/docs/docs/03-interactivity-and-dynamic-uis.ja-JP.md
deleted file mode 100644
index 43559c34855a..000000000000
--- a/docs/docs/03-interactivity-and-dynamic-uis.ja-JP.md
+++ /dev/null
@@ -1,84 +0,0 @@
----
-id: interactivity-and-dynamic-uis
-title: 相互作用と動的なUI
-permalink: interactivity-and-dynamic-uis-ja-JP.html
-prev: jsx-gotchas-ja-JP.html
-next: multiple-components-ja-JP.html
----
-
-Reactで[どうやってデータを表示するか](/react/docs/displaying-data-ja-JP.html)については既に学んでいます。これからは、どうやって相互に作用するUIを作成するかを見ていきましょう。
-
-
-## 単純な例
-
-```javascript
-var LikeButton = React.createClass({
-  getInitialState: function() {
-    return {liked: false};
-  },
-  handleClick: function(event) {
-    this.setState({liked: !this.state.liked});
-  },
-  render: function() {
-    var text = this.state.liked ? 'like' : 'haven\'t liked';
-    return (
-      <p onClick={this.handleClick}>
-        You {text} this. Click to toggle.
-      </p>
-    );
-  }
-});
-
-ReactDOM.render(
-  <LikeButton />,
-  document.getElementById('example')
-);
-```
-
-
-## イベントハンドリングとイベントの組み合わせ
-
-Reactでは、普通のHTMLで行っているように単純にキャメルケースのpropとしてイベントハンドラを渡します。ReactはIE8と同じように全てのイベントが動作することと、組み合わされたイベントシステムが実行されることを保証します。これは、Reactが、イベントがどのように発生して、仕様にそってそれをキャプチャする方法を知っていることと、イベントはイベントハンドラに渡されて、どのブラウザを使っていても、[W3Cの仕様](http://www.w3.org/TR/DOM-Level-3-Events/)と一致することを保証することを意味します。
-
-## 中身を見る: オートバインディングとイベントの委譲
-
-中身を見ていくと、Reactはコードの性能と、理解しやすさを保つためにいくつかのことを行っています。
-
-**オートバインディング:** JavaScriptでコールバックを作成するときには、普通は `this` の値が正しくなるように、インスタンスにメソッドをはっきりとバインドする必要があります。
-Reactでは、全てのメソッドが自動でコンポーネントのインスタンスにバインドされます。ReactはCPUとメモリを効率的に使えるように、バインドするメソッドを持っています。これによって、タイピングの量を少なくすることもできます！
-
-**イベントの委譲:** Reactは実際はノード自体にイベントハンドラをアタッチはしません。Reactを立ち上げる時、1つのイベントリスナを使って最上位で全てのイベントをリスニングし始めます。コンポーネントがマウントされたり、アンマウントされた時は、イベントハンドラは内部のマッピングを単純に加えたり減らしたりします。イベントが起こった時には、Reactはこのマッピングを使ってどのようにディスパッチするかを知っています。マッピングの中にイベントハンドラが無い場合は、Reactのイベントハンドラは何も行いません。なぜこれの速度が速いかについて詳しく知るためには、[David Walshの素晴らしいブログの投稿](http://davidwalsh.name/event-delegate)をご覧ください。
-
-## コンポーネントは静的なマシーンに過ぎない
-
-ReactはUIをただの静的なマシーンと考えます。UIがたくさんのstateの中にあり、それらのstateをレンダリングするものだと考えることで、UIの一貫性を保ちやすくなります。
-
-Reactでは、コンポーネントのstateをアップデートするだけで、新しいstateに基づいた新しいUIをレンダリングします。Reactは最も効率的な方法でDOMをアップデートする面倒を見てくれます。
-
-
-## どのようにStateが働くか
-
-Reactがデータの変更を通知する共通な方法は `setState(data, callback)` を呼ぶことです。このメソッドは `data` を `this.state` にマージし、コンポーネントを再度レンダリングします。コンポーネントが再度レンダリングし終わったら、オプションの `callback` が呼ばれます。ほとんどの場合、 `callback` を提供する必要はありません。ReactがUIを最新に保ってくれるからです。
-
-
-## どのコンポーネントがStateを持っているべきでしょうか？
-
-コンポーネントは単純に `props` からデータを取得し、レンダリングすべきです。しかし、時々、ユーザのインプットやサーバのリクエストや、時間の経過に反応する必要が有ります。このような場合にstateを使うのです。
-
-**コンポーネントの多くを、可能な限りステートレスに保つよう試みてください。** このようにすることで、stateを最もロジックに近い場所から離し、冗長性を減らすことができ、アプリケーションが理解しやすくなります。
-
-共通なパターンはただデータをレンダリングするいくつかのステートレスなコンポーネントを構築することで、 `props` を通してその子要素にstateを渡す階級でステートフルなコンポーネントを持つことです。ステートフルなコンポーネントは、ステートレスなコンポーネントが叙述的な方法でデータをレンダリングする助けを行う一方で、全ての相互作用のロジックを持ちます。
-
-## stateで何が行われる *べき* でしょうか？
-
-**stateはUIのアップデートのトリガーとなるコンポーネントのイベントハンドラとしてのデータを保持するべきです。** 現実のアプリでは、このデータはとても小さく、JSONでシリアライズできるものになります。ステートフルなコンポーネントを構築する時は、このstateの表現をできるだけ小さくなるように、また、 `this.state` の中だけにそれらのプロパティを貯めこむように考えてください。 `render()` の中では、このstateに基づく、他の必要な情報をただ計算してください。このように考えたりアプリケーションを記述したりすることが最も正しいアプリケーションへの道であると発見するでしょう。stateに余剰な値や、計算後の値を加えることはReactがそれらを計算してくれるのに頼るのではなく、同期的にそれらを明白に保つ必要があることを意味します。
-
-
-## stateで何が行われる *べきではない* でしょうか？
-
-`this.state` UIのstateを表す必要がある最小限の量のデータだけを保持するべきです。このような点で以下のようなものは保持するべきではありません。
-
-* **計算されたデータ:**
-stateに基づく事前に計算された値について心配は要りません。 `render()` を用いて、全ての計算を行って、UIの一貫性を保証するよりも簡単です。例えば、stateにリスト化されたアイテムの配列を持っていて、文字列としてその数をレンダリングしたいとして、それらをstateに保持するよりも `render()` メソッドに `this.state.listItems.length + ' list items'` を単純にレンダリングすれば良いのです。
-* **Reactのコンポーネント:** 隠れたpropsとstateに基づいて `render()` でそれらをビルドしてください。
-* **propsからコピーしたデータ:** 可能であれば、propsを真のソースとして使ってみてください。propsは時とともに変化し得るので、正しくstateにpropsを保持する使い方は、以前の値を知っていることになり得ます。
diff --git a/docs/docs/03-interactivity-and-dynamic-uis.ko-KR.md b/docs/docs/03-interactivity-and-dynamic-uis.ko-KR.md
deleted file mode 100644
index ef3b3526c6ce..000000000000
--- a/docs/docs/03-interactivity-and-dynamic-uis.ko-KR.md
+++ /dev/null
@@ -1,78 +0,0 @@
----
-id: interactivity-and-dynamic-uis-ko-KR
-title: 상호 작용 및 동적 UI
-permalink: interactivity-and-dynamic-uis-ko-KR.html
-prev: jsx-gotchas-ko-KR.html
-next: multiple-components-ko-KR.html
----
-
-이미 React에서 [어떻게 데이터를 표시](/react/docs/displaying-data-ko-KR.html)하는지를 배웠습니다. 이제 UI와의 상호작용을 어떻게 만드는지 살펴보죠.
-
-## 간단한 예제
-
-```javascript
-var LikeButton = React.createClass({
-  getInitialState: function() {
-    return {liked: false};
-  },
-  handleClick: function(event) {
-    this.setState({liked: !this.state.liked});
-  },
-  render: function() {
-    var text = this.state.liked ? 'like' : 'haven\'t liked';
-    return (
-      <p onClick={this.handleClick}>
-        You {text} this. Click to toggle.
-      </p>
-    );
-  }
-});
-
-ReactDOM.render(
-  <LikeButton />,
-  document.getElementById('example')
-);
-```
-
-## 이벤트 핸들링과 통합적인(Synthetic) 이벤트
-
-React에서의 이벤트 핸들러는 HTML에서 그러던 것처럼 간단히 카멜케이스 프로퍼티(camelCased prop)로 넘기면 됩니다. React의 모든 이벤트는 통합적인 이벤트 시스템의 구현으로 IE8 이상에서는 같은 행동이 보장됩니다. 즉, React는 사양에 따라 어떻게 이벤트를 일으키고(bubble) 잡는지 알고 있고, 당신이 사용하는 브라우저와 관계없이 이벤트 핸들러에 전달되는 이벤트는 [W3C 사양](http://www.w3.org/TR/DOM-Level-3-Events/)과 같도록 보장됩니다.
-
-## 기본 구현: 오토바인딩과 이벤트 델리게이션
-<a name="under-the-hood-autobinding-and-event-delegation"></a>
-
-코드를 고성능으로 유지하고 이해하기 쉽게 하기 위해, React는 보이지 않는 곳에서 몇 가지 일을 수행합니다.
-
-**오토바인딩:** JavaScript에서 콜백을 만들 때, 보통은 `this`의 값이 정확하도록 명시적으로 메소드를 인스턴스에 바인드해야 합니다. React에서는 모든 메소드가 자동으로 React의 컴포넌트 인스턴스에 바인드됩니다.(ES6 클래스 문법을 사용할 때는 재외하고) React가 바인드 메소드를 캐시하기 때문에 매우 CPU와 메모리에 효율적입니다. 타이핑해야 할 것도 줄어들죠!
-
-**이벤트 델리게이션:** React는 실제로는 노드자신에게 이벤트 핸들러를 붙이지 않습니다. React가 시작되면 React는 탑 레벨의 단일 이벤트 리스너로 모든 이벤트를 리스닝하기 시작합니다. 컴포넌트가 마운트되거나 언마운트 될 때, 이벤트 핸들러는 그냥 내부 매핑에서 넣거나 뺄 뿐입니다. 이벤트가 발생하면, React는 이 매핑을 사용해서 어떻게 디스패치할 지를 알게 됩니다. 매핑에 이벤트 핸들러가 남아있지 않으면, React의 이벤트 핸들러는 그냥 아무것도 하지 않습니다. 왜 이 방식이 빠른지 더 알고 싶으시면, [David Walsh의 멋진 블로그 글](http://davidwalsh.name/event-delegate)을 읽어 보세요.
-
-## 컴포넌트는 그냥 state 머신일 뿐
-
-React는 UI를 간단한 state 머신이라 생각합니다. UI를 다양한 state와 그 state의 렌더링으로 생각함으로써 UI를 일관성 있게 관리하기 쉬워집니다.
-
-React에서는, 간단히 컴포넌트의 state를 업데이트하고, 이 새로운 state의 UI를 렌더링합니다. React는 DOM의 변경을 가장 효율적인 방법으로 관리해줍니다.
-
-## state의 동작 원리
-
-React에게 데이터의 변경을 알리는 일반적인 방법은 `setState(data, callback)`을 호출하는 것입니다. 이 메소드는 `this.state`에 `data`를 머지하고 컴포넌트를 다시 렌더링 합니다. 컴포넌트의 재-렌더링이 끝나면, 생략가능한 `callback`이 호출됩니다. 대부분의 경우 React가 UI를 최신상태로 유지해주기 때문에 `callback`을 사용할 필요가 없습니다.
-
-## 어떤 컴포넌트가 state를 가져야 할까요?
-
-대부분의 컴포넌트는 `props`로부터 데이터를 받아 렌더할 뿐입니다만, 가끔 유저 인풋, 서버 요청, 시간의 경과에 반응해야 할 필요가 있습니다. 이럴 때 state를 사용합니다.
-
-**가능한 한 컴포넌트가 상태를 가지지 않도록(stateless) 하세요.** 이렇게 함으로써 가장 논리적인 장소로 state를 격리하게 되고 쉽게 애플리케이션을 추론할 수 있도록 중복을 최소화할 수 있습니다.
-
-일반적인 패턴은 데이터만 렌더하는 여러 상태를 가지지 않은 컴포넌트를 만들고, 그 위에 상태기반(stateful) 컴포넌트를 만들어 계층 안의 자식 컴포넌트에게 `props`를 통해 state를 전달하는 것입니다. state를 가지지 않은 컴포넌트가 선언적인 방법으로 데이터를 렌더링 하는 동안, 상태기반 컴포넌트는 모든 상호작용 로직을 캡슐화합니다.
-
-## state를 어떻게 *써야* 할까요?
-
-**state는 컴포넌트의 이벤트 핸들러에 의해 UI 업데이트를 트리거할때 변경될 가능성이 있어, 그때 사용할 데이터를 가져야 합니다.** 실제 앱에서는 이 데이터는 매우 작고 JSON 직렬화 가능한 경향이 있습니다. 상태기반 컴포넌트를 만들때, 가능한 작게 state를 서술하고 `this.state`에만 저장하도록 해보세요. 그냥 `render()` 안에서 이 state를 기반으로 다른 모든 정보를 계산합니다. 이 방식으로 애플리케이션을 작성하고 생각하면 가장 최적의 애플리케이션으로 발전해가는 경향이 있다는 것을 발견하게 될 것입니다. 꼭 필요하지 않은 값이나 계산된 값을 state에 추가하는 것은 render가 그것을 계산하는 대신에 명시적으로 그것들을 맞춰줘야 하는 것을 의미하기 때문이죠.
-
-## state를 어떻게 *쓰지 말아야* 할까요?
-
-`this.state`는 UI의 state를 표현할 최소한의 데이터만을 가져야 합니다. 그래서 이런 것들을 가지지 않게끔 해야 합니다.
-
-* **계산된 데이터:** state에 따라 값을 미리 계산하는 것에 대해 염려하지 마세요. 계산은 모두 `render()`에서 하는 것이 UI의 일관성을 유지하기 쉽습니다. 예를 들어, state에서 list items 배열을 가지고 있고 문자열으로 카운트를 렌더링 할 경우, state에 저장하기보다는 그냥 `render()` 메소드안에서 `this.state.listItems.length + ' list items'`를 렌더하세요.
-* **React 컴포넌트:** 가지고 있는 props와 state로 `render()`안에서 만드세요.
-* **props에서 복사한 데이터:** 가능한 한 원래의 소스로 props를 사용하도록 해보세요. props를 state에 저장하는 단 하나의 올바른 사용법은 이전 값을 알고 싶을 때입니다. props는 부모 컴포넌트의 재 렌더링의 결과 변경될 수도 있기 때문이죠.
diff --git a/docs/docs/03-interactivity-and-dynamic-uis.md b/docs/docs/03-interactivity-and-dynamic-uis.md
deleted file mode 100644
index ebc7980c90c4..000000000000
--- a/docs/docs/03-interactivity-and-dynamic-uis.md
+++ /dev/null
@@ -1,77 +0,0 @@
----
-id: interactivity-and-dynamic-uis
-title: Interactivity and Dynamic UIs
-permalink: interactivity-and-dynamic-uis.html
-prev: jsx-gotchas.html
-next: multiple-components.html
----
-
-You've already [learned how to display data](/react/docs/displaying-data.html) with React. Now let's look at how to make our UIs interactive.
-
-## A Simple Example
-
-```javascript
-var LikeButton = React.createClass({
-  getInitialState: function() {
-    return {liked: false};
-  },
-  handleClick: function(event) {
-    this.setState({liked: !this.state.liked});
-  },
-  render: function() {
-    var text = this.state.liked ? 'like' : 'haven\'t liked';
-    return (
-      <p onClick={this.handleClick}>
-        You {text} this. Click to toggle.
-      </p>
-    );
-  }
-});
-
-ReactDOM.render(
-  <LikeButton />,
-  document.getElementById('example')
-);
-```
-
-## Event Handling and Synthetic Events
-
-With React you simply pass your event handler as a camelCased prop similar to how you'd do it in normal HTML. React ensures that all events behave similarly in all browsers by implementing a synthetic event system. That is, React knows how to bubble and capture events according to the spec, and the events passed to your event handler are guaranteed to be consistent with [the W3C spec](http://www.w3.org/TR/DOM-Level-3-Events/), regardless of which browser you're using.
-
-## Under the Hood: Autobinding and Event Delegation
-
-Under the hood, React does a few things to keep your code performant and easy to understand.
-
-**Autobinding:** When creating callbacks in JavaScript, you usually need to explicitly bind a method to its instance such that the value of `this` is correct. With React, every method is automatically bound to its component instance ([except when using ES6 class syntax](/react/docs/reusable-components.html#no-autobinding)). React caches the bound method such that it's extremely CPU and memory efficient. It's also less typing!
-
-**Event delegation:** React doesn't actually attach event handlers to the nodes themselves. When React starts up, it starts listening for all events at the top level using a single event listener. When a component is mounted or unmounted, the event handlers are simply added or removed from an internal mapping. When an event occurs, React knows how to dispatch it using this mapping. When there are no event handlers left in the mapping, React's event handlers are simple no-ops. To learn more about why this is fast, see [David Walsh's excellent blog post](http://davidwalsh.name/event-delegate).
-
-## Components are Just State Machines
-
-React thinks of UIs as simple state machines. By thinking of a UI as being in various states and rendering those states, it's easy to keep your UI consistent.
-
-In React, you simply update a component's state, and then render a new UI based on this new state. React takes care of updating the DOM for you in the most efficient way.
-
-## How State Works
-
-A common way to inform React of a data change is by calling `setState(data, callback)`. This method merges `data` into `this.state` and re-renders the component. When the component finishes re-rendering, the optional `callback` is called. Most of the time you'll never need to provide a `callback` since React will take care of keeping your UI up-to-date for you.
-
-## What Components Should Have State?
-
-Most of your components should simply take some data from `props` and render it. However, sometimes you need to respond to user input, a server request or the passage of time. For this you use state.
-
-**Try to keep as many of your components as possible stateless.** By doing this you'll isolate the state to its most logical place and minimize redundancy, making it easier to reason about your application.
-
-A common pattern is to create several stateless components that just render data, and have a stateful component above them in the hierarchy that passes its state to its children via `props`. The stateful component encapsulates all of the interaction logic, while the stateless components take care of rendering data in a declarative way.
-
-## What *Should* Go in State?
-
-**State should contain data that a component's event handlers may change to trigger a UI update.** In real apps this data tends to be very small and JSON-serializable. When building a stateful component, think about the minimal possible representation of its state, and only store those properties in `this.state`. Inside of `render()` simply compute any other information you need based on this state. You'll find that thinking about and writing applications in this way tends to lead to the most correct application, since adding redundant or computed values to state means that you need to explicitly keep them in sync rather than rely on React computing them for you.
-
-## What *Shouldn't* Go in State?
-
-`this.state` should only contain the minimal amount of data needed to represent your UI's state. As such, it should not contain:
-
-* **Computed data:** Don't worry about precomputing values based on state — it's easier to ensure that your UI is consistent if you do all computation within `render()`. For example, if you have an array of list items in state and you want to render the count as a string, simply render `this.state.listItems.length + ' list items'` in your `render()` method rather than storing it on state.
-* **React components:** Build them in `render()` based on underlying props and state.
-* **Duplicated data from props:** Try to use props as the source of truth where possible. One valid use to store props in state is to be able to know its previous values, because props may change as the result of a parent component re-rendering.
diff --git a/docs/docs/03-interactivity-and-dynamic-uis.zh-CN.md b/docs/docs/03-interactivity-and-dynamic-uis.zh-CN.md
deleted file mode 100644
index 995924538e3f..000000000000
--- a/docs/docs/03-interactivity-and-dynamic-uis.zh-CN.md
+++ /dev/null
@@ -1,77 +0,0 @@
----
-id: interactivity-and-dynamic-uis-zh-CN
-title: 动态交互式用户界面
-permalink: interactivity-and-dynamic-uis-zh-CN.html
-prev: jsx-gotchas-zh-CN.html
-next: multiple-components-zh-CN.html
----
-
-我们已经学习如何使用 React [显示数据](/react/docs/displaying-data-zh-CN.html)。现在让我们来学习如何创建交互式界面。
-
-## 简单例子
-
-```javascript
-var LikeButton = React.createClass({
-  getInitialState: function() {
-    return {liked: false};
-  },
-  handleClick: function(event) {
-    this.setState({liked: !this.state.liked});
-  },
-  render: function() {
-    var text = this.state.liked ? 'like' : 'haven\'t liked';
-    return (
-      <p onClick={this.handleClick}>
-        You {text} this. Click to toggle.
-      </p>
-    );
-  }
-});
-
-ReactDOM.render(
-  <LikeButton />,
-  document.getElementById('example')
-);
-```
-
-## 事件处理与合成事件（Synthetic Events）
-
-React 里只需把事件处理器（event handler）以骆峰命名（camelCased）形式当作组件的 props 传入即可，就像使用普通 HTML 那样。React 内部创建一套合成事件系统来使所有事件在 IE8 和以上浏览器表现一致。也就是说，React 知道如何冒泡和捕获事件，而且你的事件处理器接收到的 events 参数与 [W3C 规范](http://www.w3.org/TR/DOM-Level-3-Events/) 一致，无论你使用哪种浏览器。
-
-## 幕后原理：自动绑定（Autobinding）和事件代理（Event Delegation）
-
-在幕后，React 做了一些操作来让代码高效运行且易于理解。
-
-**Autobinding:** 在 JavaScript 里创建回调的时候，为了保证 `this` 的正确性，一般都需要显式地绑定方法到它的实例上。在 React，所有方法被自动绑定到了它的组件实例上（除非使用ES6的class符号）。React 还缓存这些绑定方法，所以 CPU 和内存都是非常高效。而且还能减少打字！
-
-**事件代理 ：** React 实际并没有把事件处理器绑定到节点本身。当 React 启动的时候，它在最外层使用唯一一个事件监听器处理所有事件。当组件被加载和卸载时，只是在内部映射里添加或删除事件处理器。当事件触发，React 根据映射来决定如何分发。当映射里处理器时，会当作空操作处理。参考 [David Walsh 很棒的文章](http://davidwalsh.name/event-delegate) 了解这样做高效的原因。
-
-## 组件其实是状态机（State Machines）
-
-React 把用户界面当作简单状态机。把用户界面想像成拥有不同状态然后渲染这些状态，可以轻松让用户界面和数据保持一致。
-
-React 里，只需更新组件的 state，然后根据新的 state 重新渲染用户界面（不要操作 DOM）。React 来决定如何最高效地更新 DOM。
-
-## State 工作原理
-
-常用的通知 React 数据变化的方法是调用 `setState(data, callback)`。这个方法会合并（merge） `data` 到 `this.state`，并重新渲染组件。渲染完成后，调用可选的 `callback` 回调。大部分情况下不需要提供 `callback`，因为 React 会负责把界面更新到最新状态。
-
-## 哪些组件应该有 State？
-
-大部分组件的工作应该是从 `props` 里取数据并渲染出来。但是，有时需要对用户输入、服务器请求或者时间变化等作出响应，这时才需要使用 State。
-
-** 尝试把尽可能多的组件无状态化。** 这样做能隔离 state，把它放到最合理的地方，也能减少冗余并，同时易于解释程序运作过程。
-
-常用的模式是创建多个只负责渲染数据的无状态（stateless）组件，在它们的上层创建一个有状态（stateful）组件并把它的状态通过 `props` 传给子级。这个有状态的组件封装了所有用户的交互逻辑，而这些无状态组件则负责声明式地渲染数据。
-
-## 哪些 *应该* 作为 State？
-
-**State 应该包括那些可能被组件的事件处理器改变并触发用户界面更新的数据。** 真实的应用中这种数据一般都很小且能被 JSON 序列化。当创建一个状态化的组件时，想象一下表示它的状态最少需要哪些数据，并只把这些数据存入 `this.state`。在 `render()` 里再根据 state 来计算你需要的其它数据。你会发现以这种方式思考和开发程序最终往往是正确的，因为如果在 state 里添加冗余数据或计算所得数据，需要你经常手动保持数据同步，不能让 React 来帮你处理。
-
-## 哪些 *不应该* 作为 State？
-
-`this.state` 应该仅包括能表示用户界面状态所需的最少数据。因些，它不应该包括：
-
-* **计算所得数据：** 不要担心根据 state 来预先计算数据 —— 把所有的计算都放到 `render()` 里更容易保证用户界面和数据的一致性。例如，在 state 里有一个数组（listItems），我们要把数组长度渲染成字符串， 直接在 `render()` 里使用 `this.state.listItems.length + ' list items'` 比把它放到 state 里好的多。
-* **React 组件：** 在 `render()` 里使用当前 props 和 state 来创建它。
-* **基于 props 的重复数据：** 尽可能使用 props 来作为实际状态的源。把 props 保存到 state 的一个有效的场景是需要知道它以前值的时候，因为 props 可能因为父组件重绘的结果而变化。
diff --git a/docs/docs/04-multiple-components.it-IT.md b/docs/docs/04-multiple-components.it-IT.md
deleted file mode 100644
index 84b6f80aa9be..000000000000
--- a/docs/docs/04-multiple-components.it-IT.md
+++ /dev/null
@@ -1,190 +0,0 @@
----
-id: multiple-components-it-IT
-title: Componenti Multipli
-permalink: multiple-components-it-IT.html
-prev: interactivity-and-dynamic-uis-it-IT.html
-next: reusable-components-it-IT.html
----
-
-Finora abbiamo visto come scrivere un singolo componente per mostrare dati e gestire l'input dell'itente. Adesso esaminiamo una delle migliori caratteristiche di React: la componibilità.
-
-
-## Motivazione: Separazione dei Concetti
-
-Costruendo componenti modulari che riutilizzano altri componenti con interfacce ben definite, ottieni gli stessi benefici che otterresti usando funzioni o classi. Nello specifico, puoi *separare i diversi concetti* della tua applicazione nel modo che preferisci semplicemente costruendo nuovi componenti. Costruendo una libreria di componenti personalizzati per la tua applicazione, stai esprimendo la tua UI in una maniera che si adatta meglio al tuo dominio.
-
-
-## Esepmio di Composizione
-
-Creiamo un semplice componente Avatar che mostra una foto del profilo e un nome utente usando la Graph API di Facebook.
-
-```javascript
-var Avatar = React.createClass({
-  render: function() {
-    return (
-      <div>
-        <ProfilePic username={this.props.username} />
-        <ProfileLink username={this.props.username} />
-      </div>
-    );
-  }
-});
-
-var ProfilePic = React.createClass({
-  render: function() {
-    return (
-      <img src={'https://graph.facebook.com/' + this.props.username + '/picture'} />
-    );
-  }
-});
-
-var ProfileLink = React.createClass({
-  render: function() {
-    return (
-      <a href={'https://www.facebook.com/' + this.props.username}>
-        {this.props.username}
-      </a>
-    );
-  }
-});
-
-ReactDOM.render(
-  <Avatar username="pwh" />,
-  document.getElementById('example')
-);
-```
-
-
-## Possesso
-
-Nell'esempio precedente, le istanze di `Avatar` *posseggono* instanze di `ProfilePic` e `ProfileLink`. In React, **un proprietario è il componente che imposta le `props` di altri componenti**. Più formalmente, se un componente `X` è creato nel metodo `render()` del componente `Y`, si dice che `X` è *di proprietà di* `Y`. Come discusso in precedenza, un componente non può mutare le sue `props` — sono sempre consistenti con il valore che il suo proprietario ha impostato. Questa invariante fondamentale porta a UI la cui consistenza può essere garantita.
-
-È importante distinguere tra la relazione di proprietario-proprietà e la relazione genitore-figlio. La relazione proprietario-proprietà è specifica di React, mentre la relazione genitore-figlio è semplicemente quella che conosci e ami del DOM. Nell'esempio precedente, `Avatar` possiede il `div`, le istanze di `ProfilePic` e `ProfileLink`, e `div` è il **genitore** (ma non il proprietario) delle istanze di `ProfilePic` e `ProfileLink`.
-
-
-## Figli
-
-Quando crei un'istanza di un componente React, puoi includere componenti React aggiuntivi o espressioni JavaScript tra i tag di apertura e chiusura come segue:
-
-```javascript
-<Parent><Child /></Parent>
-```
-
-`Parent` può accedere ai propri figli leggendo la speciale proprietà `this.props.children`. **`this.props.children` è una struttura dati opaca:** usa le [utilità React.Children](/react/docs/top-level-api.html#react.children) per manipolare i figli.
-
-
-### Riconciliazione dei Figli
-
-**La riconciliazione è il processo per il quale React aggiorna il DOM ad ogni passata di rendering.** In generale, i figli sono riconciliati secondo l'ordine in cui sono mostrati. Per esempio, supponiamo che due passate di rendering generino rispettivamente il markup seguente:
-
-```html
-// Prima passata di rendering
-<Card>
-  <p>Paragrafo 1</p>
-  <p>Paragrafo 2</p>
-</Card>
-// Seconda passata di rendering
-<Card>
-  <p>Paragrafo 2</p>
-</Card>
-```
-
-Intuitivamente, `<p>Paragrafo 1</p>` è stato rimosso. Invece, React riconcilierà il DOM cambiando il testo contenuto nel primo figlio e distruggerà l'ultimo figlio. React reconcilia secondo l'*ordine* dei figli.
-
-
-### Figli Dotati di Stato
-
-Per molti componenti, questo non è un grande problema. Tuttavia, per i componenti dotati di stato che mantengono dati in `this.state` attraverso le diverse passate di rendering, questo può essere problematico.
-
-In molti casi, questo problema può essere aggirato nascondendo gli elementi anziché distruggendoli:
-
-```html
-// Prima passata di rendering
-<Card>
-  <p>Paragrafo 1</p>
-  <p>Paragrafo 2</p>
-</Card>
-// Seconda passata di rendering
-<Card>
-  <p style={{'{{'}}display: 'none'}}>Paragrafo 1</p>
-  <p>Paragrafo 2</p>
-</Card>
-```
-
-
-### Figli Dinamici
-
-La situazione si complica quando i figli sono rimescolati (come nei risultati della ricerca) o se nuovi componenti sono aggiunti all'inizio della lista (come negli stream). In questi casi quando l'identità e lo stato di ogni figlio deve essere preservato attraverso passate di rendering, puoi unicamente identificare ciascun figlio assegnandogli una proprietà `key`:
-
-```javascript
-  render: function() {
-    var results = this.props.results;
-    return (
-      <ol>
-        {results.map(function(result) {
-          return <li key={result.id}>{result.text}</li>;
-        })}
-      </ol>
-    );
-  }
-```
-
-Quando React riconcilia i figli dotati di `key`, si assicurerà che ciascun figlio con la proprietà `key` sia riordinato (anziché  clobbered) o distrutto (anziché riutilizzato).
-
-La proprietà `key` dovrebbe *sempre* essere fornita direttamente all'elemento del componente nell'array, non al contenitore HTML di ciascun componente dell'array:
-
-```javascript
-// SBAGLIATO!
-var ListItemWrapper = React.createClass({
-  render: function() {
-    return <li key={this.props.data.id}>{this.props.data.text}</li>;
-  }
-});
-var MyComponent = React.createClass({
-  render: function() {
-    return (
-      <ul>
-        {this.props.results.map(function(result) {
-          return <ListItemWrapper data={result}/>;
-        })}
-      </ul>
-    );
-  }
-});
-```
-```javascript
-// Corretto :)
-var ListItemWrapper = React.createClass({
-  render: function() {
-    return <li>{this.props.data.text}</li>;
-  }
-});
-var MyComponent = React.createClass({
-  render: function() {
-    return (
-      <ul>
-        {this.props.results.map(function(result) {
-           return <ListItemWrapper key={result.id} data={result}/>;
-        })}
-      </ul>
-    );
-  }
-});
-```
-
-Puoi anche assegnare chiavi ai figli passandogli un oggetto ReactFragment. Leggi [Frammenti con Chiave](create-fragment.html) per maggiori dettagli.
-
-## Flusso dei Dati
-
-In React, i dati fluiscono dal proprietario al componente posseduto attraverso le `props` come discusso in precedenza. Questo è a tutti gli effetti un binding di dati unidirezionale: i proprietari legano le proprietà dei componenti di loro proprietà a dei valori che il proprietario stesso ha calcolato in base ai propri `props` o `state`. Dal momento che questo processo avviene ricorsivamente, i cambiamenti dei dati vengono riflessi automaticamente ovunque vengano usati.
-
-
-## Una Nota sulle Prestazioni
-
-Ti starai chiedendo che cambiare i dati sia un'operazione costosa in presenza di un gran numero di nodi sotto un proprietario. La buona notizia è che JavaScript è veloce e i metodi `render()` tendono ad essere molto semplici, quindi in molte applicazioni questo è un processo estremamente veloce. Inoltre, il collo di bottiglia è quasi sempre la mutazione del DOM e non l'esecuzione di JS. React ottimizzerà tutto per te usando il raggruppamento e osservando i cambiamenti.
-
-Tuttavia, a volte vorrai avere un controllo più raffinato sulle tue prestazioni. In tal caso, ridefinisci il metodo `shouldComponentUpdate()` per restituire false quando vuoi che React salti il trattamento di un sottoalbero. Consulta [la documentazione di riferimento di React](/react/docs/component-specs.html) per maggiori informazioni.
-
-> Nota:
->
-> Se `shouldComponentUpdate()` restituisce false quando i dati sono effettivamente cambiati, React non è in grado di mantenere la tua UI in sincronia. Assicurati di usare questa tecnica con cognizione di causa, e soltanto in presenza di problemi percettibili di prestazioni. Non sottovalutare l'estrema velocità di esecuzione di JavaScript se paragonata a quella del DOM.
diff --git a/docs/docs/04-multiple-components.ja-JP.md b/docs/docs/04-multiple-components.ja-JP.md
deleted file mode 100644
index 1d6e363ec74e..000000000000
--- a/docs/docs/04-multiple-components.ja-JP.md
+++ /dev/null
@@ -1,186 +0,0 @@
----
-id: multiple-components
-title: 複数のコンポーネント
-permalink: multiple-components-ja-JP.html
-prev: interactivity-and-dynamic-uis-ja-JP.html
-next: reusable-components-ja-JP.html
----
-
-今まで、データを表示したりユーザの入力をハンドルするための1つのコンポーネントの書き方を見てきました。次に、 Reactの最も面白い特徴であるコンポーザビリティについて見ていきましょう。
-
-## 動機: 関心の分離
-
-うまく定義されたインターフェースとともに他のコンポーネントを再利用するモジュールのコンポーネントを構築することによって、関数やクラスを使う場合と同じ利益を得ることができます。特に、アプリの *異なった関心を分離* できるにも関わらず、新しいコンポーネントを単純に構築することで満足する場合には。アプリケーションにカスタムコンポーネントライブラリを構築することによって、あなたがやりたいことに最も合う方法でUIを表現することができます。
-
-## 構成例
-
-FacebookのグラフAPIを使って、プロフィール画像とユーザー名を表示する単純なアバターのコンポーネントを作ってみましょう。
-
-```javascript
-var Avatar = React.createClass({
-  render: function() {
-    return (
-      <div>
-        <ProfilePic username={this.props.username} />
-        <ProfileLink username={this.props.username} />
-      </div>
-    );
-  }
-});
-
-var ProfilePic = React.createClass({
-  render: function() {
-    return (
-      <img src={'https://graph.facebook.com/' + this.props.username + '/picture'} />
-    );
-  }
-});
-
-var ProfileLink = React.createClass({
-  render: function() {
-    return (
-      <a href={'https://www.facebook.com/' + this.props.username}>
-        {this.props.username}
-      </a>
-    );
-  }
-});
-
-ReactDOM.render(
-  <Avatar username="pwh" />,
-  document.getElementById('example')
-);
-```
-
-
-## 所有
-
-上記の例では、 `Avatar` のインスタンスは  `ProfilePic` と `ProfileLink` のインスタンスを *所有* しています。Reactでは、 **所有者は、他のコンポーネントの `props` をセットするコンポーネントです。** 正式に言うと、もし `Y` コンポーネントの `render()` メソッドの中に `X` コンポーネントが作られた場合、 `X` は `Y` に所有されていると言います。以前述べたように、コンポーネントはそれ自身の `props` を変化させることはできません。 `props` は常に、所有者が彼らにセットしたものと一貫性があります。このキー要素は一貫性があることを保証するために、UIに反映されます。
-
-所有者と所有される側の関係と、親子の関係の違いを示すのは重要です。所有者と所有される側の関係はReact独特です。一方で、親子の関係は単純にDOMから分かる、愛すべき関係です。上の例では、 `Avatar` は `div` を所有しますが、 `ProfilePic` と `ProfileLink` インスタンスと、 `div` は  `ProfilePic` と `ProfileLink`インスタンスの **親** (しかし、所有者ではありません)です。
-
-
-## 子
-
-Reactのコンポーネントのインスタンスを作成する時には、以下のように開始タグと終了タグの間に付加的なReactのコンポーネントやJavaScriptの表現を含めることができます。
-
-```javascript
-<Parent><Child /></Parent>
-```
-
-`Parent` は特別な  `this.props.children` というプロパティでアクセスすることで、子要素を読み取ることができます。 **`this.props.children` は不透明なデータ構造です。** 操作するには[React.Children utilities](/react/docs/top-level-api.html#react.children)を使用してください。
-
-
-### 子要素の調和
-
-**調和はReactが新しいレンダリングのパスごとにDOMをアップデートするプロセスです。** 一般的に、子要素はレンダリングされる順序に従って調和します。例えば、2つのレンダリングパスを考えると、以下のそれぞれのマークアップが生成されます。
-
-```html
-// パス1のレンダリング
-<Card>
-  <p>Paragraph 1</p>
-  <p>Paragraph 2</p>
-</Card>
-// パス2のレンダリング
-<Card>
-  <p>Paragraph 2</p>
-</Card>
-```
-
-直感的には、 `<p>Paragraph 1</p>` が削除されたように思えます。代わりに、Reactは1つ目の子要素のテキストコンテンツを変更し、最後の子要素を削除するという変更を加えることでDOMを調和させます。Reactは子要素の *順序* に従って調和するのです。
-
-
-
-### ステートフルな子要素
-
-多くのコンポーネントにとって、これは大きな処理ではありません。しかし、レンダリングのパスを超えて、 `this.state` にデータを保持しているステートフルなコンポーネントにとっては、これはとても問題になり得ます。
-
-多くのケースにおいては、以下のように、削除する代わりに要素を隠すことで回避することがあります。
-
-```html
-// パス1のレンダリング
-<Card>
-  <p>Paragraph 1</p>
-  <p>Paragraph 2</p>
-</Card>
-// パス2のレンダリング
-<Card>
-  <p style={{'{{'}}display: 'none'}}>Paragraph 1</p>
-  <p>Paragraph 2</p>
-</Card>
-```
-
-
-### 動的な子要素
-
-子要素がシャッフルされているような時（検索結果のように）や、リストの最初に新しいコンポーネントが追加されるような時（ストリームのように）には、状況はさらに複雑になります。そういったケースでは、それぞれの子要素のアイデンティティやstateがレンダリングパスを保持する必要があり、以下のように `key` を認識することでそれぞれの子要素をただ1つに識別できます。
-
-```javascript
-  render: function() {
-    var results = this.props.results;
-    return (
-      <ol>
-        {results.map(function(result) {
-          return <li key={result.id}>{result.text}</li>;
-        })}
-      </ol>
-    );
-  }
-```
-
-Reactがキー付けされた子要素を調和させるとき、 `key` と子要素が再び整理される（けんかをする代わりに）か削除されます（再利用される代わりに）。
-
-`key` は以下のように *常に* 配列の中でコンポーネントに直接提供されるべきで、その配列の中でそれぞれのコンポーネントのHTMLの子要素の入れ物に提供されるべきではありません。
-
-```javascript
-// 間違い！
-var ListItemWrapper = React.createClass({
-  render: function() {
-    return <li key={this.props.data.id}>{this.props.data.text}</li>;
-  }
-});
-var MyComponent = React.createClass({
-  render: function() {
-    return (
-      <ul>
-        {this.props.results.map(function(result) {
-          return <ListItemWrapper data={result}/>;
-        })}
-      </ul>
-    );
-  }
-});
-
-// 正解 :)
-var ListItemWrapper = React.createClass({
-  render: function() {
-    return <li>{this.props.data.text}</li>;
-  }
-});
-var MyComponent = React.createClass({
-  render: function() {
-    return (
-      <ul>
-        {this.props.results.map(function(result) {
-           return <ListItemWrapper key={result.id} data={result}/>;
-        })}
-      </ul>
-    );
-  }
-});
-```
-
-Reactのフラグのオブジェクトを渡すことで子要素をキー付けすることもできます。詳細は、[キー付けされたフラグ](create-fragment.html)をご覧ください。
-
-## データフロー
-
-Reactの、 `props` を通した所有者から所有されるコンポーネントへのデータフローは今までに記述してきました。これは実際には一方向のデータバインディングです。所有者は所有しているコンポーネントのpropsを、所有者が `props` か `state` に基づいて計算したいくつかの値にバインドします。このプロセスが何度も行われるので、データの変更は彼らが使われるところは自動的にどこでも反映されます。
-
-## パフォーマンスの注意
-
-みなさんは所有者の下にたくさんのノードがあるときには、データの変更には多くのコストがかかると考えるでしょう。良いニュースとして、JavaScriptは早く、 `render()` メソッドはとても単純になりやすいので、多くのアプリケーションにおいて、こういったことは非常に早くなります。加えて、ボトルネックとなるものの多くは、JSの実行ではなく、DOMの変更です。Reactは変更の一括処理と検知を使うことによって、それを最適化しています。
-
-しかし、パフォーマンスについて、よりよい制御を持つことを求める時もあるでしょう。こういったケースで、Reactがサブツリーの処理をスキップすることを求めるなら、 `shouldComponentUpdate()` が単純にfalseを返すようにオーバーライドしてください。更に情報を得たい場合には、[Reactのリファレンス文書](/react/docs/component-specs.html)を読んでください。
-
-> 注意:
-> `shouldComponentUpdate()` がデータが実際に変わった時にfalseを返したならば、ReactはUIを同期的に保つことができません。このメソッドを使う際には、何を行っているか理解してください。そして、顕著なパフォーマンスの問題がある時にだけ、この関数を使ってください。DOMと比較して、JavaScriptが速いことを過小評価しないでください。
diff --git a/docs/docs/04-multiple-components.ko-KR.md b/docs/docs/04-multiple-components.ko-KR.md
deleted file mode 100644
index ec8d8c751d44..000000000000
--- a/docs/docs/04-multiple-components.ko-KR.md
+++ /dev/null
@@ -1,183 +0,0 @@
----
-id: multiple-components-ko-KR
-title: 복합 컴포넌트
-permalink: multiple-components-ko-KR.html
-prev: interactivity-and-dynamic-uis-ko-KR.html
-next: reusable-components-ko-KR.html
----
-
-지금까지, 단일 컴포넌트에서 데이터를 표시하고 유저 입력을 다루는 것을 살펴보았습니다. 다음엔 React의 최고의 기능 중 하나인 조합가능성(composability)을 살펴봅시다.
-
-## 동기: 관심의 분리
-
-명확히 정의된 인터페이스와 다른 컴포넌트를 재사용해 모듈러 컴포넌트를 구축하면, 함수와 클래스를 이용했을 때 얻을 수 있는 이점 대부분을 얻을 수 있습니다. 특히 앱에서 *다른 관심을 분리*할 수 있습니다.아무리 간단히 새 컴포넌트를 만들었다고 해도 말이죠. 당신의 애플리케이션에서 쓸 커스텀 컴포넌트 라이브러리를 만들어서, 당신의 도메인에 최적화된 방법으로 UI를 표현할 수 있게 됩니다.
-
-## 조합(Composition) 예제
-
-간단히 페이스북 그래프 API를 사용해 프로필 사진과 유저이름을 보여주는 아바타 컴포넌트를 만든다고 합시다.
-
-```javascript
-var Avatar = React.createClass({
-  render: function() {
-    return (
-      <div>
-        <ProfilePic username={this.props.username} />
-        <ProfileLink username={this.props.username} />
-      </div>
-    );
-  }
-});
-
-var ProfilePic = React.createClass({
-  render: function() {
-    return (
-      <img src={'https://graph.facebook.com/' + this.props.username + '/picture'} />
-    );
-  }
-});
-
-var ProfileLink = React.createClass({
-  render: function() {
-    return (
-      <a href={'https://www.facebook.com/' + this.props.username}>
-        {this.props.username}
-      </a>
-    );
-  }
-});
-
-ReactDOM.render(
-  <Avatar username="pwh" />,
-  document.getElementById('example')
-);
-```
-
-## 소유권(Ownership)
-
-위의 예제에서, `Avatar` 인스턴스는  `ProfilePic`과 `ProfileLink`인스턴스를 *가지고* 있습니다. React에서 **소유자는 다른 컴포넌트의 `props`를 설정하는 컴포넌트입니다**. 더 정식으로 말하면, `X` 컴포넌트가 `Y` 컴포넌트의 `render()` 메소드 안에서 만들어졌다면, `Y`가 `X`를 *소유하고* 있다고 합니다. 앞에서 설명한 바와 같이, 컴포넌트는 자신의 `props`를 변경할 수 없습니다. `props`는 언제나 소유자가 설정한 것과 일치합니다. 이와 같은 근본적인 불변성은 UI가 일관성 있도록 해줍니다.
-
-소유(owner-ownee)관계와 부모·자식 관계를 구별하는 것은 중요합니다. 부모·자식 관계가 DOM에서부터 쓰던 익숙하고 이미 알고있던 단순한 것인 한편, 소유관계는 React 고유의 것입니다.  위의 예제에서, `Avatar`는 `div`, `ProfilePic`, `ProfileLink`인스턴스를 소유하고, `div`는 `ProfilePic`과 `ProfileLink`인스턴스의 (소유자가 아닌) **부모**입니다.
-
-## 자식
-
-React 컴포넌트 인스턴스를 만들 때, 추가적인 React 컴포넌트나 JavaScript 표현식을 시작과 끝 태그 사이에 넣을 수 있습니다. 이렇게 말이죠.
-
-```javascript
-<Parent><Child /></Parent>
-```
-
-`Parent`는 `this.props.children`라는 특수 prop으로 자식들을 읽을 수 있습니다. **`this.props.children` 는 불투명한 데이터 구조이며,** [React.Children 유틸리티](/react/docs/top-level-api-ko-KR.html#react.children)를 사용해 자식들을 관리합니다.
-
-### 자식 Reconciliation (비교조정)
-
-**Reconciliation은 React가 DOM을 각각 새로운 렌더 패스에 업데이트하는 과정입니다.** 일반적으로, 자식은 렌더하는 순서에 따라 비교조정됩니다. 예를 들어, 각각의 마크업을 생성하는 두 개의 렌더 패스가 있다고 해봅시다.
-
-```html
-// Render Pass 1
-<Card>
-  <p>Paragraph 1</p>
-  <p>Paragraph 2</p>
-</Card>
-// Render Pass 2
-<Card>
-  <p>Paragraph 2</p>
-</Card>
-```
-
-직관적으로 보면, `<p>Paragraph 1</p>`가 없어졌습니다만 그러는 대신에, React는 첫 번째 자식의 텍스트를 비교조정하고 마지막 자식을 파괴하도록 DOM을 비교조정할 것입니다. React는 자식들의 *순서*에 따라 비교조정합니다.
-
-### 상태기반(Stateful) 자식
-
-대부분의 컴포넌트에서는, 이것은 큰 문제가 아닙니다. 하지만 렌더 패스 간에 `this.state`를 유지하는 상태기반의 컴포넌트에서는 매우 문제가 될 수 있습니다.
-
-대부분의 경우, 이 문제는 엘리먼트를 파괴하지 않고 숨김으로써 피해갈 수 있습니다.
-
-```html
-// Render Pass 1
-<Card>
-  <p>Paragraph 1</p>
-  <p>Paragraph 2</p>
-</Card>
-// Render Pass 2
-<Card>
-  <p style={{'{{'}}display: 'none'}}>Paragraph 1</p>
-  <p>Paragraph 2</p>
-</Card>
-```
-
-<a name="dynamic-children"></a>
-### 동적 자식
-
-자식들이 섞이거나(검색의 결과같은 경우) 새로운 컴포넌트가 목록의 앞에 추가(스트림같은 경우)된다면 상황은 점점 더 까다로워집니다. 이런 때에의 동일성과 각 자식의 상태는 반드시 렌더 패스 간에 유지돼야 합니다. 각 자식에 `key`를 할당 함으로써 독자적으로 식별할 수 있습니다.
-
-```javascript
-  render: function() {
-    var results = this.props.results;
-    return (
-      <ol>
-        {results.map(function(result) {
-          return <li key={result.id}>{result.text}</li>;
-        })}
-      </ol>
-    );
-  }
-```
-
-React가 키가 있는 자식들을 비교조정할 때, React는 `key`가 있는 자식이 (오염(clobbered)되는 대신) 재배치되고 (재사용되는 대신) 파괴되도록 보장할 것입니다.
-
-`key`는 *항상* 배열 안의 각 컴포넌트의 컨테이너 HTML 자식이 아닌 컴포넌트에게 직접 주어져야 합니다.
-
-```javascript
-// 틀림!
-var ListItemWrapper = React.createClass({
-  render: function() {
-    return <li key={this.props.data.id}>{this.props.data.text}</li>;
-  }
-});
-var MyComponent = React.createClass({
-  render: function() {
-    return (
-      <ul>
-        {this.props.results.map(function(result) {
-          return <ListItemWrapper data={result}/>;
-        })}
-      </ul>
-    );
-  }
-});
-```
-```javascript
-// 맞음 :)
-var ListItemWrapper = React.createClass({
-  render: function() {
-    return <li>{this.props.data.text}</li>;
-  }
-});
-var MyComponent = React.createClass({
-  render: function() {
-    return (
-      <ul>
-        {this.props.results.map(function(result) {
-           return <ListItemWrapper key={result.id} data={result}/>;
-        })}
-      </ul>
-    );
-  }
-});
-```
-
-ReactFragment 객체를 넘기는 것으로 자식에 키를 할당할 수도 있습니다. 자세한 내용은 [키가 할당된 프래그먼트](create-fragment-ko-KR.html)를 참고하세요.
-
-## 데이터 흐름
-
-React에서 데이터는 위에서 말한 것처럼 `props`를 통해 소유자로부터 소유한 컴포넌트로 흐릅니다. 이것은 사실상 단방향 데이터 바인딩입니다. 소유자는 `props`나 `state`를 기준으로 계산한 어떤 값으로 소유한 컴포넌트의 props를 바인드합니다. 이 과정은 재귀적으로 발생하므로, 데이터의 변경은 자동으로 모든 곳에 반영됩니다.
-
-## 성능의 주의점
-
-소유자가 가지고 있는 노드의 수가 많아지면 데이터가 변화하는 비용이 증가할 것으로 생각할 수도 있습니다. 좋은 소식은 JavaScript의 속도는 빠르고 `render()` 메소드는 꽤 간단한 경향이 있어, 대부분 애플리케이션에서 매우 빠르다는 점입니다. 덧붙여, 대부분의 병목 현상은 JS 실행이 아닌 DOM 변경에서 일어나고, React는 배치와 탐지 변경을 이용해 최적화해 줍니다.
-
-하지만, 가끔 성능을 위해 정교하게 제어해야 할 때도 있습니다. 이런 경우, React가 서브트리의 처리를 건너 뛰도록 간단히 `shouldComponentUpdate()`를 오버라이드해 false를 리턴하게 할 수 있습니다. 좀 더 자세한 정보는 [React 참조 문서](/react/docs/component-specs-ko-KR.html)를 보세요.
-
-> 주의:
->
-> 데이터가 실제로는 변경되었지만 `shouldComponentUpdate()`가 false를 리턴한다면 React는 UI를 싱크시킬수 없습니다. 이 기능을 사용할 때에는 자신이 지금 무엇을 하고 있는지 알고 있고, 눈에 띄는 성능 문제가 있을 경우에만 사용하세요. JavaScript는 DOM에 비해 빠릅니다. 과소평가하지 마세요.
diff --git a/docs/docs/04-multiple-components.md b/docs/docs/04-multiple-components.md
deleted file mode 100644
index 08009746f69f..000000000000
--- a/docs/docs/04-multiple-components.md
+++ /dev/null
@@ -1,182 +0,0 @@
----
-id: multiple-components
-title: Multiple Components
-permalink: multiple-components.html
-prev: interactivity-and-dynamic-uis.html
-next: reusable-components.html
----
-
-So far, we've looked at how to write a single component to display data and handle user input. Next let's examine one of React's finest features: composability.
-
-## Motivation: Separation of Concerns
-
-By building modular components that reuse other components with well-defined interfaces, you get much of the same benefits that you get by using functions or classes. Specifically you can *separate the different concerns* of your app however you please simply by building new components. By building a custom component library for your application, you are expressing your UI in a way that best fits your domain.
-
-## Composition Example
-
-Let's create a simple Avatar component which shows a Facebook page picture and name using the Facebook Graph API.
-
-```javascript
-var Avatar = React.createClass({
-  render: function() {
-    return (
-      <div>
-        <PagePic pagename={this.props.pagename} />
-        <PageLink pagename={this.props.pagename} />
-      </div>
-    );
-  }
-});
-
-var PagePic = React.createClass({
-  render: function() {
-    return (
-      <img src={'https://graph.facebook.com/' + this.props.pagename + '/picture'} />
-    );
-  }
-});
-
-var PageLink = React.createClass({
-  render: function() {
-    return (
-      <a href={'https://www.facebook.com/' + this.props.pagename}>
-        {this.props.pagename}
-      </a>
-    );
-  }
-});
-
-ReactDOM.render(
-  <Avatar pagename="Engineering" />,
-  document.getElementById('example')
-);
-```
-
-## Ownership
-
-In the above example, instances of `Avatar` *own* instances of `PagePic` and `PageLink`. In React, **an owner is the component that sets the `props` of other components**. More formally, if a component `X` is created in component `Y`'s `render()` method, it is said that `X` is *owned by* `Y`. As discussed earlier, a component cannot mutate its `props` — they are always consistent with what its owner sets them to. This fundamental invariant leads to UIs that are guaranteed to be consistent.
-
-It's important to draw a distinction between the owner-ownee relationship and the parent-child relationship. The owner-ownee relationship is specific to React, while the parent-child relationship is simply the one you know and love from the DOM. In the example above, `Avatar` owns the `div`, `PagePic` and `PageLink` instances, and `div` is the **parent** (but not owner) of the `PagePic` and `PageLink` instances.
-
-## Children
-
-When you create a React component instance, you can include additional React components or JavaScript expressions between the opening and closing tags like this:
-
-```javascript
-<Parent><Child /></Parent>
-```
-
-`Parent` can read its children by accessing the special `this.props.children` prop. **`this.props.children` is an opaque data structure:** use the [React.Children utilities](/react/docs/top-level-api.html#react.children) to manipulate them.
-
-### Child Reconciliation
-
-**Reconciliation is the process by which React updates the DOM with each new render pass.** In general, children are reconciled according to the order in which they are rendered. For example, suppose two render passes generate the following respective markup:
-
-```html
-// Render Pass 1
-<Card>
-  <p>Paragraph 1</p>
-  <p>Paragraph 2</p>
-</Card>
-// Render Pass 2
-<Card>
-  <p>Paragraph 2</p>
-</Card>
-```
-
-Intuitively, `<p>Paragraph 1</p>` was removed. Instead, React will reconcile the DOM by changing the text content of the first child and destroying the last child. React reconciles according to the *order* of the children.
-
-### Stateful Children
-
-For most components, this is not a big deal. However, for stateful components that maintain data in `this.state` across render passes, this can be very problematic.
-
-In most cases, this can be sidestepped by hiding elements instead of destroying them:
-
-```html
-// Render Pass 1
-<Card>
-  <p>Paragraph 1</p>
-  <p>Paragraph 2</p>
-</Card>
-// Render Pass 2
-<Card>
-  <p style={{'{{'}}display: 'none'}}>Paragraph 1</p>
-  <p>Paragraph 2</p>
-</Card>
-```
-
-### Dynamic Children
-
-The situation gets more complicated when the children are shuffled around (as in search results) or if new components are added onto the front of the list (as in streams). In these cases where the identity and state of each child must be maintained across render passes, you can uniquely identify each child by assigning it a `key`:
-
-```javascript
-  render: function() {
-    var results = this.props.results;
-    return (
-      <ol>
-        {results.map(function(result) {
-          return <li key={result.id}>{result.text}</li>;
-        })}
-      </ol>
-    );
-  }
-```
-
-When React reconciles the keyed children, it will ensure that any child with `key` will be reordered (instead of clobbered) or destroyed (instead of reused).
-
-The `key` should *always* be supplied directly to the components in the array, not to the container HTML child of each component in the array:
-
-```javascript
-// WRONG!
-var ListItemWrapper = React.createClass({
-  render: function() {
-    return <li key={this.props.data.id}>{this.props.data.text}</li>;
-  }
-});
-var MyComponent = React.createClass({
-  render: function() {
-    return (
-      <ul>
-        {this.props.results.map(function(result) {
-          return <ListItemWrapper data={result}/>;
-        })}
-      </ul>
-    );
-  }
-});
-```
-```javascript
-// Correct :)
-var ListItemWrapper = React.createClass({
-  render: function() {
-    return <li>{this.props.data.text}</li>;
-  }
-});
-var MyComponent = React.createClass({
-  render: function() {
-    return (
-      <ul>
-        {this.props.results.map(function(result) {
-           return <ListItemWrapper key={result.id} data={result}/>;
-        })}
-      </ul>
-    );
-  }
-});
-```
-
-You can also key children by passing a ReactFragment object. See [Keyed Fragments](create-fragment.html) for more details.
-
-## Data Flow
-
-In React, data flows from owner to owned component through `props` as discussed above. This is effectively one-way data binding: owners bind their owned component's props to some value the owner has computed based on its `props` or `state`. Since this process happens recursively, data changes are automatically reflected everywhere they are used.
-
-## A Note on Performance
-
-You may be thinking that it's expensive to change data if there are a large number of nodes under an owner. The good news is that JavaScript is fast and `render()` methods tend to be quite simple, so in most applications this is extremely fast. Additionally, the bottleneck is almost always the DOM mutation and not JS execution. React will optimize this for you by using batching and change detection.
-
-However, sometimes you really want to have fine-grained control over your performance. In that case, simply override `shouldComponentUpdate()` to return false when you want React to skip processing of a subtree. See [the React reference docs](/react/docs/component-specs.html) for more information.
-
-> Note:
->
-> If `shouldComponentUpdate()` returns false when data has actually changed, React can't keep your UI in sync. Be sure you know what you're doing while using it, and only use this function when you have a noticeable performance problem. Don't underestimate how fast JavaScript is relative to the DOM.
diff --git a/docs/docs/04-multiple-components.zh-CN.md b/docs/docs/04-multiple-components.zh-CN.md
deleted file mode 100644
index 309d44eb9720..000000000000
--- a/docs/docs/04-multiple-components.zh-CN.md
+++ /dev/null
@@ -1,182 +0,0 @@
----
-id: multiple-components-zh-CN
-title: 复合组件
-permalink: multiple-components-zh-CN.html
-prev: interactivity-and-dynamic-uis-zh-CN.html
-next: reusable-components-zh-CN.html
----
-
-目前为止，我们已经学了如何用单个组件来展示数据和处理用户输入。下一步让我们来体验 React 最激动人心的特性之一：可组合性（composability）。
-
-## 动机：关注分离
-
-通过复用那些接口定义良好的组件来开发新的模块化组件，我们得到了与使用函数和类相似的好处。具体来说就是能够通过开发简单的组件把程序的*不同关注面分离*。如果为程序开发一套自定义的组件库，那么就能以最适合业务场景的方式来展示你的用户界面。
-
-## 组合实例
-
-让我们用 Facebook Graph API 来开发一个显示 Facebook 页面图片和用户名的简单 Avatar 组件吧。
-
-```javascript
-var Avatar = React.createClass({
-  render: function() {
-    return (
-      <div>
-        <PagePic pagename={this.props.pagename} />
-        <PageLink pagename={this.props.pagename} />
-      </div>
-    );
-  }
-});
-
-var PagePic = React.createClass({
-  render: function() {
-    return (
-      <img src={'https://graph.facebook.com/' + this.props.pagename + '/picture'} />
-    );
-  }
-});
-
-var PageLink = React.createClass({
-  render: function() {
-    return (
-      <a href={'https://www.facebook.com/' + this.props.pagename}>
-        {this.props.pagename}
-      </a>
-    );
-  }
-});
-
-ReactDOM.render(
-  <Avatar pagename="Engineering" />,
-  document.getElementById('example')
-);
-```
-
-## 从属关系
-
-上面例子中，`Avatar` 拥有 `PagePic` 和 `PageLink` 的实例。`拥有者` 就是给其它组件设置 `props` 的那个组件。更正式地说，如果组件 `Y` 在 `render()` 方法是创建了组件 `X`，那么 `Y` 就拥有 `X`。上面讲过，组件不能修改自身的 `props` - 它们总是与它们拥有者设置的保持一致。这是保持用户界面一致性的基本不变量。
-
-把从属关系与父子关系加以区别至关重要。从属关系是 React 特有的，而父子关系简单来讲就是DOM 里的标签的关系。在上一个例子中，`Avatar` 拥有 `div`、`PagePic` 和 `PageLink` 实例，`div` 是 `PagePic` 和 `PageLink` 实例的**父级**（但不是拥有者）。
-
-## 子级
-
-实例化 React 组件时，你可以在开始标签和结束标签之间引用在React 组件或者Javascript 表达式：
-
-```javascript
-<Parent><Child /></Parent>
-```
-
-`Parent` 能通过专门的 `this.props.children`  props 读取子级。**`this.props.children` 是一个不透明的数据结构：** 通过 [React.Children 工具类](/react/docs/top-level-api.html#react.children) 来操作。
-
-### 子级校正（Reconciliation）
-
-**校正就是每次 render 方法调用后 React 更新 DOM 的过程。** 一般情况下，子级会根据它们被渲染的顺序来做校正。例如，下面代码描述了两次渲染的过程：
-
-```html
-// 第一次渲染
-<Card>
-  <p>Paragraph 1</p>
-  <p>Paragraph 2</p>
-</Card>
-// 第二次渲染
-<Card>
-  <p>Paragraph 2</p>
-</Card>
-```
-
-直观来看，只是删除了`<p>Paragraph 1</p>`。事实上，React 先更新第一个子级的内容，然后删除最后一个组件。React 是根据子级的*顺序*来校正的。
-
-### 子组件状态管理
-
-对于大多数组件，这没什么大碍。但是，对于使用 `this.state` 来在多次渲染过程中里维持数据的状态化组件，这样做潜在很多问题。
-
-多数情况下，可以通过隐藏组件而不是删除它们来绕过这些问题。
-
-```html
-// 第一次渲染
-<Card>
-  <p>Paragraph 1</p>
-  <p>Paragraph 2</p>
-</Card>
-// 第二次渲染
-<Card>
-  <p style={{'{{'}}display: 'none'}}>Paragraph 1</p>
-  <p>Paragraph 2</p>
-</Card>
-```
-
-### 动态子级
-
-如果子组件位置会改变（如在搜索结果中）或者有新组件添加到列表开头（如在流中）情况会变得更加复杂。如果子级要在多个渲染阶段保持自己的特征和状态，在这种情况下，你可以通过给子级设置惟一标识的 `key` 来区分。
-
-```javascript
-  render: function() {
-    var results = this.props.results;
-    return (
-      <ol>
-        {results.map(function(result) {
-          return <li key={result.id}>{result.text}</li>;
-        })}
-      </ol>
-    );
-  }
-```
-
-当 React 校正带有 key 的子级时，它会确保它们被重新排序（而不是破坏）或者删除（而不是重用）。
-`务必` 把 `key` 添加到子级数组里组件本身上，而不是每个子级内部最外层 HTML 上：
-
-```javascript
-// 错误！
-var ListItemWrapper = React.createClass({
-  render: function() {
-    return <li key={this.props.data.id}>{this.props.data.text}</li>;
-  }
-});
-var MyComponent = React.createClass({
-  render: function() {
-    return (
-      <ul>
-        {this.props.results.map(function(result) {
-          return <ListItemWrapper data={result}/>;
-        })}
-      </ul>
-    );
-  }
-});
-```
-```javascript
-// 正确 :)
-var ListItemWrapper = React.createClass({
-  render: function() {
-    return <li>{this.props.data.text}</li>;
-  }
-});
-var MyComponent = React.createClass({
-  render: function() {
-    return (
-      <ul>
-        {this.props.results.map(function(result) {
-           return <ListItemWrapper key={result.id} data={result}/>;
-        })}
-      </ul>
-    );
-  }
-});
-```
-
-也可以传递ReactFragment 对象 来做有 key 的子级。详见[Keyed Fragments](create-fragment.html)
-
-## 数据流
-
-React 里，数据通过上面介绍过的 `props` 从拥有者流向归属者。这就是高效的单向数据绑定(one-way data binding)：拥有者通过它的 `props` 或 `state` 计算出一些值，并把这些值绑定到它们拥有的组件的 props 上。因为这个过程会递归地调用，所以数据变化会自动在所有被使用的地方自动反映出来。
-
-
-## 性能提醒
-
-你或许会担心如果一个拥有者有大量子级时，对于数据变化做出响应非常耗费性能。值得庆幸的是执行 JavaScript  非常的快，而且 `render()` 方法一般比较简单，所以在大部分应用里这样做速度极快。此外，性能的瓶颈大多是因为 DOM 更新，而非 JS 执行，而且 React 会通过批量更新和变化检测来优化性能。
-
-但是，有时候需要做细粒度的性能控制。这种情况下，可以重写 `shouldComponentUpdate()` 方法返回 false 来让 React 跳过对子树的处理。参考 [React reference docs](/react/docs/component-specs.html) 了解更多。
-
-> 注意：
->
-> 如果在数据变化时让 `shouldComponentUpdate()` 返回 false，React 就不能保证用户界面同步。当使用它的时候一定确保你清楚到底做了什么，并且只在遇到明显性能问题的时候才使用它。不要低估 JavaScript 的速度，DOM 操作通常才是慢的原因。
diff --git a/docs/docs/05-reusable-components.it-IT.md b/docs/docs/05-reusable-components.it-IT.md
deleted file mode 100644
index e313ca65c314..000000000000
--- a/docs/docs/05-reusable-components.it-IT.md
+++ /dev/null
@@ -1,263 +0,0 @@
----
-id: reusable-components-it-IT
-title: Componenti Riutilizzabili
-permalink: reusable-components-it-IT.html
-prev: multiple-components-it-IT.html
-next: transferring-props-it-IT.html
----
-
-Quando disegni interfacce, separa gli elementi comuni di design (bottoni, campi dei moduli, componenti di layout, etc.) in componenti riutilizzabili con interfacce ben definite. In questo modo, la prossima volta che dovrai costruire una nuova UI, puoi scrivere molto meno codice. Ciò significa tempi di sviluppo più brevi, meno bachi, e meno byte trasferiti sulla rete.
-
-
-## Validazione delle Proprietà
-
-Mentre la tua applicazione cresce, è utile assicurarsi che i tuoi componenti vengano usati correttamente. Ciò viene fatto permettendoti di specificare i `propTypes`. `React.PropTypes` esporta una gamma di validatori che possono essere usati per assicurarsi che i dati che ricevi siano validi. Quando ad una proprietà è assegnato un valore non valido, sarà mostrato un avvertimento nella console JavaScript. Nota che per motivi di prestazioni, `propTypes` è utilizzato soltanto nella modalità di sviluppo. Di seguito trovi un esempio che documenta i diversi validatori che vengono forniti:
-
-```javascript
-React.createClass({
-  propTypes: {
-    // Puoi dichiarare che una proprietà è uno specifico tipo primitivo JS. In
-    // maniera predefinita, questi sono tutti opzionali.
-    optionalArray: React.PropTypes.array,
-    optionalBool: React.PropTypes.bool,
-    optionalFunc: React.PropTypes.func,
-    optionalNumber: React.PropTypes.number,
-    optionalObject: React.PropTypes.object,
-    optionalString: React.PropTypes.string,
-
-    // Tutto ciò che può essere mostrato: numeri, stringhe, elementi, o un array
-    // (o frammento) contenente questi tipi.
-    optionalNode: React.PropTypes.node,
-
-    // Un elemento React.
-    optionalElement: React.PropTypes.element,
-
-    // Puoi anche dichiarare che una proprietà è un'istanza di una classe. Questo
-    // validatore usa l'operatore instanceof di JS.
-    optionalMessage: React.PropTypes.instanceOf(Message),
-
-    // Puoi assicurarti che la tua proprietà sia ristretta a valori specifici
-    // trattandoli come una enumerazione.
-    optionalEnum: React.PropTypes.oneOf(['News', 'Photos']),
-
-    // Un oggetto che può essere di uno tra diversi tipi
-    optionalUnion: React.PropTypes.oneOfType([
-      React.PropTypes.string,
-      React.PropTypes.number,
-      React.PropTypes.instanceOf(Message)
-    ]),
-
-    // Un array di un tipo specificato
-    optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),
-
-    // Un oggetto con proprietà dai valori di un tipo specificato
-    optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),
-
-    // Un oggetto che accetta una forma particolare
-    optionalObjectWithShape: React.PropTypes.shape({
-      color: React.PropTypes.string,
-      fontSize: React.PropTypes.number
-    }),
-
-    // Puoi concatenare ciascuna delle precedenti con `isRequired` per assicurarti
-    // che venga mostrato un avvertimento se la proprietà non viene impostata.
-    requiredFunc: React.PropTypes.func.isRequired,
-
-    // Un valore di un tipo qualsiasi
-    requiredAny: React.PropTypes.any.isRequired,
-
-    // Puoi inoltre specificare un validatore personalizzato. Deve restituire un
-    // oggetto di tipo Error se la validazione fallisce. Non lanciare eccezioni
-    // o utilizzare `console.warn`, in quanto non funzionerebbe all'interno di
-    // `oneOfType`.
-    customProp: function(props, propName, componentName) {
-      if (!/matchme/.test(props[propName])) {
-        return new Error('Validazione fallita!');
-      }
-    }
-  },
-  /* ... */
-});
-```
-
-
-## Valori Predefiniti delle Proprietà
-
-React ti permette di definire valori predefiniti per le tue `props` in una maniera molto dichiarativa:
-
-```javascript
-var ComponentWithDefaultProps = React.createClass({
-  getDefaultProps: function() {
-    return {
-      value: 'valore predefinito'
-    };
-  }
-  /* ... */
-});
-```
-
-Il risultato di `getDefaultProps()` sarà conservato e usato per assicurarsi che `this.props.value` avrà sempre un valore se non è stato specificato dal componente proprietario. Ciò ti permette di utilizzare in sicurezza le tue proprietà senza dover scrivere codice fragile e ripetitivo per gestirlo da te.
-
-
-## Trasferire le  Proprietà: Una Scorciatoia
-
-Un tipo comune di componente React è uno che estende un elemento basico HTML in maniera semplice. Spesso vorrai copiare qualsiasi attributo HTML passato al tuo componente all'elemento HTML sottostante per risparmiare del codice. Puoi usare la sintassi _spread_ di JSX per ottenerlo:
-
-```javascript
-var CheckLink = React.createClass({
-  render: function() {
-    // Questo prende ciascuna proprietà passata a CheckLink e la copia su <a>
-    return <a {...this.props}>{'√ '}{this.props.children}</a>;
-  }
-});
-
-ReactDOM.render(
-  <CheckLink href="/checked.html">
-    Clicca qui!
-  </CheckLink>,
-  document.getElementById('example')
-);
-```
-
-## Figlio Singolo
-
-Con `React.PropTypes.element` puoi specificare che solo un figlio unico possa essere passato come figli ad un componente.
-
-```javascript
-var MyComponent = React.createClass({
-  propTypes: {
-    children: React.PropTypes.element.isRequired
-  },
-
-  render: function() {
-    return (
-      <div>
-        {this.props.children} // Questo deve essere esattamente un elemento oppure lancerà un'eccezione.
-      </div>
-    );
-  }
-
-});
-```
-
-## Mixin
-
-I componenti sono la maniera migliore di riutilizzare il codice in React, ma a volte componenti molto diversi possono condividere funzionalità comune. Questi sono a volte chiamate [responsabilità trasversali](https://en.wikipedia.org/wiki/Cross-cutting_concern). React fornisce i `mixin` per risolvere questo problema.
-
-Un caso d'uso comune è un componente che desidera aggiornarsi ad intervalli di tempo. È facile usare `setInterval()`, ma è anche importante cancellare la chiamata ripetuta quando non è più necessaria per liberare memoria. React fornisce dei [metodi del ciclo di vita](/react/docs/working-with-the-browser.html#component-lifecycle) che ti permettono di sapere quando un componente sta per essere creato o distrutto. Creiamo un semplice mixin che usa questi metodi per fornire una facile funzione `setInterval()` che sarà automaticamente rimossa quando il tuo componente viene distrutto.
-
-```javascript
-var SetIntervalMixin = {
-  componentWillMount: function() {
-    this.intervals = [];
-  },
-  setInterval: function() {
-    this.intervals.push(setInterval.apply(null, arguments));
-  },
-  componentWillUnmount: function() {
-    this.intervals.forEach(clearInterval);
-  }
-};
-
-var TickTock = React.createClass({
-  mixins: [SetIntervalMixin], // Usa il mixin
-  getInitialState: function() {
-    return {seconds: 0};
-  },
-  componentDidMount: function() {
-    this.setInterval(this.tick, 1000); // Chiama un metodo del mixin
-  },
-  tick: function() {
-    this.setState({seconds: this.state.seconds + 1});
-  },
-  render: function() {
-    return (
-      <p>
-        React has been running for {this.state.seconds} seconds.
-      </p>
-    );
-  }
-});
-
-ReactDOM.render(
-  <TickTock />,
-  document.getElementById('example')
-);
-```
-
-Una caratteristica interessante dei mixin è che, se un componente usa molteplici mixin e diversi mixin definiscono lo stesso metodo del ciclo di vita (cioè diversi mixin desiderano effettuare una pulizia quando il componente viene distrutto), viene garantito che tutti i metodi del ciclo di vita verranno chiamati. I metodi definiti nei mixin vengono eseguiti nell'ordine in cui i mixin sono elencati, seguiti da una chiamata al metodo definito nel componente.
-
-## Classi ES6
-
-Puoi anche definire le tue classi React come pure classi JavaScript. Per esempio, usando la sintassi delle classi ES6:
-
-```javascript
-class HelloMessage extends React.Component {
-  render() {
-    return <div>Ciao {this.props.name}</div>;
-  }
-}
-ReactDOM.render(<HelloMessage name="Sebastian" />, mountNode);
-```
-
-L'API è simile a `React.createClass` con l'eccezione del metodo `getInitialState`. Anziché fornire un metodo `getInitialState` a parte, imposti la tua proprietà `state` nel costruttore.
-
-Un'altra differenza è che `propTypes` e `defaultProps` sono definite come proprietà del costruttore anziché nel corpo della classe.
-
-```javascript
-export class Counter extends React.Component {
-  constructor(props) {
-    super(props);
-    this.state = {count: props.initialCount};
-  }
-  tick() {
-    this.setState({count: this.state.count + 1});
-  }
-  render() {
-    return (
-      <div onClick={this.tick.bind(this)}>
-        Click: {this.state.count}
-      </div>
-    );
-  }
-}
-Counter.propTypes = { initialCount: React.PropTypes.number };
-Counter.defaultProps = { initialCount: 0 };
-```
-
-### Niente Binding Automatico
-
-I metodi seguono la stessa semantica delle classi ES6 regolari, ciò significa che non effettuano il binding automatico di `this` all'istanza. Dovrai pertanto usare esplicitamente `.bind(this)` oppure [le funzioni freccia](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) `=>`.
-
-### Niente Mixin
-
-Sfortunatamente, ES6 è stato lanciato senza alcun supporto per i mixin. Di conseguenza non vi è alcun supporto per i mixin quando usi React con le classi ES6. Stiamo lavorando per rendere più semplice il supporto dei relativi casi d'uso senza ricorrere ai mixin.
-
-
-
-## Funzioni Prive di Stato
-
-Puoi anche definire le tue classi React come semplici funzioni JavaScript. Ad esempio usando la sintassi della funzione priva di stato:
-
-```javascript
-function HelloMessage(props) {
-  return <div>Ciao {props.name}</div>;
-}
-ReactDOM.render(<HelloMessage name="Sebastian" />, mountNode);
-```
-
-Oppure usando la nuova sintassi freccia di ES6:
-
-```javascript
-const HelloMessage = (props) => <div>Ciao {props.name}</div>;
-ReactDOM.render(<HelloMessage name="Sebastian" />, mountNode);
-```
-
-
-Questa API semplificata dei componenti è intesa per i componenti che sono pure funzioni dele proprietà. Questi componenti non devono trattenere stato interno, non hanno istanze di supporto, e non posseggono metodi di ciclo di vita. Sono pure trasformate funzionali del loro input, con zero codice boilerplate.
-
-> NOTA:
->
-> Poiché le funzioni prive di stato non hanno un'istanza di supporto, non puoi assegnare un ref a un componente creato con una funzione priva di stato. Normalmente questo non è un problema, poiché le funzioni prive di stato non forniscono un'API imperativa. Senza un'API imperativa, non puoi comunque fare molto con un'istanza. Tuttavia, se un utente desidera trovare il nodo DOM di un componente creato con una funzione priva di stato, occorre avvolgere il componente in un altro componente dotato di stato (ad es. un componente classe ES6) e assegnare il ref al componente dotato di stato.
-
-In un mondo ideale, la maggior parte dei tuoi componenti sarebbero funzioni prive di stato poiché questi componenti privi di stato seguono un percorso più rapido all'interno del core di React. Questo è un pattern raccomandato, quando possibile.
diff --git a/docs/docs/05-reusable-components.ja-JP.md b/docs/docs/05-reusable-components.ja-JP.md
deleted file mode 100644
index 2fdfbb1ccd57..000000000000
--- a/docs/docs/05-reusable-components.ja-JP.md
+++ /dev/null
@@ -1,230 +0,0 @@
----
-id: reusable-components
-title: 再利用可能なコンポーネント
-permalink: reusable-components-ja-JP.html
-prev: multiple-components-ja-JP.html
-next: transferring-props-ja-JP.html
----
-
-インターフェースをデザインするとき、明確に定義されたインターフェースでは共通のデザイン要素（ボタン、フォームフィールド、レイアウトコンポーネントなど）を再利用可能なコンポーネントにブレークダウンします。そのような方法をとることで、次にUIを作成する必要があるときに、書くコードが少なくて済みます。これは、開発速度を上げ、バグを減らし、導線を減らすことを意味します。
-
-## Propのバリデーション
-
-アプリが大きくなっていくにつれて、コンポーネントが正しく使われていることを保証することが役に立つようになります。`propTypes` を指定することでそういったことができるようになります。`React.PropTypes` はあなたが受け取ったデータが正しいことを認識するのに使われるバリデータを出力します。不正な値がpropに渡されたときは、警告がJavaScriptコンソールに表示されます。パフォーマンスの点で、 `propTypes` は開発モードでのみチェックされることに注意してください。異なるバリデータが提供された際の例を表すドキュメントは以下の通りです。
-
-```javascript
-React.createClass({
-  propTypes: {
-    // propがJSのプリミティブ型であると宣言できます。
-    // デフォルトで、以下は全てオプションです。
-    optionalArray: React.PropTypes.array,
-    optionalBool: React.PropTypes.bool,
-    optionalFunc: React.PropTypes.func,
-    optionalNumber: React.PropTypes.number,
-    optionalObject: React.PropTypes.object,
-    optionalString: React.PropTypes.string,
-
-    // 何でもレンダリングできます。number、string、要素やそれらを含む配列など。
-    optionalNode: React.PropTypes.node,
-
-    // Reactの要素。
-    optionalElement: React.PropTypes.element,
-
-    // propがクラスのインスタンスであるとの宣言もできます。
-    // JSのinstanceofオペレータを使用しています。
-    optionalMessage: React.PropTypes.instanceOf(Message),
-
-    // 以下をenumとして扱うことで、propがある値であると保証できます。
-    optionalEnum: React.PropTypes.oneOf(['News', 'Photos']),
-
-    // たくさんの型のうちのひとつになりうるオブジェクト
-    optionalUnion: React.PropTypes.oneOfType([
-      React.PropTypes.string,
-      React.PropTypes.number,
-      React.PropTypes.instanceOf(Message)
-    ]),
-
-    // ある型の配列
-    optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),
-
-    // プロパティの値がある型のものであるオブジェクト
-    optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),
-
-    // 特定の形をとるオブジェクト
-    optionalObjectWithShape: React.PropTypes.shape({
-      color: React.PropTypes.string,
-      fontSize: React.PropTypes.number
-    }),
-
-    // `isRequired` は上記のどの値にも繋げることができますが、
-    // propが提供されなかったときには警告が出ることに注意してください。
-    requiredFunc: React.PropTypes.func.isRequired,
-
-    // どのようなデータ型の値でも大丈夫です
-    requiredAny: React.PropTypes.any.isRequired,
-
-    // バリデータをカスタマイズすることもできます。
-    // 以下はバリデーションが落ちた時にはエラーを返します。
-    // `oneOfType` の中で動かなくなるので、 `console.warn` や throw はしないでください。
-    customProp: function(props, propName, componentName) {
-      if (!/matchme/.test(props[propName])) {
-        return new Error('Validation failed!');
-      }
-    }
-  },
-  /* ... */
-});
-```
-
-
-## デフォルトのPropの値
-
-Reactは以下のように、とても宣言的な方法で `props` のデフォルト値を定義できます。
-
-```javascript
-var ComponentWithDefaultProps = React.createClass({
-  getDefaultProps: function() {
-    return {
-      value: 'default value'
-    };
-  }
-  /* ... */
-});
-```
-
-`getDefaultProps()` の結果は `this.props.value` が親コンポーネントで制限されなかった場合に値を保証するためにキャッシュされて使われます。これによって、自分自身でハンドルするための壊れやすいコードを何度も書くことなくpropsをただ安全に使うことができます。
-
-## Propsの移動: ショートカット
-
-Reactのコンポーネントに共通しているのは、単純な方法で基本的なHTML要素を拡張していることです。よく、
-コンポーネントに渡されるHTML属性を、型付けを守るために、基本的なHTML要素にコピーしたいと考える人もいます。このようなことを行うために、JSXの _拡張された_ シンタックスを使うことができます。
-
-```javascript
-var CheckLink = React.createClass({
-  render: function() {
-    // 以下はCheckLinkに渡されたどんなpropsをとることができ、<a>タグにコピーすることもできます。
-    return <a {...this.props}>{'√ '}{this.props.children}</a>;
-  }
-});
-
-ReactDOM.render(
-  <CheckLink href="/checked.html">
-    Click here!
-  </CheckLink>,
-  document.getElementById('example')
-);
-```
-
-## 単一の子要素
-
-`React.PropTypes.element` を使って、childrenとしてコンポーネントにただ一つの子要素が渡されるよう制限できます。
-
-```javascript
-var MyComponent = React.createClass({
-  propTypes: {
-    children: React.PropTypes.element.isRequired
-  },
-
-  render: function() {
-    return (
-      <div>
-        {this.props.children} // これは1つの要素でなくてはなりません。さもなければエラーがthrowされます。
-      </div>
-    );
-  }
-
-});
-```
-
-## ミックスイン
-
-コンポーネントはReactでコードを再利用する最良の方法ですが、全く異なったコンポーネントが共通の機能性を共有することもあります。それらは[横断的関心事](https://en.wikipedia.org/wiki/Cross-cutting_concern)と呼ばれることもあります。Reactはこの問題を解決するために、 `mixins` を提供しています。
-
-共通のユースケースとしては、時間の間隔によって、コンポーネントにそれ自身をアップデートさせたい場合があります。 `setInterval()` を使うのは簡単ですが、メモリをセーブするためにもう必要でなくなった場合にはインターバルをキャンセルすることが重要です。Reactは[ライフサイクルメソッド](/react/docs/working-with-the-browser.html#component-lifecycle)を提供しており、コンポーネントが作成されようとしたり削除されようとした時にそれを検知することができます。コンポーネントが削除されたときに自動的にクリーンアップしてくれる、簡単な `setInterval()` 関数を提供する以下のようなメソッドを使って単純なミックスインを作成してみましょう。
-
-```javascript
-var SetIntervalMixin = {
-  componentWillMount: function() {
-    this.intervals = [];
-  },
-  setInterval: function() {
-    this.intervals.push(setInterval.apply(null, arguments));
-  },
-  componentWillUnmount: function() {
-    this.intervals.forEach(clearInterval);
-  }
-};
-
-var TickTock = React.createClass({
-  mixins: [SetIntervalMixin], // ミックスインを使う
-  getInitialState: function() {
-    return {seconds: 0};
-  },
-  componentDidMount: function() {
-    this.setInterval(this.tick, 1000); // ミックスインのメソッドを呼ぶ
-  },
-  tick: function() {
-    this.setState({seconds: this.state.seconds + 1});
-  },
-  render: function() {
-    return (
-      <p>
-        React has been running for {this.state.seconds} seconds.
-      </p>
-    );
-  }
-});
-
-ReactDOM.render(
-  <TickTock />,
-  document.getElementById('example')
-);
-```
-
-ミックスインの素晴らしい特徴はコンポーネントが複数のミックスインを使っていて、いくつかのミックスインが同じライフサイクルメソッドを定義している場合（すなわち、コンポーネントが削除された際に幾つかのミックスインがクリーンアップを行いたい場合）に、すべてのライフサイクルメソッドが呼ばれることを保証することです。ミックスインで定義されたメソッドは、ミックスインが並んでいる順番に走り、コンポーネントのメソッド呼び出しで呼ばれます。
-
-## ES6のクラス
-
-ReactのクラスをただのJavaScriptのクラスとして定義することもできます。例えば、ES6 のクラスシンタックスを使うと、以下のようになります。
-
-```javascript
-class HelloMessage extends React.Component {
-  render() {
-    return <div>Hello {this.props.name}</div>;
-  }
-}
-ReactDOM.render(<HelloMessage name="Sebastian" />, mountNode);
-```
-
-APIは `getInitialState` という例外を除き、 `React.createClass` と同じです。APIが異なっている `getInitialState` メソッドを提供する代わりに、コンストラクタの中に `state` プロパティをセットします。
-
-他の違いは、 `propTypes` と `defaultProps` はクラスのボディに定義される代わりにコンストラクタにプロパティとして定義されます。
-
-```javascript
-export class Counter extends React.Component {
-  constructor(props) {
-    super(props);
-    this.state = {count: props.initialCount};
-  }
-  tick() {
-    this.setState({count: this.state.count + 1});
-  }
-  render() {
-    return (
-      <div onClick={this.tick.bind(this)}>
-        Clicks: {this.state.count}
-      </div>
-    );
-  }
-}
-Counter.propTypes = { initialCount: React.PropTypes.number };
-Counter.defaultProps = { initialCount: 0 };
-```
-
-### オートバインディングしません
-
-メソッドは標準のES6のクラスと同じ仕様です。それは、 `this` をインスタンスに自動的にバインドしないことを意味します。明確に `.bind(this)` を使うか [アロー関数](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/) `=>` を使ってください。
-
-### ミックスインはありません
-
-不幸なことに、ES6はミックスインのサポートを行いません。それゆえ、ReactをES6のクラスと一緒に使う際にはミックスインのサポートはありません。代わりに、ミックスインに頼ることなくそれらのユースケースをサポートするのが簡単になるよう努力しています。
diff --git a/docs/docs/05-reusable-components.ko-KR.md b/docs/docs/05-reusable-components.ko-KR.md
deleted file mode 100644
index c89e74980be6..000000000000
--- a/docs/docs/05-reusable-components.ko-KR.md
+++ /dev/null
@@ -1,257 +0,0 @@
----
-id: reusable-components-ko-KR
-title: 재사용가능한 컴포넌트
-permalink: reusable-components-ko-KR.html
-prev: multiple-components-ko-KR.html
-next: transferring-props-ko-KR.html
----
-
-인터페이스를 설계할 때, 공통적으로 사용되는 디자인 요소들(버튼, 폼 필드, 레이아웃 컴포넌트 등.)을 잘 정의된 인터페이스의 재사용 가능한 컴포넌트로 분해합니다. 이런 방법으로 다음에 UI를 구축할 때에는 훨씬 적은 코드로 만들 수 있습니다. 이 말은 더 빠른 개발 시간, 더 적은 버그, 더 적은 용량으로 할 수 있다는 뜻이죠.
-
-## Prop 검증
-
-앱의 규모가 커지면 컴포넌트들이 바르게 사용되었는지 확인하는게 도움이 됩니다. 확인은 `propTypes`를 명시해서 할 수 있습니다. `React.PropTypes`는 받은 데이터가 적절한지(valid) 확인하는데 사용할 수 있는 다양한 검증자(validator)를 제공합니다. prop에 부적절한 값을 명시한다면 JavaScript 콘솔에 경고가 보일 것입니다. 성능상의 문제로 `propTypes`는 개발 모드에서만 검사됩니다. 다음은 제공되는 검증자를 설명하는 예제입니다.
-
-```javascript
-React.createClass({
-  propTypes: {
-    // 특정 JavaScript 프리미티브 타입에 대한 prop을 명시할 수 있습니다.
-    // 기본적으로 이것들은 모두 선택적입니다.
-    optionalArray: React.PropTypes.array,
-    optionalBool: React.PropTypes.bool,
-    optionalFunc: React.PropTypes.func,
-    optionalNumber: React.PropTypes.number,
-    optionalObject: React.PropTypes.object,
-    optionalString: React.PropTypes.string,
-
-    // 렌더링될 수 있는 모든 것: 숫자, 문자열, 요소
-    // 이것들을 포함하는 배열(이나 프래그먼트)
-    optionalNode: React.PropTypes.node,
-
-    // React 엘리먼트
-    optionalElement: React.PropTypes.element,
-
-    // 클래스의 인스턴스 또한 prop으로 명시할 수 있습니다. JavaScript의 instanceof
-    // 연산자를 사용합니다.
-    optionalMessage: React.PropTypes.instanceOf(Message),
-
-    // 열거형처럼 특정 값들로만 prop을 제한해서 사용할 수 있습니다.
-    optionalEnum: React.PropTypes.oneOf(['News', 'Photos']),
-
-    // 많은 타입들 중 하나로 사용할 수 있는 객체가 될 수도 있습니다.
-    optionalUnion: React.PropTypes.oneOfType([
-      React.PropTypes.string,
-      React.PropTypes.number,
-      React.PropTypes.instanceOf(Message)
-    ]),
-
-    // 특정 타입의 배열
-    optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),
-
-    // 특정 타입의 속성값을 갖는 객체
-    optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),
-
-    // 특정한 형태(shape)의 객체
-    optionalObjectWithShape: React.PropTypes.shape({
-      color: React.PropTypes.string,
-      fontSize: React.PropTypes.number
-    }),
-
-    // 위에 언급된 것들을 `isRequired`로 연결해서 prop이 제공되지 않을 때 경고를
-    // 띄우도록 할 수도 있습니다.
-    requiredFunc: React.PropTypes.func.isRequired,
-
-    // 어떤 데이터 타입도 가능
-    requiredAny: React.PropTypes.any.isRequired,
-
-    // 물론 사용자 정의 검증자도 지정할 수 있습니다. 이는 검증이 실패했을 때
-    // Error 객체를 리턴해야합니다. `console.warn`을 이나 throw를 하면 안됩니다.
-    // 그렇게하면 `oneOfType` 안에서 작동하지 않습니다.
-    customProp: function(props, propName, componentName) {
-      if (!/matchme/.test(props[propName])) {
-        return new Error('Validation failed!');
-      }
-    }
-  },
-  /* ... */
-});
-```
-
-## 기본 Prop 값
-
-React는 매우 선언적(declarative)인 방법으로 `props`의 기본값을 정의할 수 있게 해줍니다.
-
-```javascript
-var ComponentWithDefaultProps = React.createClass({
-  getDefaultProps: function() {
-    return {
-      value: 'default value'
-    };
-  }
-  /* ... */
-});
-```
-
-`getDefaultProps()`의 결과값은 캐시가 되며, 부모 컴포넌트에서 명시되지 않았을 때 `this.props.value`가 값을 가질 수 있도록 해주는데 사용됩니다.`getDefaultProps()`를 사용하면 반복적이고 깨지기 쉬운 코드를 짤 필요없이 그냥 안전하게 prop을 사용할 수 있습니다.
-
-## Prop 전달하기: 단축
-
-React 컴포넌트의 흔히 그냥 기본 HTML 엘리먼트를 확장해서 씁니다. 타이핑을 아끼기 위해 기저의 HTML 엘리먼트에 HTML 속성들을 단순히 복사하는 컴포넌트가 필요할 수도 있습니다. JSX의 _spread_ 문법을 사용하면 이렇게 할 수 있습니다.
-
-```javascript
-var CheckLink = React.createClass({
-  render: function() {
-    // 모든 prop을 받아서 CheckLink에 넘기고 <a>에 복사합니다.
-    return <a {...this.props}>{'√ '}{this.props.children}</a>;
-  }
-});
-
-ReactDOM.render(
-  <CheckLink href="/checked.html">
-    Click here!
-  </CheckLink>,
-  document.getElementById('example')
-);
-```
-
-## 단일 자식
-
-`React.PropTypes.element`을 통해 컴포넌트에 한 자식만 보내도록 명시할 수 있습니다.
-
-```javascript
-var MyComponent = React.createClass({
-  propTypes: {
-    children: React.PropTypes.element.isRequired
-  },
-
-  render: function() {
-    return (
-      <div>
-        {this.props.children} // 정확히 한 엘리먼트여야만 하며, 아니면 에러가 발생합니다.
-      </div>
-    );
-  }
-
-});
-```
-
-## 믹스인
-
-컴포넌트는 React에서 코드를 재사용할 수 있는 최고의 방법이지만, 가끔 아주 다른 컴포넌트에서 공통 기능이 필요한 때도 있습니다. 이런 상황을 [공통된 관심사(cross-cutting concerns)](https://en.wikipedia.org/wiki/Cross-cutting_concern)라 부르며, React에서는 `mixins`으로 이 문제를 해결합니다.
-
-예를 들어, 컴포넌트가 주기적으로 업데이트되길 원할 경우가 있습니다. `setInterval()`을 사용하면 쉽지만, 필요 없어지면 메모리를 아끼기 위해 주기를 꼭 취소해야 합니다. React는 컴포넌트가 막 생성거나 없어질 때를 [생명주기 메소드](/react/docs/working-with-the-browser-ko-KR.html#component-lifecycle)를 통해 알려줍니다. 이런 메소드들을 사용해서 컴포넌트가 사라질 때 자동으로 정리해주는 `setInterval()`를 제공해주는 간단한 믹스인을 만들어보겠습니다.
-
-```javascript
-var SetIntervalMixin = {
-  componentWillMount: function() {
-    this.intervals = [];
-  },
-  setInterval: function() {
-    this.intervals.push(setInterval.apply(null, arguments));
-  },
-  componentWillUnmount: function() {
-    this.intervals.forEach(clearInterval);
-  }
-};
-
-var TickTock = React.createClass({
-  mixins: [SetIntervalMixin], // 믹스인 사용
-  getInitialState: function() {
-    return {seconds: 0};
-  },
-  componentDidMount: function() {
-    this.setInterval(this.tick, 1000); // 믹스인에 있는 메소드를 호출
-  },
-  tick: function() {
-    this.setState({seconds: this.state.seconds + 1});
-  },
-  render: function() {
-    return (
-      <p>
-        React has been running for {this.state.seconds} seconds.
-      </p>
-    );
-  }
-});
-
-ReactDOM.render(
-  <TickTock />,
-  document.getElementById('example')
-);
-```
-
-믹스인의 괜찮은 점은 컴포넌트가 여러 믹스인을 사용하고 여러 믹스인에서 같은 생명주기 메소드를 사용할 때(예를 들어, 여러 믹스인에서 컴포넌트가 사라질 때 뭔가 정리하려 한다면) 모든 생명주기 메소드들의 실행은 보장됩니다. 믹스인에 정의된 메소드은 컴포넌트의 메소드가 호출됨에 따라 믹스인이 나열된 순서대로 실행됩니다.
-
-<a name="es6-classes"></a>
-## ES6 클래스
-
-React 클래스를 일반적인 JavaScript 클래스로 선언할 수도 있습니다. 다음의 예제는 ES6 클래스 문법을 사용합니다:
-
-```javascript
-class HelloMessage extends React.Component {
-  render() {
-    return <div>Hello {this.props.name}</div>;
-  }
-}
-ReactDOM.render(<HelloMessage name="Sebastian" />, mountNode);
-```
-
-API는 `getInitialState`를 제외하고 `React.createClass`와 유사합니다. 별도의 `getInitialState` 메소드 대신에, 필요한 `state` 프로퍼티를 생성자에서 설정할 수 있습니다.
-
-또다른 차이점은 `propTypes`와 `defaultProps`가 클래스의 내부가 아니라 생성자의 프로퍼티로 정의되어 있다는 것입니다.
-
-```javascript
-export class Counter extends React.Component {
-  constructor(props) {
-    super(props);
-    this.state = {count: props.initialCount};
-  }
-  tick() {
-    this.setState({count: this.state.count + 1});
-  }
-  render() {
-    return (
-      <div onClick={this.tick.bind(this)}>
-        Clicks: {this.state.count}
-      </div>
-    );
-  }
-}
-Counter.propTypes = { initialCount: React.PropTypes.number };
-Counter.defaultProps = { initialCount: 0 };
-```
-
-### 자동 바인딩 안됨
-
-메소드는 일반 ES6 클래스와 동일한 시멘틱을 따릅니다. `this`를 인스턴스에 자동으로 바인딩하지 않는다는 이야기입니다. 명시적으로 `.bind(this)`나 [화살표 함수(arrow function)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) `=>`를 사용하세요.
-
-### 믹스인 안됨
-
-불행하게도 ES6는 믹스인에 대한 지원이 없이 출시되었기 때문에, React에서 ES6 클래스를 사용한다면 믹스인을 사용할 방법이 없습니다. 대신, 우리는 믹스인에 의존하지 않고도 동작하도록 만들기 위해 열심히 노력하고 있습니다.
-
-<a name="stateless-functions"></a>
-## 상태를 가지지 않는 함수
-
-React 클래스를 일반 JavaScript 함수로 작성할 수도 있습니다. 상태를 가지지 않는 함수 문법을 사용하는 예제입니다.
-
-```javascript
-function HelloMessage(props) {
-  return <div>Hello {props.name}</div>;
-}
-ReactDOM.render(<HelloMessage name="Sebastian" />, mountNode);
-```
-
-아니면 ES6의 화살표 문법을 사용할 수 있습니다.
-
-```javascript
-const HelloMessage = (props) => <div>Hello {props.name}</div>;
-ReactDOM.render(<HelloMessage name="Sebastian" />, mountNode);
-```
-
-이 단순화된 컴포넌트 API는 prop의 순수 함수인 컴포넌트를 나타냅니다. 이 컴포넌트는 내부 상태가 없어야 하고, 내부 인스턴스가 없어야 하고, 컴포넌트 생명주기 메소드가 없어야 합니다. 아무런 준비 과정없이 입력에 대한 순수한 기능적 변환이어야 합니다.
-
-> 주의:
->
-> 상태를 가지지 않는 함수는 내부 인스턴스가 없기 때문에, ref를 상태를 가지지않는 함수에 넣을 수 없습니다. 상태를 가지지 않는 함수는 명령형(imperative) API를 제공하지 않기 때문에 일반적으로 이것은 문제가 되지 않습니다. 명령형 API없이 인스턴스에 할 수 있는 것이 많지 않기도 하죠. 하지만 상태를 가지지 않는 컴포넌트의 DOM 노드를 검색하길 원한다면, 반드시 상태 기반 컴포넌트(예. ES6 클래스 컴포넌트)로 컴포넌트를 감싸고 상태 기반 래퍼 컴포넌트에 ref를 붙여야 합니다.
-
-이상적으로는, 대부분의 컴포넌트는 상태를 가지지 않는 함수여야 합니다. 왜냐 하면 이런 상태를 가지지 않는 컴포넌트는 React 코어 안에서 더 빠른 코드 경로를 거치기 때문입니다. 이는 가능한 한 추천하는 패턴입니다.
diff --git a/docs/docs/05-reusable-components.md b/docs/docs/05-reusable-components.md
deleted file mode 100644
index 4c784f332bf0..000000000000
--- a/docs/docs/05-reusable-components.md
+++ /dev/null
@@ -1,302 +0,0 @@
----
-id: reusable-components
-title: Reusable Components
-permalink: reusable-components.html
-prev: multiple-components.html
-next: transferring-props.html
----
-
-When designing interfaces, break down the common design elements (buttons, form fields, layout components, etc.) into reusable components with well-defined interfaces. That way, the next time you need to build some UI, you can write much less code. This means faster development time, fewer bugs, and fewer bytes down the wire.
-
-## Prop Validation
-
-As your app grows it's helpful to ensure that your components are used correctly. We do this by allowing you to specify `propTypes`. `React.PropTypes` exports a range of validators that can be used to make sure the data you receive is valid. When an invalid value is provided for a prop, a warning will be shown in the JavaScript console. Note that for performance reasons `propTypes` is only checked in development mode. Here is an example documenting the different validators provided:
-
-```javascript
-React.createClass({
-  propTypes: {
-    // You can declare that a prop is a specific JS primitive. By default, these
-    // are all optional.
-    optionalArray: React.PropTypes.array,
-    optionalBool: React.PropTypes.bool,
-    optionalFunc: React.PropTypes.func,
-    optionalNumber: React.PropTypes.number,
-    optionalObject: React.PropTypes.object,
-    optionalString: React.PropTypes.string,
-
-    // Anything that can be rendered: numbers, strings, elements or an array
-    // (or fragment) containing these types.
-    optionalNode: React.PropTypes.node,
-
-    // A React element.
-    optionalElement: React.PropTypes.element,
-
-    // You can also declare that a prop is an instance of a class. This uses
-    // JS's instanceof operator.
-    optionalMessage: React.PropTypes.instanceOf(Message),
-
-    // You can ensure that your prop is limited to specific values by treating
-    // it as an enum.
-    optionalEnum: React.PropTypes.oneOf(['News', 'Photos']),
-
-    // An object that could be one of many types
-    optionalUnion: React.PropTypes.oneOfType([
-      React.PropTypes.string,
-      React.PropTypes.number,
-      React.PropTypes.instanceOf(Message)
-    ]),
-
-    // An array of a certain type
-    optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),
-
-    // An object with property values of a certain type
-    optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),
-
-    // An object taking on a particular shape
-    optionalObjectWithShape: React.PropTypes.shape({
-      color: React.PropTypes.string,
-      fontSize: React.PropTypes.number
-    }),
-
-    // You can chain any of the above with `isRequired` to make sure a warning
-    // is shown if the prop isn't provided.
-    requiredFunc: React.PropTypes.func.isRequired,
-
-    // A value of any data type
-    requiredAny: React.PropTypes.any.isRequired,
-
-    // You can also specify a custom validator. It should return an Error
-    // object if the validation fails. Don't `console.warn` or throw, as this
-    // won't work inside `oneOfType`.
-    customProp: function(props, propName, componentName) {
-      if (!/matchme/.test(props[propName])) {
-        return new Error(
-          'Invalid prop `' + propName + '` supplied to' +
-          ' `' + componentName + '`. Validation failed.'
-        );
-      }
-    },
-
-    // You can also supply a custom validator to `arrayOf` and `objectOf`.
-    // It should return an Error object if the validation fails. The validator
-    // will be called for each key in the array or object. The first two
-    // arguments of the validator are the array or object itself, and the
-    // current item's key.
-    customArrayProp: React.PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) {
-      if (!/matchme/.test(propValue[key])) {
-        return new Error(
-          'Invalid prop `' + propFullName + '` supplied to' +
-          ' `' + componentName + '`. Validation failed.'
-        );
-      }
-    })
-  },
-  /* ... */
-});
-```
-
-### Single Child
-
-With `React.PropTypes.element` you can specify that only a single child can be passed to a component as children.
-
-```javascript
-var MyComponent = React.createClass({
-  propTypes: {
-    children: React.PropTypes.element.isRequired
-  },
-
-  render: function() {
-    return (
-      <div>
-        {this.props.children} // This must be exactly one element or it will warn.
-      </div>
-    );
-  }
-
-});
-```
-
-## Default Prop Values
-
-React lets you define default values for your `props` in a very declarative way:
-
-```javascript
-var ComponentWithDefaultProps = React.createClass({
-  getDefaultProps: function() {
-    return {
-      value: 'default value'
-    };
-  }
-  /* ... */
-});
-```
-
-The result of `getDefaultProps()` will be cached and used to ensure that `this.props.value` will have a value if it was not specified by the parent component. This allows you to safely just use your props without having to write repetitive and fragile code to handle that yourself.
-
-## Transferring Props: A Shortcut
-
-A common type of React component is one that extends a basic HTML element in a simple way. Often you'll want to copy any HTML attributes passed to your component to the underlying HTML element. To save typing, you can use the JSX _spread_ syntax to achieve this:
-
-```javascript
-var CheckLink = React.createClass({
-  render: function() {
-    // This takes any props passed to CheckLink and copies them to <a>
-    return <a {...this.props}>{'√ '}{this.props.children}</a>;
-  }
-});
-
-ReactDOM.render(
-  <CheckLink href="/checked.html">
-    Click here!
-  </CheckLink>,
-  document.getElementById('example')
-);
-```
-
-## Mixins
-
-Components are the best way to reuse code in React, but sometimes very different components may share some common functionality. These are sometimes called [cross-cutting concerns](https://en.wikipedia.org/wiki/Cross-cutting_concern). React provides `mixins` to solve this problem.
-
-One common use case is a component wanting to update itself on a time interval. It's easy to use `setInterval()`, but it's important to cancel your interval when you don't need it anymore to save memory. React provides [lifecycle methods](/react/docs/working-with-the-browser.html#component-lifecycle) that let you know when a component is about to be created or destroyed. Let's create a simple mixin that uses these methods to provide an easy `setInterval()` function that will automatically get cleaned up when your component is destroyed.
-
-```javascript
-var SetIntervalMixin = {
-  componentWillMount: function() {
-    this.intervals = [];
-  },
-  setInterval: function() {
-    this.intervals.push(setInterval.apply(null, arguments));
-  },
-  componentWillUnmount: function() {
-    this.intervals.forEach(clearInterval);
-  }
-};
-
-var TickTock = React.createClass({
-  mixins: [SetIntervalMixin], // Use the mixin
-  getInitialState: function() {
-    return {seconds: 0};
-  },
-  componentDidMount: function() {
-    this.setInterval(this.tick, 1000); // Call a method on the mixin
-  },
-  tick: function() {
-    this.setState({seconds: this.state.seconds + 1});
-  },
-  render: function() {
-    return (
-      <p>
-        React has been running for {this.state.seconds} seconds.
-      </p>
-    );
-  }
-});
-
-ReactDOM.render(
-  <TickTock />,
-  document.getElementById('example')
-);
-```
-
-A nice feature of mixins is that if a component is using multiple mixins and several mixins define the same lifecycle method (i.e. several mixins want to do some cleanup when the component is destroyed), all of the lifecycle methods are guaranteed to be called. Methods defined on mixins run in the order mixins were listed, followed by a method call on the component.
-
-## ES6 Classes
-
-You may also define your React classes as a plain JavaScript class. For example using ES6 class syntax:
-
-```javascript
-class HelloMessage extends React.Component {
-  render() {
-    return <div>Hello {this.props.name}</div>;
-  }
-}
-ReactDOM.render(<HelloMessage name="Sebastian" />, mountNode);
-```
-
-The API is similar to `React.createClass` with the exception of `getInitialState`. Instead of providing a separate `getInitialState` method, you set up your own `state` property in the constructor.
-
-Another difference is that `propTypes` and `defaultProps` are defined as properties on the constructor instead of in the class body.
-
-```javascript
-export class Counter extends React.Component {
-  constructor(props) {
-    super(props);
-    this.state = {count: props.initialCount};
-    this.tick = this.tick.bind(this);
-  }
-  tick() {
-    this.setState({count: this.state.count + 1});
-  }
-  render() {
-    return (
-      <div onClick={this.tick}>
-        Clicks: {this.state.count}
-      </div>
-    );
-  }
-}
-Counter.propTypes = { initialCount: React.PropTypes.number };
-Counter.defaultProps = { initialCount: 0 };
-```
-
-### No Autobinding
-
-Methods follow the same semantics as regular ES6 classes, meaning that they don't automatically bind `this` to the instance. You'll have to explicitly use `.bind(this)` or [arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) `=>`:
-
-```javascript
-// You can use bind() to preserve `this`
-<div onClick={this.tick.bind(this)}>
-
-// Or you can use arrow functions
-<div onClick={() => this.tick()}>
-```
-
-We recommend that you bind your event handlers in the constructor so they are only bound once for every instance:
-
-```javascript
-constructor(props) {
-  super(props);
-  this.state = {count: props.initialCount};
-  this.tick = this.tick.bind(this);
-}
-```
-
-Now you can use `this.tick` directly as it was bound once in the constructor:
-
-```javascript
-// It is already bound in the constructor
-<div onClick={this.tick}>
-```
-
-This is better for performance of your application, especially if you implement [shouldComponentUpdate()](/react/docs/component-specs.html#updating-shouldcomponentupdate) with a [shallow comparison](/react/docs/shallow-compare.html) in the child components.
-
-### No Mixins
-
-Unfortunately ES6 launched without any mixin support. Therefore, there is no support for mixins when you use React with ES6 classes. Instead, we're working on making it easier to support such use cases without resorting to mixins.
-
-## Stateless Functions
-
-You may also define your React classes as a plain JavaScript function. For example using the stateless function syntax:
-
-```javascript
-function HelloMessage(props) {
-  return <div>Hello {props.name}</div>;
-}
-ReactDOM.render(<HelloMessage name="Sebastian" />, mountNode);
-```
-
-Or using the new ES6 arrow syntax:
-
-```javascript
-const HelloMessage = (props) => <div>Hello {props.name}</div>;
-ReactDOM.render(<HelloMessage name="Sebastian" />, mountNode);
-```
-
-This simplified component API is intended for components that are pure functions of their props. These components must not retain internal state, do not have backing instances, and do not have the component lifecycle methods. They are pure functional transforms of their input, with zero boilerplate.
-However, you may still specify `.propTypes` and `.defaultProps` by setting them as properties on the function, just as you would set them on an ES6 class.
-
-> NOTE:
->
-> Because stateless functions don't have a backing instance, you can't attach a ref to a stateless function component. Normally this isn't an issue, since stateless functions do not provide an imperative API. Without an imperative API, there isn't much you could do with an instance anyway. However, if a user wants to find the DOM node of a stateless function component, they must wrap the component in a stateful component (eg. ES6 class component) and attach the ref to the stateful wrapper component.
-
-In an ideal world, most of your components would be stateless functions because in the future we’ll also be able to make performance optimizations specific to these components by avoiding unnecessary checks and memory allocations. This is the recommended pattern, when possible.
diff --git a/docs/docs/05-reusable-components.zh-CN.md b/docs/docs/05-reusable-components.zh-CN.md
deleted file mode 100644
index 479466b483ff..000000000000
--- a/docs/docs/05-reusable-components.zh-CN.md
+++ /dev/null
@@ -1,257 +0,0 @@
----
-id: reusable-components-zh-CN
-title: 可复用组件
-permalink: reusable-components-zh-CN.html
-prev: multiple-components-zh-CN.html
-next: transferring-props-zh-CN.html
----
-
-设计接口的时候，把通用的设计元素（按钮，表单框，布局组件等）拆成接口良好定义的可复用的组件。这样，下次开发相同界面程序时就可以写更少的代码，也意义着更高的开发效率，更少的 Bug 和更少的程序体积。
-
-## Prop 验证
-
-随着应用不断变大，保证组件被正确使用变得非常有用。为此我们引入 `propTypes`。`React.PropTypes` 提供很多验证器 (validator) 来验证传入数据的有效性。当向 props 传入无效数据时，JavaScript 控制台会抛出警告。注意为了性能考虑，只在开发环境验证 `propTypes`。下面用例子来说明不同验证器的区别：
-
-```javascript
-React.createClass({
-  propTypes: {
-    // 可以声明 prop 为指定的 JS 基本类型。默认
-    // 情况下，这些 prop 都是可传可不传的。
-    optionalArray: React.PropTypes.array,
-    optionalBool: React.PropTypes.bool,
-    optionalFunc: React.PropTypes.func,
-    optionalNumber: React.PropTypes.number,
-    optionalObject: React.PropTypes.object,
-    optionalString: React.PropTypes.string,
-
-    // 所有可以被渲染的对象：数字，
-    // 字符串，DOM 元素或包含这些类型的数组(or fragment) 。
-    optionalNode: React.PropTypes.node,
-
-    // React 元素
-    optionalElement: React.PropTypes.element,
-
-    // 你同样可以断言一个 prop 是一个类的实例。
-    // 用 JS 的 instanceof 操作符声明 prop 为类的实例。
-    optionalMessage: React.PropTypes.instanceOf(Message),
-
-    // 你可以用 enum 的方式
-    // 确保你的 prop 被限定为指定值。
-    optionalEnum: React.PropTypes.oneOf(['News', 'Photos']),
-
-    // 指定的多个对象类型中的一个
-    optionalUnion: React.PropTypes.oneOfType([
-      React.PropTypes.string,
-      React.PropTypes.number,
-      React.PropTypes.instanceOf(Message)
-    ]),
-
-    // 指定类型组成的数组
-    optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),
-
-    // 指定类型的属性构成的对象
-    optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),
-
-    // 特定形状参数的对象
-    optionalObjectWithShape: React.PropTypes.shape({
-      color: React.PropTypes.string,
-      fontSize: React.PropTypes.number
-    }),
-
-    // 你可以在任意东西后面加上 `isRequired`
-    // 来确保 如果 prop 没有提供 就会显示一个警告。
-    requiredFunc: React.PropTypes.func.isRequired,
-
-    // 不可空的任意类型
-    requiredAny: React.PropTypes.any.isRequired,
-
-    // 你可以自定义一个验证器。如果验证失败需要返回一个 Error 对象。
-    // 不要直接使用 `console.warn` 或抛异常，
-    // 因为这在 `oneOfType` 里不起作用。
-    customProp: function(props, propName, componentName) {
-      if (!/matchme/.test(props[propName])) {
-        return new Error('Validation failed!');
-      }
-    }
-  },
-  /* ... */
-});
-```
-
-### Single Child
-
-用  `React.PropTypes.element` 你可以指定仅有一个子级能被传送给组件
-
-```javascript
-var MyComponent = React.createClass({
-  propTypes: {
-    children: React.PropTypes.element.isRequired
-  },
-
-  render: function() {
-    return (
-      <div>
-        {this.props.children} // 这里必须是一个元素否则就会警告
-      </div>
-    );
-  }
-
-});
-```
-
-## 默认 Prop 值
-
-React 支持以声明式的方式来定义 `props` 的默认值。
-
-```javascript
-var ComponentWithDefaultProps = React.createClass({
-  getDefaultProps: function() {
-    return {
-      value: 'default value'
-    };
-  }
-  /* ... */
-});
-```
-
-当父级没有传入 props 时，`getDefaultProps()` 可以保证  `this.props.value` 有默认值，注意 `getDefaultProps` 的结果会被 *缓存*。得益于此，你可以直接使用 props，而不必写手动编写一些重复或无意义的代码。
-
-## 传递 Props：捷径
-
-有一些常用的 React 组件只是对 HTML 做简单扩展。通常，你想 复制任何传进你的组件的HTML属性 到底层的HTML元素上。为了减少输入，你可以用 JSX _spread_  语法来完成：
-
-```javascript
-var CheckLink = React.createClass({
-  render: function() {
-    // 这样会把 CheckList 所有的 props 复制到 <a>
-    return <a {...this.props}>{'√ '}{this.props.children}</a>;
-  }
-});
-
-ReactDOM.render(
-  <CheckLink href="/checked.html">
-    Click here!
-  </CheckLink>,
-  document.getElementById('example')
-);
-```
-
-## Mixins
-
-组件是 React 里复用代码最佳方式，但是有时一些复杂的组件间也需要共用一些功能。有时会被称为 [跨切面关注点](https://en.wikipedia.org/wiki/Cross-cutting_concern)。React 使用 `mixins` 来解决这类问题。
-
-一个通用的场景是：一个组件需要定期更新。用 `setInterval()` 做很容易，但当不需要它的时候取消定时器来节省内存是非常重要的。React 提供 [生命周期方法](/react/docs/working-with-the-browser.html#component-lifecycle) 来告知组件创建或销毁的时间。下面来做一个简单的 mixin，使用 `setInterval()` 并保证在组件销毁时清理定时器。
-
-```javascript
-var SetIntervalMixin = {
-  componentWillMount: function() {
-    this.intervals = [];
-  },
-  setInterval: function() {
-    this.intervals.push(setInterval.apply(null, arguments));
-  },
-  componentWillUnmount: function() {
-    this.intervals.forEach(clearInterval);
-  }
-};
-
-var TickTock = React.createClass({
-  mixins: [SetIntervalMixin], // 引用 mixin
-  getInitialState: function() {
-    return {seconds: 0};
-  },
-  componentDidMount: function() {
-    this.setInterval(this.tick, 1000); // 调用 mixin 的方法
-  },
-  tick: function() {
-    this.setState({seconds: this.state.seconds + 1});
-  },
-  render: function() {
-    return (
-      <p>
-        React has been running for {this.state.seconds} seconds.
-      </p>
-    );
-  }
-});
-
-ReactDOM.render(
-  <TickTock />,
-  document.getElementById('example')
-);
-```
-
-关于 mixin 值得一提的优点是，如果一个组件使用了多个 mixin，并用有多个 mixin 定义了同样的生命周期方法（如：多个 mixin 都需要在组件销毁时做资源清理操作），所有这些生命周期方法都保证会被执行到。方法执行顺序是：首先按 mixin 引入顺序执行 mixin 里方法，最后执行组件内定义的方法。
-
-## ES6 Classes
-
-你也可以以一个简单的JavaScript 类来定义你的React classes。使用ES6 class的例子:
-
-```javascript
-class HelloMessage extends React.Component {
-  render() {
-    return <div>Hello {this.props.name}</div>;
-  }
-}
-ReactDOM.render(<HelloMessage name="Sebastian" />, mountNode);
-```
-
-API近似于 `React.createClass` 除了 `getInitialState`。 你应该在构造函数里设置你的`state`，而不是提供一个单独的  `getInitialState` 方法。
-
-另一个不同是 `propTypes` 和 `defaultProps` 在构造函数而不是class body里被定义为属性。
-
-```javascript
-export class Counter extends React.Component {
-  constructor(props) {
-    super(props);
-    this.state = {count: props.initialCount};
-  }
-  tick() {
-    this.setState({count: this.state.count + 1});
-  }
-  render() {
-    return (
-      <div onClick={this.tick.bind(this)}>
-        Clicks: {this.state.count}
-      </div>
-    );
-  }
-}
-Counter.propTypes = { initialCount: React.PropTypes.number };
-Counter.defaultProps = { initialCount: 0 };
-```
-
-### 无自动绑定
-
-方法遵循正式的ES6 class的语义，意味着它们不会自动绑定`this`到实例上。你必须显示的使用`.bind(this)` or [箭头函数](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/Arrow_functions) `=>`.
-
-### 没有 Mixins
-
-不幸的是ES6的发布没有任何mixin的支持。因此，当你在ES6 classes下使用React时不支持mixins。作为替代，我们正在努力使它更容易支持这些用例不依靠mixins。
-
-## 无状态函数
-
-你也可以用 JavaScript 函数来定义你的 React 类。例如使用无状态函数语法：
-
-```javascript
-function HelloMessage(props) {
-  return <div>Hello {props.name}</div>;
-}
-ReactDOM.render(<HelloMessage name="Sebastian" />, mountNode);
-```
-
-或者使用新的ES6箭头函数:
-
-```javascript
-const HelloMessage = (props) => <div>Hello {props.name}</div>;
-ReactDOM.render(<HelloMessage name="Sebastian" />, mountNode);
-```
-
-这个简化的组件API旨在用于那些纯函数态的组件 。这些组件必须没有保持任何内部状态，没有备份实例，也没有组件生命周期方法。他们纯粹的函数式的转化他们的输入，没有引用。
-然而，你仍然可以以设置为函数的properties的方式来指定 `.propTypes` 和 `.defaultProps`，就像你在ES6类里设置他们那样。
-
-> 注意：
->
-> 因为无状态函数没有备份实例，你不能附加一个引用到一个无状态函数组件。 通常这不是问题，因为无状态函数不提供一个命令式的API。没有命令式的API，你就没有任何需要实例来做的事。然而，如果用户想查找无状态函数组件的DOM节点，他们必须把这个组件包装在一个有状态组件里（比如，ES6 类组件） 并且连接一个引用到有状态的包装组件。
-
-在理想世界里，你的大多数组件都应该是无状态函数，因为将来我们可能会用避免不必要的检查和内存分配的方式来对这些组件进行优化。 如果可能，这是推荐的模式。
diff --git a/docs/docs/06-transferring-props.it-IT.md b/docs/docs/06-transferring-props.it-IT.md
deleted file mode 100644
index 7c828480cd9c..000000000000
--- a/docs/docs/06-transferring-props.it-IT.md
+++ /dev/null
@@ -1,153 +0,0 @@
----
-id: transferring-props-it-IT
-title: Trasferimento delle Proprietà
-permalink: transferring-props-it-IT.html
-prev: reusable-components-it-IT.html
-next: forms-it-IT.html
----
-
-Un pattern comune in React è l'uso di un'astrazione per esporre un componente. Il componente esterno espone una semplice proprietà per effettuare un'azione che può richiedere un'implementazione più complessa.
-
-Puoi usare gli [attributi spread di JSX](/react/docs/jsx-spread.html) per unire le vecchie props con valori aggiuntivi:
-
-```javascript
-<Component {...this.props} more="values" />
-```
-
-Se non usi JSX, puoi usare qualsiasi helper come l'API `Object.assign` di ES6, o il metodo `_.extend` di Underscore:
-
-```javascript
-React.createElement(Component, Object.assign({}, this.props, { more: 'values' }));
-```
-
-Nel resto di questo tutorial vengono illustrate le best practices, usando JSX e sintassi sperimentale di ES7.
-
-## Trasferimento Manuale
-
-Nella maggior parte dei casi dovresti esplicitamente passare le proprietà. Ciò assicura che venga esposto soltanto un sottoinsieme dell'API interna, del cui funzionamento si è certi.
-
-```javascript
-function FancyCheckbox(props) {
-  var fancyClass = props.checked ? 'FancyChecked' : 'FancyUnchecked';
-  return (
-    <div className={fancyClass} onClick={props.onClick}>
-      {props.children}
-    </div>
-  );
-}
-ReactDOM.render(
-  <FancyCheckbox checked={true} onClick={console.log.bind(console)}>
-    Ciao mondo!
-  </FancyCheckbox>,
-  document.getElementById('example')
-);
-```
-
-E se aggiungessimo una proprietà `name`? O una proprietà `title`? O `onMouseOver`?
-
-## Trasferire con `...` in JSX
-
-> NOTA:
->
-> La sintassi `...` fa parte della proposta Object Rest Spread. Questa proposta è in processo di diventare uno standard. Consulta la sezione [Proprietà Rest e Spread ...](/react/docs/transferring-props.html#rest-and-spread-properties-...) di seguito per maggiori dettagli.
-
-A volte passare manualmente ciascuna proprietà può essere noioso e fragile. In quei casi puoi usare l'[assegnamento destrutturante](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) con le proprietà residue per estrarre un insieme di proprietà sconosciute.
-
-Elenca tutte le proprietà che desideri consumare, seguite da `...other`.
-
-```javascript
-var { checked, ...other } = props;
-```
-
-Ciò assicura che vengano passate tutte le proprietà TRANNE quelle che stai consumando tu stesso.
-
-```javascript
-function FancyCheckbox(props) {
-  var { checked, ...other } = props;
-  var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
-  // `other` contiene { onClick: console.log } ma non la proprietà checked
-  return (
-    <div {...other} className={fancyClass} />
-  );
-}
-ReactDOM.render(
-  <FancyCheckbox checked={true} onClick={console.log.bind(console)}>
-    Ciao mondo!
-  </FancyCheckbox>,
-  document.getElementById('example')
-);
-```
-
-> NOTA:
->
-> Nell'esempio precedente, la proprietà `checked` è anche un attributo DOM valido. Se non utilizzassi la destrutturazione in questo modo, potresti inavvertitamente assegnarlo al `div`.
-
-Usa sempre il pattern di destrutturazione quando trasferisci altre proprietà sconosciute in `other`.
-
-```javascript
-function FancyCheckbox(props) {
-  var fancyClass = props.checked ? 'FancyChecked' : 'FancyUnchecked';
-  // ANTI-PATTERN: `checked` sarebbe passato al componente interno
-  return (
-    <div {...props} className={fancyClass} />
-  );
-}
-```
-
-## Consumare e Trasferire la Stessa Proprietà
-
-Se il tuo componente desidera consumare una proprietà, ma anche passarla ad altri, puoi passarla esplicitamente mediante `checked={checked}`. Questo è preferibile a passare l'intero oggetto `this.props` dal momento che è più facile effettuarne il linting e il refactoring.
-
-```javascript
-function FancyCheckbox(props) {
-  var { checked, title, ...other } = props;
-  var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
-  var fancyTitle = checked ? 'X ' + title : 'O ' + title;
-  return (
-    <label>
-      <input {...other}
-        checked={checked}
-        className={fancyClass}
-        type="checkbox"
-      />
-      {fancyTitle}
-    </label>
-  );
-}
-```
-
-> NOTA:
->
-> L'ordine è importante. Mettendo il `{...other}` prima delle tue proprietà JSX ti assicuri che il consumatore del tuo componente non possa ridefinirle. Nell'esempio precedente, abbiamo garantito che l'elemento input sarà del tipo `"checkbox"`.
-
-## Proprietà Rest e Spread `...`
-
-Le proprietà Rest ti permettono di estrarre le proprietà residue di un oggetto in un nuovo oggetto. Vengono escluse tutte le altre proprietà elencate nel pattern di destrutturazione.
-
-Questa è un'implementazione sperimentale di una [proposta ES7](https://github.com/sebmarkbage/ecmascript-rest-spread).
-
-```javascript
-var { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
-x; // 1
-y; // 2
-z; // { a: 3, b: 4 }
-```
-
-> Nota:
->
-> Questa proposta ha raggiunto lo stadio 2 ed è attivata in modo predefinito in Babel. Vecchie versioni di Babel potrebbero richiedere l'abilitazione esplicita di questa trasformazione con `babel --optional es7.objectRestSpread`
-
-## Trasferire con Underscore
-
-Se non usi JSX, puoi usare una libreria per ottenere il medesimo pattern. Underscore supporta `_.omit` per omettere delle proprietà ed `_.extend` per copiare le proprietà in un nuovo oggetto.
-
-```javascript
-function FancyCheckbox(props) {
-  var checked = props.checked;
-  var other = _.omit(props, 'checked');
-  var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
-  return (
-    React.DOM.div(_.extend({}, other, { className: fancyClass }))
-  );
-}
-```
diff --git a/docs/docs/06-transferring-props.ja-JP.md b/docs/docs/06-transferring-props.ja-JP.md
deleted file mode 100644
index 129009472a36..000000000000
--- a/docs/docs/06-transferring-props.ja-JP.md
+++ /dev/null
@@ -1,151 +0,0 @@
----
-id: transferring-props
-title: propsの移譲
-permalink: transferring-props-ja-JP.html
-prev: reusable-components-ja-JP.html
-next: forms-ja-JP.html
-
----
-
-
-コンポーネントを抽象的にラップすることはReactにおいて共通のパターンです。外のコンポーネントは単純なプロパティを表示し、中ではさらに複雑なインプリメンテーションの詳細を持つようになっています。
-
-以下のように、古いpropsと追加の値を[JSXの拡張属性](/react/docs/jsx-spread-ja-JP.html)を使ってマージすることができます。
-
-```javascript
-<Component {...this.props} more="values" />
-```
-
-JSXを使わない場合は、以下のように、ES6の `Object.assign` か Underscore の `_.extend` といったオブジェクトヘルパーを使うことができます。
-
-```javascript
-React.createElement(Component, Object.assign({}, this.props, { more: 'values' }));
-```
-
-以下のチュートリアルはベストプラクティスを提示しています。JSXや試験的なES7のシンタックスを使っています。
-
-## 手動での移動
-
-ほとんどの場合、プロパティを明確に子要素に渡すべきです。それは、内部のAPIのサブセットだけを外に出していることと、認識しているプロパティが動作することを保証します。
-
-```javascript
-function FancyCheckbox(props) {
-  var fancyClass = props.checked ? 'FancyChecked' : 'FancyUnchecked';
-  return (
-    <div className={fancyClass} onClick={props.onClick}>
-      {props.children}
-    </div>
-  );
-}
-ReactDOM.render(
-  <FancyCheckbox checked={true} onClick={console.log.bind(console)}>
-    Hello world!
-  </FancyCheckbox>,
-  document.getElementById('example')
-);
-```
-
-しかし、 `name` プロパティや `title` プロパティや `onMouseOver` はどうでしょうか？
-
-## JSXにおける `...` を使った移譲
-
-> 注意:
-> 以下の例では、実験的なES7のシンタックスであることを示すために `--harmony ` フラグが必要になります。ブラウザ上でJSXトランスフォーマーを使う際には、単純に `<script type="text/jsx;harmony=true">` を使ってスクリプトを読み込んでください。詳細については、 [レストとスプレッドのプロパティ ...](/react/docs/transferring-props.html#rest-and-spread-properties-...)をご覧ください。
-
-全てのプロパティを渡すのはバグを生みやすく、面倒くさいときがあります。そのようなケースでは、未知のプロパティのセットを使うためにレストプロパティと共に[分割代入引数](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment)を使うことができます。
-
-以下のように `...other` を使うことで、使いたいプロパティを一覧にすることができます。
-
-```javascript
-var { checked, ...other } = props;
-```
-
-これは、自分で指定したものは 除き 、全てのpropsを渡すことを保証します。
-
-```javascript
-function FancyCheckbox(props) {
-  var { checked, ...other } = props;
-  var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
-  // `other` は { onClick: console.log } を含みますが、 checked プロパティは含みません。
-  return (
-    <div {...other} className={fancyClass} />
-  );
-}
-ReactDOM.render(
-  <FancyCheckbox checked={true} onClick={console.log.bind(console)}>
-    Hello world!
-  </FancyCheckbox>,
-  document.getElementById('example')
-);
-```
-
-> 注意:
-> 上の例では、 `checked` propは正式なDOMの属性でもあります。この方法を使って分割代入を行わない場合は、無意識的に渡すこともできます。
-
-未知の `other` propsを移譲する際には、分割代入パターンを常に使ってください。
-
-```javascript
-function FancyCheckbox(props) {
-  var fancyClass = props.checked ? 'FancyChecked' : 'FancyUnchecked';
-  // アンチパターン: `checked` が内部のコンポーネントに渡されます。
-  return (
-    <div {...props} className={fancyClass} />
-  );
-}
-```
-
-## 同じpropを使い、移譲する
-
-コンポーネントがプロパティを使うだけでなく、子要素に渡したい場合は、明確に `checked={checked}` と記述することで再度渡すことができます。 `this.props` オブジェクトで全てを渡すほうが、リファクタリングやチェックをしやすいので好ましいです。
-
-```javascript
-function FancyCheckbox(props) {
-  var { checked, title, ...other } = props;
-  var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
-  var fancyTitle = checked ? 'X ' + title : 'O ' + title;
-  return (
-    <label>
-      <input {...other}
-        checked={checked}
-        className={fancyClass}
-        type="checkbox"
-      />
-      {fancyTitle}
-    </label>
-  );
-}
-```
-
-> 注意:
-> 順番の問題です。JSXのpropsの前に `{...other}` を置くことで、コンポーネントの使用者がオーバーライドできないことを保証します。上の例ではinputが `"checkbox"` 型であることを保証しました。
-
-## レストとスプレッドのプロパティ `...`
-
-レストプロパティはあるオブジェクトの残りの要素を新しいオブジェクトに引き抜きます。分割代入パターンでリストになっている全てのプロパティを外に出します。
-
-これは、[ES7プロポーサル](https://github.com/sebmarkbage/ecmascript-rest-spread)の実験的な実行です。
-
-```javascript
-var { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
-x; // 1
-y; // 2
-z; // { a: 3, b: 4 }
-```
-
-> 注意:
-> 実験的なES7のシンタックスを有効にするには、 `--harmony` フラグを[JSXコマンドラインツール](https://www.npmjs.com/package/react-tools)で使用してください。
-
-## Underscoreによる移譲
-
-JSXを使わない際には、同じパターンを行うライブラリを使うことができます。Underscoreでは、 `_.omit` を使ってプロパティをフィルタしたり、 `_.extend` を使って新しいオブジェクトにプロパティをコピーしたりできます。
-
-```javascript
-function FancyCheckbox(props) {
-  var checked = props.checked;
-  var other = _.omit(props, 'checked');
-  var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
-  return (
-    React.DOM.div(_.extend({}, other, { className: fancyClass }))
-  );
-}
-```
diff --git a/docs/docs/06-transferring-props.ko-KR.md b/docs/docs/06-transferring-props.ko-KR.md
deleted file mode 100644
index 1f4b29483151..000000000000
--- a/docs/docs/06-transferring-props.ko-KR.md
+++ /dev/null
@@ -1,155 +0,0 @@
----
-id: transferring-props-ko-KR
-title: Props 전달
-permalink: transferring-props-ko-KR.html
-prev: reusable-components-ko-KR.html
-next: forms-ko-KR.html
----
-
-React에서는 컴포넌트를 감싸서 추상화하는 것이 일반적인 패턴입니다. 외부 컴포넌트에서는 간단한 프로퍼티만을 노출하여 복잡한 세부 구현을 감출 수 있습니다.
-
-[JSX 스프레드 어트리뷰트](/react/docs/jsx-spread-ko-KR.html)를 통해 props에 추가적인 값을 병합할 수 있습니다.
-
-```javascript
-<Component {...this.props} more="values" />
-```
-
-만약 JSX를 사용하지 않는다면 ES6의 `Object.assign`나 Underscore의 `_.extend` 같은 객체 헬퍼를 사용할 수 있습니다:
-
-```javascript
-React.createElement(Component, Object.assign({}, this.props, { more: 'values' }));
-```
-
-이 튜토리얼의 나머지 부분은 모범 답안을 소개할 것입니다. JSX와 실험적인 ES7 구문을 사용합니다.
-
-## 수동적인 전달
-
-대부분의 경우 명시적으로 프로퍼티를 아래로 전달해야 합니다. 이는 동작을 확신하는 내부 API의 일부만 공개하도록 합니다.
-
-```javascript
-function FancyCheckbox(props) {
-  var fancyClass = props.checked ? 'FancyChecked' : 'FancyUnchecked';
-  return (
-    <div className={fancyClass} onClick={props.onClick}>
-      {props.children}
-    </div>
-  );
-}
-ReactDOM.render(
-  <FancyCheckbox checked={true} onClick={console.log.bind(console)}>
-    세상아 안녕!
-  </FancyCheckbox>,
-  document.getElementById('example')
-);
-```
-
-하지만 `name`이나 `title`, `onMouseOver` 같은 prop들이 더 추가된다면 어떨까요?
-
-## JSX에서 `...`를 사용해 전달하기
-
-> 주의:
->
-> `...` 구문은 객체 잔여 스프레드 제안의 일부입니다. 이 제안은 표준화 과정에 있습니다. 더 자세한 내용은 밑의 [잔여 프로퍼티와 스프레드 프로퍼티 ...](/react/docs/transferring-props.html#rest-and-spread-properties-...) 부분을 참고하세요.
-
-
-때로는 모든 프로퍼티를 일일이 전달 하는것은 지루하고 덧없는 작업입니다. 이 경우 [구조 해체 할당(destructuring assignment)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment)을 다른 프로퍼티를 함께 사용해 미상의 프로퍼티를 추출할 수 있습니다.
-
-소비할 프로퍼티들을 나열하고, 그 뒤에 `...other`를 넣습니다.
-
-```javascript
-var { checked, ...other } = props;
-```
-
-이는 지금 소비한 props를 *제외한* 나머지를 아래로 전달합니다.
-
-```javascript
-function FancyCheckbox(props) {
-  var { checked, ...other } = props;
-  var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
-  // `other`에는 { onClick: console.log }가 포함되지만 checked 프로퍼티는 제외됩니다
-  return (
-    <div {...other} className={fancyClass} />
-  );
-}
-ReactDOM.render(
-  <FancyCheckbox checked={true} onClick={console.log.bind(console)}>
-    세상아 안녕!
-  </FancyCheckbox>,
-  document.getElementById('example')
-);
-```
-
-> 주의:
->
-> 위의 예제에서는 `checked` prop 또한 마찬가지로 유효한 DOM 어트리뷰트입니다. 이런 식으로 구조의 해체(destructuring)를 하지 않으면 의도하지 않게 함께 전달될 수 있습니다.
-
-미상의 `other` props을 전달할 때는 항상 구조 해체 패턴을 사용하세요.
-
-```javascript
-function FancyCheckbox(props) {
-  var fancyClass = props.checked ? 'FancyChecked' : 'FancyUnchecked';
-  // 반례: `checked` 또한 내부 컴포넌트로 전달될 것입니다
-  return (
-    <div {...props} className={fancyClass} />
-  );
-}
-```
-
-## 같은 Prop을 소비하고 전달하기
-
-컴포넌트가 프로퍼티를 사용하지만 계속 넘기길 원한다면, `checked={checked}`처럼 명시적으로 다시 넘길 수 있습니다. 리팩토링과 린트(lint)하기가 더 쉬우므로 이 방식이 `this.props` 객체 전부를 넘기는 것보다 낫습니다.
-
-```javascript
-function FancyCheckbox(props) {
-  var { checked, title, ...other } = props;
-  var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
-  var fancyTitle = checked ? 'X ' + title : 'O ' + title;
-  return (
-    <label>
-      <input {...other}
-        checked={checked}
-        className={fancyClass}
-        type="checkbox"
-      />
-      {fancyTitle}
-    </label>
-  );
-}
-```
-
-> 주의:
->
-> 순서는 중요합니다. `{...other}`를 JSX props 이전에 넣는 것으로 컴포넌트의 사용자가 확실히 그것들을 오버라이드 할 수 없게 합니다. 위의 예제에서는 input이 `"checkbox"` 타입인 것을 보장합니다.
-
-<a name="rest-and-spread-properties-..."></a>
-## 잔여 프로퍼티와 스프레드 프로퍼티 `...`
-
-잔여(Rest, `...`) 프로퍼티는 객체에서 소비되지 않은 나머지 프로퍼티를 추출해 새로운 객체로 만들 수 있게 해 줍니다. 구조 해체 패턴에서 열거된 다른 프로퍼티들은 모두 제외됩니다.
-
-이 제안은 2 단계에 돌입해 이제 바벨에서 기본값으로 활성화되어있습니다. 바벨의 이전 버전은 `babel --optional es7.objectRestSpread`로 명시적으로 활성화 할 필요가 있을 수도 있습니다.
-
-```javascript
-var { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
-x; // 1
-y; // 2
-z; // { a: 3, b: 4 }
-```
-
-> 주의:
->
-> 실험적인 ES7 구문을 활성화하려면 [JSX 커맨드라인 도구](https://www.npmjs.com/package/react-tools)를 `--harmony` 플래그와 함께 사용하세요.
-
-## Underscore로 전달 다루기
-
-JSX를 사용하지 않는다면 라이브러리를 사용해 같은 패턴을 쓸 수 있습니다. Underscore에서는 `_.omit`을 사용해 특정 프로퍼티를 제외하거나 `_.extend`를 사용해 새로운 객체로 프로퍼티를 복사할 수 있습니다.
-
-```javascript
-function FancyCheckbox(props) {
-  var checked = props.checked;
-  var other = _.omit(props, 'checked');
-  var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
-  return (
-    React.DOM.div(_.extend({}, other, { className: fancyClass }))
-  );
-}
-```
diff --git a/docs/docs/06-transferring-props.md b/docs/docs/06-transferring-props.md
deleted file mode 100644
index 6b2280e41a16..000000000000
--- a/docs/docs/06-transferring-props.md
+++ /dev/null
@@ -1,153 +0,0 @@
----
-id: transferring-props
-title: Transferring Props
-permalink: transferring-props.html
-prev: reusable-components.html
-next: forms.html
----
-
-It's a common pattern in React to wrap a component in an abstraction. The outer component exposes a simple property to do something that might have more complex implementation details.
-
-You can use [JSX spread attributes](/react/docs/jsx-spread.html) to merge the old props with additional values:
-
-```javascript
-<Component {...this.props} more="values" />
-```
-
-If you don't use JSX, you can use any object helper such as ES6 `Object.assign` or Underscore `_.extend`:
-
-```javascript
-React.createElement(Component, Object.assign({}, this.props, { more: 'values' }));
-```
-
-The rest of this tutorial explains best practices. It uses JSX and experimental ECMAScript syntax.
-
-## Manual Transfer
-
-Most of the time you should explicitly pass the properties down. This ensures that you only expose a subset of the inner API, one that you know will work.
-
-```javascript
-function FancyCheckbox(props) {
-  var fancyClass = props.checked ? 'FancyChecked' : 'FancyUnchecked';
-  return (
-    <div className={fancyClass} onClick={props.onClick}>
-      {props.children}
-    </div>
-  );
-}
-ReactDOM.render(
-  <FancyCheckbox checked={true} onClick={console.log.bind(console)}>
-    Hello world!
-  </FancyCheckbox>,
-  document.getElementById('example')
-);
-```
-
-But what about the `name` prop? Or the `title` prop? Or `onMouseOver`?
-
-## Transferring with `...` in JSX
-
-> NOTE:
->
-> The `...` syntax is part of the Object Rest Spread proposal. This proposal is on track to become a standard. See the [Rest and Spread Properties ...](/react/docs/transferring-props.html#rest-and-spread-properties-...) section below for more details.
-
-Sometimes it's fragile and tedious to pass every property along. In that case you can use [destructuring assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) with rest properties to extract a set of unknown properties.
-
-List out all the properties that you would like to consume, followed by `...other`.
-
-```javascript
-var { checked, ...other } = props;
-```
-
-This ensures that you pass down all the props EXCEPT the ones you're consuming yourself.
-
-```javascript
-function FancyCheckbox(props) {
-  var { checked, ...other } = props;
-  var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
-  // `other` contains { onClick: console.log } but not the checked property
-  return (
-    <div {...other} className={fancyClass} />
-  );
-}
-ReactDOM.render(
-  <FancyCheckbox checked={true} onClick={console.log.bind(console)}>
-    Hello world!
-  </FancyCheckbox>,
-  document.getElementById('example')
-);
-```
-
-> NOTE:
->
-> In the example above, the `checked` prop is also a valid DOM attribute. If you didn't use destructuring in this way you might inadvertently pass it along.
-
-Always use the destructuring pattern when transferring unknown `other` props.
-
-```javascript
-function FancyCheckbox(props) {
-  var fancyClass = props.checked ? 'FancyChecked' : 'FancyUnchecked';
-  // ANTI-PATTERN: `checked` would be passed down to the inner component
-  return (
-    <div {...props} className={fancyClass} />
-  );
-}
-```
-
-## Consuming and Transferring the Same Prop
-
-If your component wants to consume a property but also wants to pass it along, you can repass it explicitly with `checked={checked}`. This is preferable to passing the full `props` object since it's easier to refactor and lint.
-
-```javascript
-function FancyCheckbox(props) {
-  var { checked, title, ...other } = props;
-  var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
-  var fancyTitle = checked ? 'X ' + title : 'O ' + title;
-  return (
-    <label>
-      <input {...other}
-        checked={checked}
-        className={fancyClass}
-        type="checkbox"
-      />
-      {fancyTitle}
-    </label>
-  );
-}
-```
-
-> NOTE:
->
-> Order matters. By putting the `{...other}` before your JSX props you ensure that the consumer of your component can't override them. In the example above we have guaranteed that the input will be of type `"checkbox"`.
-
-## Rest and Spread Properties `...`
-
-Rest properties allow you to extract the remaining properties from an object into a new object. It excludes every other property listed in the destructuring pattern.
-
-This is an experimental implementation of an [ECMAScript proposal](https://github.com/sebmarkbage/ecmascript-rest-spread).
-
-```javascript
-var { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
-x; // 1
-y; // 2
-z; // { a: 3, b: 4 }
-```
-
-> Note:
->
-> To transform rest and spread properties using Babel 6, you need to install the [`es2015`](https://babeljs.io/docs/plugins/preset-es2015/) preset, the [`transform-object-rest-spread`](https://babeljs.io/docs/plugins/transform-object-rest-spread/) plugin and configure them in the `.babelrc` file.
-
-## Transferring with Underscore
-
-If you don't use JSX, you can use a library to achieve the same pattern. Underscore supports `_.omit` to filter out properties and `_.extend` to copy properties onto a new object.
-
-```javascript
-function FancyCheckbox(props) {
-  var checked = props.checked;
-  var other = _.omit(props, 'checked');
-  var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
-  return (
-    React.DOM.div(_.extend({}, other, { className: fancyClass }))
-  );
-}
-```
diff --git a/docs/docs/06-transferring-props.zh-CN.md b/docs/docs/06-transferring-props.zh-CN.md
deleted file mode 100644
index 6bf89aa2484b..000000000000
--- a/docs/docs/06-transferring-props.zh-CN.md
+++ /dev/null
@@ -1,153 +0,0 @@
----
-id: transferring-props-zh-CN
-title: 传递 Props
-permalink: transferring-props-zh-CN.html
-prev: reusable-components-zh-CN.html
-next: forms-zh-CN.html
----
-
-React 里有一个非常常用的模式就是对组件做一层抽象。组件对外公开一个简单的属性（Props）来实现功能，但内部细节可能有非常复杂的实现。
-
-可以使用 [JSX 展开属性](/react/docs/jsx-spread-zh-CN.html) 来合并现有的 props 和其它值：
-
-```javascript
-<Component {...this.props} more="values" />
-```
-
-如果不使用 JSX，可以使用一些对象辅助方法如 ES6 的 `Object.assign` 或 Underscore `_.extend`。
-
-```javascript
-React.createElement(Component, Object.assign({}, this.props, { more: 'values' }));
-```
-
-下面的教程介绍一些最佳实践。使用了 JSX 和 试验性的ECMAScript 语法。
-
-## 手动传递
-
-大部分情况下你应该显式地向下传递 props。这样可以确保只公开你认为是安全的内部 API 的子集。
-
-```javascript
-function FancyCheckbox(props) {
-  var fancyClass = props.checked ? 'FancyChecked' : 'FancyUnchecked';
-  return (
-    <div className={fancyClass} onClick={props.onClick}>
-      {props.children}
-    </div>
-  );
-}
-ReactDOM.render(
-  <FancyCheckbox checked={true} onClick={console.log.bind(console)}>
-    Hello world!
-  </FancyCheckbox>,
-  document.getElementById('example')
-);
-```
-
-但 `name` 这个属性怎么办？还有 `title`、`onMouseOver` 这些 props？
-
-## 在 JSX 里使用 `...` 传递
-
-> 注意:
->
-> 在下面的例子中，`--harmony ` 标志是必须的因为这个语法是ES7的实验性语法。如果用浏览器中的JSX转换器，以 `<script type="text/jsx;harmony=true">`简单的打开你脚本就行了。详见[Rest and Spread Properties ...](/react/docs/transferring-props.html#rest-and-spread-properties-...)
-
-有时把所有属性都传下去是不安全或啰嗦的。这时可以使用 [解构赋值](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) 中的剩余属性特性来把未知属性批量提取出来。
-
-列出所有要当前使用的属性，后面跟着 `...other`。
-
-```javascript
-var { checked, ...other } = props;
-```
-
-这样能确保把所有 props 传下去，*除了* 那些已经被使用了的。
-
-```javascript
-function FancyCheckbox(props) {
-  var { checked, ...other } = props;
-  var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
-  // `other` 包含 { onClick: console.log } 但 checked 属性除外
-  return (
-    <div {...other} className={fancyClass} />
-  );
-}
-ReactDOM.render(
-  <FancyCheckbox checked={true} onClick={console.log.bind(console)}>
-    Hello world!
-  </FancyCheckbox>,
-  document.getElementById('example')
-);
-```
-
-> 注意:
->
-> 上面例子中，`checked` 属性也是一个有效的 DOM 属性。如果你没有使用解构赋值，那么可能无意中把它传下去。
-
-在传递这些未知的 `other` 属性时，要经常使用解构赋值模式。
-
-```javascript
-function FancyCheckbox(props) {
-  var fancyClass = props.checked ? 'FancyChecked' : 'FancyUnchecked';
-  // 反模式：`checked` 会被传到里面的组件里
-  return (
-    <div {...props} className={fancyClass} />
-  );
-}
-```
-
-## 使用和传递同一个 Prop
-
-如果组件需要使用一个属性又要往下传递，可以直接使用 `checked={checked}` 再传一次。这样做比传整个 `props` 对象要好，因为更利于重构和语法检查。
-
-```javascript
-function FancyCheckbox(props) {
-  var { checked, title, ...other } = props;
-  var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
-  var fancyTitle = checked ? 'X ' + title : 'O ' + title;
-  return (
-    <label>
-      <input {...other}
-        checked={checked}
-        className={fancyClass}
-        type="checkbox"
-      />
-      {fancyTitle}
-    </label>
-  );
-}
-```
-
-> 注意:
->
-> 顺序很重要，把 `{...other}` 放到 JSX props 前面会使它不被覆盖。上面例子中我们可以保证 input 的 type 是 `"checkbox"`。
-
-## 剩余属性和展开属性 `...`
-
-剩余属性可以把对象剩下的属性提取到一个新的对象。会把所有在解构赋值中列出的属性剔除。
-
-这是 [ECMAScript 草案](https://github.com/sebmarkbage/ecmascript-rest-spread) 中的试验特性。
-
-```javascript
-var { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
-x; // 1
-y; // 2
-z; // { a: 3, b: 4 }
-```
-
-> 注意:
->
-> 要用 Babel 6转换 rest 和 spread 属性，你需要安装 [`es2015`](https://babeljs.io/docs/plugins/preset-es2015/) preset，[`transform-object-rest-spread`](https://babeljs.io/docs/plugins/transform-object-rest-spread/) 插件并在 `.babelrc` 里配置他们.
-
-## 使用 Underscore 来传递
-
-如果不使用 JSX，可以使用一些库来实现相同效果。Underscore 提供 `_.omit` 来过滤属性，`_.extend` 复制属性到新的对象。
-
-```javascript
-function FancyCheckbox(props) {
-  var checked = props.checked;
-  var other = _.omit(props, 'checked');
-  var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
-  return (
-    React.DOM.div(_.extend({}, other, { className: fancyClass }))
-  );
-}
-```
diff --git a/docs/docs/07-forms.it-IT.md b/docs/docs/07-forms.it-IT.md
deleted file mode 100644
index eb601a39eaf4..000000000000
--- a/docs/docs/07-forms.it-IT.md
+++ /dev/null
@@ -1,165 +0,0 @@
----
-id: forms-it-IT
-title: Moduli
-permalink: forms-it-IT.html
-prev: transferring-props-it-IT.html
-next: working-with-the-browser-it-IT.html
----
-
-I componenti dei moduli come `<input>`, `<textarea>` e `<option>` differiscono dagli altri componenti nativi poiché possono essere alterati tramite interazione dell'utente. Questi componenti forniscono interfacce che rendono più semplice gestire i moduli in risposta all'interazione dell'utente.
-
-Per maggiori informazioni sugli eventi dell'elemento `<form>` consulta [Eventi dei Moduli](/react/docs/events.html#form-events).
-
-## Proprietà Interattive
-
-I componenti dei moduli supportano un numero di proprietà che vengono modificate dall'interazione dell'utente:
-
-* `value`, supportato dai elementi `<input>` e `<textarea>`.
-* `checked`, supportato dagli elementi `<input>` dal tipo `checkbox` o `radio`.
-* `selected`, supportato dagli elementi `<option>`.
-
-In HTML, in valore di `<textarea>` è impostato tramite un nodo di testo figlio. In React, devi invece usare la proprietà `value`.
-
-I componenti dei moduli ti permettono di reagire ai cambiamenti impostando una callback come proprietà `onChange`. La proprietà `onChange` funziona in tutti i browser e viene scatenata in risposta all'interazione dell'utente quando:
-
-* Il `value` di `<input>` o `<textarea>` cambia.
-* Lo stato `checked` di `<input>` cambia.
-* Lo stato `selected` di `<option>` cambia.
-
-Come tutti gli eventi DOM, la proprietà `onChange` è supportata su tutti i componenti nativi e può essere usata per gestire la propagazione di eventi di cambiamento.
-
-> Nota:
->
-> Per `<input>` e `<textarea>`, `onChange` rimpiazza — e dovrebbe generalmente essere utilizzata in sostituzione — il gestore di eventi [`oninput`](https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/oninput) nativo del DOM.
-
-
-## Componenti Controllati
-
-Un `<input>` il cui `value` è impostato è un componente *controllato*. In un `<input>` controllato, il valore dell'elemento visualizzato si riflette sempre nella sua proprietà `value`. Ad esempio:
-
-```javascript
-  render: function() {
-    return <input type="text" value="Ciao!" />;
-  }
-```
-
-Ciò visualizzerà un input che ha sempre il valore di `value` impostato a `Ciao!`. Ciascuna immissione dell'utente non avrà effetto sull'elemento visualizzato poiché React ha dichiarato il suo `value` pari a `Ciao!`. Se volessi aggiornare il `value` in risposta all'input dell'utente, puoi usare l'evento `onChange`:
-
-```javascript
-  getInitialState: function() {
-    return {value: 'Ciao!'};
-  },
-  handleChange: function(event) {
-    this.setState({value: event.target.value});
-  },
-  render: function() {
-    var value = this.state.value;
-    return <input type="text" value={value} onChange={this.handleChange} />;
-  }
-```
-
-In questo esempio, stiamo semplicemente accettando il valore più recente fornito dall'utente e aggiornando la proprietà `value` del componente `<input>`. Questo pattern semplifica l'implementazione di interfacce che rispondono o validano l'interazione dell'utente. Ad esempio:
-
-```javascript
-  handleChange: function(event) {
-    this.setState({value: event.target.value.substr(0, 140)});
-  }
-```
-
-Così si può accettare l'input dell'utente ma ne tronca il valore ai primi 140 caratteri.
-
-### Potenziali Problemi con Checkbox e Radio Button
-
-Fai attenzione che, allo scopo di normalizzare la gestione del cambiamento degli elementi checkbox e radio button, React usa un evento `click` al posto di un evento `change`. Nella maggior parte dei casi questo funziona nel modo previsto, tranne quando viene usato `preventDefault` in un gestore dell'evento `change`. `preventDefault` impedisce al browser di aggiornare visualmente l'input, anche se `checked` cambia il suo valore. Questo può essere evitato rimuovendo la chiamata a `preventDefault`, oppure effettuando il cambio del valore di `checked` tramite `setTimeout`.
-
-
-## Componenti Non Controllati
-
-Un `<input>` che non fornisce un `value` (o lo imposta a `null`) è un componente *non controllato*. In un `<input>` non controllato, il valore dell'elemento visualizzato rifletterà l'input dell'utente. Ad esempio:
-
-```javascript
-  render: function() {
-    return <input type="text" />;
-  }
-```
-
-Questo visualizzerà un campo di input il cui valore iniziale è vuoto. Ciascun input dell'utente si rifletterà immediatamente nell'elemento visualizzato. Se desideri reagire ai cambiamenti del valore, puoi usare il gestore di eventi `onChange` proprio come con i componenti controllati.
-
-### Valore Predefinito
-
-Se desideri inizializzare il componente con un valore non vuoto, puoi fornire una proprietà `defaultValue`. Ad esempio:
-
-```javascript
-  render: function() {
-    return <input type="text" defaultValue="Ciao!" />;
-  }
-```
-
-Questo esempio funzionerà in maniera simile all'esempio precedente sui **Componenti Controllati**.
-
-Similmente, `<input>` supporta `defaultChecked` e `<select>` supporta `defaultValue`.
-
-> Nota:
->
-> Le proprietà `defaultValue` e `defaultChecked` sono usate soltanto durante il rendering iniziale. Se devi aggiornare il valore in un rendering successivo, dovrai usare un [componente controllato](#controlled-components).
-
-
-## Argomenti Avanzati
-
-
-### Perché Componenti Controllati?
-
-Usare componenti di moduli come `<input>` in React presenta una difficoltà aggiuntiva, assente quando si scrive un modulo tradizionale in HTML. Ad esempio, in HTML:
-
-```html
-  <input type="text" name="title" value="Senza titolo" />
-```
-
-Questo visualizza un campo di input *inizializzato* con il valore `Senza titolo`. Quando l'utente modifica il campo, la *proprietà* `value` del nodo cambierà. Tuttavia, `node.getAttribute('value')` restituirà ancora il valore usato durante l'inizializzazione, `Senza titolo`.
-
-Diversamente dall'HTML, i componenti React devono rappresentare lo stato della vista in ciascun momento e non soltanto durante l'inizializzazione. Ad esempio, in React:
-
-```javascript
-  render: function() {
-    return <input type="text" name="title" value="Senza titolo" />;
-  }
-```
-
-Dal momento che questo metodo descrive la vista in ogni momento, il valore del campo di testo deve *sempre* essere `Senza titolo`.
-
-
-### Perché il Valore della Textarea?
-
-In HTML, il valore di `<textarea>` è solitamente impostato usando un nodo di testo figlio:
-
-```html
-  <!-- antipattern: NON FARLO! -->
-  <textarea name="description">Questa è la descrizione.</textarea>
-```
-
-Per l'HTML, questo approccio permette agli sviluppatori di fornire facilmente valori su più righe. Tuttavia, dal momento che React è JavaScript, non abbiamo limitazioni sulle stringhe e possiamo usare `\n` se desideriamo andare a capo. In un mondo in cui abbiamo `value` e `defaultValue`, il ruolo giocato dal nodo figlio è ambiguo. Per questa ragione, non dovresti utilizzare il nodo figlio quando imposti il valore delle `<textarea>`:
-
-```javascript
-  <textarea name="description" value="Questa è la descrizione." />
-```
-
-Se tuttavia decidi di *usare* il nodo di testo figlio, questo si comporterà come `defaultValue`.
-
-
-### Perché il Value di Select?
-
-L'elemento `<option>` selezionato in un elemento HTML `<select>` è normalmente specificato attraverso l'attributo `selected` dell'opzione stessa. In React, allo scopo di rendere i componenti più semplici da manipolare, viene invece adottato il formato seguente:
-
-```javascript
-  <select value="B">
-    <option value="A">Arancia</option>
-    <option value="B">Banana</option>
-    <option value="C">Ciliegia</option>
-  </select>
-```
-
-Per creare un componente non controllato, viene invece usato `defaultValue`.
-
-> Nota:
->
-> Puoi passare un array come valore dell'attributo `value`, se desideri selezionare più opzioni in un tag `select` a scelta multipla: `<select multiple={true} value={['B', 'C']}>`.
diff --git a/docs/docs/07-forms.ja-JP.md b/docs/docs/07-forms.ja-JP.md
deleted file mode 100644
index 04d8530d4fce..000000000000
--- a/docs/docs/07-forms.ja-JP.md
+++ /dev/null
@@ -1,150 +0,0 @@
----
-id: forms
-title: フォーム
-permalink: forms-ja-JP.html
-prev: transferring-props-ja-JP.html
-next: working-with-the-browser-ja-JP.html
----
-
-`<input>` や `<textarea>` や `<option>` のようなフォームのコンポーネントはユーザの入力によって変化しうるので、他のネイティブのコンポーネントとは異なります。以下のコンポーネントは、ユーザの入力に返答することにおいて、フォームを操作することを簡単にするインターフェースを提供します。
-
-`<form>` のイベントについての情報は、[フォームのイベント](/react/docs/events.html#form-events)をご覧ください。
-
-## 双方向のprops
-
-以下のように、フォームのコンポーネントはユーザの入力に影響されるいくつかのpropsをサポートしています。
-
-* `value` は `<input>` と `<textarea>` コンポーネントにサポートされています。
-* `checked` は `<input>` コンポーネントの `checkbox` か `radio` タイプにサポートされています。
-* `selected` は `<option>` コンポーネントにサポートされています。
-
-HTMLでは、 `<textarea>` の値は子要素によってセットされます。Reactでは、 `value` を代わりに使うべきです。
-
-フォームコンポーネントは `onChange` propにコールバックをセットすることで変更を検知することを可能にします。`onChange` propはブラウザ上で、ユーザの入力に返答する際に発火するために動きます。それは以下のようなタイミングです。
-
-* `<input>` か `<textarea>` の `value` が変わる時。
-* `<input>` の `checked` ステータスが変わる時。
-* `<option>` の `selected` ステータスが変わる時。
-
-全てのDOMのイベントのように、 `onChange` propは全てのネイティブのコンポーネントにサポートされており、何度も発生するチェンジイベントを検知するのに使われることもあります。
-
-> 注意:
-> `<input>` と `<textarea>` にとって、 `onChange` は DOMのビルトインの [`oninput`](https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/oninput) イベントハンドラの代替のものです。そして、一般的に、代わりに使われています。
-
-## 制御されたコンポーネント
-
-`<input>` と `value` のセットは *制御された* コンポーネントです。制御された `<input>` では、レンダリングされた要素の値は、常に `value` propを反映します。例えば、
-
-```javascript
-  render: function() {
-    return <input type="text" value="Hello!" />;
-  }
-```
-
-上記は、常に `Hello!` という値を持つinputをレンダリングするでしょう。ユーザのinputはレンダリングされた要素に何も影響を与えないでしょう。なぜなら、Reactが、値が `Hello!` になるように宣言しているからです。ユーザのinputに返答する形で値を更新したいなら、以下のように `onChange` イベントが使用できます。
-
-```javascript
-  getInitialState: function() {
-    return {value: 'Hello!'};
-  },
-  handleChange: function(event) {
-    this.setState({value: event.target.value});
-  },
-  render: function() {
-    var value = this.state.value;
-    return <input type="text" value={value} onChange={this.handleChange} />;
-  }
-```
-
-この例では、ユーザから提供された、最新の値を単純に受け入れ `<input>` コンポーネントの `value` propを更新します。 このパターンはユーザの入力に返答したり、バリデーションしたりするインターフェースを実行することを簡単にします。例えば、
-
-```javascript
-  handleChange: function(event) {
-    this.setState({value: event.target.value.substr(0, 140)});
-  }
-```
-
-上記はユーザのinputを受け入れますが、値を最初の140字に切り取ります。
-
-
-## 制御されないコンポーネント
-
-`value` を与えられていない（もしくは `null` がセットされている） `<input>` は *制御されない* コンポーネントです。制御されない `<input>` では、レンダリングされた要素の値はユーザのinputを反映します。例えば、
-
-```javascript
-  render: function() {
-    return <input type="text" />;
-  }
-```
-
-上記は、空の値で最初は始まるinputをレンダリングします。どのようなユーザのinputも即座にレンダリングされた要素によって反映されます。値の更新を検知したいなら、 `onChange` イベントを、制御されたコンポーネントと同様に使用することができます。
-
-コンポーネントを空ではない値で初期化したいなら、 `defaultValue` propを提供することができます。例えば、
-
-```javascript
-  render: function() {
-    return <input type="text" defaultValue="Hello!" />;
-  }
-```
-
-この例は、上記の **制御されたコンポーネント** の例と同じように動くでしょう。
-
-同様に、 `<input>` は `defaultChecked` をサポートし、 `<select>` は `defaultValue` をサポートします。
-
-## 高度なトピック
-
-
-### なぜコントロールされたコンポーネントを使うのでしょうか？
-
-`<input>` のようなフォームのコンポーネントをReactで使うことは、伝統的なHTMLのフォームを書いた時には無視される表現であることを表します。例えば、HTMLでは、
-
-```html
-  <input type="text" name="title" value="Untitled" />
-```
-
-上記は、 `Untitled` という値で *初期化* されたinputをレンダリングします。ユーザがinputを更新する時、ノードの `value` *プロパティ* が変更されるでしょう。しかし、 `node.getAttribute('value')` は初期化の際に使用された値である `Untitled` をまだリターンします。
-
-HTMLと違って、Reactのコンポーネントは初期化の時だけではなく、いつでもビューのステータスを再度表示しなくてはなりません。例えば、Reactでは、
-
-```javascript
-  render: function() {
-    return <input type="text" name="title" value="Untitled" />;
-  }
-```
-
-このメソッドがいつでもビューを描画するので、次のテキストの入力の値は *常に* `Untitled` になります。
-
-
-### なぜテキストエリアの値を使うのでしょうか？
-
-HTMLでは、 `<textarea>` の値は普通、以下のようにその子要素を使うことでセットされます。
-
-```html
-  <!-- 反例: このようにはしないでください！ -->
-  <textarea name="description">This is the description.</textarea>
-```
-
-HTMLでは、開発者は簡単に複数行に渡る値を提供できます。しかし、ReactがJavaScriptであるので、文字列の制限を私たちは持っておらず、改行をしたい場合は `\n` を使えます。 `value` と `defaultValue` を私たちが持っている世界では、子要素が果たす役割は曖昧になっています。この理由から、以下のように `<textarea>` の値をセットする際には子要素を使うべきではありません。
-
-```javascript
-  <textarea name="description" value="This is a description." />
-```
-
-子要素を使うことを *決めた* 場合は、 `defaultValue` と同様の動きをします。
-
-### なぜセレクトバリューを使うのでしょうか？
-
-HTMLの `<select>` の選択された `<option>` は、普通はオプションの `selected` 属性によって指定されます。Reactでは、コンポーネントの操作を簡単にするために、以下のようなフォーマットが代わりに適用されます。
-
-```javascript
-  <select value="B">
-    <option value="A">Apple</option>
-    <option value="B">Banana</option>
-    <option value="C">Cranberry</option>
-  </select>
-```
-
-制御されないコンポーネントを作成するために、 `defaultValue` が代わりに使われます。
-
-> 注意:
-> 配列を `value` 属性の中に渡すことができます。これで、以下のように、 `select` タグの中で複数のオプションを選択することができます。 `<select multiple={true} value={['B', 'C']}>`
diff --git a/docs/docs/07-forms.ko-KR.md b/docs/docs/07-forms.ko-KR.md
deleted file mode 100644
index a40583a6c334..000000000000
--- a/docs/docs/07-forms.ko-KR.md
+++ /dev/null
@@ -1,160 +0,0 @@
----
-id: forms-ko-KR
-title: 폼
-permalink: forms-ko-KR.html
-prev: transferring-props-ko-KR.html
-next: working-with-the-browser-ko-KR.html
----
-
-`<input>`, `<textarea>`, `<option>` 같은 폼 컴포넌트는 다른 네이티브 컴포넌트와 다릅니다. 왜냐하면, 사용자의 상호작용에 의해 변경될 수 있기 때문이죠. 이런 컴포넌트들은 사용자의 상호작용에 반응하여 폼을 더 쉽게 관리할 수 있도록 인터페이스를 제공합니다.
-
-`<form>` 이벤트에 관한 정보는 [폼 이벤트](/react/docs/events-ko-KR.html#form-events)를 보세요.
-
-## Props의 상호작용
-
-폼 컴포넌트는 사용자 상호작용을 통해 영향을 받는 몇 가지 props를 지원합니다.
-
-* `value`: `<input>`, `<textarea>` 컴포넌트에서 사용가능.
-* `checked`: `checkbox`, `radio`타입의 `<input>` 컴포넌트에서 사용가능.
-* `selected`: `<option>` 컴포넌트에서 사용가능.
-
-HTML에서는 `<textarea>` 태그의 값을 설정할 때 `<textarea>` 태그의 자식이 사용되지만, React에서는 `value` 를 사용해야 합니다.
-
-폼 컴포넌트는 `onChange` prop의 콜백을 설정하여 변경을 감시(listening)할 수 있습니다. `onChange` prop는 브라우저에 관계없이 다음과 같은 사용자 상호작용에 반응합니다.
-
-* `<input>`, `<textarea>`의 `value` 변경.
-* `<input>`의 `checked` state 변경.
-* `<option>`의 `selected` state 변경.
-
-모든 DOM 이벤트처럼 `onChange` prop은 모든 네이티브 컴포넌트에서 지원되며 일어난(bubbled) 변경 이벤트를 감시하는데 사용할 수 있습니다.
-
-> 주의:
->
-> `<input>`, `<textarea>`에서는 `onChange`가 DOM의 [`oninput`](https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/oninput) 이벤트 핸들러와 같은 기능을 제공하므로 일반적인 경우에는 `onChange`를 사용하세요.
-
-<a name="controlled-components"></a>
-## 제어되는(controlled) 컴포넌트
-
-`value`가 설정된 `<input>`은 *제어되는* 컴포넌트입니다. 제어되는 `<input>`에서, 렌더 엘리먼트의 값은 항상 `value` prop을 반영합니다. 예를 들어,
-
-```javascript
-  render: function() {
-    return <input type="text" value="Hello!" />;
-  }
-```
-
-이것은 항상 `Hello!`의 값을 가지는 input을 렌더합니다. 어떤 사용자 입력도 렌더된 엘리먼트에는 영향을 주지 않는데, 왜냐하면 React가 값을 `Hello!`로 설정했기 때문입니다. 사용자 입력에 따라 값을 업데이트하길 원한다면, `onChange` 이벤트를 사용할 수 있습니다.
-
-```javascript
-  getInitialState: function() {
-    return {value: 'Hello!'};
-  },
-  handleChange: function(event) {
-    this.setState({value: event.target.value});
-  },
-  render: function() {
-    var value = this.state.value;
-    return <input type="text" value={value} onChange={this.handleChange} />;
-  }
-```
-
-이 예제에서는, 단순히 사용자가 주는 최신값을 받고 `<input>` 컴포넌트의 `value` prop을 업데이트하고 있습니다. 이 패턴은 사용자의 상호작용에 반응하거나 검증하는 인터페이스를 쉽게 구현하게 합니다. 예를 들어,
-
-```javascript
-  handleChange: function(event) {
-    this.setState({value: event.target.value.substr(0, 140)});
-  }
-```
-
-이것은 사용자 입력을 받아들이지만, 시작에서부터 140자로 값을 자릅니다.
-
-### 체크박스와 라디오 버튼의 잠제적인 문제
-
-변경 핸들링을 일반화하기 위해 React는 `change` 이벤트 대신에 `click` 이벤트를 사용하는 것에 주의하세요. `change` 핸들러 안에서 `preventDefault`를 호출하는 경우를 재외하고 이 동작은 예상대로 동작합니다. 이런 경우 `preventDefault`를 제거하거나,  `setTimeout`에 `checked`의 전환을 넣어서 해결 가능합니다.
-
-## 제어되지 않는(Uncontrolled) 컴포넌트
-
-`value` 가 없(거나 `null`로 설정되어 있)는 `<input>`은 *제어되지 않는* 컴포넌트입니다. 제어되지 않는 `<input>`에서 렌더된 엘리먼트의 value값은 사용자의 입력을 반영합니다. 예를 들어,
-
-```javascript
-  render: function() {
-    return <input type="text" />;
-  }
-```
-
-이것은 빈 값으로 시작되는 input을 렌더합니다. 임의의 사용자 입력은 즉시 렌더된 엘리먼트에 반영됩니다. 값의 업데이트를 감시하길 원한다면, 제어되는 컴포넌트처럼 `onChange` 이벤트를 사용할 수 있습니다.
-
-### 기본 값
-
-비어 있지 않은 값으로 초기화하길 원한다면, `defaultValue` prop로 할 수 있습니다. 예를 들어,
-
-```javascript
-  render: function() {
-    return <input type="text" defaultValue="Hello!" />;
-  }
-```
-
-이 예제는 위에있는 **제어되지 않는 컴포넌트**에 더 가깝게 동작할 것입니다.
-
-마찬가지로, `<input>`은 `defaultChecked`를 지원하고 `<select>`는 `defaultValue`를 지원합니다.
-
-> 주의:
->
-> `defaultValue`, `defaultChecked` prop은 최초 렌더에서만 사용됩니다. 뒤에 일어나는 렌더에서 값을 업데이트할 필요가 있다면,  [제어되는(controlled) 컴포넌트](#controlled-components)를 사용하셔야 합니다.
-
-## 심화 주제
-
-### 왜 제어되는 컴포넌트인가요?
-
-React에서 `<input>`같은 폼 컴포넌트를 사용하면, 전통적인 폼 HTML을 쓸 때에는 없던 어려운 문제가 있습니다. 예를 들어 HTML에서
-
-```html
-  <input type="text" name="title" value="Untitled" />
-```
-
-이렇게 하면 input은 `Untitled` 값으로 *초기화* 됩니다. 사용자가 input을 업데이트할 때, 노드의 `value` *프로퍼티*가 변경될 것입니다. 하지만, `node.getAttribute('value')`은 여전히 초기화 때 사용했던 값인 `Untitled`를 리턴합니다.
-
-HTML과 다르게, React 컴포넌트는 초기화 시점 뿐만 아니라, 어떤 시점이라도 반드시 뷰의 state를 나타내야 합니다. 예를 들어 React에서
-
-```javascript
-  render: function() {
-    return <input type="text" name="title" value="Untitled" />;
-  }
-```
-
-이 메소드가 어떤 시점에도 뷰를 기술하기 때문에, 텍스트 input의 값은 *언제나* `Untitled`입니다.
-
-### 왜 Textarea에 value를 사용하나요?
-
-HTML에서, `<textarea>`의 값은 보통 그것의 자식들로 설정됩니다.
-
-```html
-  <!-- 안티패턴: 이렇게 하지 마세요! -->
-  <textarea name="description">이것은 설명입니다.</textarea>
-```
-
-HTML에서는 이렇게 하면 여러 줄의 값을 쉽게 개발자가 넣을 수 있게 합니다. 하지만, React는 JavaScript기 때문에, 우리는 문자열 제한이 없고 개행이 필요하면 `\n`을 사용할 수 있습니다. 이 곳에서는 `value`와 `defaultValue`가 있고, 그것이 자식들의 역할을 모호하게 합니다. 이런 이유로, `<textarea>`의 값을 설정할 때에는 자식들을 사용하지 않아야 합니다.
-
-```javascript
-  <textarea name="description" value="이것은 설명입니다." />
-```
-
-자식들을 사용하기로 *했다면*, 자식들은 `defaultValue`처럼 동작할 것입니다.
-
-### 왜 Select에 value를 사용하나요?
-
-HTML `<select>`에서 선택된 `<option>`은 보통 option의 `selected` 어트리뷰트로 기술됩니다. React에서는 컴포넌트를 관리하기 쉽게 하기 위해, 다음 형식이 대신 채용됐습니다.
-
-```javascript
-  <select value="B">
-    <option value="A">Apple</option>
-    <option value="B">Banana</option>
-    <option value="C">Cranberry</option>
-  </select>
-```
-
-제어되지 않는 컴포넌트로 만드려면, 대신 `defaultValue`를 사용하세요.
-
-> 주의:
->
-> `select` 태그에 여러 옵션을 선택할 수 있도록, `value` 어트리뷰트에 배열을 넘길 수도 있습니다. `<select multiple={true} value={['B', 'C']}>`
diff --git a/docs/docs/07-forms.md b/docs/docs/07-forms.md
deleted file mode 100644
index e7e769cd02b6..000000000000
--- a/docs/docs/07-forms.md
+++ /dev/null
@@ -1,168 +0,0 @@
----
-id: forms
-title: Forms
-permalink: forms.html
-prev: transferring-props.html
-next: working-with-the-browser.html
----
-
-Form components such as `<input>`, `<textarea>`, and `<option>` differ from other native components because they can be mutated via user interactions. These components provide interfaces that make it easier to manage forms in response to user interactions.
-
-For information on events on `<form>` see [Form Events](/react/docs/events.html#form-events).
-
-## Interactive Props
-
-Form components support a few props that are affected via user interactions:
-
-* `value`, supported by `<input>` and `<textarea>` components.
-* `checked`, supported by `<input>` components of type `checkbox` or `radio`.
-* `selected`, supported by `<option>` components.
-
-In HTML, the value of `<textarea>` is set via children. In React, you should use `value` instead.
-
-Form components allow listening for changes by setting a callback to the `onChange` prop. The `onChange` prop works across browsers to fire in response to user interactions when:
-
-* The `value` of `<input>` or `<textarea>` changes.
-* The `checked` state of `<input>` changes.
-* The `selected` state of `<option>` changes.
-
-Like all DOM events, the `onChange` prop is supported on all native components and can be used to listen to bubbled change events.
-
-> Note:
->
-> For `<input>` and `<textarea>`, `onChange` supersedes — and should generally be used instead of — the DOM's built-in [`oninput`](https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/oninput) event handler.
-
-## Controlled Components
-
-A **controlled** `<input>` has a `value` prop. Rendering a controlled `<input>` will reflect the value of the `value` prop.
-
-```javascript
-  render: function() {
-    return <input type="text" value="Hello!" />;
-  }
-```
-
-User input will have no effect on the rendered element because React has declared the value to be `Hello!`. To update the value in response to user input, you could use the `onChange` event:
-
-```javascript
-  getInitialState: function() {
-    return {value: 'Hello!'};
-  },
-  handleChange: function(event) {
-    this.setState({value: event.target.value});
-  },
-  render: function() {
-    return (
-      <input
-        type="text"
-        value={this.state.value}
-        onChange={this.handleChange}
-      />
-    );
-  }
-```
-
-In this example, we are accepting the value provided by the user and updating the `value` prop of the `<input>` component. This pattern makes it easy to implement interfaces that respond to or validate user interactions. For example:
-
-```javascript
-  handleChange: function(event) {
-    this.setState({value: event.target.value.substr(0, 140)});
-  }
-```
-
-This would accept user input and truncate the value to the first 140 characters.
-
-A **Controlled** component does not maintain its own internal state; the component renders purely based on props.
-
-### Potential Issues With Checkboxes and Radio Buttons
-
-Be aware that, in an attempt to normalize change handling for checkbox and radio inputs, React uses a `click` event in place of a `change` event. For the most part this behaves as expected, except when calling `preventDefault` in a `change` handler. `preventDefault` stops the browser from visually updating the input, even if `checked` gets toggled. This can be worked around either by removing the call to `preventDefault`, or putting the toggle of `checked` in a `setTimeout`.
-
-## Uncontrolled Components
-
-An `<input>` without a `value` property is an *uncontrolled* component:
-
-```javascript
-  render: function() {
-    return <input type="text" />;
-  }
-```
-
-This will render an input that starts off with an empty value. Any user input will be immediately reflected by the rendered element. If you wanted to listen to updates to the value, you could use the `onChange` event just like you can with controlled components.
-
-An **uncontrolled** component maintains its own internal state.
-
-### Default Value
-
-If you want to initialize the component with a non-empty value, you can supply a `defaultValue` prop. For example:
-
-```javascript
-  render: function() {
-    return <input type="text" defaultValue="Hello!" />;
-  }
-```
-
-This example will function much like the **Controlled Components** example above.
-
-Likewise, `<input type="checkbox">` and `<input type="radio">` support `defaultChecked`, and `<select>` supports `defaultValue`.
-
-> Note:
->
-> The `defaultValue` and `defaultChecked` props are only used during initial render. If you need to update the value in a subsequent render, you will need to use a [controlled component](#controlled-components).
-
-## Advanced Topics
-
-### Why Controlled Components?
-
-Using form components such as `<input>` in React presents a challenge that is absent when writing traditional form HTML. For example, in HTML:
-
-```html
-  <input type="text" name="title" value="Untitled" />
-```
-
-This renders an input *initialized* with the value, `Untitled`. When the user updates the input, the node's `value` *property* will change. However, `node.getAttribute('value')` will still return the value used at initialization time, `Untitled`.
-
-Unlike HTML, React components must represent the state of the view at any point in time and not only at initialization time. For example, in React:
-
-```javascript
-  render: function() {
-    return <input type="text" name="title" value="Untitled" />;
-  }
-```
-
-Since this method describes the view at any point in time, the value of the text input should *always* be `Untitled`.
-
-### Why Textarea Value?
-
-In HTML, the value of `<textarea>` is usually set using its children:
-
-```html
-  <!-- antipattern: DO NOT DO THIS! -->
-  <textarea name="description">This is the description.</textarea>
-```
-
-For HTML, this easily allows developers to supply multiline values. However, since React is JavaScript, we do not have string limitations and can use `\n` if we want newlines. In a world where we have `value` and `defaultValue`, it is ambiguous what role children play. For this reason, you should not use children when setting `<textarea>` values:
-
-```javascript
-  <textarea name="description" value="This is a description." />
-```
-
-If you *do* decide to use children, they will behave like `defaultValue`.
-
-### Why Select Value?
-
-The selected `<option>` in an HTML `<select>` is normally specified through that option's `selected` attribute. In React, in order to make components easier to manipulate, the following format is adopted instead:
-
-```javascript
-  <select value="B">
-    <option value="A">Apple</option>
-    <option value="B">Banana</option>
-    <option value="C">Cranberry</option>
-  </select>
-```
-
-To make an uncontrolled component, `defaultValue` is used instead.
-
-> Note:
->
-> You can pass an array into the `value` attribute, allowing you to select multiple options in a `select` tag: `<select multiple={true} value={['B', 'C']}>`.
diff --git a/docs/docs/07-forms.zh-CN.md b/docs/docs/07-forms.zh-CN.md
deleted file mode 100644
index bda03b7beb45..000000000000
--- a/docs/docs/07-forms.zh-CN.md
+++ /dev/null
@@ -1,168 +0,0 @@
----
-id: forms-zh-CN
-title: 表单组件
-permalink: forms-zh-CN.html
-prev: transferring-props-zh-CN.html
-next: working-with-the-browser-zh-CN.html
----
-
-诸如 `<input>`、`<textarea>`、`<option>` 这样的表单组件不同于其他组件，因为他们可以通过用户交互发生变化。这些组件提供的界面使响应用户交互的表单数据处理更加容易。
-
-关于 `<form>` 事件详情请查看 [表单事件](/react/docs/events-zh-CN.html#form-events)。
-
-## 交互属性
-
-表单组件支持几个受用户交互影响的属性：
-
-* `value`，用于 `<input>`、`<textarea>` 组件。
-* `checked`，用于类型为 `checkbox` 或者 `radio` 的 `<input>` 组件。
-* `selected`，用于 `<option>` 组件。
-
-在 HTML 中，`<textarea>` 的值通过子节点设置；在 React 中则应该使用 `value` 代替。
-
-表单组件可以通过 `onChange` 回调函数来监听组件变化。当用户做出以下交互时，`onChange` 执行并通过浏览器做出响应：
-
-* `<input>` 或 `<textarea>` 的 `value` 发生变化时。
-* `<input>` 的 `checked` 状态改变时。
-* `<option>` 的 `selected` 状态改变时。
-
-和所有 DOM 事件一样，所有的 HTML 原生组件都支持 `onChange` 属性，而且可以用来监听冒泡的 `change` 事件。
-
-> 注意:
->
-> 对于 `<input>` and `<textarea>`， `onChange` 取代 — 一般应该用来替代 — DOM内建的 [`oninput`](https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/oninput) 事件处理。
-
-## 受控组件
-
-一个*受控*的 `<input>` 有一个 `value` prop。渲染一个受控 `<input>` 会反映 `value` prop 的值。
-
-```javascript
-  render: function() {
-    return <input type="text" value="Hello!" />;
-  }
-```
-
-用户输入在被渲染的元素里将没有作用,因为 React 已经声明值为 `Hello!`。要更新 value 来响应用户输入，你可以使用 `onChange` 事件：
-
-```javascript
-  getInitialState: function() {
-    return {value: 'Hello!'};
-  },
-  handleChange: function(event) {
-    this.setState({value: event.target.value});
-  },
-  render: function() {
-    return (
-      <input
-        type="text"
-        value={this.state.value}
-        onChange={this.handleChange}
-      />
-    );
-  }
-```
-
-在这个例子中，我们接受用户提供的值并更新 `<input>` 组件的 `value` prop。这个模式使实现响应或者验证用户输入的界面更容易。例如：
-
-```javascript
-  handleChange: function(event) {
-    this.setState({value: event.target.value.substr(0, 140)});
-  }
-```
-
-上面的代码接受用户输入，并截取前 140 个字符。
-
-受控组件不维持一个自己的内部状态;它单纯的基于 props 渲染。
-
-### 复选框与单选按钮的潜在问题
-
-当心，在力图标准化复选框与单选按钮的变换处理中，React使用`click` 事件代替 `change` 事件。在大多数情况下它们表现的如同预期，除了在`change` handler中调用`preventDefault` 。`preventDefault` 阻止了浏览器视觉上更新输入，即使`checked`被触发。变通的方式是要么移除`preventDefault`的调用，要么把`checked` 的触发放在一个`setTimeout`里。
-
-## 不受控组件
-
-一个没有 `value` 属性的 `<input>` 是一个不*受控*组件:
-
-```javascript
-  render: function() {
-    return <input type="text" />;
-  }
-```
-
-上面的代码将渲染出一个空值的输入框，用户输入将立即反应到元素上。和受控元素一样，使用 `onChange` 事件可以监听值的变化。
-
-*不受控*组件维持它自己的内部状态。
-
-### 默认值
-
-如果想给组件设置一个非空的初始值，可以使用 `defaultValue` 属性。例如：
-
-```javascript
-  render: function() {
-    return <input type="text" defaultValue="Hello!" />;
-  }
-```
-
-这个例子会像上面的 **不受控组件** 例子一样运行。
-
-同样的， `<input type="checkbox">` 和 `<input type="radio">` 支持 `defaultChecked` 、 `<select>` 支持 `defaultValue`.
-
-> 注意:
->
->  `defaultValue` 和 `defaultChecked` props 只能在内部渲染时被使用。 如果你需要在随后的渲染更新值, 你需要使用 [受控组件](#受控组件).
-
-## 高级主题
-
-### 为什么使用受控组件？
-
-在 React 中使用诸如 `<input>` 的表单组件时，遇到了一个在传统 HTML 中没有的挑战。比如下面的代码：
-
-```html
-  <input type="text" name="title" value="Untitled" />
-```
-
-它渲染一个*初始值*为 `Untitled` 的输入框。当用户改变输入框的值时，节点的 `value` 属性( *property*)将随之变化，但是 `node.getAttribute('value')` 还是会返回初始设置的值 `Untitled`.
-
-与 HTML 不同，React 组件必须在任何时间点表现视图的状态，而不仅仅是在初始化时。比如在 React 中：
-
-```javascript
-  render: function() {
-    return <input type="text" name="title" value="Untitled" />;
-  }
-```
-
-既然这个方法描述了在任意时间点上的视图，那么文本输入框的值就应该*始终*为 `Untitled`。
-
-### 为什么 `<textarea>` 使用 `value` 属性？
-
-在 HTML 中， `<textarea>` 的值通常使用子节点设置：
-
-```html
-  <!-- 反例：在 React 中不要这样使用！ -->
-  <textarea name="description">This is the description.</textarea>
-```
-
-对 HTML 而言，让开发者设置多行的值很容易。但是，React 是 JavaScript，没有字符串限制，可以使用 `\n` 实现换行。简言之，React 已经有 `value`、`defaultValue` 属性，`</textarea>` 组件的子节点扮演什么角色就有点模棱两可了。基于此， 设置 `<textarea>` 值时不应该使用子节点：
-
-```javascript
-  <textarea name="description" value="This is a description." />
-```
-
-如果 *非要* 使用子节点，效果和使用 `defaultValue` 一样。
-
-### 为什么 `<select>` 使用 `value` 属性
-
-HTML 中 `<select>` 通常使用 `<option>` 的 `selected` 属性设置选中状态；React 为了更方面的控制组件，采用以下方式代替：
-
-```javascript
-  <select value="B">
-    <option value="A">Apple</option>
-    <option value="B">Banana</option>
-    <option value="C">Cranberry</option>
-  </select>
-```
-
-如果是不受控组件，则使用 `defaultValue`。
-
-> 注意：
->
-> 给 `value` 属性传递一个数组，可以选中多个选项：`<select multiple={true} value={['B', 'C']}>`。
diff --git a/docs/docs/08-working-with-the-browser.it-IT.md b/docs/docs/08-working-with-the-browser.it-IT.md
deleted file mode 100644
index bc78bf8e15ce..000000000000
--- a/docs/docs/08-working-with-the-browser.it-IT.md
+++ /dev/null
@@ -1,109 +0,0 @@
----
-id: working-with-the-browser-it-IT
-title: Lavorare con il Browser
-permalink: working-with-the-browser-it-IT.html
-prev: forms-it-IT.html
-next: more-about-refs-it-IT.html
----
-
-React offre potenti astrazioni che ti liberano in molti casi dal compito di manipolare direttamente il DOM, ma a volte potresti avere bisogno di accedere alle API sottostanti, ad esempio per lavorare con una libreria di terze parti o altro codice preesistente.
-
-
-## Il DOM Virtuale
-
-React è così veloce perché non interagisce direttamente con il DOM. React gestisce una rappresentazione veloce del DOM in memoria. I metodi `render()` restituiscono una *descrizione* del DOM, e React può confrontare questa descrizione con la rappresentazione in memoria per calcolare la maniera più veloce di aggiornare il browser.
-
-In aggiunta, React implementa un intero sistema di eventi sintetici che fa in modo che tutti gli oggetti evento siano conformi alle specifiche W3C nonostante le incompatibilità dei browser, e ciascun evento si propaga in maniera consistente ed efficiente in ogni browser. Puoi anche utilizzare alcuni eventi HTML5 in IE8!
-
-Nella maggior parte dei casi è sufficiente rimanere nel mondo del "browser fittizio" di React poiché più efficiente e facile da concepire. Tuttavia, a volte potresti aver bisogno di accedere alle API sottostanti, ad esempio per lavorare con una libreria di terze parti come un plugin jQuery. React fornisce convenienti vie di fuga perché tu possa utilizzare direttamente le API DOM sottostanti.
-
-
-## I Ref e findDOMNode()
-
-Per interagire con il browser, avrai bisogno di un riferimento a un nodo DOM. Puoi assegnare un attributo `ref` a ciascun elemento, ciò ti permette di fare riferimento all'**istanza di supporto** del componente. Questo è utile se devi invocare funzioni imperative sul componente, oppure desideri accedere ai nodi DOM sottostanti. Per saperne di piu sui ref, incluso la maniera di usarli con efficacia, leggi la nostra documentazione [riferimenti a componenti](/react/docs/more-about-refs-it-IT.html).
-
-
-## Ciclo di Vita del Componente
-
-I componenti hanno tree fasi principali del ciclo di vita:
-
-* **Montaggio:** Un componente sta venendo inserito nel DOM.
-* **Aggiornamento:** Viene effettuato nuovamente il rendering del componente per determinare se il DOM vada aggiornato.
-* **Smontaggio:** Un componente sta venendo rimosso dal DOM.
-
-React offre metodi del ciclo di vita che puoi specificare per inserirti in questo processo. Offriamo dei metodi il cui nome inizia per **will**, chiamati immediatamente prima che qualcosa accada, o per **did** che sono chiamati immediatamente dopo che qualcosa è accaduto.
-
-
-### Montaggio
-
-* `getInitialState(): object` è invocato prima che un componente viene montato. Componenti dotati di stato dovrebbero implementare questo metodo e restituire lo stato iniziale.
-* `componentWillMount()` è invocato immediatamente prima che si effettui il montaggio.
-* `componentDidMount()` è invocato immediatamente dopo che il montaggio è avvenuto. L'inizializzazione che richiede l'esistenza di nodi DOM dovrebbe avvenire in questo metodo.
-
-
-### Aggiornamento
-
-* `componentWillReceiveProps(object nextProps)` è invocato quando un componente montato riceve nuove proprietà. Questo metodo dovrebbe essere utilizzato per confrontare `this.props` e `nextProps` per effettuare transizioni di stato utilizzando `this.setState()`.
-* `shouldComponentUpdate(object nextProps, object nextState): boolean` è invocato quando un componente decide se i cambiamenti debbano risultare in un aggiornamento del DOM. Implementa questo metodo come un'ottimizzazione per confrontare `this.props` con `nextProps` e `this.state` con `nextState`, e restituisci `false` se React debba rimandare l'aggiornamento.
-* `componentWillUpdate(object nextProps, object nextState)` è invocato immediatamente prima che l'aggiornamento avvenga. Non puoi chiamare `this.setState()` al suo interno.
-* `componentDidUpdate(object prevProps, object prevState)` è invocato immediatamente dopo che l'aggiornamento è avvenuto.
-
-
-### Smontaggio
-
-* `componentWillUnmount()` è invocato immediatamente prima che un componente venga smontato e distrutto. Puoi effettuare operazioni di pulizia al suo interno.
-
-
-### Metodi Montati
-
-Componenti compositi _montati_ supportano anche i seguenti metodi:
-
-* `findDOMNode(): DOMElement` può essere invocato su ciascun componente montato per ottenere un riferimento al suo nodo DOM.
-* `forceUpdate()` può essere invocato su ciascun componente montato quando si è certi che un aspetto interno del componente è cambiato senza usare `this.setState()`.
-
-
-## Supporto per i Browser e Polyfill
-
-A Facebook supportiamo vecchi browser, incluso IE8. Abbiamo impiegato per un lungo tempo i polyfill per consentirci di scrivere JS con un occhio al futuro. Ciò significa che non abbiamo una quantità di hack sparsi nel nostro codice e possiamo tuttavia aspettarci che il nostro codice "semplicemente funzioni". Ad esempio, anziché usare `+new Date()`, possiamo scrivere `Date.now()`. Dal momento che la versione open source di React è la stessa che usiamo internamente, vi abbiamo applicato la stessa filosofia di scrivere JS guardando avanti.
-
-In aggiunta a questa filosofia, abbiamo anche deciso, in qualità di autori di una libreria JS, non dovremmo fornire i polyfill assieme alla nostra libreria. Se ciascuna libreria facesse ciò, con buona probabilità invieresti lo stesso polyfill diverse volte, cosa che potrebbe risultare in una rilevante quantità di codice inutilizzato. Se il tuo prodotto deve supportare vecchi browser, con buona probabilità stai già usando qualcosa come [es5-shim](https://github.com/es-shims/es5-shim).
-
-
-### Polyfill Richiesti per Supportare Vecchi Browser
-
-`es5-shim.js` tratto da [es5-shim di kriskowal](https://github.com/es-shims/es5-shim) fornisce le seguenti API indispensabili a React:
-
-* `Array.isArray`
-* `Array.prototype.every`
-* `Array.prototype.forEach`
-* `Array.prototype.indexOf`
-* `Array.prototype.map`
-* `Date.now`
-* `Function.prototype.bind`
-* `Object.keys`
-* `String.prototype.split`
-* `String.prototype.trim`
-
-`es5-sham.js`, anch'esso tratto da [es5-shim di kriskowal](https://github.com/es-shims/es5-shim), provides the following that React needs:
-
-* `Object.create`
-* `Object.freeze`
-
-La build non minificata di React richiede le seguenti API tratte da [console-polyfill di paulmillr](https://github.com/paulmillr/console-polyfill).
-
-* `console.*`
-
-Quando si usano elementi HTML5 in IE8 incluso `<section>`, `<article>`, `<nav>`, `<header>` e `<footer>`, è inoltre necessario includere [html5shiv](https://github.com/aFarkas/html5shiv) o uno script equivalente.
-
-
-### Problemi Cross-browser
-
-Nonostante React sia molto buono ad astrarre le differenze tra browser, alcuni browser sono limitati o presentano comportamenti scorretti per i quali non abbiamo potuto trovare un rimedio.
-
-
-#### Evento onScroll su IE8
-
-Su IE8 l'evento `onScroll` non viene propagato, e IE8 non possiede una API per definire gestori di eventi nella fase di cattura dell'evento, con il risultato che React non ha alcun modo di reagire a questi eventi.
-Al momento i gestori di questo evento vengono ignorati su IE8.
-
-Leggi la issue [onScroll doesn't work in IE8](https://github.com/facebook/react/issues/631) su GitHub per maggiori informazioni.
diff --git a/docs/docs/08-working-with-the-browser.ja-JP.md b/docs/docs/08-working-with-the-browser.ja-JP.md
deleted file mode 100644
index f8e0dee80bd0..000000000000
--- a/docs/docs/08-working-with-the-browser.ja-JP.md
+++ /dev/null
@@ -1,137 +0,0 @@
----
-id: working-with-the-browser
-title: ブラウザと動くこと
-permalink: working-with-the-browser-ja-JP.html
-prev: forms-ja-JP.html
-next: more-about-refs-ja-JP.html
----
-
-Reactはほとんどのケースで、DOMを直接触ることからあなたを解放するパワフルな抽象性を提供します。しかし、単純に根本的なAPIにアクセスする必要がある場合もあります。サードパーティのライブラリや現存するコードと動かす必要があるかもしれません。
-
-## 仮想DOM
-
-ReactはDOMと直接対話を行わないため、とても速いです。Reactは速いメモリ上のDOMの表現を持っています。 `render()` メソッドはDOMの *記述* をリターンします。Reactはこの記述とメモリ上の表現のdiffをとることができ、ブラウザを更新する最速の方法を計算することができます。
-
-加えて、Reactはブラウザ依存があるにも関わらず、W3Cの使用に則っていると保証されているイベントオブジェクトのような、完全に合成されたイベントシステムを実行します。HTML5のイベントをIE8で使うこともできます！
-
-パフォーマンスが優れており、簡単であると思われるので、ほとんどの場合、Reactの「偽のブラウザ」を使うべきです。しかし、jQueryプラグインのようなサードパーティのライブラリと動かすかもしれません。基本的なAPIに単純にアクセスする必要がある時もあります。Reactは基本的なDOMのAPIを直接使うための脱出口を提供しています。
-
-## 参照とfindDOMNode()
-
-ブラウザと相互に影響するために、DOMノードへの参照が必要になるでしょう。ReactはコンポーネントのDOMノードへの参照を得ることができる `ReactDOM.findDOMNode(component)` 関数を持っています。
-
-> 注意:
-> `findDOMNode()` はマウントされたコンポーネントの上でのみ動きます（これは、DOMに配置されたコンポーネントという意味です）。まだマウントされていない（まだ作成されていないコンポーネントの上で `render()` の `findDOMNode()` を呼ぶようなものです）コンポーネントの上でこれを呼ぼうとした場合、例外がスローされます。
-
-Reactのコンポーネントへの参照を得るためには、現在のReactコンポーネントを得るために `this` を使ったり、あなたがオーナーのコンポーネントを表す参照を使ったりできます。それらは、以下のように動きます。
-
-```javascript
-var MyComponent = React.createClass({
-  handleClick: function() {
-    // 生のDOMのAPIを使ってテキスト入力に明確にフォーカスします。
-    ReactDOM.findDOMNode(this.refs.myTextInput).focus();
-  },
-  render: function() {
-    // この参照属性はコンポーネントがマウントされた時に、
-    // this.refs のコンポーネントへの参照を追加します。
-    return (
-      <div>
-        <input type="text" ref="myTextInput" />
-        <input
-          type="button"
-          value="Focus the text input"
-          onClick={this.handleClick}
-        />
-      </div>
-    );
-  }
-});
-
-ReactDOM.render(
-  <MyComponent />,
-  document.getElementById('example')
-);
-```
-
-
-## 参照に関しての詳細
-
-参照に関して、詳細に学ぶためと、効率的にそれらを使う方法については、[参照に関しての詳細](/react/docs/more-about-refs.html)ドキュメントを読んでください。
-
-
-## コンポーネントライフサイクル
-
-コンポーネントは以下のように、ライフサイクルの3つのパートを持っています
-
-* **マウンティング:** コンポーネントはDOMにインサートされます。
-* **アップデーティング:** DOMがアップデートする必要があるとき、コンポーネントを決定するために再度レンダリングされます。
-* * **アンマウンティング:** コンポーネントはDOMから削除されます。
-
-Reactは上記のプロセスになるように指定できるライフサイクルメソッドを提供します。私たちは何かが起こる直前に呼ばれる **未来の** メソッドと何かが起こった直後に呼ばれる **過去の** メソッドを使うことができます。
-
-### マウンティング
-
-* `getInitialState(): object` はコンポーネントがマウントされる前に実行されます。ステートフルなコンポーネントはこのメソッドをインプリメントする必要があり、最初のstateのデータをリターンする必要があります。
-* `componentWillMount()` はマウンティングが起きる直前に実行されます。
-* `componentDidMount()` はマウンティングが起きた直後に実行されます。DOMノードを必要とする初期化はここで行われるべきです。
-
-### アップデーティング
-
-* `componentWillReceiveProps(object nextProps)` はマウントされたコンポーネントが新しいpropsを受け取ったときに実行されます。このメソッドは `this.setState()` を使ったstateの変更を実行するために `this.props` と `nextProps` とを比較するのに使われるべきです。
-* `shouldComponentUpdate(object nextProps, object nextState): boolean` は何かしらの変更がDOMをアップデートしなければいけないかどうかコンポーネントが決めるときに実行されます。このメソッドを `this.props` と `nextProps` そして `this.state` と `nextState` の比較の最適化のために実行してください。そして、Reactがアップデートをスキップするべきときには `false` を返してください。
-* `componentWillUpdate(object nextProps, object nextState)` はアップデーティングが発生する直前に実行されます。ここで `this.setState()` を呼ぶことはできません。
-* `componentDidUpdate(object prevProps, object prevState)` はアップデーティングが発生した直後に実行されます。
-
-### アンマウンティング
-
-* `componentWillUnmount()` はコンポーネントがアンマウントされ、削除される直前に実行されます。クリーンアップはここで行われるべきです。
-
-### マウントのメソッド
-
-_マウントされた_ 複合的なコンポーネントも以下のようなメソッドをサポートします。
-
-* `findDOMNode(): DOMElement` はレンダリングされたDOMノードへの参照を得るために、どのマウントされたコンポーネントの上でも実行されます。
-* `forceUpdate()` は `this.setState()` を使うことなくコンポーネントのstateが変更された際にさらにその詳細について知るときにどのマウントされたコンポーネントの上でも実行されます。
-
-## ブラウザのサポートとポリフィル
-
-Facebookでは、IE8を含む古いブラウザをサポートしています。私たちは将来に向けたJSを書くことができるように、長い間ポリフィルを使ってきました。これは、私たちのコードベースにたくさんの処理が散らばり、「ただ動くだけの」コードであることを予想することしかできないことを意味します。例えば、 `+new Date()` を見る代わりに、  `Date.now()` と記述しています。オープンソースであるReactを私たちは内部で使っているので、将来に向けたJSを使うという哲学を持ち越しています。
-
-この哲学に加えて、私たちはJSのライブラリの作者として、ライブラリの一部としてポリフィルを含めるべきではないというスタンスをとっています。全てのライブラリがこのようなことを行ったなら、死んだコードの大きな塊になりうる同じポリフィルを何度も記述しなくてもよくなるでしょう。あなたのプロダクトが古いブラウザをサポートする必要があるなら、[es5-shim](https://github.com/es-shims/es5-shim)のようなものを使うことにチャンスがあるでしょう。
-
-### ポリフィルは古いブラウザをサポートする必要があります
-
-[kriskowal's es5-shim](https://github.com/es-shims/es5-shim) の `es5-shim.js` はReactが必要とする以下のようなものを提供します。
-
-* `Array.isArray`
-* `Array.prototype.every`
-* `Array.prototype.forEach`
-* `Array.prototype.indexOf`
-* `Array.prototype.map`
-* `Date.now`
-* `Function.prototype.bind`
-* `Object.keys`
-* `String.prototype.split`
-* `String.prototype.trim`
-
-[kriskowal's es5-shim](https://github.com/es-shims/es5-shim)の `es5-sham.js` もまたReactが必要とする以下のようなものを提供します。
-
-* `Object.create`
-* `Object.freeze`
-
-小さくされていないReactのビルドは[paulmillr's console-polyfill](https://github.com/paulmillr/console-polyfill)にある以下のようなものを必要とします。
-
-* `console.*`
-
-`<section>` 、 `<article>` 、 `<nav>` 、 `<header>` 、 `<footer>` を含むHTML5の要素をIE8で使うときには、[html5shiv](https://github.com/aFarkas/html5shiv)か、似たようなスクリプトをインクルードする必要があります。
-
-### クロスブラウザの問題
-
-Reactはブラウザ間の違いを抽象化することにおいてとても優れていますが、一時的な解決ができない、制限や独特な動作をするブラウザもあります。
-
-#### IE8のonScrollイベント
-
-IE8では `onScroll` イベントは発火せず、イベントのフェーズをキャプチャするハンドラを定義するAPIを持っていません。それは、Reactがそれらのイベントを検知する方法が無いということを意味します。現状、IE8ではこのイベントは無視されています。
-
-詳細な情報については、GitHubのイシューである[onScrollがIE8で動かない](https://github.com/facebook/react/issues/631)を参照してください。
-
diff --git a/docs/docs/08-working-with-the-browser.ko-KR.md b/docs/docs/08-working-with-the-browser.ko-KR.md
deleted file mode 100644
index 6b9e51ea6084..000000000000
--- a/docs/docs/08-working-with-the-browser.ko-KR.md
+++ /dev/null
@@ -1,100 +0,0 @@
----
-id: working-with-the-browser-ko-KR
-title: 브라우저에서의 동작
-permalink: working-with-the-browser-ko-KR.html
-prev: forms-ko-KR.html
-next: more-about-refs-ko-KR.html
----
-
-React는 대부분의 경우 직접 DOM을 다루지 않아도 될만큼 강력한 추상화를 제공합니다. 하지만 서드파티 라이브러리나 기존의 코드들을 다루다 보면 간혹 기저(underlying)의 API에 접근해야 할 때도 있습니다.
-
-
-## 가상의 DOM
-
-React는 DOM을 직접 다루지 않기 때문에 매우 빠릅니다. React는 메모리에(in-memory) DOM의 표상(representation)을 관리합니다. `render()` 메소드는 사실은 DOM의 *서술*를 반환하고, React는 이를 메모리에 있는 DOM의 표상과 비교해 가장 빠른 방식으로 계산해서 브라우저를 업데이트해 줍니다.
-
-게다가 React는 브라우저의 괴악함(quirks)에도 불구하고 모든 이벤트 객체가 W3C 명세를 보장하도록 통합적인 이벤트 시스템을 구현했습니다. 모든 것이 일관된 방식으로 일어나고(bubbles) 효율적으로 크로스 브라우징을 수행합니다. 심지어 IE8에서도 HTML5 이벤트를 사용할 수 있습니다!
-
-더 효율적이고 쉬우므로 대개의 경우 React의 "가짜 브라우저"를 이용해 작업을 하게 될 것입니다. 하지만 간혹 jQuery 플러그인 같은 서드파티 라이브러리를 다루다 보면 기저(underlying)의 API에 접근할 필요가 있을지도 모릅니다. React는 기저의 DOM API를 직접 다루는 회피방법을 제공합니다.
-
-
-## Refs와 findDOMNode()
-
-브라우저와 상호 작용하려면 DOM 노드에 대한 참조가 필요합니다. `ref`를 어떤 엘리먼트에도 붙일 수 있으며, 이를 통해 컴포넌트 **지원 인스턴스**를 참조 할 수 있습니다. 이는 컴포넌트에 필수 적인 기능을 호출할 때나 기저의 DOM 노드에 접근하고 싶을 때 유용합니다. [refs에서 컴포넌트로](/react/docs/more-about-refs-ko-KR.html) 문서에서 refs를 효율적으로 사용하는 법을 포함해 더 많은 내용을 익혀보세요.
-
-
-<a name="component-lifecycle"></a>
-## 컴포넌트 생명주기
-
-컴포넌트의 생명주기에는 세 가지 주요 부분이 있습니다:
-
-* **Mounting:** 컴포넌트가 DOM에 삽입되고 있습니다.
-* **Updating:** 컴포넌트가 DOM의 업데이트 여부를 결정하기 위해 다시 렌더링되고 있습니다.
-* **Unmounting:** 컴포넌트가 DOM에서 제거되고 있습니다.
-
-React는 이 프로세스에 훅을 지정할 수 있는 생명주기 메소드를 제공합니다. 발생 직전 시점을 위한 **will** 메소드, 발생 직후 시점을 위한 **did** 메소드가 있습니다.
-
-### Mounting
-
-* `getInitialState(): object`는 컴포넌트가 마운트되기 전에 호출됩니다. 상태기반 컴포넌트는 이를 구현하고 초기 상태 데이터를 리턴합니다.
-* `componentWillMount()`는 마운팅되기 직전에 호출됩니다.
-* `componentDidMount()`는 마운팅 직후 호출됩니다. 초기화에 필요한 DOM 노드는 이곳에 있어야 합니다.
-
-### Updating
-
-* `componentWillReceiveProps(object nextProps)`는 마운트된 컴포넌트가 새로운 props을 받을 때 호출됩니다. 이 메소드는 `this.props`와 `nextProps`을 비교하여 `this.setState()`를 사용해 상태 변환을 수행하는데 사용되야 합니다.
-* `shouldComponentUpdate(object nextProps, object nextState): boolean`는 컴포넌트가 어떤 변경이 DOM의 업데이트를 보증하는지 결정해야 할 때 호출됩니다. 최적화하려면, React가 업데이트를 무시해야할 때 `this.props`와 `nextProps`를, `this.state`와 `nextState`를 비교해 `false`를 리턴하면 됩니다.
-* `componentWillUpdate(object nextProps, object nextState)`는 업데이트가 발생하기 직전에 호출됩니다. 이 시점에는 `this.setState()`를 호출할 수 없습니다.
-* `componentDidUpdate(object prevProps, object prevState)`는 업데이트가 발생한 후 즉시 호출됩니다.
-
-### Unmounting
-
-* `componentWillUnmount()`는 컴포넌트가 언마운트되어 파괴되기 직전에 호출됩니다. 정리(Cleanup)는 여기서 처리해야 합니다.
-
-### Mounted 메소드
-
-_마운트된_ 합성 컴포넌트들은 다음과 같은 메소드를 지원합니다:
-
-* `component.forceUpdate()`는 `this.setState()`를 사용하지 않고 변경된 컴포넌트의 상태의 변경을 적용하고 싶을 때 마운트된 컴포넌트에서 사용할 수 있습니다.
-
-## 브라우저 지원과 Polyfill
-
-페이스북에서 우리는 IE8을 포함한 구식 브라우저를 지원합니다. 미래지향적인 JS를 작성할 수 있도록 우리는 polyfill을 오랫동안 써왔습니다. 이는 우리의 코드베이스에 구식 브라우저를 위한 코드뭉치를 흩뿌려 놓을 필요가 없으며 그럼에도 우리의 코드가 "잘 작동"할 것이라 예상할 수 있음을 의미합니다. 예를 들어, `+new Date()` 대신에 그냥 `Date.now()`를 사용할 수 있습니다. 오픈소스 React는 우리가 내부에서 사용하는것과 동일하기 때문에, 우리는 이를 통해 미래지향적인 JS를 사용하는 철학을 전달했습니다.
-
-그 철학에 더하여, 우리는 또한 JS 라이브러리의 저자로서 polyfill을 라이브러리에 포함해서 배포하지 않습니다. 만약 모든 라이브러리가 이런 짓을 하면, 같은 polyfill을 여러 번 내리게 되어 쓸모없이 크기만 차지하는 죽은 코드들을 만들 것 입니다. 당신의 제품이 구식 브라우저를 지원해야한다면, [es5-shim](https://github.com/es-shims/es5-shim) 같은 녀석을 사용할 기회가 있었을 겁니다.
-
-### Polyfill은 구식 브라우저를 지원하기 위해 필요하다
-
-[kriskowal's es5-shim](https://github.com/es-shims/es5-shim)의 `es5-shim.js`는 React에 필요한 다음의 기능을 제공합니다:
-
-* `Array.isArray`
-* `Array.prototype.every`
-* `Array.prototype.forEach`
-* `Array.prototype.indexOf`
-* `Array.prototype.map`
-* `Date.now`
-* `Function.prototype.bind`
-* `Object.keys`
-* `String.prototype.split`
-* `String.prototype.trim`
-
-[kriskowal's es5-shim](https://github.com/kriskowal/es5-shim)의 `es5-sham.js`는, React에 필요한 다음의 기능도 제공합니다:
-
-* `Object.create`
-* `Object.freeze`
-
-압축되지 않은 React 빌드는 [paulmillr의 console-polyfill](https://github.com/paulmillr/console-polyfill)에서 다음의 기능이 필요합니다.
-
-* `console.*`
-
-`<section>`, `<article>`, `<nav>`, `<header>`, `<footer>`등 HTML5 엘리먼트를 IE8에서 이용하려면 [html5shiv](https://github.com/aFarkas/html5shiv)같은 스크립트가 추가로 필요합니다.
-
-### 크로스 브라우징 이슈
-
-React가 브라우저별 차이점을 썩 잘 추상화하긴 했지만 일부는 한정적이거나 우리가 발견하지 못한 이상한(quirky) 동작을 보여주기도 합니다.
-
-#### IE8에서의 onScroll 이벤트
-
-IE8에서는 `onScroll` 이벤트가 일어나지(bubble) 않으며, IE8은 이벤트의 캡쳐링 단계를 위한 핸들러를 정의하는 API를 갖고 있지 않습니다. 이는 React가 이 이벤트를 이해(listen) 할 방법이 없음을 뜻합니다. 현재 이 이벤트 핸들러는 IE8에서 무시됩니다.
-
-더 많은 정보는 [onScroll doesn't work in IE8](https://github.com/facebook/react/issues/631) GitHub 이슈를 살펴보세요.
diff --git a/docs/docs/08-working-with-the-browser.md b/docs/docs/08-working-with-the-browser.md
deleted file mode 100644
index 645f66850e9b..000000000000
--- a/docs/docs/08-working-with-the-browser.md
+++ /dev/null
@@ -1,60 +0,0 @@
----
-id: working-with-the-browser
-title: Working With the Browser
-permalink: working-with-the-browser.html
-prev: forms.html
-next: more-about-refs.html
----
-
-React provides powerful abstractions that free you from touching the DOM directly in most cases, but sometimes you simply need to access the underlying API, perhaps to work with a third-party library or existing code.
-
-## The Virtual DOM
-
-React is very fast because it never talks to the DOM directly. React maintains a fast in-memory representation of the DOM. `render()` methods actually return a *description* of the DOM, and React can compare this description with the in-memory representation to compute the fastest way to update the browser.
-
-Additionally, React implements a full synthetic event system such that all event objects are guaranteed to conform to the W3C spec despite browser quirks, and everything bubbles consistently and efficiently across browsers. You can even use some HTML5 events in older browsers that don't ordinarily support them!
-
-Most of the time you should stay within React's "faked browser" world since it's more performant and easier to reason about. However, sometimes you simply need to access the underlying API, perhaps to work with a third-party library like a jQuery plugin. React provides escape hatches for you to use the underlying DOM API directly.
-
-## Refs and findDOMNode()
-
-To interact with the browser, you'll need a reference to a DOM node. You can attach a `ref` to any element, which allows you to reference the **backing instance** of the component.  This is useful if you need to invoke imperative functions on the component, or want to access the underlying DOM nodes.  To learn more about refs, including ways to use them effectively, see our [refs to components](/react/docs/more-about-refs.html) documentation.
-
-## Component Lifecycle
-
-Components have three main parts of their lifecycle:
-
-* **Mounting:** A component is being inserted into the DOM.
-* **Updating:** A component is being re-rendered to determine if the DOM should be updated.
-* **Unmounting:** A component is being removed from the DOM.
-
-React provides lifecycle methods that you can specify to hook into this process. We provide **will** methods, which are called right before something happens, and **did** methods which are called right after something happens.
-
-### Mounting
-
-* `getInitialState(): object` is invoked before a component is mounted. Stateful components should implement this and return the initial state data.
-* `componentWillMount()` is invoked immediately before mounting occurs.
-* `componentDidMount()` is invoked immediately after mounting occurs. Initialization that requires DOM nodes should go here.
-
-### Updating
-
-* `componentWillReceiveProps(object nextProps)` is invoked when a mounted component receives new props. This method should be used to compare `this.props` and `nextProps` to perform state transitions using `this.setState()`.
-* `shouldComponentUpdate(object nextProps, object nextState): boolean` is invoked when a component decides whether any changes warrant an update to the DOM. Implement this as an optimization to compare `this.props` with `nextProps` and `this.state` with `nextState` and return `false` if React should skip updating.
-* `componentWillUpdate(object nextProps, object nextState)` is invoked immediately before updating occurs. You cannot call `this.setState()` here.
-* `componentDidUpdate(object prevProps, object prevState)` is invoked immediately after updating occurs.
-
-### Unmounting
-
-* `componentWillUnmount()` is invoked immediately before a component is unmounted and destroyed. Cleanup should go here.
-
-### Mounted Methods
-
-_Mounted_ composite components also support the following method:
-
-* `component.forceUpdate()` can be invoked on any mounted component when you know that some deeper aspect of the component's state has changed without using `this.setState()`.
-
-## Browser Support
-
-React supports most popular browsers, including Internet Explorer 9 and above.
-
-(We don't support older browsers that don't support ES5 methods, but you may find that your apps do work in older browsers if polyfills such as [es5-shim and es5-sham](https://github.com/es-shims/es5-shim) are included in the page. You're on your own if you choose to take this path.)
diff --git a/docs/docs/08-working-with-the-browser.zh-CN.md b/docs/docs/08-working-with-the-browser.zh-CN.md
deleted file mode 100644
index 0a21d85c1cb9..000000000000
--- a/docs/docs/08-working-with-the-browser.zh-CN.md
+++ /dev/null
@@ -1,97 +0,0 @@
----
-id: working-with-the-browser-zh-CN
-title: 与浏览器协作
-permalink: working-with-the-browser-zh-CN.html
-prev: forms-zh-CN.html
-next: more-about-refs-zh-CN.html
----
-
-React提供了强大的抽象机制使你在大多数情况下免于直接接触DOM，但有时你仅仅只需要访问底层API，也许是为了与第三方库或者已有的代码协作。
-
-## 虚拟DOM
-
-React非常快速是因为它从不直接操作DOM。React维持了一个快速的内存中的DOM表示。`render()` 方法实际上返回一个对DOM的*描述*，然后React能根据内存中的“描述”来比较此“描述”以计算出最快速的方法更新浏览器。
-
-此外，React实现了一个完备的合成事件(synthetic event)系统，以使得所有的事件对象都被保证符合W3C细则，而不论各个浏览器的怪癖，并且所有事件跨浏览器地一致并高效的冒泡（bubbles），你甚至能在IE8里使用一些HTML5事件！
-
-大多数时间你应该和React的"伪造浏览器"呆在一起，因为它更高性能并且容易推理。然而，有时你只需要访问底层API，或许是为了与第三方库比如一个jQuery插件协作。React为你提供了安全仓口来直接使用底层API。
-
-## Refs 和 findDOMNode()
-
-为了与浏览器互动，你需要一个指向DOM node的引用。你可以连接一个 `ref` 到任何的元素，这允许你引用 组件的 **backing instance**  。它很有用，如果你需要在组件上调用命令式函数，或者想访问底层的DOM节点。要了解很多关于 refs，包括更有效使用他们的方法，请查看我们的 [关于Refs的更多内容](/react/docs/more-about-refs-zh-CN.html) 文档。
-
-## 组件的生命周期
-
-组件的生命周期有三个主要部分：
-
-* **挂载:** 组件被注入DOM。
-* **更新:** 组件被重新渲染来决定DOM是否应被更新。
-* **卸载:** 组件从DOM中被移除。
-
-React提供生命周期方法，以便你可以指定钩挂到这个过程上。我们提供了 **will** 方法，该方法在某事发生前被调用，**did**方法，在某事发生后被调用。
-
-### 挂载
-
-* `getInitialState(): object` 在组件挂载前被调用. 有状态组件(Stateful components) 应该实现此函数并返回初始state的数据。
-* `componentWillMount()` 在挂载发生前被立即调用。
-* `componentDidMount()` 在挂载发生后被立即调用。 需要DOM node的初始化应该放在这里。
-
-### 更新
-
-* `componentWillReceiveProps(object nextProps)` 当挂载的组件接收到新的props时被调用。此方法应该被用于比较`this.props` 和 `nextProps`以用于使用`this.setState()`执行状态转换。
-* `shouldComponentUpdate(object nextProps, object nextState): boolean` 当组件决定任何改变是否要更新到DOM时被调用。作为一个优化实现比较`this.props` 和 `nextProps` 、`this.state` 和 `nextState` ，如果React应该跳过更新，返回`false`。
-* `componentWillUpdate(object nextProps, object nextState)` 在更新发生前被立即调用。你不能在此调用`this.setState()`。
-* `componentDidUpdate(object prevProps, object prevState)` 在更新发生后被立即调用。
-
-### 卸载
-
-* `componentWillUnmount()` 在组件被卸载和摧毁后被立即调用。清理应该放在这里。
-
-### 已挂载的方法
-
-_Mounted_ 复合组件同样支持以下方法:
-
-* `component.forceUpdate()` 可以在任何已挂载的组件上调用，在你知道 某些深处的组件状态被未使用 `this.setState()` 改变了时。
-
-## 浏览器支持和填充物(polyfills)
-
-在 Facebook，我们支持老浏览器，包括IE8。我们由来已久的有适当的填充物(polyfills)来让我们写前瞻性的js。这意味着我们在代码库中没有一堆散落在各处的技巧(hacks)并且我们依然能期望我们的代码"可行（just work）"。例如，我可以只写 `Date.now()`，而不是额外看到`+new Date()`。既然开源的React和我们内部使用的一样，我们也应用了这种使用前瞻性js的哲学。
-
-除了这种哲学外，我们也采用了这样的立场，我们，作为一个JS库的作者，不应该把polyfills作为我们库的一部分。如果所有的库这样做，就有很大的机会发送同样的polyfill多次，这可能是一个相当大的无用代码。如果你的产品需要支援老的浏览器，你很有可能已经在使用某些东西比如[es5-shim](https://github.com/es-shims/es5-shim)。
-
-### 需要用来支持旧浏览器的Polyfills
-
-来自 [kriskowal's es5-shim](https://github.com/es-shims/es5-shim)的`es5-shim.js`  提供了如下React需要的东西：
-
-* `Array.isArray`
-* `Array.prototype.every`
-* `Array.prototype.forEach`
-* `Array.prototype.indexOf`
-* `Array.prototype.map`
-* `Date.now`
-* `Function.prototype.bind`
-* `Object.keys`
-* `String.prototype.split`
-* `String.prototype.trim`
-
-同样来自 [kriskowal's es5-shim](https://github.com/es-shims/es5-shim)的`es5-sham.js`, 提供了如下React需要的东西：
-
-* `Object.create`
-* `Object.freeze`
-
-非最小化的React build需要如下，来自[paulmillr's console-polyfill](https://github.com/paulmillr/console-polyfill).
-
-* `console.*`
-
-当在IE8里使用HTML5元素，包括`<section>`, `<article>`, `<nav>`, `<header>`, 和 `<footer>`, 同样必须包含[html5shiv](https://github.com/aFarkas/html5shiv) 或者类似的脚本。
-
-### 跨浏览器问题
-
-尽管React在抽象浏览器不同时做的相当好，但一些浏览器被限制或者表现出怪异的行为，我们没能找到变通的方案解决。
-
-#### IE8的onScroll事件
-
-在IE8`onScroll` 事件不冒泡，并且IE8没有定义事件捕获阶段handlers的API，意味React这没有办法去监听这些事件。
-目前这个事件的handler在IE8中是被忽略的。
-
-参见 [onScroll doesn't work in IE8](https://github.com/facebook/react/issues/631) GitHub问题 来获得更多信息.
diff --git a/docs/docs/08.1-more-about-refs.it-IT.md b/docs/docs/08.1-more-about-refs.it-IT.md
deleted file mode 100644
index 2fbff0b7304f..000000000000
--- a/docs/docs/08.1-more-about-refs.it-IT.md
+++ /dev/null
@@ -1,141 +0,0 @@
----
-id: more-about-refs-it-IT
-title: Riferimenti ai Componenti
-permalink: more-about-refs-it-IT.html
-prev: working-with-the-browser-it-IT.html
-next: tooling-integration-it-IT.html
----
-Dopo aver costruito il tuo componente, potresti trovarti nella situazione di volere invocare dei metodi sulle istanze di componenti restituite da `render()`. Nella maggior parte dei casi, questo non è necessario poiché il flusso di dati reattivo assicura sempre che le proprietà più recenti siano assegnate a ciascun figlio prodotto da `render()`. Tuttavia, esistono dei casi in cui potrebbe essere necessario o desiderabile, quindi React fornisce una via d'uscita conosciuta come `refs`. Queste `refs` (riferimenti) sono particolarmente utili quando vuoi: trovare il markup DOM prodotto da un componente (ad esempio, per posizionarlo in modo assoluto), usare componenti React in una più ampia applicazione non-React, oppure effettuare la transizione del tuo codice a React.
-
-Vediamo come ottenere un ref, e quindi passiamo ad un esempio completo.
-
-## Il ref restituito da ReactDOM.render
-
-Da non confondersi con il metodo `render()` che definisci sul tuo componente (il quale restituisce un elemento DOM virtuale), [ReactDOM.render()](/react/docs/top-level-api-it-IT.html#reactdom.render) restituisce un riferimento all'**istanza di supporto** del tuo componente (o `null` per i [componenti privi di stato](/react/docs/reusable-components.html#stateless-functions)).
-
-
-```js
-var myComponent = ReactDOM.render(<MyComponent />, myContainer);
-```
-
-Tieni a mente, tuttavia, che JSX non restituisce un'istanza di un componente! È solo un **ReactElement**: una rappresentazione leggera che istruisce React su come il componente montato debba apparire.
-
-```js
-var myComponentElement = <MyComponent />; // Questo è un semplice ReactElement.
-
-// Qui va del codice...
-
-var myComponentInstance = ReactDOM.render(myComponentElement, myContainer);
-myComponentInstance.doSomething();
-```
-
-> Nota:
->
-> Questo deve essere usato soltanto al livello più alto. All'interno dei componenti, lascia che i tuoi `props` e `state` gestiscano la comunicazione con i componenti figli, oppure utilizza uno degli altri metodi per ottenere un ref (attributo stringa o callback).
-
-
-## L'Attributo ref Come Callback
-
-React supporta un attributo speciale che puoi assegnare a qualsiasi componente. L'attributo `ref` può essere una funzione callback, che sarà eseguita immediatamente dopo che il componente viene montato. Il componente referenziato sarà passato come parametro, e la funzione callback può utilizzare il componente immediatamente, oppure conservarne un riferimento per un uso successivo, o entrambe.
-
-È semplice come aggiungere un attributo `ref` a qualsiasi cosa restituita da `render` usando una funzione freccia di ES6:
-
-```js
-  render: function() {
-    return (
-      <TextInput
-        ref={function(input) {
-          if (input != null) {
-            input.focus();
-          }
-        }} />
-    );
-  },
-```
-
-oppure usando una funzione freccia ES6:
-
-```js
-  render: function() {
-    return <TextInput ref={(c) => this._input = c} />;
-  },
-  componentDidMount: function() {
-    this._input.focus();
-  },
-```
-
-Nota che quando il componente referenziato viene smontato e quando il valore di ref cambia, ref sarà chiamata con `null` come argomento. Ciò impedisce i memory leak nel caso in cui l'istanza venga conservata, come nel primo esempio. Nota che quando assegni il valore di ref a un'espressione di funzione in linea come negli esempi precedenti, React vede un oggetto funzione diverso ogni volta e pertanto in occasione di ciascun aggiornamento, ref verrà chiamata con `null` immediatamente prima di essere chiamata con l'istanza del componente.
-
-Puoi accedere al nodo DOM del componente direttamente chiamando `ReactDOM.findDOMNode(argomentoDellaTuaCallback)`.
-
-
-## L'Attributo ref Come Stringa
-
-React supporta anche l'uso di una stringa (anziché una callback) come proprietà ref su qualsiasi componente, sebbene allo stato attuale questo approccio sia quasi esclusivamente superato.
-
-1. Assegna un attributo `ref` a qualsiasi cosa restituita da `render` come:
-
-    ```html
-    <input ref="myInput" />
-    ```
-
-2. Altrove nel codice (tipicamente in un gestore di eventi), accedi all'**istanza di supporto** tramite `this.refs` come segue:
-
-    ```javascript
-    this.refs.myInput
-    ```
-
-  Puoi accedere direttamente al nodo DOM del componente chiamando `ReactDOM.findDOMNode(this.refs.myInput)`.
-
-
-## Un Esempio Completo
-Per ottenere un riferimento a un componente React, puoi usare `this` per ottenere il componente React attuale, oppure usare un ref per ottenere un riferimento a un componente di tua proprietà. Il funzionamento è il seguente:
-
-```javascript
-var MyComponent = React.createClass({
-  handleClick: function() {
-    // Assegna il focus esplicitamente al campo di testo usando l'API DOM nativa.
-    this.myTextInput.focus();
-  },
-  render: function() {
-    // L'attributo ref aggiunge un riferimento al componente a this.refs quando
-    // il componente viene montato
-    return (
-      <div>
-        <input type="text" ref={(ref) => this.myTextInput = ref} />
-        <input
-          type="button"
-          value="Assegna il focus al campo di testo"
-          onClick={this.handleClick}
-        />
-      </div>
-    );
-  }
-});
-
-ReactDOM.render(
-  <MyComponent />,
-  document.getElementById('example')
-);
-```
-
-In questo esempio, otteniamo un riferimento all'**istanza di supporto** del campo di testo e vi invochiamo il metodo `focus()` quando il bottone viene cliccato.
-
-Per componenti compositi, il riferimento si riferisce a un'istanza della classe del componente, quindi puoi invocare ogni metodo definito in tale classe. Se devi accedere al nodo DOM sottostante per il componente, puoi usare [ReactDOM.findDOMNode](/react/docs/top-level-api-it-IT.html#reactdom.finddomnode).
-
-## Riassunto
-
-I riferimenti `ref` sono la maniera corretta di inviare un messaggio a una precisa istanza di un figlio in una maniera che sarebbe impraticabile attraverso le normali proprietà `props` e `state` di React. Tuttavia, esse non dovrebbero essere la tua astrazione principale per far fluire i dati attraverso la tua applicazione. In modo predefinito, usa il flusso dati di React e utilizza i `ref` per casi d'uso che sono intrinsecamente non reattivi.
-
-### Benefici:
-
-- Puoi definire ogni metodo pubblico nelle classi dei tuoi componenti (come un metodo per reimpostare un Typeahead) e chiamare tali metodi pubblici attraverso i riferimenti (come ad esempio `this.refs.myTypeahead.reset()`).
-- Effettuare misure sul DOM richiede quasi sempre l'accesso ad un componente "nativo" come `<input />` accedendo il suo nodo DOM sottostante attraverso `ReactDOM.findDOMNode(this.refs.myInput)`. I riferimenti sono uno degli unici metodi praticabili per fare ciò in maniera affidabile.
-- I riferimenti sono gestiti automaticamente per te! Se un figlio è distrutto, anche il suo riferimento è distrutto. Pertanto non preoccuparti del consumo di memoria (a meno che tu non faccia qualcosa di folle per conservare un riferimento).
-
-### Precauzioni:
-
-- *Non accedere mai* ai riferimenti dentro il metodo render di un componente - oppure mentre il metodo render di qualsiasi componente è in esecuzione ovunque nella pila di chiamate.
-- Se vuoi preservare la resilienza al Crushing del compilatore Google Closure Compiler, assicurati di non accedere mai come proprietà a ciò che è stato specificato come stringa. Ciò significa che devi accedere come `this.refs['myRefString']` se il tuo ref è stato definito come `ref="myRefString"`.
-- Se non hai ancora programmato parecchie applicazioni con React, la tua prima inclinazione è solitamente di provare a utilizzare i riferimenti per "fare succedere qualcosa" nella tua applicazione. Se questo è il tuo caso, fermati un momento e pensa in maniera critica al luogo corretto nella gerarchia dei componenti in cui lo `state` debba trovarsi. Spesso ti accorgerai che il luogo corretto per "possedere" lo stato si trova a un livello più alto nella gerarchia. Posizionare lì lo stato spesso elimina ogni necessità di usare i `ref` per "fare accadere qualcosa" – al contrario, il flusso dei dati solitamente otterrà lo scopo desiderato.
-- I ref non possono essere assegnati a [funzioni prive di stato](/react/docs/reusable-components-it-IT.html#stateless-functions), poiché il componente non possiede un'istanza di supporto. Puoi tuttavia racchiudere un componente privo di stato in un componente composito standard e assegnare il ref al componente composito.
diff --git a/docs/docs/08.1-more-about-refs.ja-JP.md b/docs/docs/08.1-more-about-refs.ja-JP.md
deleted file mode 100644
index 1b27d6c09e78..000000000000
--- a/docs/docs/08.1-more-about-refs.ja-JP.md
+++ /dev/null
@@ -1,147 +0,0 @@
----
-id: more-about-refs
-title: 参照についての詳細
-permalink: more-about-refs-ja-JP.html
-prev: working-with-the-browser-ja-JP.html
-next: tooling-integration-ja-JP.html
-
----
-renderメソッドからUIの構成をリターンした後、あなたは「リーチアウト」を見て、renderから返ってきたコンポーネントのインスタンスの上でメソッドを実行するでしょう。多くの場合、アプリケーションにおいて、データフローを作成することは必要ではありません。リアクティブなデータフローは常に最新の `props` が `render()` から出力されたそれぞれの子要素に送られたことを保証するからです。しかし、まだ必要であったり、利益をもたらすケースもあります。
-
-`''` という空の文字列でその値をアップデートした後にフォーカスするということを `<input />` 要素（インスタンスのサブ階層に存在します）に伝えたいという場合を考えましょう。
-
-```javascript
-  var App = React.createClass({
-    getInitialState: function() {
-      return {userInput: ''};
-    },
-    handleChange: function(e) {
-      this.setState({userInput: e.target.value});
-    },
-    clearAndFocusInput: function() {
-      this.setState({userInput: ''}); // inputをクリアします
-      // ここで、<input /> にフォーカスさせたいです！
-    },
-    render: function() {
-      return (
-        <div>
-          <div onClick={this.clearAndFocusInput}>
-            Click to Focus and Reset
-          </div>
-          <input
-            value={this.state.userInput}
-            onChange={this.handleChange}
-          />
-        </div>
-      );
-    }
-  });
-```
-
-この例では、どうにかしてinputに何かを「伝え」たいということに着目してください。何かというのは、propsから推測できるものではありません。このケースでは、inputが今フォーカスされるべきであるということを「伝え」たいのです。しかし、いくつか問題があります。`render()` で返されるものは実際の「子供の」要素ではありません。しかし、特別なインスタンスにおいて子要素の *説明* を行うよりかは、スナップショットを見ていったほうがいいでしょう。
-
-> 注意:
-> `render()` からリターンされるものは *実際に* レンダリングされた子要素のインスタンスではないと覚えておいてください。 `render()` からリターンされるものは、ある特定の時点においてのコンポーネントの副階層にある単なる子要素のインスタンスの *説明* に過ぎません。
-
-これは、 `render()` からリターンされる何かを「保持し続ける」ことはできないことを意味します。そして、それは何かしら意味のあることであると予測できます。
-
-```javascript
-  // 反例: このようには記述しないでください！
-  render: function() {
-    var myInput = <input />;          // このinputの上にあるメソッドを未来のいつかの
-    this.rememberThisInput = myInput; // タイミングで呼ぼうとしています！いえいっ！
-    return (
-      <div>
-        <div>...</div>
-        {myInput}
-      </div>
-    );
-  }
-```
-
-この反例では、 `<input />` は単に `<input />` の *説明* に過ぎず、この説明は `<input />` の *現実の*  **バッキングインスタンス** を作るために使われます。
-
-では、inputの *現実の* バッキングインスタンスについて、どのように話していきましょうか？
-
-## 参照の文字列属性
-
-Reactは `render()` からの出力であるコンポーネントであれば何でもアタッチできるとても特別なプロパティをサポートしています。この特別なプロパティは `render()` からのリターンである **バッキングインスタンス** に対応したものに参照することを許可します。これはどのタイミングにおいても、固有のインスタンスであることを保証されています。
-
-これは以下のように単純です。
-
-1. 以下のように、 `render` からのリターンであれば何でも `ref` 属性をアサインする。
-
-  ```html
-  <input ref="myInput" />
-  ```
-
-2. いくつかの他のコードは（一般的にイベントハンドラのコード）、以下にあるように `this.refs` を通して **バッキングインスタンス** にアクセスします。
-
-  ```javascript
-  this.refs.myInput
-  ```
-
-`ReactDOM.findDOMNode(this.refs.myInput)` を呼ぶことで、コンポーネントのDOMノードに直接アクセスできる。
-
-## 参照のコールバック属性
-
-`ref` 属性は名前の代わりのコールバック関数になり得ます。このコールバックはコンポーネントがマウントされた直後に実行されます。参照されたコンポーネントはパラメータとして渡され、コールバック関数はコンポーネントを即座に使用するか、または将来使用するために参照を保存します（またはその両方を行います）。
-
-これは、以下のように、 `render` でリターンされてきたものに `ref` 属性をアサインするのと同じくらい簡単です。
-
-  ```html
-  <input ref={ function(component){ ReactDOM.findDOMNode(component).focus();} } />
-  ```
-
-
-## 完全な例
-
-```javascript
-  var App = React.createClass({
-    getInitialState: function() {
-      return {userInput: ''};
-    },
-    handleChange: function(e) {
-      this.setState({userInput: e.target.value});
-    },
-    clearAndFocusInput: function() {
-      // inputをクリアする
-      this.setState({userInput: ''}, function() {
-        // このコードはコンポーネントが再度レンダリングされた後に実行されます。
-        ReactDOM.findDOMNode(this.refs.theInput).focus();   // どーん！フォーカスされました！
-      });
-    },
-    render: function() {
-      return (
-        <div>
-          <div onClick={this.clearAndFocusInput}>
-            Click to Focus and Reset
-          </div>
-          <input
-            ref="theInput"
-            value={this.state.userInput}
-            onChange={this.handleChange}
-          />
-        </div>
-      );
-    }
-  });
-```
-
-この例では、レンダリング関数は `<input />` インスタンスの説明をリターンします。しかし、実際のインスタンスは `this.refs.theInput` を通してアクセスされます。 `ref="theInput"` を持つ子要素のコンポーネントが `render` からリターンされる限り、 `this.refs.theInput` は固有のインスタンスにアクセスするでしょう。これは `<Typeahead ref="myTypeahead" />` のような高階層の（DOMでない）コンポーネントでも同様に動きます。
-
-## 要約
-
-リアクティブな `props` と `state` を通してのストリーミングのアクセスは便利とは言えないため、参照は特定の子要素のインスタンスにメッセージを送るための素晴らしい方法です。しかし、それらは、アプリケーションを通したデータフローの抽象化につながるわけではありません。デフォルトで、リアクティブなデータフローを使ってください。そして、ユースケースのために `ref` を保存するのは本質的にはリアクティブではありません。
-
-### 利益:
-
-- コンポーネントクラス（例えば、Typeaheadのリセットメソッドのようなもの）にパブリックなメソッドを定義できる。また、参照（例えば、 `this.refs.myTypeahead.reset()` のように）を通してそれらのパブリックなメソッドを呼べる。
-- DOMの計測を行うことは大体いつも `<input />` のような「ネイティブの」コンポーネントや `ReactDOM.findDOMNode(this.refs.myInput)` を通した根本のDOMノードにアクセスすることを必要とします。参照は、こういったことを期待通りに行う唯一の実用的な方法です。
-- 参照は自動的に管理されます！もし子要素が削除されたら、その参照もまた削除されます。メモリに関しての心配は要りません（あなた自身が参照を維持するために何かおかしなことを行っていなければ）。
-
-### 警告:
-
-- *決して* コンポーネントのレンダリングメソッドの中の参照にアクセスしてはいけません。たとえコンポーネントのレンダリングメソッドのいずれかがコールスタックの中のどこかで動いているとしても。
-- もしGoogle Closure Compilerのクラッシュからの回復を守りたいなら、文字列として指定されたプロパティとしてアクセスしてはいけないことに気をつけてください。これは、 `ref="myRefString"` として参照が定義されている場合は、 `this.refs['myRefString']` を使ってアクセスしなければいけないことを意味します。
-- まだReactでプログラムを書いたことがない場合は、アプリケーションで「何かを起こす」ために参照を使おうとするでしょう。もしそのケースだった場合は、時間をかけて `state` がコンポーネントの階層のどこで保持されるべきか批評的に考えてください。多くの場合は、そのstateを「保持する」ための固有の場所が階層の高いレベルにあることがクリアになります。そのstateをその場所に配置することはよく「何かを起こす」ために `ref` を使うための願望を排除します。代わりに、データフローは普通、目標を達成します。
diff --git a/docs/docs/08.1-more-about-refs.ko-KR.md b/docs/docs/08.1-more-about-refs.ko-KR.md
deleted file mode 100644
index 9611c4488376..000000000000
--- a/docs/docs/08.1-more-about-refs.ko-KR.md
+++ /dev/null
@@ -1,139 +0,0 @@
----
-id: more-about-refs-ko-KR
-title: refs에서 컴포넌트로
-permalink: more-about-refs-ko-KR.html
-prev: working-with-the-browser-ko-KR.html
-next: tooling-integration-ko-KR.html
----
-컴포넌트를 빌드한 후에는 `render()`에서 반환된 컴포넌트 인스턴스에 접근하거나 메소드를 호출할 방법이 필요할 수도 있습니다. 반응적 데이터 플로우가 `render()`의 결과물에서 최신의 `props`가 각각의 자식으로 보내진 것을 항상 보장하기 때문에 애플리케이션의 데이터 플로우를 만드는데 대체로 이런 작업은 필요가 없지만, 여전히 이런 작업이 필요하거나 유리한 경우가 있긴 합니다. React는 이를 위해 `refs`라는 탈출구를 제공합니다. `refs`(레퍼런스)는 특히 다음과 같은 경우 유용합니다: 컴포넌트에 의해 렌더된 DOM 마크업을 찾을때 (인스턴스내의 절대적인 위치), 큰 프로젝트의 일부에 React 컴포넌트를 사용하는 경우 또는 기존의 코드베이스를 React로 변경하는 경우.
- 
-ref를 어떻게 얻는지 살펴보고, 예제를 완성해 봅시다.
-
-## ReactDOM.render에서 반환된 ref
-
-컴포넌트에서 정의한, 가상의 DOM 엘리먼트를 반환하는 `render()`와 헷갈리지 않도록 합니다. [ReactDOM.render()](/react/docs/top-level-api-ko-KR.html#reactdom.render)는 컴포넌트의 **지원 인스턴스(backing instance)**에 대한 참조를 반환 합니다. [상태를 가지지 않는 컴포넌트](/react/docs/reusable-components-ko-KR.html#stateless-functions)에 대해선 `null`을 반환하죠.
-
-
-```js
-var myComponent = ReactDOM.render(<MyComponent />, myContainer);
-```
- 
-명심하세요. 위의 코드는 컴포넌트 인스턴스를 반환하지 않습니다! 이는 그저 **ReactElement**:React에 마운트된 컴포넌트가 어떻게 보여야 할지 알려주는 경량의 표상(representation) 입니다.
-
-```js
-var myComponentElement = <MyComponent />; // 이건 그냥 ReactElement 입니다.
-
-// 여기 코드가 위치합니다...
-
-var myComponentInstance = ReactDOM.render(myComponentElement, myContainer);
-myComponentInstance.doSomething();
-```
-
-> 주의:
->
-> 이는 오직 최상위 레벨에서만 사용되어야 합니다. 컴포넌트의 내부에서는 `props`와 `state`가 자식 컴포넌트와 통신하도록 하거나 문자열이나 콜백 어트리뷰트 등 ref를 얻어오는 다른 방법을 사용하도록 하세요.
-
-## ref 콜백 어트리뷰트
- 
-React는 어떤 컴포넌트에든 추가할 수 있는 특별한 어트리뷰트를 제공합니다. `ref` 어트리뷰트는 콜백 함수일 수 있으며 이는 컴포넌트가 마운트 된 후 즉시 실행됩니다. 참조된 컴포넌트는 파라미터로 전달될 것이며 콜백 함수는 즉시, 혹은 미래에 사용하기 위해 컴포넌트의 참조를 저장합니다.
-
-`render`에서 반환되는 무엇에든 `ref` 어트리뷰트를 추가하는 것은 간단합니다: 
-
-```js
-  render: function() {
-    return (
-      <TextInput
-        ref={function(input) {
-          if (input != null) {
-            input.focus();
-          }
-        }} />
-    );
-  },
-```
-ES6 화살표 함수를 사용한다면 다음과 같습니다:
-
-```js
-  render: function() {
-    return <TextInput ref={(c) => this._input = c} />;
-  },
-  componentDidMount: function() {
-    this._input.focus();
-  },
-```
-
-`<div />` 같은 DOM 컴포넌트에 ref를 추가하면 DOM 노드를 얻게 됩니다; `<TextInput />` 같은 합성 컴포넌트에 ref를 추가하면 React 클래스 인스턴스를 얻게 됩니다. 후자의 경우, 클래스에 정의되어 있는 노출된 메소드를 호출할 수 있습니다.
-
-참조된 컴포넌트가 언마운트되고 ref가 변경되면 이전의 ref는 `null`을 인수로 호출됨을 주의 하세요. 이는 첫번째 예제에서처럼 인스턴트가 저장된 경우의 메모리 누수를 방지합니다. 또한 예제와 같이 ref를 인라인 함수 표현식으로 서술하게되면 React는 모든 업데이트에 대해 다른 함수 객체를 참조하게 됩니다. ref는 컴포넌트의 인스턴스의 호출 이전에  `null` 객체와 함께 즉시 호출될 것입니다.
-
-## ref 문자열 어트리뷰트
-
-React는 ref에 콜백 대신 문자열도 지원합니다 이런 접근은 이제 과거의 것이긴 합니다.
-
-
-1. `render`에서 반환된 값을 `ref` 어트리뷰트에 할당합니다:
-
-    ```html
-    <input ref="myInput" />
-    ```
-
-2. 다른 코드(일반적으로는 이벤트 핸들러 코드)에서 `this.refs`를 통해 **지원 인스턴스**에 접근 합니다:
-
-    ```javascript
-    var input = this.refs.myInput;
-    var inputValue = input.value;
-    var inputRect = input.getBoundingClientRect();
-    ```
-
-## 최종 예제
-React 컴포넌트의 참조를 얻기 위해서, 현재의 React 컴포넌트를 위해서는 `this`를, 소유한 컴포넌트에 대해서는 ref를 사용할 수 있습니다. 다음과 같이 작동 합니다:
-
-```javascript
-var MyComponent = React.createClass({
-  handleClick: function() {
-    // 명시적으로 텍스트 인풋에 포커스하기 위해 raw DOM API를 사용합니다.
-    this.myTextInput.focus();
-  },
-  render: function() {
-    // ref 어트리뷰트는 컴포넌트가 마운트되면 
-    // this.refs에 컴포넌트에 대한 참조를 추가합니다.
-    return (
-      <div>
-        <input type="text" ref={(ref) => this.myTextInput = ref} />
-        <input
-          type="button"
-          value="Focus the text input"
-          onClick={this.handleClick}
-        />
-      </div>
-    );
-  }
-});
-
-ReactDOM.render(
-  <MyComponent />,
-  document.getElementById('example')
-);
-```
-
-이 예제에서, 텍스트 인풋의 **지원 인스턴스**에 대한 참조를 얻었으며 버튼이 클릭되었을때 `focus()`를 호출했습니다.
-
-합성 컴포넌트에서는 참조는 컴포넌트 클래스의 인스턴스를 가리키기 때문에 클래스에 정의된 어떤 메소드도 호출할 수 있습니다. 컴포넌트의 기저에 있는 DOM 노드에 접근하기 위해서는 [ReactDOM.findDOMNode](/react/docs/top-level-api-ko-KR.html#reactdom.finddomnode)를 "탈출구"로 사용할 수 있습니다. 하지만 이는 캡슐화를 깨며, 대부분의 경우 React 모델을 이용해 더 명확한 방법으로 구조를 짤 수 있기 때문에 추천하지 않습니다.
- 
-
-## 요약
-
-Refs는 반응적인 `props`와 `state` 스트리밍을 통해서는 불편했던 특정한 자식 인스턴스에 메시지 보내기를 수행하는 좋은 방법입니다. 하지만 애플리케이션의 데이터 플로우 전반에 사용해도 되는 go-to 같은 개념은 아닙니다. 기본적으로는 반응적인 데이터 플로우를 사용하고, `ref`는 근본적으로 반응적이지 않은 경우에만 사용하세요.
-
-### 이점:
-
-- 컴포넌트 클래스에 public 메소드(ex. Typeahead의 reset)를 선언할 수 있으며 refs를 통해 그를 호출할 수 있습니다. (ex. `this.refs.myTypeahead.reset()`) 대부분, 이는 선언적으로 refs를 사용하는 것보다 내장 React 데이터 흐름을 명확하게 합니다.
-- DOM을 측정하기 위해서는 거의 항상 `<input />` 같은 "기본" 컴포넌트를 다루고 ref를 통해 그 기저의 DOM 노드에 접근해야 합니다. Refs는 이 일을 확실하게 수행하는 몇 안 되는 실용적인 방법의 하나입니다.
-- Refs는 자동으로 관리합니다! 자식이 파괴되면, 그의 ref도 마찬가지로 파괴됩니다. 참조를 유지하기 위해 뭔가 미친 짓을 하지 않는 한, 메모리 걱정은 하지 않아도 됩니다.
-
-### 주의:
-
-- 컴포넌트의 렌더 메소드에서는, 혹은 컴포넌트의 렌더 메소드가 콜스택 어디에서든 실행되는 동안에는 절대 접근하지 마세요.
-- Google Closure Compiler에서의 어드벤스드 모드 분쇄 복원력 유지(to preserve advanced-mode crushing resilience)를 위해서는 문자열로 정의한 것을 절대 프로퍼티로 접근하지 마세요. ref가 ref="myRefString"으로 정의되어 있다면 this.refs['myRefString']으로만 접근해야 한다는 이야기 입니다.
-- React로 앱을 여럿 만들어 본 경험이 없다면, 보통은 처음엔 앱에서 "무언가 일어나도록" 하는데 refs를 사용하게 될 것입니다. 이 경우, 잠시 시간을 내어 `state`가 컴포넌트 계층구조의 어느 부분에서 관리되어야 할지 비판적으로 생각해 봅시다. 대개는 state가 계층구조의 더 높은 레벨에서 "소유"하는 것이 타당함이 명확해집니다. 그렇게 함으로써 `ref`를 사용해 "무언가 일어나도록" 하려는 욕망이 대부분 제거됩니다. - 대신에 데이터 플로우를 통해 대개 원하는 바를 달성하게 될 것입니다.
-- Refs는 [상태를 가지지 않는 함수](/react/docs/reusable-components-ko-KR.html#stateless-functions)에 붙일 수 없습니다. 왜냐하면 컴포넌트가 내부 인스턴스를 가지지 않기 때문입니다. 상태를 가지지 않는 컴포넌트는 항상 일반 컴포넌트로 감싸 ref를 조합 컴포넌트에 붙일 수 있습니다.
diff --git a/docs/docs/08.1-more-about-refs.md b/docs/docs/08.1-more-about-refs.md
deleted file mode 100644
index 5bca86e75cb2..000000000000
--- a/docs/docs/08.1-more-about-refs.md
+++ /dev/null
@@ -1,139 +0,0 @@
----
-id: more-about-refs
-title: Refs to Components
-permalink: more-about-refs.html
-prev: working-with-the-browser.html
-next: tooling-integration.html
----
-After building your component, you may find yourself wanting to "reach out" and invoke methods on component instances returned from `render()`. In most cases, this should be unnecessary because the reactive data flow always ensures that the most recent props are sent to each child that is output from `render()`. However, there are a few cases where it still might be necessary or beneficial, so React provides an escape hatch known as `refs`. These `refs` (references) are especially useful when you need to: find the DOM markup rendered by a component (for instance, to position it absolutely), use React components in a larger non-React application, or transition your existing codebase to React.
-
-Let's look at how to get a ref, and then dive into a complete example.
-
-## The ref returned from ReactDOM.render
-
-Not to be confused with the `render()` function that you define on your component (and which returns a virtual DOM element), [ReactDOM.render()](/react/docs/top-level-api.html#reactdom.render) will return a reference to your component's **backing instance** (or `null` for [stateless components](/react/docs/reusable-components.html#stateless-functions)).
-
-
-```js
-var myComponent = ReactDOM.render(<MyComponent />, myContainer);
-```
-
-Keep in mind, however, that the JSX doesn't return a component instance! It's just a **ReactElement**: a lightweight representation that tells React what the mounted component should look like.
-
-```js
-var myComponentElement = <MyComponent />; // This is just a ReactElement.
-
-// Some code here...
-
-var myComponentInstance = ReactDOM.render(myComponentElement, myContainer);
-myComponentInstance.doSomething();
-```
-
-> Note:
->
-> This should only ever be used at the top level. Inside components, let your `props` and `state` handle communication with child components, or use one of the other methods of getting a ref (string attribute or callbacks).
-
-## The ref Callback Attribute
-
-React supports a special attribute that you can attach to any component. The `ref` attribute can be a callback function, and this callback will be executed immediately after the component is mounted. The referenced component will be passed in as a parameter, and the callback function may use the component immediately, or save the reference for future use (or both).
-
-It's as simple as adding a `ref` attribute to anything returned from `render`:
-
-```js
-  render: function() {
-    return (
-      <TextInput
-        ref={function(input) {
-          if (input != null) {
-            input.focus();
-          }
-        }} />
-    );
-  },
-```
-or using an ES6 arrow function:
-
-```js
-  render: function() {
-    return <TextInput ref={(c) => this._input = c} />;
-  },
-  componentDidMount: function() {
-    this._input.focus();
-  },
-```
-
-When attaching a ref to a DOM component like `<div />`, you get the DOM node back; when attaching a ref to a composite component like `<TextInput />`, you'll get the React class instance. In the latter case, you can call methods on that component if any are exposed in its class definition.
-
-Note that when the referenced component is unmounted and whenever the ref changes, the old ref will be called with `null` as an argument. This prevents memory leaks in the case that the instance is stored, as in the first example. Also note that when writing refs with inline function expressions as in the examples here, React sees a different function object each time so on every update, ref will be called with `null` immediately before it's called with the component instance.
-
-## The ref String Attribute
-
-React also supports using a string (instead of a callback) as a ref prop on any component, although this approach is mostly legacy at this point.
-
-1. Assign a `ref` attribute to anything returned from `render` such as:
-
-    ```html
-    <input ref="myInput" />
-    ```
-
-2. In some other code (typically event handler code), access the **backing instance** via `this.refs` as in:
-
-    ```javascript
-    var input = this.refs.myInput;
-    var inputValue = input.value;
-    var inputRect = input.getBoundingClientRect();
-    ```
-
-## A Complete Example
-In order to get a reference to a React component, you can either use `this` to get the current React component, or you can use a ref to get a reference to a component you own. They work like this:
-
-```javascript
-var MyComponent = React.createClass({
-  handleClick: function() {
-    // Explicitly focus the text input using the raw DOM API.
-    if (this.myTextInput !== null) {
-      this.myTextInput.focus();
-    }
-  },
-  render: function() {
-    // The ref attribute is a callback that saves a reference to the
-    // component to this.myTextInput when the component is mounted.
-    return (
-      <div>
-        <input type="text" ref={(ref) => this.myTextInput = ref} />
-        <input
-          type="button"
-          value="Focus the text input"
-          onClick={this.handleClick}
-        />
-      </div>
-    );
-  }
-});
-
-ReactDOM.render(
-  <MyComponent />,
-  document.getElementById('example')
-);
-```
-
-In this example, we get a reference to the text input **backing instance** and we call `focus()` when the button is clicked.
-
-For composite components, the reference will refer to an instance of the component class so you can invoke any methods that are defined on that class. If you need access to the underlying DOM node for that component, you can use [ReactDOM.findDOMNode](/react/docs/top-level-api.html#reactdom.finddomnode) as an "escape hatch" but we don't recommend it since it breaks encapsulation and in almost every case there's a clearer way to structure your code within the React model.
-
-## Summary
-
-Refs are a great way to send a message to a particular child instance in a way that would be inconvenient to do via streaming Reactive `props` and `state`. They should, however, not be your go-to abstraction for flowing data through your application. By default, use the Reactive data flow and save `ref`s for use cases that are inherently non-reactive.
-
-### Benefits:
-
-- You can define any public method on your component classes (such as a reset method on a Typeahead) and call those public methods through refs (such as `this.refs.myTypeahead.reset()`). In most cases, it's clearer to use the built-in React data flow instead of using refs imperatively.
-- Performing DOM measurements almost always requires reaching out to a "native" component such as `<input />` and accessing its underlying DOM node using a ref. Refs are one of the only practical ways of doing this reliably.
-- Refs are automatically managed for you! If that child is destroyed, its ref is also destroyed for you. No worrying about memory here (unless you do something crazy to retain a reference yourself).
-
-### Cautions:
-
-- *Never* access refs inside of any component's render method – or while any component's render method is even running anywhere in the call stack.
-- If you want to preserve Google Closure Compiler advanced-mode crushing resilience, make sure to never access as a property what was specified as a string. This means you must access using `this.refs['myRefString']` if your ref was defined as `ref="myRefString"`.
-- If you have not programmed several apps with React, your first inclination is usually going to be to try to use refs to "make things happen" in your app. If this is the case, take a moment and think more critically about where state should be owned in the component hierarchy. Often, it becomes clear that the proper place to "own" that state is at a higher level in the hierarchy. Placing the state there often eliminates any desire to use `ref`s to "make things happen" – instead, the data flow will usually accomplish your goal.
-- Refs may not be attached to a [stateless function](/react/docs/reusable-components.html#stateless-functions), because the component does not have a backing instance. You can always wrap a stateless component in a standard composite component and attach a ref to the composite component.
diff --git a/docs/docs/08.1-more-about-refs.zh-CN.md b/docs/docs/08.1-more-about-refs.zh-CN.md
deleted file mode 100644
index 7223edfda86d..000000000000
--- a/docs/docs/08.1-more-about-refs.zh-CN.md
+++ /dev/null
@@ -1,137 +0,0 @@
----
-id: more-about-refs-zh-CN
-title: 对组件的refs
-permalink: more-about-refs-zh-CN.html
-prev: working-with-the-browser-zh-CN.html
-next: tooling-integration-zh-CN.html
----
-在建立你的组件以后，你也许发现你想“接触”并且调用从 `render()`返回的组件实例上的方法。大部分情况下，这是不必要的因为响应式的数据流总是确保最近的 props 被送到每一个从 `render()` 输出的子级。然而，有一些情况下它仍旧是必要或者有益的，所以 React 提供了一个被称为 `refs` 的安全舱口。这些 `refs` （引用） 在你需要时特别有用 如：查找被组件绘制的 DOM 标记（例如，绝对定位它），使用 React 组件在一个大的非React组件里，或者转换你已有的代码库到React。
-
-让我们来看看怎样取得一个ref，然后深入完整的例子。
-
-## 从 ReactDOM.render 返回的 ref
-
-不要被 你在你的组件（它返回一个虚拟的DOM元素）里定义的 `render()` 迷惑了， [ReactDOM.render()](/react/docs/top-level-api.html#reactdom.render) 会返回一个对你的组件的 **backing instance** 的引用（或者 `null` for [stateless components](/react/docs/reusable-components.html#stateless-functions)).
-
-
-```js
-var myComponent = ReactDOM.render(<MyComponent />, myContainer);
-```
-
-记住，不管怎样，JSX不会返回一个组件的实例！它只是一个 **ReactElement**: 一个轻量级的表达，告诉React被挂载的组件应该长什么样。
-
-```js
-var myComponentElement = <MyComponent />; // 这只是一个 ReactElement.
-
-// 省略一些代码 ...
-
-var myComponentInstance = ReactDOM.render(myComponentElement, myContainer);
-myComponentInstance.doSomething();
-```
-
-> 注意:
->
-> 这只应该用在顶层上。在组件内部，让你的 `props` 和 `state` 来处理和子组件的通信，或者使用其他获取ref的方法（string attribute or callbacks）。
-
-## ref Callback 属性
-
-React支持一种非常特殊的属性，你可以附加到任何的组件上。 `ref` 属性可以是一个回调函数，这个回调函数会在组件被挂载后立即执行。被引用的组件会被作为参数传递，回调函数可以用立即使用这个组件，或者保存引用以后使用（或者二者皆是）。
-
-简单的说就是添加一个 `ref` 属性到任何从 `render` 返回的东西上：
-
-```js
-  render: function() {
-    return (
-      <TextInput
-        ref={function(input) {
-          if (input != null) {
-            input.focus();
-          }
-        }} />
-    );
-  },
-```
-或者使用ES6的箭头函数:
-
-```js
-  render: function() {
-    return <TextInput ref={(c) => this._input = c} />;
-  },
-  componentDidMount: function() {
-    this._input.focus();
-  },
-```
-
-当连接一个ref到一个DOM组件如 `<div />`，你取回DOM节点;当连接一个ref到一个复合组件如 `<TextInput />`，你会得到React类的实例。在后一种情况下，你可以调用任何那个组件的类暴露的方法。
-
-注意当被引用的组件卸载和每当ref变动，旧的ref将会被以`null`做参数调用。这阻止了在实例被保存的情况下的内存泄露，如第一个例子。注意当像在这里的例子，使用内联函数表达式写refs，React在每次更新都看到不同的函数对象，ref将会被以`null` 立即调用在它被以组件实例调用前。
-
-## ref String 属性
-
-React同样支持使用一个字符串（代替回调函数）在任意组件上作为一个 ref prop，尽管这个方法在这点上主要是遗留物。
-
-1. 赋值`ref`属性为任何从`render` 返回的东西，比如：
-
-    ```html
-    <input ref="myInput" />
-    ```
-
-2. 在其他一些代码中（典型的事件处理代码），通过`this.refs`访问 **支持实例(backing instance)**，如：
-
-    ```javascript
-    var input = this.refs.myInput;
-    var inputValue = input.value;
-    var inputRect = input.getBoundingClientRect();
-    ```
-
-## 完整的示例
-为了获取一个React组件的引用，你既可以使用 `this` 来获取当前的React组件，也可以使用一个 ref 来获取一个你拥有的组件的引用。他们像这样工作：
-
-```javascript
-var MyComponent = React.createClass({
-  handleClick: function() {
-    // Explicitly focus the text input using the raw DOM API.
-    this.myTextInput.focus();
-  },
-  render: function() {
-    // The ref attribute adds a reference to the component to
-    // this.refs when the component is mounted.
-    return (
-      <div>
-        <input type="text" ref={(ref) => this.myTextInput = ref} />
-        <input
-          type="button"
-          value="Focus the text input"
-          onClick={this.handleClick}
-        />
-      </div>
-    );
-  }
-});
-
-ReactDOM.render(
-  <MyComponent />,
-  document.getElementById('example')
-);
-```
-
-在这个例子中，我们获得一个对 text input **backing instance** 的引用 并且当按钮被点击时我们调用 `focus()`。
-
-对于复合组件，引用会指向一个组件类的实例所以你可以调用那个类定义的任何方法。如果你需要访问那个组件的底层的DOM节点，你可以使用 [ReactDOM.findDOMNode](/react/docs/top-level-api.html#reactdom.finddomnode) 作为一个 `安全舱口` 但是我们不推荐这样，因为它打破了封装，在大多数情况下都有一个清晰的方法来以React模式构建你的代码.
-
-## 总结
-
-Refs是一种很好的发送消息给特定子实例(通过流式的Reactive `props` 和 `state`来做会不方便)的方式。它们应该，不论怎样，不是你数据流通你的应用的首选。默认情况下，使用响应式数据流，并为本身不是reactive的用例保存`ref`s。
-
-### 优点:
-
-- 你可以在你的组件类里定义任何的公开方法（比如在一个Typeahead的重置方法）然后通过refs调用那些公开方法（比如`this.refs.myTypeahead.reset()`）。在大多数情况下，使用内建的React数据流更清晰，而不是使用强制的ref。
-- 实行DOM测量几乎总是需要接触到 "原生" 组件比如 `<input />` 并且通过 ref 访问它的底层DOM节点。 Refs 是唯一一个可靠的完成这件事的实际方式。
-- Refs 是为你自动管理的！如果子级被销毁了，它的ref也同样为你销毁了。这里不用担心内存（除非你做了一些疯狂的事情来自己保持一份引用）。
-
-### 注意事项:
-
-- *绝不* 在任何组件的 render 方法中访问 refs - 或者当任何组件的render方法还在调用栈上的任何地方运行时。
-- 如果你想要保留Google Closure Compiler advanced-mode crushing resilience，务必不要以属性的方式访问指明为字符串的属性。这意味这你必须用`this.refs['myRefString']`访问，如果你的ref被定义为`ref="myRefString"`。
-- 如果你没有用React写过数个程序，你的第一反应通常是打算试着用refs来在你的应用里"让事情发生"。如果是这样，花一些时间并且更精密的思考`state`应该属于组件层级的哪个位置。常常，这会变得清晰：正确的"拥有"那个属性的地方应该在层级的更高层上。把state放在那里 往往消除了任何使用`ref`s 来 "让事情发生"的渴望 - 作为替代，数据流通常将完成你的目标。
-- Refs 不能连接到一个 [stateless function（无状态函数）](/react/docs/reusable-components.html#stateless-functions)，因为这些组件没有支持实例。你总是可以包装一个无状态组件在一个标准复合组件里并且连接一个ref到这个复合组件。
diff --git a/docs/docs/09-tooling-integration.it-IT.md b/docs/docs/09-tooling-integration.it-IT.md
deleted file mode 100644
index a9e03108a5b3..000000000000
--- a/docs/docs/09-tooling-integration.it-IT.md
+++ /dev/null
@@ -1,74 +0,0 @@
----
-id: tooling-integration-it-IT
-title: Integrazione con Strumenti
-permalink: tooling-integration-it-IT.html
-prev: more-about-refs-it-IT.html
-next: addons-it-IT.html
----
-
-Ciascun progetto utilizza un sistema differente per la build e il deploy di JavaScript. Abbiamo provato a rendere React il più possibile  indipendente dall'ambiente di sviluppo.
-
-## React
-
-### React hosted su un CDN
-
-Offriamo versioni di React su CDN [nella nostra pagina dei download](/react/downloads.html). Questi file precompilati usano il formato dei moduli UMD. Inserirli con un semplice tag `<script>` inietterà una variabile globale `React` nel tuo ambiente. Questo approccio dovrebbe funzionare senza alcuna configurazione in ambienti CommonJS ed AMD.
-
-
-### Usare il ramo master
-
-Abbiamo istruzioni per compilare dal ramo `master` [nel nostro repositorio GitHub](https://github.com/facebook/react). Costruiamo un albero di moduli CommonJS sotto `build/modules` che puoi inserire in ogni ambiente o strumento di packaging che supporta CommonJS.
-
-## JSX
-
-### Trasformazione di JSX nel browser
-
-Se preferisci usare JSX, Babel fornisce un [trasformatore ES6 e JSX nel browser per lo sviluppo](http://babeljs.io/docs/usage/browser/) chiamato browser.js che può essere incluso da una release npm `babel-core` oppure da [CDNJS](http://cdnjs.com/libraries/babel-core). Includi un tag `<script type="text/babel">` per scatenare il trasformatore JSX.
-
-> Nota:
->
-> Il trasformatore JSX nel browser è piuttosto grande e risulta in calcoli aggiuntivi lato client che possono essere evitati. Non utilizzare in produzione — vedi la sezione successiva.
-
-
-### In Produzione: JSX Precompilato
-
-Se hai [npm](https://www.npmjs.com/), puoi eseguire `npm install -g babel`. Babel include il supporto per React v0.12 e v0.13. I tag sono automaticamente trasformati negli equivalenti `React.createElement(...)`, `displayName` è automaticamente desunto e aggiunto a tutte le classi React.createClass.
-
-Questo strumento tradurrà i file che usano la sintassi JSX a file in semplice JavaScript che possono essere eseguiti direttamente dal browser. Inoltre, osserverà le directory per te e trasformerà automaticamente i file quando vengono modificati; ad esempio: `babel --watch src/ --out-dir lib/`.
-
-In maniera predefinita, vengono trasformati i file JSX con un'estensione `.js`. Esegui `babel --help` per maggiori informazioni su come usare Babel.
-
-Output di esempio:
-
-```
-$ cat test.jsx
-var HelloMessage = React.createClass({
-  render: function() {
-    return <div>Ciao {this.props.name}</div>;
-  }
-});
-
-ReactDOM.render(<HelloMessage name="John" />, mountNode);
-$ babel test.jsx
-"use strict";
-
-var HelloMessage = React.createClass({
-  displayName: "HelloMessage",
-
-  render: function render() {
-    return React.createElement(
-      "div",
-      null,
-      "Hello ",
-      this.props.name
-    );
-  }
-});
-
-ReactDOM.render(React.createElement(HelloMessage, { name: "John" }), mountNode);
-```
-
-
-### Progetti Open Source Utili
-
-La comunità open source ha creato strumenti che integrano JSX con diversi editor e sistemi di build. Consulta [integrazioni JSX ](https://github.com/facebook/react/wiki/Complementary-Tools#jsx-integrations) per una lista completa.
diff --git a/docs/docs/09-tooling-integration.ja-JP.md b/docs/docs/09-tooling-integration.ja-JP.md
deleted file mode 100644
index dac8fe1e9179..000000000000
--- a/docs/docs/09-tooling-integration.ja-JP.md
+++ /dev/null
@@ -1,41 +0,0 @@
----
-id: tooling-integration
-title: インテグレーションツール
-permalink: tooling-integration-ja-JP.html
-prev: more-about-refs-ja-JP.html
-next: addons-ja-JP.html
----
-
-全てのプロジェクトがJavaScriptをビルドしたりデプロイするのに様々なシステムを使用しています。私たちはReactをできるだけ環境不問にしようとしています。
-
-## React
-
-### CDNにホストされたReact
-
-[ダウンロードページ](/react/downloads.html)でCDNにホストされたバージョンのReactが提供されています。それらの、事前にビルドされたファイルはUMDモジュールフォーマットを使用しています。簡単な `<script>` タグを使ってそれらを導入することで、あなたの環境でグローバルに `React` を使うことができます。CommonJSの外や、AMDの環境でも、それは動作するでしょう。
-
-### masterを使う
-
-[GitHubリポジトリに](https://github.com/facebook/react) `master` からビルドする説明が書いてあります。`build/modules` の下にCommonJSモジュールのツリーをビルドします。それらは、どんな環境やCommonJSがサポートされているパッケージングツールでも導入できます。
-
-## JSX
-
-### ブラウザ上でのJSXの変換
-
-JSXを使用したい場合、[ダウンロードページに](/react/downloads.html)開発のためにブラウザ上でのJSXトランスフォーマーを提供しています。単純に `<script type="text/jsx">` をインクルードすることでJSXトランスフォーマーを使用できます。
-
-> 注意:
-> ブラウザ上でのJSXトランスフォーマーをとても大きく、避けることのできるクライアントサイドの計算になりかねません。プロダクションでは使わないでください。詳細は次のセクションをご覧ください。
-
-### プロダクションで使う場合:事前にコンパイルされたJSX
-
-[npm](https://www.npmjs.com/)がインストールされている場合、コマンドラインの `jsx` ツールは単純に `npm install -g react-tools` コマンドを流せばインストールできます。このツールはJSXを使用しているファイルを直接ブラウザ上で動く生のJavaScriptファイルに変換します。また、ディレクトリをウォッチして、ファイルが変更されたら自動的に変換を行います。例えば、次のようなコマンドで。 `jsx --watch src/ build/`
-
-デフォルトで、拡張子が `.js` のJSXファイルは変換されます。拡張子が `.jsx` のファイルを変換するには `jsx --extension jsx src/ build/` コマンドを使用してください。
-
-このツールの使用方法についての詳細の情報については、 `jsx --help` コマンドを使用してください。
-
-
-### 役に立つオープンソースのプロジェクト
-
-オープンソースコミュニティがJSXをいくつかのエディタやビルドシステムで使用するためのツールを作成しました。一覧は[JSXのインテグレーション](https://github.com/facebook/react/wiki/Complementary-Tools#jsx-integrations)を参照してください。
diff --git a/docs/docs/09-tooling-integration.ko-KR.md b/docs/docs/09-tooling-integration.ko-KR.md
deleted file mode 100644
index db7722074bcb..000000000000
--- a/docs/docs/09-tooling-integration.ko-KR.md
+++ /dev/null
@@ -1,80 +0,0 @@
----
-id: tooling-integration-ko-KR
-title: 툴 통합
-permalink: tooling-integration-ko-KR.html
-prev: more-about-refs-ko-KR.html
-next: addons-ko-KR.html
----
-
-모든 프로젝트는 JavaScript를 빌드, 배포할 때 다른 시스템을 사용합니다. 우리는 가능한 한 React를 환경에 구속받지 않도록 하려 노력했습니다.
-
-## React
-
-### CDN-호스트 React
-
-[다운로드 페이지](/react/downloads.html)에서 React의 CDN 호스트 버전을 제공합니다. 이 미리 빌드된 파일들은 UMD 모듈 포맷을 사용합니다. 간단한 `<script>` 태그로 넣어보면 `React` 글로벌이 환경으로 주입(inject)될 것입니다. CommonJS와 AMD환경에서 별도의 작업 없이도 동작해야 합니다.
-
-
-### master 사용하기
-
-[GitHub 저장소](https://github.com/facebook/react)의 `master`에 빌드 방법이 있습니다. 이는 `build/modules`에 CommonJS 모듈 트리를 빌드합니다. 이는 CommonJS를 지원하는 어떤 환경이나 패키징 툴에도 넣을 수 있습니다.
-
-## JSX
-
-### 브라우저에서 JSX 변환
-
-JSX를 사용하신다면, Babel에서 browser.js라는 [개발용 브라우저 ES6, JSX 변환기](http://babeljs.io/docs/usage/browser/)를 제공합니다. 이는 `babel-core`의 npm 릴리스나 [CDNJS](http://cdnjs.com/libraries/babel-core)로 넣을 수 있습니다. `<script type="text/babel">`를 넣으면 JSX 변환기가 작동합니다.
-
-> 주의:
->
-> 브라우저 JSX 변환기는 꽤 크고 안 할 수도 있는 클라이언트 측 연산을 하게 됩니다. 프로덕션 환경에서 사용하지 마시고, 다음 단락을 보세요.
-
-
-### 상용화하기: 미리 컴파일된 JSX
-
-[npm](https://www.npmjs.com/) 모듈을 가지고 있다면, `npm install -g babel-cli`를 실행할 수 있습니다. Babel은 React v0.12이상을 내장 지원합니다. 태그는 자동적으로 동등한 `React.createElement(...)`로 변환되며, `displayName`은 모든 `React.createClass` 호출에 자동으로 추론, 추가됩니다.
-
-이 툴은 JSX 구문을 일반적인 JavaScript파일로 변환해 브라우져에서 바로 실행할 수 있도록 합니다. 디렉터리를 감시해 파일이 변경되었을 때 자동으로 변환하도록 할 수도 있습니다. 예를 들면 `babel --watch src/ --out-dir lib/` 이렇게요.
-
-Babel 6부터 기본값으로 변환기가 포함되지 않게 되었습니다. 이는 `babel` 명령을 실행할 때나 `.babelrc`에 반드시 옵션을 지정해야 한다는 뜻입니다. React를 사용할 때 가장 일반적인 방법은 `es2015`, `react` 프리셋을 사용하는 것입니다. Babel의 변경에 대한 좀 더 자세한 정보는 [블로그에 올라온 Babel 6 공지 글](http://babeljs.io/blog/2015/10/29/6.0.0/)을 읽어보세요.
-
-ES2015 문법과 React를 사용하려 할 경우의 예제입니다.
-
-```
-npm install babel-preset-es2015 babel-preset-react
-babel --presets es2015,react --watch src/ --out-dir lib/
-```
-
-기본적으로는 JSX 파일들은 `.js` 확장자로 변환됩니다. 바벨을 어떻게 사용하는지 더 자세하게 알고싶으시면 `babel --help`를 실행해 보세요.
-
-출력 예:
-
-```
-$ cat test.jsx
-var HelloMessage = React.createClass({
-  render: function() {
-    return <div>Hello {this.props.name}</div>;
-  }
-});
-
-ReactDOM.render(<HelloMessage name="John" />, mountNode);
-$ babel test.jsx
-"use strict";
-var HelloMessage = React.createClass({
-  displayName: "HelloMessage",
-  render: function render() {
-    return React.createElement(
-      "div",
-      null,
-      "Hello ",
-      this.props.name
-    );
-  }
-});
-
-ReactDOM.render(React.createElement(HelloMessage, { name: "John" }), mountNode);
-```
-
-### 도움되는 오픈소스 프로젝트들
-
-오픈 소스 커뮤니티는 JSX와 연동하는 여러 에디터와 빌드 시스템을 만들었습니다. 전 목록은 [JSX 연동](https://github.com/facebook/react/wiki/Complementary-Tools#jsx-integrations)에서 보세요.
diff --git a/docs/docs/09-tooling-integration.md b/docs/docs/09-tooling-integration.md
deleted file mode 100644
index 8c90f512b9b1..000000000000
--- a/docs/docs/09-tooling-integration.md
+++ /dev/null
@@ -1,80 +0,0 @@
----
-id: tooling-integration
-title: Tooling Integration
-permalink: tooling-integration.html
-prev: more-about-refs.html
-next: addons.html
----
-
-Every project uses a different system for building and deploying JavaScript. We've tried to make React as environment-agnostic as possible.
-
-## React
-
-### CDN-hosted React
-
-We provide CDN-hosted versions of React [on our download page](/react/downloads.html). These pre-built files use the UMD module format. Dropping them in with a simple `<script>` tag will inject a `React` global into your environment. It should also work out-of-the-box in CommonJS and AMD environments.
-
-### Using master
-
-We have instructions for building from `master` [in our GitHub repository](https://github.com/facebook/react). We build a tree of CommonJS modules under `build/modules` which you can drop into any environment or packaging tool that supports CommonJS.
-
-## JSX
-
-### In-browser JSX Transform
-
-If you like using JSX, Babel 5 provided an in-browser ES6 and JSX transformer for development called browser.js that can be included from [CDNJS](http://cdnjs.com/libraries/babel-core/5.8.34). Include a `<script type="text/babel">` tag to engage the JSX transformer.
-
-> Note:
->
-> The in-browser JSX transformer is fairly large and results in extraneous computation client-side that can be avoided. Do not use it in production — see the next section.
-
-### Productionizing: Precompiled JSX
-
-If you have [npm](https://www.npmjs.com/), you can run `npm install -g babel-cli`. Babel has built-in support for React v0.12+. Tags are automatically transformed to their equivalent `React.createElement(...)`, `displayName` is automatically inferred and added to all `React.createClass` calls.
-
-This tool will translate files that use JSX syntax to plain JavaScript files that can run directly in the browser. It will also watch directories for you and automatically transform files when they are changed; for example: `babel --watch src/ --out-dir lib/`.
-
-Beginning with Babel 6, there are no transforms included by default. This means that options must be specified when running the `babel` command, or a `.babelrc` must specify options. Additional packages must also be installed which bundle together a number of transforms, called presets. The most common use when working with React will be to include the `es2015` and `react` presets. More information about the changes to Babel can be found in [their blog post announcing Babel 6](http://babeljs.io/blog/2015/10/29/6.0.0/).
-
-Here is an example of what you will do if using ES2015 syntax and React:
-
-```
-npm install babel-preset-es2015 babel-preset-react
-babel --presets es2015,react --watch src/ --out-dir lib/
-```
-
-By default JSX files with a `.js` extension are transformed. Run `babel --help` for more information on how to use Babel.
-
-Example output:
-
-```
-$ cat test.jsx
-var HelloMessage = React.createClass({
-  render: function() {
-    return <div>Hello {this.props.name}</div>;
-  }
-});
-
-ReactDOM.render(<HelloMessage name="John" />, mountNode);
-$ babel test.jsx
-"use strict";
-
-var HelloMessage = React.createClass({
-  displayName: "HelloMessage",
-
-  render: function render() {
-    return React.createElement(
-      "div",
-      null,
-      "Hello ",
-      this.props.name
-    );
-  }
-});
-
-ReactDOM.render(React.createElement(HelloMessage, { name: "John" }), mountNode);
-```
-
-### Helpful Open-Source Projects
-
-The open-source community has built tools that integrate JSX with several editors and build systems. See [JSX integrations](https://github.com/facebook/react/wiki/Complementary-Tools#jsx-integrations) for the full list.
diff --git a/docs/docs/09-tooling-integration.zh-CN.md b/docs/docs/09-tooling-integration.zh-CN.md
deleted file mode 100644
index 3471219e564a..000000000000
--- a/docs/docs/09-tooling-integration.zh-CN.md
+++ /dev/null
@@ -1,80 +0,0 @@
----
-id: tooling-integration-zh-CN
-title: 工具集成
-permalink: tooling-integration-zh-CN.html
-prev: more-about-refs-zh-CN.html
-next: addons-zh-CN.html
----
-
-每个项目使用一个不同的系统来建立和部署JavaScript.我们努力使React尽可能环境无关。
-
-## React
-
-### CDN-hosted React
-
-我们提供了CDN-hosted版本的React[在我们的下载页面](/react/downloads.html).这些预构建的文件使用UMD模块格式。将他们放进一个简单的`<script>` 标签将会注入一个`React` 全局变量到你的环境里。这也同样在CommonJS 和 AMD 环境里开箱即用。
-
-### 使用 master
-
-我们[在我们的 GitHub repository](https://github.com/facebook/react)有从`master`构建的说明。我们在`build/modules` 下构建了一个CommonJS模块的树，你可以把它放到任何支持CommonJS的环境或者打包工具里。
-
-## JSX
-
-### 浏览器中的JSX转化
-
-如果你喜欢使用JSX，Babel5 提供了被称为browser.js 用于开发的一个浏览器内的 ES6 和 JSX 转换器，它可以从 [CDNJS](http://cdnjs.com/libraries/babel-core/5.8.34) 引用。Include `<script type="text/babel">` 标记来使用 JSX 转换器.
-
-> 注意:
->
-> 浏览器中的JSX转换器相当大并且导致额外的本可避免的客户端计算。不要在生产环境中使用 - 见下一节。
-
-### 投入生产: 预编译 JSX
-
-如果你有[npm](https://www.npmjs.com/)，你可以运行 `npm install -g babel-cli`. Babel 对React v0.12+ 有内建支持。 标签被自动转化为它们的等价物`React.createElement(...)`, `displayName` 被自动推断并添加到所有的React.createClass 调用。
-
-这个工具会把使用JSX语法的文件转化为简单的可直接在浏览器运行的JavaScript文件。它同样将为你监视目录并自动转化文件当他们变动时；例如：`babel --watch src/ --out-dir lib/`.
-
-从 Babel 6 开始，默认不再包含转换。这意味这必须在运行 `babel` 命令时指定选项，或者 `.babelrc` 必须指定选项。附加的捆绑了一大批转化的包(presets)也同样需要被安装.协同React工作最常用的是 `es2015` 和 `react` presets.更多关于 Babel 变化的信息可以在 [Babel 6 博客发布的信息](http://babeljs.io/blog/2015/10/29/6.0.0/)上找到.
-
-这里是一个要使用ES2015 语法和 React 你该怎样做的例子：
-
-```
-npm install babel-preset-es2015 babel-preset-react
-babel --presets es2015,react --watch src/ --out-dir lib/
-```
-
-默认模式下带有`.js`后缀的JSX文件被转化。运行 `babel --help` 获取更多关于如何使用 Babel 的信息。
-
-输出的例子：
-
-```
-$ cat test.jsx
-var HelloMessage = React.createClass({
-  render: function() {
-    return <div>Hello {this.props.name}</div>;
-  }
-});
-
-ReactDOM.render(<HelloMessage name="John" />, mountNode);
-$ babel test.jsx
-"use strict";
-
-var HelloMessage = React.createClass({
-  displayName: "HelloMessage",
-
-  render: function render() {
-    return React.createElement(
-      "div",
-      null,
-      "Hello ",
-      this.props.name
-    );
-  }
-});
-
-ReactDOM.render(React.createElement(HelloMessage, { name: "John" }), mountNode);
-```
-
-### 有帮助的开源项目
-
-开源社区已经创建了一些集成JSX到数个编辑器和构建系统的工具。全部列表请见[JSX integrations](https://github.com/facebook/react/wiki/Complementary-Tools#jsx-integrations) 。
diff --git a/docs/docs/10-addons.it-IT.md b/docs/docs/10-addons.it-IT.md
deleted file mode 100644
index 51c06f3b1d6e..000000000000
--- a/docs/docs/10-addons.it-IT.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-id: addons-it-IT
-title: Add-ons
-permalink: addons-it-IT.html
-prev: tooling-integration-it-IT.html
-next: animation-it-IT.html
----
-
-`React.addons` è il luogo in cui parcheggiamo utili strumenti per costruire applicazioni React. **Questi strumenti devono essere considerati sperimentali** ma saranno eventualmente inclusi nel nucleo o una libreria ufficiale di utilities:
-
-- [`TransitionGroup` e `CSSTransitionGroup`](animation-it-IT.html), per gestire animazioni e transizioni che sono solitamente difficili da implementare, come ad esempio prima della rimozione di un componente.
-- [`LinkedStateMixin`](two-way-binding-helpers-it-IT.html), per semplificare la coordinazione tra lo stato del componente e l'input dell'utente in un modulo.
-- [`cloneWithProps`](clone-with-props-it-IT.html), per eseguire una copia superficiale di componenti React e cambiare le loro proprietà.
-- [`createFragment`](create-fragment-it-IT.html), per creare un insieme di figli con chiavi esterne.
-- [`update`](update-it-IT.html), una funzione di utilità che semplifica la gestione di dati immutabili in JavaScript.
-- [`PureRenderMixin`](pure-render-mixin-it-IT.html), un aiuto per incrementare le prestazioni in certe situazioni.
-
-Gli add-ons elencati di seguito si trovano esclusivamente nella versione di sviluppo (non minificata) di React:
-
-- [`TestUtils`](test-utils-it-IT.html), semplici helper per scrivere dei test case (soltanto nella build non minificata).
-- [`Perf`](perf-it-IT.html), per misurare le prestazioni e fornirti suggerimenti per l'ottimizzazione.
-
-Per ottenere gli add-on, usa `react-with-addons.js` (e la sua controparte non minificata) anziché il solito `react.js`.
-
-Quandi si usa il pacchetto react di npm, richiedi semplicemente `require('react/addons')` anziché `require('react')` per ottenere React con tutti gli add-on.
diff --git a/docs/docs/10-addons.ja-JP.md b/docs/docs/10-addons.ja-JP.md
deleted file mode 100644
index df9b68b64589..000000000000
--- a/docs/docs/10-addons.ja-JP.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-id: addons
-title: アドオン
-permalink: addons-ja-JP.html
-prev: tooling-integration-ja-JP.html
-next: animation-ja-JP.html
----
-
-`React.addons` はReactのアプリケーションを作成する上で便利なユーティリティを置いておくための場所です。 **それらは実験的なものであると考えられるべきです。** しかし、ゆくゆくはコアに入ってくるか、以下のような承認されたユーティリティとなるでしょう。
-
-- アニメーションや推移を扱う[`TransitionGroup` や `CSSTransitionGroup`](animation-ja-JP.html)は多くの場合実行するのが簡単ではありません。例えば、コンポーネントの削除の前などは。
-- [`LinkedStateMixin`](two-way-binding-helpers-ja-JP.html)はユーザのフォームの入力データとコンポーネントのstateの間の調整を単純化します。
-- [`cloneWithProps`](clone-with-props-ja-JP.html)はReactのコンポーネントのシャローコピーを作成したり、それらのpropsを変更したりします。
-- [`createFragment`](create-fragment-ja-JP.html)は外部のキー化された子要素のセットを作成します。
-- [`update`](update-ja-JP.html)はJavaScriptでイミュータブルなデータを扱うことを簡単にするヘルパーの関数です。
-- [`PureRenderMixin`](pure-render-mixin-ja-JP.html)は特定のシチュエーションでパフォーマンスを改善します。
-以下のアドオンはReactだけの開発版（縮小されていない版）です。
-
-- [`TestUtils`](test-utils-ja-JP.html)はテストケースを記述する単純なヘルパーです（縮小されていないビルドのみ）。
-- [`Perf`](perf-ja-JP.html)はパフォーマンスを測り、どこを最適化するかのヒントを与えます。
-
-アドオンを使うには、共通の `react.js` を使うよりも `react-with-addons.js` （とその縮小されたもの）を使ってください。
-
-npmからReactのパッケージを使う際には、Reactと全てのアドオンを使うために `require('react')` を使う代わりに、単純に `require('react/addons')` を使ってください。
diff --git a/docs/docs/10-addons.ko-KR.md b/docs/docs/10-addons.ko-KR.md
deleted file mode 100644
index 86339f2ffc6e..000000000000
--- a/docs/docs/10-addons.ko-KR.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-id: addons-ko-KR
-title: 애드온
-permalink: addons-ko-KR.html
-prev: tooling-integration-ko-KR.html
-next: animation-ko-KR.html
----
-
-React 애드온은 React 앱을 만드는 데 유용한 유틸리티의 모음입니다. **실험적인 기능으로 취급해야 하고** 코어보다 더 자주 변경될 수 있습니다.
-
-- [`TransitionGroup` 과 `CSSTransitionGroup`](animation-ko-KR.html)은 예를 들면 컴포넌트 삭제 직전의 트랜지션 처럼, 구현하기 까다로운 애니메이션과 트랜지션을 다룹니다.
-- [`LinkedStateMixin`](two-way-binding-helpers-ko-KR.html)는 사용자 입력과 컴포넌트의 state사이의 조정(coordination)을 단순화 합니다.
-- [`cloneWithProps`](clone-with-props-ko-KR.html)는 React 컴포넌트를 얕은 복사를 하고 props를 변경합니다.
-- [`createFragment`](create-fragment-ko-KR.html)는 외부에서 키가 할당된 자식들의 모음을 만듭니다.
-- [`update`](update-ko-KR.html)는 JavaScript안에서 불변 데이터를 다루기 쉽게하는 헬퍼 함수입니다.
-- [`PureRenderMixin`](pure-render-mixin-ko-KR.html)는 특정 상황에서 성능을 향상시켜 줍니다.
-
-밑에 있는 애드온은 React 개발 (압축되지 않은) 버전에서만 사용가능 합니다.
-
-- [`TestUtils`](test-utils-ko-KR.html)는 테스트 케이스를 적기 위한 간단한 헬퍼입니다. (압축되지 않은 빌드에서만 사용가능)
-- [`Perf`](perf-ko-KR.html)는 성능을 측정하고, 최적화를 위한 힌트를 제공합니다.
-
-애드온을 쓰려면, npm에서 각각 설치하세요.(예를 들면, `npm install react-addons-pure-render-mixin`) npm을 사용하지 않는 애드온 사용법에 대한 지원은 없습니다.
diff --git a/docs/docs/10-addons.md b/docs/docs/10-addons.md
deleted file mode 100644
index 1cf0294cfffa..000000000000
--- a/docs/docs/10-addons.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-id: addons
-title: Add-ons
-permalink: addons.html
-prev: tooling-integration.html
-next: animation.html
----
-
-The React add-ons are a collection of useful utility modules for building React apps. **These should be considered experimental** and tend to change more often than the core.
-
-- [`TransitionGroup` and `CSSTransitionGroup`](animation.html), for dealing with animations and transitions that are usually not simple to implement, such as before a component's removal.
-- [`LinkedStateMixin`](two-way-binding-helpers.html), to simplify the coordination between user's form input data and the component's state.
-- [`cloneWithProps`](clone-with-props.html), to make shallow copies of React components and change their props.
-- [`createFragment`](create-fragment.html), to create a set of externally-keyed children.
-- [`update`](update.html), a helper function that makes dealing with immutable data in JavaScript easier.
-- [`PureRenderMixin`](pure-render-mixin.html), a performance booster under certain situations.
-- [`shallowCompare`](shallow-compare.html), a helper function that performs a shallow comparison for props and state in a component to decide if a component should update.
-
-The add-ons below are in the development (unminified) version of React only:
-
-- [`TestUtils`](test-utils.html), simple helpers for writing test cases.
-- [`Perf`](perf.html), a performance profiling tool for finding optimization opportunities.
-
-To get the add-ons, install them individually from npm (e.g., `npm install react-addons-pure-render-mixin`). We don't support using the addons if you're not using npm.
diff --git a/docs/docs/10-addons.zh-CN.md b/docs/docs/10-addons.zh-CN.md
deleted file mode 100644
index 468373b7b5d5..000000000000
--- a/docs/docs/10-addons.zh-CN.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-id: addons-zh-CN
-title: 插件
-permalink: addons-zh-CN.html
-prev: tooling-integration-zh-CN.html
-next: animation-zh-CN.html
----
-
-React插件是一系列的用来构建 React app的有用模块。 **这些应该被认为是实验性的** 并趋向于比core变动更频繁。
-
-- [`TransitionGroup` 和 `CSSTransitionGroup`](animation.html), 用来处理通常不能简单实现的动画和转换，比如在组件移除之前。
-- [`LinkedStateMixin`](two-way-binding-helpers.html), 简化用户的表单输入数据与组件状态的协调。
-- [`cloneWithProps`](clone-with-props.html), 创建React组件的浅拷贝并改变它们的props。
-- [`createFragment`](create-fragment.html), 创建一组外键的子级。
-- [`update`](update.html), 一个使不可变数据在JavaScript里更易处理的辅助函数。
-- [`PureRenderMixin`](pure-render-mixin.html), 一个特定情况下的性能优化器。
-- [`shallowCompare`](shallow-compare.html), 一个辅助函数，用来对 props 和 state在组件里 执行浅比较 以决定一个组件是否应该更新。
-
-下面的插件只存在开发版(未压缩)React中：
-
-- [`TestUtils`](test-utils.html), 用于写测试用例的简单的辅助工具。
-- [`Perf`](perf.html), 一个用于查找优化机会的性能分析工具。
-
-要获取插件，单独从npm安装他们(例如 `npm install react-addons-pure-render-mixin`).我们不支持使用插件如果你没有用npm.
diff --git a/docs/docs/10.1-animation.it-IT.md b/docs/docs/10.1-animation.it-IT.md
deleted file mode 100644
index 609b1c28a90e..000000000000
--- a/docs/docs/10.1-animation.it-IT.md
+++ /dev/null
@@ -1,252 +0,0 @@
----
-id: animation-it-IT
-title: Animazioni
-permalink: animation-it-IT.html
-prev: addons-it-IT.html
-next: two-way-binding-helpers-it-IT.html
----
-
-React offre un componente addon `ReactTransitionGroup` come una API di basso livello per le animazioni, e un `ReactCSSTransitionGroup` per implementare facilmente animazioni e transizioni CSS di base.
-
-## API di Alto Livello: `ReactCSSTransitionGroup`
-
-`ReactCSSTransitionGroup` è basato su `ReactTransitionGroup` ed è una maniera semplice di effettuare transizioni e animazioni CSS quando un componente React viene aggiunto o rimosso dal DOM. È ispirato all'eccellente libreria [ng-animate](http://www.nganimate.org/).
-
-### Per Cominciare
-
-`ReactCSSTransitionGroup` è l'interfaccia a `ReactTransitions`. Questo è un semplice elemento che racchiude tutti i componenti che desideri animare. Ecco un esempio in cui facciamo apparire e scomparire gli elementi di una lista.
-
-```javascript{28-30}
-var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
-
-var TodoList = React.createClass({
-  getInitialState: function() {
-    return {items: ['ciao', 'mondo', 'clicca', 'qui']};
-  },
-  handleAdd: function() {
-    var newItems =
-      this.state.items.concat([prompt('Scrivi del testo')]);
-    this.setState({items: newItems});
-  },
-  handleRemove: function(i) {
-    var newItems = this.state.items;
-    newItems.splice(i, 1);
-    this.setState({items: newItems});
-  },
-  render: function() {
-    var items = this.state.items.map(function(item, i) {
-      return (
-        <div key={item} onClick={this.handleRemove.bind(this, i)}>
-          {item}
-        </div>
-      );
-    }.bind(this));
-    return (
-      <div>
-        <button onClick={this.handleAdd}>Aggiungi Elemento</button>
-        <ReactCSSTransitionGroup transitionName="example" transitionEnterTimeout={500} transitionLeaveTimeout={300}>
-          {items}
-        </ReactCSSTransitionGroup>
-      </div>
-    );
-  }
-});
-```
-> Nota:
->
-> Devi fornire [l'attributo `key`](/react/docs/multiple-components.html#dynamic-children) per tutti i figli di `ReactCSSTransitionGroup`, anche quando stai visualizzando un singolo elemento. Questo è il modo in cui React determina quali figli sono stati aggiunti, rimossi, o sono rimasti.
-
-In questo componente, quando un nuovo elemento viene aggiunto a `ReactCSSTransitionGroup` riceverà la classe CSS `example-enter` e la classe CSS `example-enter-active` allo scatto successivo. Questa è una convenzione basata sul valore della proprietà `transitionName`.
-
-Puoi usare queste classi per scatenare una animazione o transizione CSS. Ad esempio, prova ad aggiungere questo CSS e aggiungere un nuovo elemento alla lista:
-
-```css
-.example-enter {
-  opacity: 0.01;
-}
-
-.example-enter.example-enter-active {
-  opacity: 1;
-  transition: opacity 500ms ease-in;
-}
-
-.example-leave {
-  opacity: 1;
-}
-
-.example-leave.example-leave-active {
-  opacity: 0.01;
-  transition: opacity 300ms ease-in;
-}
-```
-
-Ti accorgerai che la durata delle animazioni devono essere specificate sia nel CSS che nel metodo render; questo suggerisce a React quando rimuovere le classi di animazione dall'elemento e -- se sta venendo rimosso -- quando rimuovere l'elemento dal DOM.
-
-### Animare il Montaggio Iniziale
-
-`ReactCSSTransitionGroup` fornisce la proprietà opzionale `transitionAppear`, per aggiungere una fase aggiuntiva di transizione al montaggio iniziale del componente. In genere non c'è alcuna fase di transizione al montaggio iniziale in quanto il valore predefinito di `transitionAppear` è `false`. L'esempio seguente passa la proprietà `transitionAppear` con il valore `true`.
-
-```javascript{3-5}
-  render: function() {
-    return (
-      <ReactCSSTransitionGroup transitionName="example" transitionAppear={true} transitionAppearTimeout={500}>
-        <h1>Dissolvenza al Montaggio Iniziale</h1>
-      </ReactCSSTransitionGroup>
-    );
-  }
-```
-
-Durante il montaggio iniziale `ReactCSSTransitionGroup` otterrà la classe CSS `example-appear` e la classe CSS `example-appear-active` allo scatto successivo.
-
-```css
-.example-appear {
-  opacity: 0.01;
-}
-
-.example-appear.example-appear-active {
-  opacity: 1;
-  transition: opacity .5s ease-in;
-}
-```
-
-Al montaggio iniziale, tutti i figli di `ReactCSSTransitionGroup` saranno marcati come `appear` ma non `enter`. Tuttavia, tutti i figli aggiunti in seguito ad un `ReactCSSTransitionGroup` esistente saranno marcati come `enter` ma non `appear`.
-
-> Nota:
->
-> La proprietà `transitionAppear` è stata aggiunta a `ReactCSSTransitionGroup` nella versione `0.13`. Per mantenere la compatibilità con le versioni precedenti, il valore predefinito è impostato a `false`.
-
-### Classi Personalizzate
-
-È anche possibile usare nomi di classi personalizzate per ciascuna delle fasi delle tue transizioni. Anziché passare una stringa come valore di `transitionName` puoi assegnare un oggetto che contiene i nomi delle classi `enter` o `leave`, oppure un oggetto contenente i nomi delle classi per `enter`, `enter-active`, `leave-active`e  `leave`. Se vengono forniti soltanto i nomi delle classi enter e leave, le classi per enter-active e leave-active saranno determinate aggiungendo il suffisso '-active' ai rispettivi nomi delle classi. Ecco due esempi che usano le classi personalizzate:
-
-```javascript
-  ...
-  <ReactCSSTransitionGroup
-    transitionName={ {
-      enter: 'enter',
-      enterActive: 'enterActive',
-      leave: 'leave',
-      leaveActive: 'leaveActive',
-      appear: 'appear',
-      appearActive: 'appearActive'
-    } }>
-    {item}
-  </ReactCSSTransitionGroup>
-
-  <ReactCSSTransitionGroup
-    transitionName={ {
-      enter: 'enter',
-      leave: 'leave',
-      appear: 'appear'
-    } }>
-    {item2}
-  </ReactCSSTransitionGroup>
-  ...
-```
-
-### I Gruppi di Animazioni Devono Essere Montati per Funzionare
-
-Per applicare le transizioni ai suoi figli, il `ReactCSSTransitionGroup` deve già essere montato nel DOM oppure la proprietà `transitionAppear` deve essere impostata a `true`. L'esempio seguente non funziona, poiché `ReactCSSTransitionGroup` sta venendo montato assieme al nuovo elemento, anziché il nuovo elemento venire montato dentro di esso. Confronta questo esempio con la sezione precedente [Per Cominciare](#getting-started) per notare la differenza.
-
-```javascript{12-15}
-  render: function() {
-    var items = this.state.items.map(function(item, i) {
-      return (
-        <div key={item} onClick={this.handleRemove.bind(this, i)}>
-          <ReactCSSTransitionGroup transitionName="example">
-            {item}
-          </ReactCSSTransitionGroup>
-        </div>
-      );
-    }, this);
-    return (
-      <div>
-        <button onClick={this.handleAdd}>Aggiungi Elemento</button>
-        {items}
-      </div>
-    );
-  }
-```
-
-### Animare Uno o Nessun Elemento
-
-Nell'esempio precedente, abbiamo visualizzato una lista di elementi in `ReactCSSTransitionGroup`. Tuttavia, i figli di `ReactCSSTransitionGroup` possono anche essere un solo o nessun elemento. Questo rende possibile animare un singolo elemento che viene aggiunto o rimosso. Similarmente, puoi animare un nuovo elemento che sistituisce l'elemento corrente. Ad esempio, possiamo implementare un semplice carosello di immagini come segue:
-
-```javascript{10-12}
-var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
-
-var ImageCarousel = React.createClass({
-  propTypes: {
-    imageSrc: React.PropTypes.string.isRequired
-  },
-  render: function() {
-    return (
-      <div>
-        <ReactCSSTransitionGroup transitionName="carousel" transitionEnterTimeout={300} transitionLeaveTimeout={300}>
-          <img src={this.props.imageSrc} key={this.props.imageSrc} />
-        </ReactCSSTransitionGroup>
-      </div>
-    );
-  }
-});
-```
-
-### Disattivare le Animazioni
-
-Se lo desideri, puoi disattivare le animazioni `enter` o `leave`. Ad esempio, a volte potresti volere un'animazione per `enter` ma non una per `leave`, ma `ReactCSSTransitionGroup` attende che l'animazione sia completata prima di rimuovere il tuo nodo DOM. Puoi aggiungere le proprietà `transitionEnter={false}` o `transitionLeave={false}` a `ReactCSSTransitionGroup` per disattivare le rispettive animazioni.
-
-> Nota:
->
-> Quando si usa `ReactCSSTransitionGroup`, non c'è alcun modo per cui i tuoi componenti vengano avvisati quando la transizione è terminata o per effettuare una logica complessa durante l'animazione. Se vuoi un controllo più fine, puoi usare la API di basso livello `ReactTransitionGroup` che fornisce degli hook che puoi utilizzare per effettuare transizioni personalizzate.
-
-## API di Basso Livello: `ReactTransitionGroup`
-
-`ReactTransitionGroup` è la base per le animazioni. È accessibile come `React.addons.TransitionGroup`. Quando vi sono aggiunti o rimossi dichiarativamente dei figli (come negli esempi precedenti) degli speciali hook del ciclo di vita sono invocati su di essi.
-
-### `componentWillAppear(callback)`
-
-Viene chiamato allo stesso momento di `componentDidMount()` per i componenti inizialmente montati in un `TransitionGroup`. Bloccherà l'esecuzione di altre animazioni finché `callback` non viene chiamata. Viene chiamata solo durante il rendering iniziale di un `TransitionGroup`.
-
-### `componentDidAppear()`
-
-Viene chiamato dopo che la funzione `callback` passata a `componentWillAppear` è stata chiamata.
-
-### `componentWillEnter(callback)`
-
-Viene chiamato allo stesso momento di `componentDidMount()` per i componenti aggiunti ad un `TransitionGroup` esistente. Bloccherà l'esecuzione di altre animazioni finché `callback` non viene chiamata. Non viene chiamata durante il rendering iniziale di un `TransitionGroup`.
-
-### `componentDidEnter()`
-
-Viene chiamato dopo che la funzione `callback` passata a `componentWillEnter` è stata chiamata.
-
-### `componentWillLeave(callback)`
-
-Viene chiamato quando il figlio è stato rimosso dal `ReactTransitionGroup`. Nonostante il figlio sia stato rimosso, `ReactTransitionGroup` lo manterrà nel DOM finché `callback` non viene chiamata.
-
-### `componentDidLeave()`
-
-Viene chiamato quando la `callback` `willLeave` viene chiamata (contemporaneamente a `componentWillUnmount`).
-
-### Rendering di un Componente Diverso
-
-In maniera predefinita, `ReactTransitionGroup` viene visualizzato come uno `span`. Puoi cambiare questo comportamento fornento una proprietà `component`. Ad esempio, ecco come puoi visualizzare un `<ul>`:
-
-```javascript{1}
-<ReactTransitionGroup component="ul">
-  ...
-</ReactTransitionGroup>
-```
-
-È possibile utilizzare ciascun componente DOM che React può visualizzare. Tuttavia, `component` non deve necessariamente essere un componente DOM. Può infatti essere qualunque componente React; anche componenti scritti da te!
-
-> Nota:
->
-> Prima della v0.12, quando venivano usati componenti DOM, la proprietà `component` doveva essere un riferimento a `React.DOM.*`. Dal momento che il componente è semplicemente passato a `React.createElement`, deve ora essere una stringa. Per componenti compositi si deve passare il metodo factory.
-
-Ciascuna proprietà aggiuntiva definita dall'utente diverrà una proprietà del componente visualizzato. Ad esempio, ecco come visualizzeresti un `<ul>` con una classe CSS:
-
-```javascript{1}
-<ReactTransitionGroup component="ul" className="animated-list">
-  ...
-</ReactTransitionGroup>
-```
diff --git a/docs/docs/10.1-animation.ja-JP.md b/docs/docs/10.1-animation.ja-JP.md
deleted file mode 100644
index be3c1378ab0c..000000000000
--- a/docs/docs/10.1-animation.ja-JP.md
+++ /dev/null
@@ -1,221 +0,0 @@
----
-id: animation
-title: アニメーション
-permalink: animation-ja-JP.html
-prev: addons-ja-JP.html
-next: two-way-binding-helpers-ja-JP.html
----
-
-ReactはアニメーションのためにローレベルAPIとして `ReactTransitionGroup` アドオンコンポーネントと、基本的なCSSアニメーションとトランジションを簡単に実行するために `ReactCSSTransitionGroup` を提供しています。
-
-## ハイレベルAPI: `ReactCSSTransitionGroup`
-
-`ReactCSSTransitionGroup` は `ReactTransitionGroup` に基づいており、ReactコンポーネントがDOMを作成したり、削除したりする際に、CSSのトランジションとアニメーションを行う簡単な方法です。これは、素晴らしい[ng-animate](http://www.nganimate.org/)ライブラリにインスパイアされています。
-
-### はじめに
-
-`ReactCSSTransitionGroup` は `ReactTransitions` のインターフェースです。アニメーションに関心がある全てのコンポーネントをラップする単純な要素です。以下が、リストのアイテムをフェードインやフェードアウトさせる例です。
-
-```javascript{28-30}
-var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
-
-var TodoList = React.createClass({
-  getInitialState: function() {
-    return {items: ['hello', 'world', 'click', 'me']};
-  },
-  handleAdd: function() {
-    var newItems =
-      this.state.items.concat([prompt('Enter some text')]);
-    this.setState({items: newItems});
-  },
-  handleRemove: function(i) {
-    var newItems = this.state.items;
-    newItems.splice(i, 1);
-    this.setState({items: newItems});
-  },
-  render: function() {
-    var items = this.state.items.map(function(item, i) {
-      return (
-        <div key={item} onClick={this.handleRemove.bind(this, i)}>
-          {item}
-        </div>
-      );
-    }.bind(this));
-    return (
-      <div>
-        <button onClick={this.handleAdd}>Add Item</button>
-        <ReactCSSTransitionGroup transitionName="example">
-          {items}
-        </ReactCSSTransitionGroup>
-      </div>
-    );
-  }
-});
-```
-> 注意:
-> もし子要素を1つだけレンダリングするとしても、 `ReactCSSTransitionGroup` の全ての子要素に提供しなければなりません。これが、Reactが、子要素が作成されているか、削除されたか、あるいはそのままであるか判断する方法です。
-
-このコンポーネントでは、 `ReactCSSTransitionGroup` に新しいアイテムが追加された次の瞬間に、 `example-enter` CSSクラスと `example-enter-active` CSSクラスを得ます。これは、 `transitionName` propに基づく習慣です。
-
-これらのクラスはCSSアニメーションやトランジションのトリガーとして使うことができます。例えば、以下のようにして、このCSSを加え、新しいリストアイテムを加えてみましょう。
-
-```css
-.example-enter {
-  opacity: 0.01;
-  transition: opacity .5s ease-in;
-}
-
-.example-enter.example-enter-active {
-  opacity: 1;
-}
-```
-
-アイテムを削除しようとしたときに、 `ReactCSSTransitionGroup` がDOMの中にそれを保持していることに気づくでしょう。縮小化されていないReactのビルドとアドオンを使っているならば、Reactがアニメーションやトランジションが起こることを予期しているという警告が出るでしょう。これは、 `ReactCSSTransitionGroup` がアニメーションが終わるまでDOM要素をページに保持し続けるからです。以下のCSSを加えてみましょう。
-
-```css
-.example-leave {
-  opacity: 1;
-  transition: opacity .5s ease-in;
-}
-
-.example-leave.example-leave-active {
-  opacity: 0.01;
-}
-```
-
-### 最初のマウントにおけるアニメーション
-
-`ReactCSSTransitionGroup` は `transitionAppear` というオプションのプロパティを提供します。コンポーネントの最初のマウントの際に、更なるトランジションのフェーズを加えるためです。一般的には、 `transitionAppear` が `false` である最初のマウントの際にはトランジションのフェーズはありません。 `transitionAppear` プロパティを値が `true` である状態で渡す以下の例を見てみましょう。
-
-```javascript{3-5}
-  render: function() {
-    return (
-      <ReactCSSTransitionGroup transitionName="example" transitionAppear={true}>
-        <h1>Fading at Initial Mount</h1>
-      </ReactCSSTransitionGroup>
-    );
-  }
-```
-
-最初のマウントの間、 `ReactCSSTransitionGroup` は `example-appear` CSSクラスを得て、次の瞬間に `example-appear-active` CSSクラスを加えます。
-
-```css
-.example-appear {
-  opacity: 0.01;
-  transition: opacity .5s ease-in;
-}
-
-.example-appear.example-appear-active {
-  opacity: 1;
-}
-```
-
-最初のマウントの際には、 `ReactCSSTransitionGroup` の全ての子要素は `appear` しますが、 `enter` はしません。一方、存在する `ReactCSSTransitionGroup` に後から加えられた子要素は全て `enter` しますが、 `appear` はしません。
-
-> 注意:
-> `transitionAppear` プロパティはバージョン `0.13` で `ReactCSSTransitionGroup` に加えられました。後方互換性を維持するために、デフォルトの値は `false` に指定されています。
-
-### アニメーショングループを動かすためには、マウントされている必要があります
-
-子要素にトランジションを適用するためには、 `ReactCSSTransitionGroup` はすでにDOMにマウントされているか、 `transitionAppear` プロパティに `true` がセットされている必要があります。以下の例は動きません。 `ReactCSSTransitionGroup` が新しいアイテムとともにマウントされており、新しいマウントがマウントされていないからです。これと上の[はじめに](#getting-started) とで違いを比較してみてください。
-
-```javascript{12-15}
-  render: function() {
-    var items = this.state.items.map(function(item, i) {
-      return (
-        <div key={item} onClick={this.handleRemove.bind(this, i)}>
-          <ReactCSSTransitionGroup transitionName="example">
-            {item}
-          </ReactCSSTransitionGroup>
-        </div>
-      );
-    }, this);
-    return (
-      <div>
-        <button onClick={this.handleAdd}>Add Item</button>
-        {items}
-      </div>
-    );
-  }
-```
-
-### 1個か0個のアイテムをアニメーションする
-
-上の例では、 `ReactCSSTransitionGroup` にアイテムのリストをレンダリングしました。しかし、 `ReactCSSTransitionGroup` の子要素は1個や0個のアイテムになり得ます。単一の要素が作成や削除のアニメーションを可能にします。同様に、現在の要素を置き換える新しい要素をアニメーションできます。例えば、以下のように、1つの画像でカルーセルを実行できます。
-
-```javascript{10-12}
-var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
-
-var ImageCarousel = React.createClass({
-  propTypes: {
-    imageSrc: React.PropTypes.string.isRequired
-  },
-  render: function() {
-    return (
-      <div>
-        <ReactCSSTransitionGroup transitionName="carousel">
-          <img src={this.props.imageSrc} key={this.props.imageSrc} />
-        </ReactCSSTransitionGroup>
-      </div>
-    );
-  }
-});
-```
-
-### アニメーションを作動させないようにする
-
-もししたいならば、 `enter` や `leave` のアニメーションを無効にすることもできます。例えば、 `enter` アニメーションは行いたいが、 `leave` のアニメーションは行いたくない場合があるでしょう。しかし、 `ReactCSSTransitionGroup` はDOMのノードが削除される前にアニメーションが終わるのを待ちます。`ReactCSSTransitionGroup` がそれらのアニメーションを無効化するために、 `transitionEnter={false}` や `transitionLeave={false}` といったプロパティを追加することができます。
-
-> 注意:
-> `ReactCSSTransitionGroup` を使う際には、コンポーネントがトランジションが終わったことを検知したり、アニメーション関連でさらに複雑なロジックを実行するといったことはできません。更に細かな制御を求める場合は、トランジションをカスタムするために必要なフックを提供するローレベルの `ReactTransitionGroup` APIを使用できます。
-
-## ローレベルAPI: `ReactTransitionGroup`
-
-`ReactTransitionGroup` はアニメーションの基盤です。 `React.addons.TransitionGroup` と同じくらい簡単に使用できます。これによって（上記の例のように）、宣言的に子要素が追加されたり削除されたりするときに、それらの上で特別なライフサイクルのフックが呼ばれます。
-
-### `componentWillAppear(callback)`
-
-このメソッドは `TransitionGroup` の中で最初にマウントされるコンポーネントのために `componentDidMount()` と同時に呼ばれます。これは、 `callback` が呼ばれるまで、他のアニメーションが発生するのをブロックします。これは、 `TransitionGroup` の最初のレンダリングのときにのみ呼ばれます。
-
-### `componentDidAppear()`
-
- `componentWillAppear` が呼ばれて渡される `callback` 関数の後に呼ばれます。
-
-### `componentWillEnter(callback)`
-
-これは、存在する `TransitionGroup` に追加されるコンポーネントのために、 `componentDidMount()` と同時に呼ばれます。これは、 `callback` が呼ばれるまで、他のアニメーションが発生するのをブロックします。これは、 `TransitionGroup` の最初のレンダリングのときには呼ばれません。
-
-### `componentDidEnter()`
-
-`componentWillEnter` が呼ばれて渡される `callback` 関数の後に呼ばれます。
-
-### `componentWillLeave(callback)`
-
-これは、 `ReactTransitionGroup` から子要素が削除されたときに呼ばれます。子要素が削除されても、 `ReactTransitionGroup` は `callback` が呼ばれるまでDOMの中に子要素を保持し続けます。
-
-### `componentDidLeave()`
-
-これは、 `willLeave` の `callback` が呼ばれた際に呼ばれます（ `componentWillUnmount` と同時です）。
-
-### 異なるコンポーネントをレンダリングする
-
-デフォルトで、 `ReactTransitionGroup` は `span` としてレンダリングされます。この動きは、 `component` プロパティによって変更できます。例えば、 `<ul>` をレンダリングしたい場合は以下のようになります。
-
-```javascript{1}
-<ReactTransitionGroup component="ul">
-  ...
-</ReactTransitionGroup>
-```
-
-Reactがレンダリングできる全てのDOMコンポーネントが使用できます。しかし、 `component` はDOMコンポーネントである必要はありません。あなたが求めているどんなReactのコンポーネントにもなり得ます。あなた自身が記述したものにもです！
-
-> 注意:
-> v0.12以前では、DOMのコンポーネントを使用する際には、 `component` プロパティが `React.DOM.*` を参照している必要がありました。コンポーネントが単純に `React.createElement`から渡されていたからです。これは今は文字列である必要があります。複合的なコンポーネントは複合的なものを渡す必要があります。
-
-全ての付加的な、ユーザー定義のプロパティはレンダリングされたコンポーネントのプロパティになります。例えば、以下はCSSクラスとともに `<ul>` をレンダリングする方法です。
-
-```javascript{1}
-<ReactTransitionGroup component="ul" className="animated-list">
-  ...
-</ReactTransitionGroup>
-```
diff --git a/docs/docs/10.1-animation.ko-KR.md b/docs/docs/10.1-animation.ko-KR.md
deleted file mode 100644
index dc6d5f14de52..000000000000
--- a/docs/docs/10.1-animation.ko-KR.md
+++ /dev/null
@@ -1,250 +0,0 @@
----
-id: animation-ko-KR
-title: 애니메이션
-permalink: animation-ko-KR.html
-prev: addons-ko-KR.html
-next: two-way-binding-helpers-ko-KR.html
----
-
-React에는 애니메이션을 위한 저 수준 API로 `ReactTransitionGroup` 애드온 컴포넌트가 있고 간단히 기초 CSS 애니메이션과 트랜지션을 구현할 수 있는 `ReactCSSTransitionGroup`가 있습니다.
-
-## 고 레벨 API: `ReactCSSTransitionGroup`
-
-`ReactCSSTransitionGroup`는 `ReactTransitionGroup`를 기반으로 React 컴포넌트가 DOM에 들어가거나 나올때의 CSS의 트랜지션과 애니메이션을 구현하기 쉽게합니다. 이는 [ng-animate](http://www.nganimate.org/) 라이브러리에 영향을 받았습니다.
-
-<a name="getting-stared"></a>
-### 시작하기
-
-`ReactCSSTransitionGroup`은 `ReactTransitions`을 위한 인터페이스입니다. 이는 애니메이션을 제어할 모든 컴포넌트를 감싸는 하나의 엘리먼트 입니다. 아래는 목록의 아이템을 페이드 인/아웃하는 간단한 예제입니다.
-
-```javascript{28-30}
-var ReactCSSTransitionGroup = require('react-addons-css-transition-group');
-
-var TodoList = React.createClass({
-  getInitialState: function() {
-    return {items: ['hello', 'world', 'click', 'me']};
-  },
-  handleAdd: function() {
-    var newItems =
-      this.state.items.concat([prompt('Enter some text')]);
-    this.setState({items: newItems});
-  },
-  handleRemove: function(i) {
-    var newItems = this.state.items;
-    newItems.splice(i, 1);
-    this.setState({items: newItems});
-  },
-  render: function() {
-    var items = this.state.items.map(function(item, i) {
-      return (
-        <div key={item} onClick={this.handleRemove.bind(this, i)}>
-          {item}
-        </div>
-      );
-    }.bind(this));
-    return (
-      <div>
-        <button onClick={this.handleAdd}>Add Item</button>
-        <ReactCSSTransitionGroup transitionName="example" transitionEnterTimeout={500} transitionLeaveTimeout={300}>
-          {items}
-        </ReactCSSTransitionGroup>
-      </div>
-    );
-  }
-});
-```
-
-> 주의:
->
-> `ReactCSSTransitionGroup`의 모든 자식은 [`key` 어트리뷰트](/react/docs/multiple-components-ko-KR.html#dynamic-children)를 반드시 만들어야 합니다. 한 아이템을 렌더할 때도 예외는 아닙니다. 키는 React가 어떤 자식이 들어오고, 나가고, 머무르는지 파악할 때 사용합니다.
-
-이 컴포넌트에서 새로운 아이템이 `ReactCSSTransitionGroup`에 추가되면 `example-enter` 아이템은 CSS 클래스를 가지게 되고 다음 순간에 `example-enter-active` CSS 클래스가 추가됩니다. 이는 `transitionName` prop을 기반으로 한 관례입니다.
-
-이 클래스들은 CSS 애니메이션이나 트랜지션을 일으키는데 사용할 수 있습니다. 예를 들어, 이 CSS를 넣은 후 아이템을 추가해 보세요.
-
-```css
-.example-enter {
-  opacity: 0.01;
-}
-
-.example-enter.example-enter-active {
-  opacity: 1;
-  transition: opacity 500ms ease-in;
-}
-
-.example-leave {
-  opacity: 1;
-}
-
-.example-leave.example-leave-active {
-  opacity: 0.01;
-  transition: opacity 300ms ease-in;
-}
-```
-
-에니메이션 기간이 CSS와 렌더 메소드 양쪽에 지정될 필요가 있다는 것에 주의하셔야 합니다. 이는 엘리먼트에서 애니메이션 클래스를 제거할 때 (만약 남아있다면) DOM에서 엘리먼트를 제거할 때 React에 알려줍니다.
-
-### 처음 마운트에서 애니메이션 하기
-
-`ReactCSSTransitionGroup`은 컴포넌트를 처음 마운트할 때 추가 트렌지션 단계를 추가하기 위해, 선택적인 prop `transitionAppear`를 제공합니다. 일반적으로 처음 마운트할 때 트렌지션 단계를 넣지 않기 때문에 `transitionAppear`의 기본 값은 `false`입니다. 뒤의 예제는 `transitionAppear` prop에 `true` 값을 넘기고 있습니다.
-
-```javascript{3-5}
-  render: function() {
-    return (
-      <ReactCSSTransitionGroup transitionName="example" transitionAppear={true} transitionAppearTimeout={500}>
-        <h1>Fading at Initial Mount</h1>
-      </ReactCSSTransitionGroup>
-    );
-  }
-```
-
-처음 마운트할 때 `ReactCSSTransitionGroup`은 `example-appear` CSS 클래스를 받고 그 다음에 `example-appear-active` CSS 클래스가 추가됩니다.
-
-```css
-.example-appear {
-  opacity: 0.01;
-}
-
-.example-appear.example-appear-active {
-  opacity: 1;
-  transition: opacity .5s ease-in;
-}
-```
-
-처음 마운트할 때, `ReactCSSTransitionGroup`의 모든 자식은 `appear`하지만 `enter`하지 않습니다. 하지만, 존재하는 `ReactCSSTransitionGroup`에 추가되는 모든 자식은 `enter`하지만 `appear`하지 않습니다.
-
-> 주의:
->
-> `transitionAppear` prop은 버전 `0.13`에서 `ReactCSSTransitionGroup`에 추가되었습니다. 하위 호환성을 생각해서, 기본 값은 `false`로 설정되어 있습니다.
-
-### 커스텀 클래스
-
-트렌지션의 각 단계에서 커스텀 클래스 이름을 사용할 수도 있습니다. transitionName에 문자열을 넘기는 대신 `enter`, `leave` 같은 클래스 이름의 객체나 `enter`, `enter-active`, `leave-active`, `leave`같은 클래스 이름의 객체를 넘길 수 있습니다. enter, leave 클래스만 있다면, enter-active, leave-active 클래스는 클래스 이름 뒤에 '-active'를 붙여서 정할 수 있습니다. 커스텀 클래스를 사용한 예제입니다.
-
-```javascript
-  ...
-  <ReactCSSTransitionGroup
-    transitionName={ {
-      enter: 'enter',
-      enterActive: 'enterActive',
-      leave: 'leave',
-      leaveActive: 'leaveActive',
-      appear: 'appear',
-      appearActive: 'appearActive'
-    } }>
-    {item}
-  </ReactCSSTransitionGroup>
-
-  <ReactCSSTransitionGroup
-    transitionName={ {
-      enter: 'enter',
-      leave: 'leave',
-      appear: 'appear'
-    } }>
-    {item2}
-  </ReactCSSTransitionGroup>
-  ...
-```
-
-### 애니메이션 그룹이 작동하려면 마운트가 필요
-
-자식들에게 트랜지션을 적용하려면 `ReactCSSTransitionGroup`은 이미 DOM에 마운트되어 있거나 prop `transitionAppear`가 `true`로 설정되어야만 합니다. 예를 들어, 밑의 코드는 동작하지 않을 것입니다. 왜냐하면 `ReactCSSTransitionGroup` 안에서 새 아이템을 마운트하는 대신 새 아이템과 같이 `ReactCSSTransitionGroup`를 마운트했기 때문입니다. 이 것을 위에 있는 [시작하기](#getting-stared) 항목과 비교해보세요.
-
-```javascript{12-15}
-  render: function() {
-    var items = this.state.items.map(function(item, i) {
-      return (
-        <div key={item} onClick={this.handleRemove.bind(this, i)}>
-          <ReactCSSTransitionGroup transitionName="example">
-            {item}
-          </ReactCSSTransitionGroup>
-        </div>
-      );
-    }, this);
-    return (
-      <div>
-        <button onClick={this.handleAdd}>Add Item</button>
-        {items}
-      </div>
-    );
-  }
-```
-
-### 아이템 하나이거나 없을 때의 애니메이션
-
-위의 예제에서 `ReactCSSTransitionGroup`에 아이템 목록을 렌더했지만, `ReactCSSTransitionGroup`의 자식은 하나이거나 없을 수도 있습니다. 이는 한 엘리먼트가 들어오고 나가는 것의 애니메이션을 가능하게 합니다. 비슷하게, 현재 엘리먼트가 나가는 동안 새 앨리먼트의 애니메이션을 하면, 새 엘리먼트가 현재 엘리먼트를 교체하는 애니메이션을 만들 수 있습니다. 예를 들어 이렇게 간단한 이미지 회전 베너(carousel)를 구현할 수 있습니다.
-
-```javascript{10-12}
-var ReactCSSTransitionGroup = require('react-addons-css-transition-group');
-
-var ImageCarousel = React.createClass({
-  propTypes: {
-    imageSrc: React.PropTypes.string.isRequired
-  },
-  render: function() {
-    return (
-      <div>
-        <ReactCSSTransitionGroup transitionName="carousel" transitionEnterTimeout={300} transitionLeaveTimeout={300}>
-          <img src={this.props.imageSrc} key={this.props.imageSrc} />
-        </ReactCSSTransitionGroup>
-      </div>
-    );
-  }
-});
-```
-
-### 애니메이션 비활성화
-
-원한다면 `enter`나 `leave` 애니메이션을 비활성화 할 수 있습니다. 예를 들어, `enter` 애니메이션만 필요하고 `leave` 애니메이션은 필요없지만, `ReactCSSTransitionGroup`이 DOM 노드를 없애기 전 애니메이션이 완료되길 기다리고 있는 경우에 사용할 수 있습니다. `ReactCSSTransitionGroup`에 `transitionEnter={false}`나 `transitionLeave={false}` props를 추가하면 그 애니메이션을 비활성화 할 수 있습니다.
-
-> 주의:
->
-> `ReactCSSTransitionGroup`를 사용할 때는, 트랜지션이 종료되었을 때나 애니메이션 근처에서 더 복잡한 로직을 실행할 때 컴포넌트에 통지할 방법이 없습니다. 보다 세밀하게 제어하고 싶다면, 커스텀 트랜지션에 필요한 훅을 제공하는 저수준 `ReactTransitionGroup` API를 이용할 수 있습니다.
-
-## 저수준 API: `ReactTransitionGroup`
-
-`ReactTransitionGroup`은 애니메이션의 기초입니다. 이는 `require('react-addons-transition-group')`으로 접근할 수 있습니다. 위의 예제처럼 자식들이 선언적으로 여기에 추가되거나 삭제되는 경우, 특별한 훅이 이 생명주기에서 호출됩니다.
-
-### `componentWillAppear(callback)`
-
-이미 있는 `TransitionGroup`에 컴포넌트를 추가할 때 호출되는 `componentDidMount()`와 같이 호출됩니다. 이는 `callback`이 호출될 때까지 다른 애니메이션을 막습니다. `TransitionGroup`의 최초 렌더에서만 호출됩니다.
-
-### `componentDidAppear()`
-
-이는 `componentWillAppear`에 넘겨졌던 `callback` 함수가 호출된 다음에 호출됩니다.
-
-### `componentWillEnter(callback)`
-
-이미 있는 `TransitionGroup`에 컴포넌트를 추가할 때 호출되는 `componentDidMount()`와 같이 호출됩니다. 이는 `callback`이 호출될 때까지 다른 애니메이션을 막습니다. `TransitionGroup`의 최조 렌더에서는 불려지지 않습니다.
-
-### `componentDidEnter()`
-
-이는 `componentWillEnter`에 넘겨주었던 `callback` 함수가 호출된 다음에 호출됩니다.
-
-### `componentWillLeave(callback)`
-
-이는 `ReactTransitionGroup`에서 자식이 제거되었을 때 호출됩니다. 자식이 제거되었다고 해도 `ReactTransitionGroup`는 `callback`이 호출될 때까지 DOM에 자식을 남겨둡니다.
-
-### `componentDidLeave()`
-
-이는 `willLeave` `callback`이 호출될 때 호출됩니다. (`componentWillUnmount`와 같은 타이밍)
-
-### 다른 컴포넌트 렌더하기
-
-기본적으로 `ReactTransitionGroup`은 `span`으로 렌더합니다. `component` prop으로 이 행동을 바꿀 수 있습니다. 예를 들어, `<ul>`을 렌더하고 싶다면 이렇게 하면 됩니다.
-
-```javascript{1}
-<ReactTransitionGroup component="ul">
-  ...
-</ReactTransitionGroup>
-```
-
-React가 렌더할 수 있는 DOM 컴포넌트는 전부 사용할 수 있습니다. 하지만 `component`가 DOM 컴포넌트일 필요는 없습니다. React 컴포넌트라면 무엇이든 넣을 수 있습니다. 직접 구현한 컴포넌트여도 됩니다! 그냥 `component={List}`를 적으면 컴포넌트는 `this.props.children`로 받을 수 있습니다.
-
-사용자 정의를 포함한 어떤 프로퍼티도 렌더된 컴포넌트의 프로퍼티가 됩니다. 예를 들어, `<ul>`에 CSS 클래스를 넣어서 렌더하려면 이렇게 하면 됩니다.
-
-```javascript{1}
-<ReactTransitionGroup component="ul" className="animated-list">
-  ...
-</ReactTransitionGroup>
-```
diff --git a/docs/docs/10.1-animation.md b/docs/docs/10.1-animation.md
deleted file mode 100644
index 117b0e77e896..000000000000
--- a/docs/docs/10.1-animation.md
+++ /dev/null
@@ -1,274 +0,0 @@
----
-id: animation
-title: Animation
-permalink: animation.html
-prev: addons.html
-next: two-way-binding-helpers.html
----
-
-React provides a `ReactTransitionGroup` add-on component as a low-level API for animation, and a `ReactCSSTransitionGroup` for easily implementing basic CSS animations and transitions.
-
-## High-level API: `ReactCSSTransitionGroup`
-
-`ReactCSSTransitionGroup` is based on `ReactTransitionGroup` and is an easy way to perform CSS transitions and animations when a React component enters or leaves the DOM. It's inspired by the excellent [ng-animate](http://www.nganimate.org/) library.
-
-### Getting Started
-
-`ReactCSSTransitionGroup` is the interface to `ReactTransitions`. This is a simple element that wraps all of the components you are interested in animating. Here's an example where we fade list items in and out.
-
-```javascript{28-30}
-var ReactCSSTransitionGroup = require('react-addons-css-transition-group');
-
-var TodoList = React.createClass({
-  getInitialState: function() {
-    return {items: ['hello', 'world', 'click', 'me']};
-  },
-  handleAdd: function() {
-    var newItems =
-      this.state.items.concat([prompt('Enter some text')]);
-    this.setState({items: newItems});
-  },
-  handleRemove: function(i) {
-    var newItems = this.state.items.slice();
-    newItems.splice(i, 1);
-    this.setState({items: newItems});
-  },
-  render: function() {
-    var items = this.state.items.map(function(item, i) {
-      return (
-        <div key={item} onClick={this.handleRemove.bind(this, i)}>
-          {item}
-        </div>
-      );
-    }.bind(this));
-    return (
-      <div>
-        <button onClick={this.handleAdd}>Add Item</button>
-        <ReactCSSTransitionGroup transitionName="example" transitionEnterTimeout={500} transitionLeaveTimeout={300}>
-          {items}
-        </ReactCSSTransitionGroup>
-      </div>
-    );
-  }
-});
-```
-
-> Note:
->
-> You must provide [the `key` attribute](/react/docs/multiple-components.html#dynamic-children) for all children of `ReactCSSTransitionGroup`, even when only rendering a single item. This is how React will determine which children have entered, left, or stayed.
-
-In this component, when a new item is added to `ReactCSSTransitionGroup` it will get the `example-enter` CSS class and the `example-enter-active` CSS class added in the next tick. This is a convention based on the `transitionName` prop.
-
-You can use these classes to trigger a CSS animation or transition. For example, try adding this CSS and adding a new list item:
-
-```css
-.example-enter {
-  opacity: 0.01;
-}
-
-.example-enter.example-enter-active {
-  opacity: 1;
-  transition: opacity 500ms ease-in;
-}
-
-.example-leave {
-  opacity: 1;
-}
-
-.example-leave.example-leave-active {
-  opacity: 0.01;
-  transition: opacity 300ms ease-in;
-}
-```
-
-You'll notice that animation durations need to be specified in both the CSS and the render method; this tells React when to remove the animation classes from the element and -- if it's leaving -- when to remove the element from the DOM.
-
-### Animate Initial Mounting
-
-`ReactCSSTransitionGroup` provides the optional prop `transitionAppear`, to add an extra transition phase at the initial mount of the component. There is generally no transition phase at the initial mount as the default value of `transitionAppear` is `false`. The following is an example which passes the prop `transitionAppear` with the value `true`.
-
-```javascript{3-5}
-  render: function() {
-    return (
-      <ReactCSSTransitionGroup transitionName="example" transitionAppear={true} transitionAppearTimeout={500}>
-        <h1>Fading at Initial Mount</h1>
-      </ReactCSSTransitionGroup>
-    );
-  }
-```
-
-During the initial mount `ReactCSSTransitionGroup` will get the `example-appear` CSS class and the `example-appear-active` CSS class added in the next tick.
-
-```css
-.example-appear {
-  opacity: 0.01;
-}
-
-.example-appear.example-appear-active {
-  opacity: 1;
-  transition: opacity .5s ease-in;
-}
-```
-
-At the initial mount, all children of the `ReactCSSTransitionGroup` will `appear` but not `enter`. However, all children later added to an existing `ReactCSSTransitionGroup` will `enter` but not `appear`.
-
-> Note:
->
-> The prop `transitionAppear` was added to `ReactCSSTransitionGroup` in version `0.13`. To maintain backwards compatibility, the default value is set to `false`.
-
-### Custom Classes
-
-It is also possible to use custom class names for each of the steps in your transitions. Instead of passing a string into transitionName you can pass an object containing either the `enter` and `leave` class names, or an object containing the `enter`, `enter-active`, `leave-active`, and `leave` class names. If only the enter and leave classes are provided, the enter-active and leave-active classes will be determined by appending '-active' to the end of the class name. Here are two examples using custom classes:
-
-```javascript
-  ...
-  <ReactCSSTransitionGroup
-    transitionName={ {
-      enter: 'enter',
-      enterActive: 'enterActive',
-      leave: 'leave',
-      leaveActive: 'leaveActive',
-      appear: 'appear',
-      appearActive: 'appearActive'
-    } }>
-    {item}
-  </ReactCSSTransitionGroup>
-
-  <ReactCSSTransitionGroup
-    transitionName={ {
-      enter: 'enter',
-      leave: 'leave',
-      appear: 'appear'
-    } }>
-    {item2}
-  </ReactCSSTransitionGroup>
-  ...
-```
-
-### Animation Group Must Be Mounted To Work
-
-In order for it to apply transitions to its children, the `ReactCSSTransitionGroup` must already be mounted in the DOM or the prop `transitionAppear` must be set to `true`. The example below would not work, because the `ReactCSSTransitionGroup` is being mounted along with the new item, instead of the new item being mounted within it. Compare this to the [Getting Started](#getting-started) section above to see the difference.
-
-```javascript{12-15}
-  render: function() {
-    var items = this.state.items.map(function(item, i) {
-      return (
-        <div key={item} onClick={this.handleRemove.bind(this, i)}>
-          <ReactCSSTransitionGroup transitionName="example">
-            {item}
-          </ReactCSSTransitionGroup>
-        </div>
-      );
-    }, this);
-    return (
-      <div>
-        <button onClick={this.handleAdd}>Add Item</button>
-        {items}
-      </div>
-    );
-  }
-```
-
-### Animating One or Zero Items
-
-In the example above, we rendered a list of items into `ReactCSSTransitionGroup`. However, the children of `ReactCSSTransitionGroup` can also be one or zero items. This makes it possible to animate a single element entering or leaving. Similarly, you can animate a new element replacing the current element. For example, we can implement a simple image carousel like this:
-
-```javascript{10-12}
-var ReactCSSTransitionGroup = require('react-addons-css-transition-group');
-
-var ImageCarousel = React.createClass({
-  propTypes: {
-    imageSrc: React.PropTypes.string.isRequired
-  },
-  render: function() {
-    return (
-      <div>
-        <ReactCSSTransitionGroup transitionName="carousel" transitionEnterTimeout={300} transitionLeaveTimeout={300}>
-          <img src={this.props.imageSrc} key={this.props.imageSrc} />
-        </ReactCSSTransitionGroup>
-      </div>
-    );
-  }
-});
-```
-
-### Disabling Animations
-
-You can disable animating `enter` or `leave` animations if you want. For example, sometimes you may want an `enter` animation and no `leave` animation, but `ReactCSSTransitionGroup` waits for an animation to complete before removing your DOM node. You can add `transitionEnter={false}` or `transitionLeave={false}` props to `ReactCSSTransitionGroup` to disable these animations.
-
-> Note:
->
-> When using `ReactCSSTransitionGroup`, there's no way for your components to be notified when a transition has ended or to perform any more complex logic around animation. If you want more fine-grained control, you can use the lower-level `ReactTransitionGroup` API which provides the hooks you need to do custom transitions.
-
-## Low-level API: `ReactTransitionGroup`
-
-`ReactTransitionGroup` is the basis for animations. It is accessible from `require('react-addons-transition-group')`. When children are declaratively added or removed from it (as in the example above) special lifecycle hooks are called on them.
-
-### `componentWillAppear(callback)`
-
-This is called at the same time as `componentDidMount()` for components that are initially mounted in a `TransitionGroup`. It will block other animations from occurring until `callback` is called. It is only called on the initial render of a `TransitionGroup`.
-
-### `componentDidAppear()`
-
-This is called after the `callback` function that was passed to `componentWillAppear` is called.
-
-### `componentWillEnter(callback)`
-
-This is called at the same time as `componentDidMount()` for components added to an existing `TransitionGroup`. It will block other animations from occurring until `callback` is called. It will not be called on the initial render of a `TransitionGroup`.
-
-### `componentDidEnter()`
-
-This is called after the `callback` function that was passed to `componentWillEnter` is called.
-
-### `componentWillLeave(callback)`
-
-This is called when the child has been removed from the `ReactTransitionGroup`. Though the child has been removed, `ReactTransitionGroup` will keep it in the DOM until `callback` is called.
-
-### `componentDidLeave()`
-
-This is called when the `willLeave` `callback` is called (at the same time as `componentWillUnmount`).
-
-### Rendering a Different Component
-
-By default `ReactTransitionGroup` renders as a `span`. You can change this behavior by providing a `component` prop. For example, here's how you would render a `<ul>`:
-
-```javascript{1}
-<ReactTransitionGroup component="ul">
-  ...
-</ReactTransitionGroup>
-```
-
-Any additional, user-defined, properties will become properties of the rendered component. For example, here's how you would render a `<ul>` with CSS class:
-
-```javascript{1}
-<ReactTransitionGroup component="ul" className="animated-list">
-  ...
-</ReactTransitionGroup>
-```
-
-Every DOM component that React can render is available for use. However, `component` does not need to be a DOM component. It can be any React component you want; even ones you've written yourself! Just write `component={List}` and your component will receive `this.props.children`.
-
-### Rendering a Single Child
-
-People often use `ReactTransitionGroup` to animate mounting and unmounting of a single child such as a collapsible panel. Normally `ReactTransitionGroup` wraps all its children in a `span` (or a custom `component` as described above). This is because any React component has to return a single root element, and `ReactTransitionGroup` is no exception to this rule.
-
-However if you only need to render a single child inside `ReactTransitionGroup`, you can completely avoid wrapping it in a `<span>` or any other DOM component. To do this, create a custom component that renders the first child passed to it directly:
-
-```javascript{1}
-var FirstChild = React.createClass({
-  render: function() {
-    var children = React.Children.toArray(this.props.children);
-    return children[0] || null;
-  }
-});
-```
-
-Now you can specify `FirstChild` as the `component` prop in `<ReactTransitionGroup>` props and avoid any wrappers in the result DOM:
-
-```javascript{1}
-<ReactTransitionGroup component={FirstChild}>
-  {someCondition ? <MyComponent /> : null}
-</ReactTransitionGroup>
-```
-
-This only works when you are animating a single child in and out, such as a collapsible panel. This approach wouldn't work when animating multiple children or replacing the single child with another child, such as an image carousel. For an image carousel, while the current image is animating out, another image will animate in, so `<ReactTransitionGroup>` needs to give them a common DOM parent. You can't avoid the wrapper for multiple children, but you can customize the wrapper with the `component` prop as described above.
diff --git a/docs/docs/10.1-animation.zh-CN.md b/docs/docs/10.1-animation.zh-CN.md
deleted file mode 100644
index e24c578cf536..000000000000
--- a/docs/docs/10.1-animation.zh-CN.md
+++ /dev/null
@@ -1,249 +0,0 @@
----
-id: animation-zh-CN
-title: 动画
-permalink: animation-zh-CN.html
-prev: addons-zh-CN.html
-next: two-way-binding-helpers-zh-CN.html
----
-
-React 提供了一个 `ReactTransitionGroup` 插件作为动画的底层API,和一个 `ReactCSSTransitionGroup` 用于轻松实现基础的CSS动画和过渡。
-
-## 高级 API: `ReactCSSTransitionGroup`
-
-`ReactCSSTransitionGroup` 基于 `ReactTransitionGroup` 是一个当React组件进入或离开DOM时，执行CSS动画和过渡的简单方法。它的灵感来自于杰出的 [ng-animate](http://www.nganimate.org/) 库。
-
-### 入门指南
-
-`ReactCSSTransitionGroup` 是 `ReactTransitions` 的接口。这是一个简单的元素，包裹了所有你感兴趣的动画组件。这里是一个淡入和淡出列表项目的例子。
-
-```javascript{28-30}
-var ReactCSSTransitionGroup = require('react-addons-css-transition-group');
-
-var TodoList = React.createClass({
-  getInitialState: function() {
-    return {items: ['hello', 'world', 'click', 'me']};
-  },
-  handleAdd: function() {
-    var newItems =
-      this.state.items.concat([prompt('Enter some text')]);
-    this.setState({items: newItems});
-  },
-  handleRemove: function(i) {
-    var newItems = this.state.items.slice();
-    newItems.splice(i, 1);
-    this.setState({items: newItems});
-  },
-  render: function() {
-    var items = this.state.items.map(function(item, i) {
-      return (
-        <div key={item} onClick={this.handleRemove.bind(this, i)}>
-          {item}
-        </div>
-      );
-    }.bind(this));
-    return (
-      <div>
-        <button onClick={this.handleAdd}>Add Item</button>
-        <ReactCSSTransitionGroup transitionName="example" transitionEnterTimeout={500} transitionLeaveTimeout={300}>
-          {items}
-        </ReactCSSTransitionGroup>
-      </div>
-    );
-  }
-});
-```
-> 注意:
->
-> 你必须为`ReactCSSTransitionGroup`的所有子级提供 [ `key` 属性](/react/docs/multiple-components.html#dynamic-children)，即使只渲染一个项目。这就是React将决定哪一个子级进入，离开，或者停留
-
-在这个组件，当一个新的项目被添加到 `ReactCSSTransitionGroup` ,他将得到`example-enter` CSS类 并且在下一刻`example-enter-active` CSS类被添加。这是一个基于`transitionName` prop 的约定。
-
-你可以使用这些类来触发CSS动画和过渡。比如，尝试添加这个CSS和添加一个新的列表项：
-
-```css
-.example-enter {
-  opacity: 0.01;
-}
-
-.example-enter.example-enter-active {
-  opacity: 1;
-  transition: opacity 500ms ease-in;
-}
-
-.example-leave {
-  opacity: 1;
-}
-
-.example-leave.example-leave-active {
-  opacity: 0.01;
-  transition: opacity 300ms ease-in;
-}
-```
-
-你会注意到动画持续时间需要被同时在CSS和渲染方法里被指定;这告诉React什么时候从元素中移除动画类，并且 -- 如果它正在离开 -- 何时从DOM移除元素。
-
-### 让初始化挂载动画
-
-`ReactCSSTransitionGroup` 提供了可选的prop `transitionAppear`，来为在组件初始挂载添加一个额外的过渡阶段。 通常在初始化挂载时没有过渡阶段因为`transitionAppear` 的默认值为`false`。下面是一个传递`transitionAppear` 为值`true`的例子。
-
-```javascript{3-5}
-  render: function() {
-    return (
-      <ReactCSSTransitionGroup transitionName="example" transitionAppear={true} transitionAppearTimeout={500}>
-        <h1>Fading at Initial Mount</h1>
-      </ReactCSSTransitionGroup>
-    );
-  }
-```
-
-在初始化挂载时 `ReactCSSTransitionGroup` 将获得`example-appear` CSS类 并且`example-appear-active` CSS 类在下一刻被添加。
-
-```css
-.example-appear {
-  opacity: 0.01;
-}
-
-.example-appear.example-appear-active {
-  opacity: 1;
-  transition: opacity .5s ease-in;
-}
-```
-
-在初始化挂载，所有的 `ReactCSSTransitionGroup` 子级将会 `appear` 但不 `enter`。然而，所有后来添加到已存在的 `ReactCSSTransitionGroup` 的子级将 `enter` 但不 `appear`。
-
-> 注意:
->
-> prop `transitionAppear` 在版本 `0.13` 被添加到 `ReactCSSTransitionGroup`。为了保持向后兼容，默认值被设置为 `false`。
-
-### 制定类
-
-可以为你的每一步过渡使用制定类名字。代理传递一个字符串到transitionName，你可以传递一个含有`enter` 或者`leave` 类名的对象，或者一个含有 `enter`, `enter-active`, `leave-active`, 和 `leave` 类名的对象。只要提供了enter 和 leave 的类，enter-active 和 leave-active 类会被决定为后缀'-active' 到类名的尾部。这里是两个使用制定类的例子：
-
-```javascript
-  ...
-  <ReactCSSTransitionGroup
-    transitionName={ {
-      enter: 'enter',
-      enterActive: 'enterActive',
-      leave: 'leave',
-      leaveActive: 'leaveActive',
-      appear: 'appear',
-      appearActive: 'appearActive'
-    } }>
-    {item}
-  </ReactCSSTransitionGroup>
-
-  <ReactCSSTransitionGroup
-    transitionName={ {
-      enter: 'enter',
-      leave: 'leave',
-      appear: 'appear'
-    } }>
-    {item2}
-  </ReactCSSTransitionGroup>
-  ...
-```
-
-### 动画组必须挂载才工作
-
-为了使过渡效果应用到子级上，`ReactCSSTransitionGroup`必须已经挂载到了DOM或者 prop `transitionAppear` 必须被设置为 `true`。下面的例子不会工作，因为 `ReactCSSTransitionGroup` 随同新项目被挂载，而不是新项目在它内部被挂载。将这与上面的[入门指南](#入门指南)部分比较一下，看看不同。
-
-```javascript{12-15}
-  render: function() {
-    var items = this.state.items.map(function(item, i) {
-      return (
-        <div key={item} onClick={this.handleRemove.bind(this, i)}>
-          <ReactCSSTransitionGroup transitionName="example">
-            {item}
-          </ReactCSSTransitionGroup>
-        </div>
-      );
-    }, this);
-    return (
-      <div>
-        <button onClick={this.handleAdd}>Add Item</button>
-        {items}
-      </div>
-    );
-  }
-```
-
-### 动画一个或者零个项目 Animating One or Zero Items
-
-在上面的例子中，我们渲染了一系列的项目到`ReactCSSTransitionGroup`里。然而 `ReactCSSTransitionGroup` 的子级同样可以是一个或零个项目。这使它能够动画化单个元素的进入和离开。同样，你可以动画化一个新的元素替换当前元素。例如，我们可以像这样实现一个简单的图片轮播器：
-
-```javascript{10-12}
-var ReactCSSTransitionGroup = require('react-addons-css-transition-group');
-
-var ImageCarousel = React.createClass({
-  propTypes: {
-    imageSrc: React.PropTypes.string.isRequired
-  },
-  render: function() {
-    return (
-      <div>
-        <ReactCSSTransitionGroup transitionName="carousel" transitionEnterTimeout={300} transitionLeaveTimeout={300}>
-          <img src={this.props.imageSrc} key={this.props.imageSrc} />
-        </ReactCSSTransitionGroup>
-      </div>
-    );
-  }
-});
-```
-
-### 禁用动画
-
-如果你想,你可以禁用 `enter` 或者 `leave` 动画。例如，有时你可能想要一个 `enter` 动画，不要 `leave` 动画，但是 `ReactCSSTransitionGroup` 会在移除你的DOM节点之前等待一个动画完成。你可以添加`transitionEnter={false}` 或者 `transitionLeave={false}` props 到 `ReactCSSTransitionGroup` 来禁用这些动画。
-
-> 注意：
->
-> 当使用 `ReactCSSTransitionGroup` 时，没有办法通知你的组件何时过渡效果结束或者在动画时执行任何复杂的逻辑运算。如果你想要更多细粒度的控制，你可以使用底层的 `ReactTransitionGroup` API，它提供了你自定义过渡效果所需要的挂钩。
-
-## 底层 API: `ReactTransitionGroup`
-
-`ReactTransitionGroup`是动画的基础。它通过 `require('react-addons-transition-group')` 访问。当子级被声明式的从其中添加或移除（就像上面的例子）时，特殊的生命周期挂钩会在它们上面被调用。
-
-### `componentWillAppear(callback)`
-
-对于被初始化挂载到 `TransitionGroup` 的组件，它和 `componentDidMount()` 在相同时间被调用 。它将会阻塞其它动画发生，直到`callback`被调用。它只会在 `TransitionGroup` 初始化渲染时被调用。
-
-### `componentDidAppear()`
-
-在 传给`componentWillAppear` 的 `回调` 函数被调用后调用。
-
-### `componentWillEnter(callback)`
-
-对于被添加到已存在的 `TransitionGroup` 的组件，它和 `componentDidMount()` 在相同时间被调用 。它将会阻塞其它动画发生，直到`callback`被调用。它不会在 `TransitionGroup` 初始化渲染时被调用。
-
-### `componentDidEnter()`
-
-在传给 `componentWillEnter` 的`回调`函数被调用之后调用。
-
-### `componentWillLeave(callback)`
-
-在子级从 `ReactTransitionGroup` 中移除时调用。虽然子级被移除了，`ReactTransitionGroup` 将会保持它在DOM中，直到`callback`被调用。
-
-### `componentDidLeave()`
-
-在`willLeave` `callback` 被调用的时候调用（与 `componentWillUnmount` 同一时间）。
-
-### 渲染一个不同的组件
-
-默认情况下 `ReactTransitionGroup` 渲染为一个 `span`。你可以通过提供一个 `component` prop 来改变这种行为。例如，下面是你将如何渲染一个`<ul>`：
-
-```javascript{1}
-<ReactTransitionGroup component="ul">
-  ...
-</ReactTransitionGroup>
-```
-
-每一个React能渲染的DOM组件都是可用的。然而，`组件`不需要是一个DOM组件。它可以是任何你想要的React组件；甚至是你自己已经写好的！只要写 `component={List}` 你的组件会收到 `this.props.children`
-
-
-任何额外的、用户定义的属性将会成为已渲染的组件的属性。例如，以下是你将如何渲染一个带有css类的 `<ul>`：
-
-```javascript{1}
-<ReactTransitionGroup component="ul" className="animated-list">
-  ...
-</ReactTransitionGroup>
-```
diff --git a/docs/docs/10.10-shallow-compare.md b/docs/docs/10.10-shallow-compare.md
deleted file mode 100644
index 4ce3ee4107ec..000000000000
--- a/docs/docs/10.10-shallow-compare.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-id: shallow-compare
-title: Shallow Compare
-permalink: shallow-compare.html
-prev: perf.html
-next: advanced-performance.html
----
-
-`shallowCompare` is a helper function to achieve the same functionality as `PureRenderMixin` while using ES6 classes with React.
-
-If your React component's render function is "pure" (in other words, it renders the same result given the same props and state), you can use this helper function for a performance boost in some cases.
-
-Example:
-
-```js
-var shallowCompare = require('react-addons-shallow-compare');
-export class SampleComponent extends React.Component {
-  shouldComponentUpdate(nextProps, nextState) {
-    return shallowCompare(this, nextProps, nextState);
-  }
-
-  render() {
-    return <div className={this.props.className}>foo</div>;
-  }
-}
-```
-
-`shallowCompare` performs a shallow equality check on the current `props` and `nextProps` objects as well as the current `state` and `nextState` objects.  
-It does this by iterating on the keys of the objects being compared and returning false when the value of a key in each object are not strictly equal.
-
-`shallowCompare` returns `true` if the shallow comparison for props or state fails and therefore the component should update.  
-`shallowCompare` returns `false` if the shallow comparison for props and state both pass and therefore the component does not need to update.
diff --git a/docs/docs/10.10-shallow-compare.zh-CN.md b/docs/docs/10.10-shallow-compare.zh-CN.md
deleted file mode 100644
index 6ed9a161bb7c..000000000000
--- a/docs/docs/10.10-shallow-compare.zh-CN.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-id: shallow-compare-zh-CN
-title: 浅比较
-permalink: shallow-compare-zh-CN.html
-prev: perf-zh-CN.html
-next: advanced-performance-zh-CN.html
----
-
-`shallowCompare` 是一个辅助函数 在以ES6类使用React时，完成和 `PureRenderMixin` 相同的功能。
-
-如果你的React组件的绘制函数是 “干净的” （换句话说，它在给定的 props 和 state 下绘制相同的结果）,你可以使用这个辅助函数以在某些情况下提升性能。
-
-例如:
-
-```js
-var shallowCompare = require('react-addons-shallow-compare');
-export class SampleComponent extends React.Component {
-  shouldComponentUpdate(nextProps, nextState) {
-    return shallowCompare(this, nextProps, nextState);
-  }
-
-  render() {
-    return <div className={this.props.className}>foo</div>;
-  }
-}
-```
-
-`shallowCompare` 对当前的 `props` 和 `nextProps`对象 执行一个浅的相等检查，同样对于 `state` 和 `nextState`对象。
-它 通过迭代比较对象的keys 并在 对象的key值不严格相等时返回false 实现此功能.
-
-`shallowCompare` 返回 `true` 如果对 props 或 state的浅比较失败，因此组件应该更新。
-`shallowCompare` 返回 `false` 如果对 props 或 state的浅比较都通过了，因此组件不应该更新。
diff --git a/docs/docs/10.2-form-input-binding-sugar.it-IT.md b/docs/docs/10.2-form-input-binding-sugar.it-IT.md
deleted file mode 100644
index 923bd07f1145..000000000000
--- a/docs/docs/10.2-form-input-binding-sugar.it-IT.md
+++ /dev/null
@@ -1,114 +0,0 @@
----
-id: two-way-binding-helpers-it-IT
-title: Helper Per Binding Bidirezionali
-permalink: two-way-binding-helpers-it-IT.html
-prev: animation-it-IT.html
-next: test-utils-it-IT.html
----
-
-`ReactLink` è una maniera semplice di esprimere binding bidirezionali con React.
-
-> Nota:
->
-> Se hai poca esperienza del framework, nota che `ReactLink` non è necessario per molte applicazioni e dovrebbe essere utilizzato con cautela.
-
-In React, i dati fluiscono in una direzione: dal proprietario ai figli. Questo poiché i dati fluiscono in una sola direzione nel [modello di computazione di Von Neumann](https://en.wikipedia.org/wiki/Von_Neumann_architecture). Puoi pensare ad esso come "binding unidirezionale dei dati."
-
-Tuttavia, esistono parecchie applicazioni che richiedono di leggere dati e farli fluire nuovamente nel tuo programma. Ad esempio, quando sviluppi dei moduli, vorrai spesso aggiornare uno `state` di React quando ricevi un input dall'utente. O forse vuoi effettuare il layout in JavaScript e reagire ai cambiamenti nelle dimensioni di alcuni elementi DOM.
-
-In React, questo verrebbe implementato ascoltando un evento "change", leggendo la tua fonte di dati (solitamente il DOM) e chiamando `setState()` su uno dei tuoi componenti. "Chiudere il ciclo del flusso dei dati" esplicitamente conduce a programmi più comprensibili e mantenibili. Consulta [la nostra documentazione sui moduli](/react/docs/forms.html) per maggiori informazioni.
-
-Il binding bidirezionale -- assicurarsi implicitamente che alcuni valori nel DOM siano sempre consistenti con degli `state` in  React -- è più conciso e supporta un'ampia varietà di applicazioni. Abbiamo fornito `ReactLink`: zucchero sintattico per impostare il pattern del ciclo del flusso di dati descritto in predecenza, ovvero "collegare" una fonte di dati con lo `state` di React.
-
-> Nota:
->
-> `ReactLink` è soltanto uno strato di astrazione e convenzioni attorno al pattern `onChange`/`setState()`. Non cambia fondamentalmente la maniera in cui i dati fluiscono all'interno della tua applicazione React.
-
-## ReactLink: Prima e Dopo
-
-Ecco un semplice esempio di modulo che non utilizza `ReactLink`:
-
-```javascript
-var NoLink = React.createClass({
-  getInitialState: function() {
-    return {message: 'Ciao!'};
-  },
-  handleChange: function(event) {
-    this.setState({message: event.target.value});
-  },
-  render: function() {
-    var message = this.state.message;
-    return <input type="text" value={message} onChange={this.handleChange} />;
-  }
-});
-```
-
-Ciò funziona molto bene e il flusso di dati è molto chiaro. Tuttavia, in presenza di un gran numero di campi del modulo può risultare assai prolisso. Utilizziamo `ReactLink` per risparmiarci la scrittura di un po' di codice:
-
-```javascript{2,7}
-var WithLink = React.createClass({
-  mixins: [React.addons.LinkedStateMixin],
-  getInitialState: function() {
-    return {message: 'Ciao!'};
-  },
-  render: function() {
-    return <input type="text" valueLink={this.linkState('message')} />;
-  }
-});
-```
-
-`LinkedStateMixin` aggiunge un metodo chiamato `linkState()` al tuo componente React. `linkState()` restituisce un oggetto `ReactLink` contenente il valore attuae dello stato React e una callback per cambiarlo.
-
-Gli oggetti `ReactLink` possono essere passati su e giù nell'albero come proprietà, quindi è facile (ed esplicito) impostare un binding bidirezionale tra un componente in profondità nella gerarchia e dello stato che si trova più in alto nella gerarchia.
-
-Nota che i checkbox hanno un comportamento speciale riguardo il loro attributo `value`, che è il valore che sarà inviato all'inoltro del modulo se il checkbox è spuntato (il valore predefinito è `on`). L'attributo `value` non è aggiornato quando il checkbox viene spuntato o deselezionato. Per i checkbox occorre usare `checkedLink` anziché `valueLink`:
-```
-<input type="checkbox" checkedLink={this.linkState('booleanValue')} />
-```
-
-
-## Dietro le Quinte
-
-Ci sono due ambiti in `ReactLink`: il posto in cui crei l'istanza di `ReactLink` e il posto in cui la utilizzi. Per dimostrare quanto sia semplice usare `ReactLink`, riscriviamo ciascun ambito separatamente perché sia più esplicito.
-
-### ReactLink Senza LinkedStateMixin
-
-```javascript{5-7,9-12}
-var WithoutMixin = React.createClass({
-  getInitialState: function() {
-    return {message: 'Ciao!'};
-  },
-  handleChange: function(newValue) {
-    this.setState({message: newValue});
-  },
-  render: function() {
-    var valueLink = {
-      value: this.state.message,
-      requestChange: this.handleChange
-    };
-    return <input type="text" valueLink={valueLink} />;
-  }
-});
-```
-
-Come puoi vedere, gli oggetti `ReactLink` sono semplici oggetti che hanno due proprietà: `value` e `requestChange`. `LinkedStateMixin` è altrettanto semplice: popola semplicemente questi campi con un valore da `this.state` e una callback che invoca `this.setState()`.
-
-### ReactLink Senza valueLink
-
-```javascript
-var WithoutLink = React.createClass({
-  mixins: [React.addons.LinkedStateMixin],
-  getInitialState: function() {
-    return {message: 'Ciao!'};
-  },
-  render: function() {
-    var valueLink = this.linkState('message');
-    var handleChange = function(e) {
-      valueLink.requestChange(e.target.value);
-    };
-    return <input type="text" value={valueLink.value} onChange={handleChange} />;
-  }
-});
-```
-
-La proprietà `valueLink` è anche abbastanza semplice. Gestisce semplicemente l'evento `onChange` e invoca `this.props.valueLink.requestChange()`, e inoltre utilizza `this.props.valueLink.value` anziché `this.props.value`. Tutto qua!
diff --git a/docs/docs/10.2-form-input-binding-sugar.ja-JP.md b/docs/docs/10.2-form-input-binding-sugar.ja-JP.md
deleted file mode 100644
index 7f5ee3c96876..000000000000
--- a/docs/docs/10.2-form-input-binding-sugar.ja-JP.md
+++ /dev/null
@@ -1,114 +0,0 @@
----
-id: two-way-binding-helpers
-title: 2ウェイバインディングのヘルパ
-permalink: two-way-binding-helpers-ja-JP.html
-prev: animation-ja-JP.html
-next: test-utils-ja-JP.html
----
-
-`ReactLink` はReactで2ウェイバインディングを表現する簡単な方法です。
-
-> 注意:
-> もしあなたがフレームワークについてあまりよく知らないのであれば、 `ReactLink` は多くのアプリケーションには必要なく、慎重に使うべきであることに注意してください。
-
-Reactでは所有者から子要素へと、データの流れは一方向です。これはデータが[Von Neumannのコンピューティングモデル](https://en.wikipedia.org/wiki/Von_Neumann_architecture)によって一方向にのみ流れるからです。これを「1ウェイデータバインディング」だと考えることができます。
-
-しかし、データやプログラムに戻る流れを読む必要が有るアプリケーションもたくさんあります。例えば、フォームを作る際に、ユーザのインプットを受け取った時には、Reactの `state` を更新したいと思うことはよくあるでしょう。または、JavaScriptでレイアウトを形作ったり、DOM要素のサイズの変化に反応したいと思うでしょう。
-
-Reactでは、「変更」のイベントを検知し、データソース（普通はDOMです）を読み、コンポーネントのうちの1つの上で `setState()` を呼ぶことでこの要求を満たすことができます。「データフローのループを止めること」は理解しやすく、維持しやすいプログラムを明確に導きます。詳細な情報については、[フォームのドキュメント](/react/docs/forms-ja-JP.html)をご覧ください。
-
-2ウェイバインディングはDOMの値が常にReactの `state` と一致していることを暗黙に強制しますが、簡潔で、多くの種類のアプリケーションをサポートします。上で説明されているような共通のデータフローループパターンのセットアップや、データソースをReactの `state` に「接続する」ための糖衣構文である `ReactLink` が提供されています。
-
-> 注意:
-> `ReactLink` は薄いラッパーであり、 `onChange`/`setState()` パターンにおける習慣です。Reactアプリケーションのデータフローの方法を根本から変えるようなものではありません。
-
-## ReactLink: ビフォーアフター
-
-以下が、 `ReactLink` を使用しない単純なフォームの例です。
-
-```javascript
-var NoLink = React.createClass({
-  getInitialState: function() {
-    return {message: 'Hello!'};
-  },
-  handleChange: function(event) {
-    this.setState({message: event.target.value});
-  },
-  render: function() {
-    var message = this.state.message;
-    return <input type="text" value={message} onChange={this.handleChange} />;
-  }
-});
-```
-
-これはとてもよく動き、データがどう流れているかとても明確です。しかし、たくさんのフォームのフィールドがあった場合、少し冗長になります。以下のように、 `ReactLink` を使うことでタイピング量が少なくて済みます。
-
-```javascript{2,7}
-var WithLink = React.createClass({
-  mixins: [React.addons.LinkedStateMixin],
-  getInitialState: function() {
-    return {message: 'Hello!'};
-  },
-  render: function() {
-    return <input type="text" valueLink={this.linkState('message')} />;
-  }
-});
-```
-
-`LinkedStateMixin` は `linkState()` と呼ばれるReactコンポーネントにメソッドを追加します。
-`linkState()` はReactのステータスの現在の値と、それを変更するコールバックを持った `ReactLink` オブジェクトを返します。
-
-`ReactLink` オブジェクトはプロパティとして、木構造の上や下に渡される可能性があります。だから、階層の深い位置にいるコンポーネントと階層の高い位置にいるステータスの間の2ウェイバインディングをセットアップすることは簡単（で、明確）です。
-
-チェックボックスはその `value` 属性に対しての特別な態度を持っていることに注意してください。それは、チェックボックスがチェックされている（デフォルトで `on` ）場合にフォームのサブミットで送信される値です。 `value` 属性はチェックボックスがチェックされていても、チェックされていなくても、更新されません。チェックボックスについては、`valueLink` の代わりに、 `checkedLink` を使うべきです。以下のように。
-
-```
-<input type="checkbox" checkedLink={this.linkState('booleanValue')} />
-```
-
-
-## フードの下
-
-`ReactLink` には2つの側面があります。 `ReactLink` のインスタンスを作成する場所と、それを使う場所です。 `ReactLink` がどれだけ単純か証明するために、それぞれの側面を分けて、明確に再度記述してみましょう。
-
-### LinkedStateMixinを使わないReactLink
-
-```javascript{5-7,9-12}
-var WithoutMixin = React.createClass({
-  getInitialState: function() {
-    return {message: 'Hello!'};
-  },
-  handleChange: function(newValue) {
-    this.setState({message: newValue});
-  },
-  render: function() {
-    var valueLink = {
-      value: this.state.message,
-      requestChange: this.handleChange
-    };
-    return <input type="text" valueLink={valueLink} />;
-  }
-});
-```
-
-今まで見てきたように `ReactLink` オブジェクトは `value` と `requestChange` プロパティだけを持ったとても単純なオブジェクトです。そして、 `LinkedStateMixin` も同様に単純です。それらのフィールドを `this.state` の値と、 `this.setState()` を呼ぶコールバックで満たします。
-
-### valueLinkを使わないReactLink
-
-```javascript
-var WithoutLink = React.createClass({
-  mixins: [React.addons.LinkedStateMixin],
-  getInitialState: function() {
-    return {message: 'Hello!'};
-  },
-  render: function() {
-    var valueLink = this.linkState('message');
-    var handleChange = function(e) {
-      valueLink.requestChange(e.target.value);
-    };
-    return <input type="text" value={valueLink.value} onChange={handleChange} />;
-  }
-});
-```
-
-`valueLink` プロパティも同様にとても単純です。単純に `onChange` イベントをハンドルし、 `this.props.valueLink.requestChange()` を呼び、 `this.props.value` の代わりに `this.props.valueLink.value` を使用します。それだけです！
diff --git a/docs/docs/10.2-form-input-binding-sugar.ko-KR.md b/docs/docs/10.2-form-input-binding-sugar.ko-KR.md
deleted file mode 100644
index e7c46602e3e5..000000000000
--- a/docs/docs/10.2-form-input-binding-sugar.ko-KR.md
+++ /dev/null
@@ -1,117 +0,0 @@
----
-id: two-way-binding-helpers-ko-KR
-title: 양방향 바인딩 핼퍼
-permalink: two-way-binding-helpers-ko-KR.html
-prev: animation-ko-KR.html
-next: test-utils-ko-KR.html
----
-
-`ReactLink`는 React에서 양방향 바인딩을 표현하는 쉬운 방법입니다.
-
-> 주의:
->
-> 프레임워크를 새로 접하신다면, 대부분의 애플리케이션에서 `ReactLink`는 필요없고 신중히 사용하셔야 함을 알려드립니다.
-
-React에서 데이터 흐름은 소유주에서 자식으로의 단방향입니다. 이는 [폰 노이만 컴퓨팅 모델](http://ko.wikipedia.org/wiki/%ED%8F%B0_%EB%85%B8%EC%9D%B4%EB%A7%8C_%EA%B5%AC%EC%A1%B0)의 데이터가 단방향으로 흐르기 때문입니다. 이것을 "단방향 데이터 바인딩"으로 생각하셔도 됩니다.
-
-하지만 많은 애플리케이션에서 데이터를 요청해서 프로그램으로 돌려줍니다. 예를 들어, 폼을 개발한다면, 사용자 입력을 받았을 때 `state`를 바꾸거나, JavaScript안에서 레이아웃을 바꾸고 그에 따라 어떤 DOM 엘리먼트의 크기를 바꾸게 하고 싶을 수도 있습니다.
-
-React에서 이는 "change" 이벤트를 감시하고 데이터 소스(보통 DOM)에서 읽어 컴포넌트에서 `setState()`를 호출하는 식으로 할 수 있습니다. "데이터 흐름 반복을 제한"하면 더 이해하기 편하고, 쉽게 유지보수할 수 있는 프로그램이 만들어지는 것은 명확합니다. 더 자세한 내용은 [폼 문서](/react/docs/forms-ko-KR.html)를 확인하세요.
-
-양방향 바인딩(묵시적으로 DOM의 어떤 값은 React `state`와 일치하도록 강제하는 것)은 간결하기도 하고 다양한 애플리케이션을 지원 할 수 있습니다. React는 `ReactLink`를 제공합니다. 이는 위에서 설명한 일반적인 데이터 흐름 반복 패턴을 설정하거나, 어떤 데이터 소스를 React `state`로 "링크하는" 편의 문법입니다.
-
-> 주의:
->
-> `ReactLink`는 얇은 레퍼고 `onChange`/`setState()`패턴 부분의 관례일 뿐입니다. React 애플리케이션에서의 데이터 흐름을 근본적으로 바꾸지는 않습니다.
-
-## ReactLink: 적용 전후
-
-`ReactLink`를 사용하지 않는 간단한 폼 예제입니다.
-
-```javascript
-var NoLink = React.createClass({
-  getInitialState: function() {
-    return {message: '안녕!'};
-  },
-  handleChange: function(event) {
-    this.setState({message: event.target.value});
-  },
-  render: function() {
-    var message = this.state.message;
-    return <input type="text" value={message} onChange={this.handleChange} />;
-  }
-});
-```
-
-이것은 정말 잘 동작하고, 데이터가 어떻게 흐르는지 매우 명확하게 보여지지만, 폼필드가 많을 경우 약간 장황해 질 수 있습니다. 타이핑을 줄이기 위해 `ReactLink`를 사용해 보겠습니다.
-
-```javascript{4,9}
-var LinkedStateMixin = require('react-addons-linked-state-mixin');
-
-var WithLink = React.createClass({
-  mixins: [LinkedStateMixin],
-  getInitialState: function() {
-    return {message: 'Hello!'};
-  },
-  render: function() {
-    return <input type="text" valueLink={this.linkState('message')} />;
-  }
-});
-```
-
-`LinkedStateMixin`는 React 컴포넌트에 `linkState()`라는 메서드를 추가합니다. `linkState()`는 React state의 현재 값과 그것을 변경할 때의 콜백을 가지는 `ReactLink` 객체를 리턴합니다.
-
-`ReactLink` 객체는 props로 트리의 위나 아래로 넘길 수 있어서, 쉽고 명확하게 계층구조에서 깊이 있는 컴포넌트와 높이 있는 state 사이의 양방향 바인딩을 설정할 수 있습니다.
-
-checkbox의 `value` 어트리뷰트는 다른 것과 다르게 checkbox가 체크되었을 때 폼 submit에 값이 전달되는 것에 주의하세요.(기본값 `on`) 그래서 `value` 어트리뷰트는 checkbox가 체크되거나 해제될 때 업데이트되지 않습니다. checkbox에서는 `valueLink`대신 `checkedLink`를 사용하셔야 합니다.
-```
-<input type="checkbox" checkedLink={this.linkState('booleanValue')} />
-```
-
-## 내부 구조
-
-`ReactLink`에는 크게 인스턴스를 생성하는 면과 사용하는 면이 있습니다. `ReactLink`가 얼마나 간단한지 확인하기 위해, 이 부분들을 보다 명시적으로 고쳐 봅시다.
-
-### LinkedStateMixin 없이 ReactLink 쓰기
-
-```javascript{5-7,9-12}
-var WithoutMixin = React.createClass({
-  getInitialState: function() {
-    return {message: 'Hello!'};
-  },
-  handleChange: function(newValue) {
-    this.setState({message: newValue});
-  },
-  render: function() {
-    var valueLink = {
-      value: this.state.message,
-      requestChange: this.handleChange
-    };
-    return <input type="text" valueLink={valueLink} />;
-  }
-});
-```
-
-보시다시피, `ReactLink` 객체는 `value`와 `requestChange` prop만 가지는 매우 간단한 객체입니다. `LinkedStateMixin`도 간단합니다. 그냥 `this.state`의 값과 `this.setState()`에서 호출되는 콜백을 필드로 가질 뿐입니다.
-
-### valueLink 없이 ReactLink 쓰기
-
-```javascript
-var LinkedStateMixin = require('react-addons-linked-state-mixin');
-
-var WithoutLink = React.createClass({
-  mixins: [LinkedStateMixin],
-  getInitialState: function() {
-    return {message: 'Hello!'};
-  },
-  render: function() {
-    var valueLink = this.linkState('message');
-    var handleChange = function(e) {
-      valueLink.requestChange(e.target.value);
-    };
-    return <input type="text" value={valueLink.value} onChange={handleChange} />;
-  }
-});
-```
-
-`valueLink` prop도 간단합니다. 단순히 `onChange` 이벤트를 처리하고 `this.props.valueLink.requestChange()`를 호출하고 `this.props.value`대신 `this.props.valueLink.value`를 사용합니다. 그게 다에요!
diff --git a/docs/docs/10.2-form-input-binding-sugar.md b/docs/docs/10.2-form-input-binding-sugar.md
deleted file mode 100644
index 7c4ae378ee1d..000000000000
--- a/docs/docs/10.2-form-input-binding-sugar.md
+++ /dev/null
@@ -1,117 +0,0 @@
----
-id: two-way-binding-helpers
-title: Two-Way Binding Helpers
-permalink: two-way-binding-helpers.html
-prev: animation.html
-next: test-utils.html
----
-
-`ReactLink` is an easy way to express two-way binding with React.
-
-> Note:
->
-> ReactLink is deprecated as of React v15. The recommendation is to explicitly set the value and change handler, instead of using ReactLink.
-
-In React, data flows one way: from owner to child. This is because data only flows one direction in [the Von Neumann model of computing](https://en.wikipedia.org/wiki/Von_Neumann_architecture). You can think of it as "one-way data binding."
-
-However, there are lots of applications that require you to read some data and flow it back into your program. For example, when developing forms, you'll often want to update some React `state` when you receive user input. Or perhaps you want to perform layout in JavaScript and react to changes in some DOM element size.
-
-In React, you would implement this by listening to a "change" event, read from your data source (usually the DOM) and call `setState()` on one of your components. "Closing the data flow loop" explicitly leads to more understandable and easier-to-maintain programs. See [our forms documentation](/react/docs/forms.html) for more information.
-
-Two-way binding -- implicitly enforcing that some value in the DOM is always consistent with some React `state` -- is concise and supports a wide variety of applications. We've provided `ReactLink`: syntactic sugar for setting up the common data flow loop pattern described above, or "linking" some data source to React `state`.
-
-> Note:
->
-> `ReactLink` is just a thin wrapper and convention around the `onChange`/`setState()` pattern. It doesn't fundamentally change how data flows in your React application.
-
-## ReactLink: Before and After
-
-Here's a simple form example without using `ReactLink`:
-
-```javascript
-var NoLink = React.createClass({
-  getInitialState: function() {
-    return {message: 'Hello!'};
-  },
-  handleChange: function(event) {
-    this.setState({message: event.target.value});
-  },
-  render: function() {
-    var message = this.state.message;
-    return <input type="text" value={message} onChange={this.handleChange} />;
-  }
-});
-```
-
-This works really well and it's very clear how data is flowing, however, with a lot of form fields it could get a bit verbose. Let's use `ReactLink` to save us some typing:
-
-```javascript{4,9}
-var LinkedStateMixin = require('react-addons-linked-state-mixin');
-
-var WithLink = React.createClass({
-  mixins: [LinkedStateMixin],
-  getInitialState: function() {
-    return {message: 'Hello!'};
-  },
-  render: function() {
-    return <input type="text" valueLink={this.linkState('message')} />;
-  }
-});
-```
-
-`LinkedStateMixin` adds a method to your React component called `linkState()`. `linkState()` returns a `ReactLink` object which contains the current value of the React state and a callback to change it.
-
-`ReactLink` objects can be passed up and down the tree as props, so it's easy (and explicit) to set up two-way binding between a component deep in the hierarchy and state that lives higher in the hierarchy.
-
-Note that checkboxes have a special behavior regarding their `value` attribute, which is the value that will be sent on form submit if the checkbox is checked (defaults to `on`). The `value` attribute is not updated when the checkbox is checked or unchecked. For checkboxes, you should use `checkedLink` instead of `valueLink`:
-```
-<input type="checkbox" checkedLink={this.linkState('booleanValue')} />
-```
-
-## Under the Hood
-
-There are two sides to `ReactLink`: the place where you create the `ReactLink` instance and the place where you use it. To prove how simple `ReactLink` is, let's rewrite each side separately to be more explicit.
-
-### ReactLink Without LinkedStateMixin
-
-```javascript{5-7,9-12}
-var WithoutMixin = React.createClass({
-  getInitialState: function() {
-    return {message: 'Hello!'};
-  },
-  handleChange: function(newValue) {
-    this.setState({message: newValue});
-  },
-  render: function() {
-    var valueLink = {
-      value: this.state.message,
-      requestChange: this.handleChange
-    };
-    return <input type="text" valueLink={valueLink} />;
-  }
-});
-```
-
-As you can see, `ReactLink` objects are very simple objects that just have a `value` and `requestChange` prop. And `LinkedStateMixin` is similarly simple: it just populates those fields with a value from `this.state` and a callback that calls `this.setState()`.
-
-### ReactLink Without valueLink
-
-```javascript
-var LinkedStateMixin = require('react-addons-linked-state-mixin');
-
-var WithoutLink = React.createClass({
-  mixins: [LinkedStateMixin],
-  getInitialState: function() {
-    return {message: 'Hello!'};
-  },
-  render: function() {
-    var valueLink = this.linkState('message');
-    var handleChange = function(e) {
-      valueLink.requestChange(e.target.value);
-    };
-    return <input type="text" value={valueLink.value} onChange={handleChange} />;
-  }
-});
-```
-
-The `valueLink` prop is also quite simple. It simply handles the `onChange` event and calls `this.props.valueLink.requestChange()` and also uses `this.props.valueLink.value` instead of `this.props.value`. That's it!
diff --git a/docs/docs/10.2-form-input-binding-sugar.zh-CN.md b/docs/docs/10.2-form-input-binding-sugar.zh-CN.md
deleted file mode 100644
index 5adb0145da6b..000000000000
--- a/docs/docs/10.2-form-input-binding-sugar.zh-CN.md
+++ /dev/null
@@ -1,117 +0,0 @@
----
-id: two-way-binding-helpers-zh-CN
-title: 双向绑定辅助
-permalink: two-way-binding-helpers-zh-CN.html
-prev: animation-zh-CN.html
-next: test-utils-zh-CN.html
----
-
-`ReactLink` 是一个用React表达双向绑定的简单方法。
-
-> 注意：
->
-> 在 React v15 中 ReactLink 被弃用了。推荐明确的设置值和变动的处理，而不是使用 ReactLink。
-
-在React里，数据单向流动： 从拥有者到子级。这是因为数据只单向流动[the Von Neumann model of computing](https://en.wikipedia.org/wiki/Von_Neumann_architecture)。你可以把它想象为 “单向数据绑定”。
-
-然而，有很多应用需要你去读某些数据并回流他们到你的程序。例如，当开发forms，你会常常想更新一些React `state` 当你收到用户输入的时候。或者也许你想在JavaScript完成布局并相应一些DOM元素大小的变化。
-
-在React里，你可以用监听 "change" 事件来实现它，从你的数据源（通常是DOM）读取并在你的某个组件调用 `setState()` 。明确的"Closing the data flow loop" 致使了更容易理解和维护的程序。更多信息见[our forms documentation](/react/docs/forms.html).
-
-双向绑定 -- 隐含的强迫DOM里的某些值总是和某些React `state` 同步 -- 简洁并支持大量多样的应用。 我们提供了 `ReactLink`：设置如上描述的通用数据回流模式的语法糖，或者 "linking" 某些数据结构到 React `state`.
-
-> 注意:
->
-> `ReactLink` 只是一层对 `onChange`/`setState()` 模式的薄包装。它没有根本性的改变你的React应用里数据如何流动。
-
-## ReactLink: 之前和之后
-
-这里有一个简单的 不用 `ReactLink` 的 form 例子：
-
-```javascript
-var NoLink = React.createClass({
-  getInitialState: function() {
-    return {message: 'Hello!'};
-  },
-  handleChange: function(event) {
-    this.setState({message: event.target.value});
-  },
-  render: function() {
-    var message = this.state.message;
-    return <input type="text" value={message} onChange={this.handleChange} />;
-  }
-});
-```
-
-这个工作的很好并且数据如何流动很清晰，然而，当有大量的 form fields时，可能会有些冗长。让我们使用  `ReactLink` 来节省我们的输入：
-
-```javascript{4,9}
-var LinkedStateMixin = require('react-addons-linked-state-mixin');
-
-var WithLink = React.createClass({
-  mixins: [LinkedStateMixin],
-  getInitialState: function() {
-    return {message: 'Hello!'};
-  },
-  render: function() {
-    return <input type="text" valueLink={this.linkState('message')} />;
-  }
-});
-```
-
-`LinkedStateMixin` 添加了一个 `linkState()` 方法到你的React组件。`linkState()` 返回一个 `ReactLink` 包含当前React state值的对象和一个改变它的回调函数。
-
-`ReactLink` 对象可以作为props在树中上下传递，所以很容易（显示的）在深层次的组件和高层次的state之间 设置双向绑定。
-
-注意 checkboxes 有一个关于他们 `value` 属性的特殊行为，这个行为是 如果checkbox被选中 值会在表单提交时被发送。 `value` 不会 checkbox 选中或是不选中时更新。对于checkboxes，你应该用`checkedLink` 代替 `valueLink`:
-```
-<input type="checkbox" checkedLink={this.linkState('booleanValue')} />
-```
-
-## 引擎盖下
-
-这里对 `ReactLink`有两方面：创建`ReactLink`的实例以及使用它的地方。为了证明`ReactLink`有多简单，让我们重写两方面一边更好的理解。
-
-### ReactLink Without LinkedStateMixin
-
-```javascript{5-7,9-12}
-var WithoutMixin = React.createClass({
-  getInitialState: function() {
-    return {message: 'Hello!'};
-  },
-  handleChange: function(newValue) {
-    this.setState({message: newValue});
-  },
-  render: function() {
-    var valueLink = {
-      value: this.state.message,
-      requestChange: this.handleChange
-    };
-    return <input type="text" valueLink={valueLink} />;
-  }
-});
-```
-
-正如你所见，`ReactLink`对象是非常简单,只有`value`和`requestChange`属性.并且`LinkStateMixin`也很简单:它只是作用(populates)于`this.state`的元素值并且回调名为`this.setState()`的函数.
-
-### ReactLink Without valueLink
-
-```javascript
-var LinkedStateMixin = require('react-addons-linked-state-mixin');
-
-var WithoutLink = React.createClass({
-  mixins: [LinkedStateMixin],
-  getInitialState: function() {
-    return {message: 'Hello!'};
-  },
-  render: function() {
-    var valueLink = this.linkState('message');
-    var handleChange = function(e) {
-      valueLink.requestChange(e.target.value);
-    };
-    return <input type="text" value={valueLink.value} onChange={handleChange} />;
-  }
-});
-```
-
-对于`valueLink`的属性同样也很简单,它只是简单的处理`onChange`事件,调用`this.props.valueLink.requestChange()`的时候也使用`this.props.valueLink.requestChange()`代替`this.props.value`.这就是双向绑定!
diff --git a/docs/docs/10.3-class-name-manipulation.it-IT.md b/docs/docs/10.3-class-name-manipulation.it-IT.md
deleted file mode 100644
index 9ec5c2cd000d..000000000000
--- a/docs/docs/10.3-class-name-manipulation.it-IT.md
+++ /dev/null
@@ -1,62 +0,0 @@
----
-id: class-name-manipulation-it-IT
-title: Manipolazione del Nome di Classe
-permalink: class-name-manipulation-it-IT.html
-prev: two-way-binding-helpers-it-IT.html
-next: test-utils-it-IT.html
----
-
-> NOTA:
->
-> Questo modulo esiste adesso in forma separata come [JedWatson/classnames](https://github.com/JedWatson/classnames) ed è indipendente da React. Questo add-on verrà quindi rimosso nell'immediato futuro.
-
-`classSet()` è una elegante utility per manipolare facilmente la stringa dell'attributo `class` del DOM.
-
-Ecco uno scenario comune e la sua soluzione senza `classSet()`:
-
-```javascript
-// all'interno di un componente React `<Message />`
-render: function() {
-  var classString = 'message';
-  if (this.props.isImportant) {
-    classString += ' message-important';
-  }
-  if (this.props.isRead) {
-    classString += ' message-read';
-  }
-  // 'message message-important message-read'
-  return <div className={classString}>Fantastico, vediamoci lì.</div>;
-}
-```
-
-Questo può facilmente diventare noioso, in quanto assegnare stringhe per nomi di classi può essere difficile da leggere e soggetto ad errori. `classSet()` risolve questo problema:
-
-```javascript
-render: function() {
-  var cx = React.addons.classSet;
-  var classes = cx({
-    'message': true,
-    'message-important': this.props.isImportant,
-    'message-read': this.props.isRead
-  });
-  // same final string, but much cleaner
-  return <div className={classes}>Fantastico, vediamoci lì.</div>;
-}
-```
-
-Quando usi `classSet()`, passa un oggetto le cui chiavi sono i nomi di classe CSS di cui potresti o meno avere bisogno. Valori di verità risulteranno nell'inclusione della chiave nella stringa risultante.
-
-`classSet()` ti permette inoltre di passare nomi di classe che devono essere concatenati come argomenti:
-
-```javascript
-render: function() {
-  var cx = React.addons.classSet;
-  var importantModifier = 'message-important';
-  var readModifier = 'message-read';
-  var classes = cx('message', importantModifier, readModifier);
-  // Final string is 'message message-important message-read'
-  return <div className={classes}>Fantastico, vediamoci lì.</div>;
-}
-```
-
-Niente più hack per concatenare le stringhe!
diff --git a/docs/docs/10.3-class-name-manipulation.ja-JP.md b/docs/docs/10.3-class-name-manipulation.ja-JP.md
deleted file mode 100644
index d96ecb44f01f..000000000000
--- a/docs/docs/10.3-class-name-manipulation.ja-JP.md
+++ /dev/null
@@ -1,61 +0,0 @@
----
-id: class-name-manipulation
-title: クラス名の操作
-permalink: class-name-manipulation-ja-JP.html
-prev: two-way-binding-helpers-ja-JP.html
-next: test-utils-ja-JP.html
----
-
-> 注意:
-> このモジュールは現在[JedWatson/classnames](https://github.com/JedWatson/classnames)に独立して存在しており、Reactは変更を検知していません。したがって、こちらは将来削除される予定です。
-
-`classSet()` はDOMの `class` 文字列を簡単に操作するすっきりとしたユーティリティです。
-
-以下は、 `classSet()` を使用しない共通なシナリオと解決策です。
-
-```javascript
-// `<Message />` などの中のReactコンポーネント
-render: function() {
-  var classString = 'message';
-  if (this.props.isImportant) {
-    classString += ' message-important';
-  }
-  if (this.props.isRead) {
-    classString += ' message-read';
-  }
-  // 'message message-important message-read'
-  return <div className={classString}>Great, I'll be there.</div>;
-}
-```
-
-上記は、クラス名を文字列として渡しているので、面倒で、読みにくく、エラーが発生しやすくなります。以下のように、 `classSet()` を使用するとこの問題が解決します。
-
-```javascript
-render: function() {
-  var cx = React.addons.classSet;
-  var classes = cx({
-    'message': true,
-    'message-important': this.props.isImportant,
-    'message-read': this.props.isRead
-  });
-  // 同様に最終的には文字列になりますが、クリアにはなります
-  return <div className={classes}>Great, I'll be there.</div>;
-}
-```
-
- `classSet()` を使用する際には、キーと、必要であったり、必要でないCSSのクラス名をオブジェクトとして渡してください。値が真であるものはキーとなり、最終的には文字列の一部になります。
-
-`classSet()` もまた、以下のように連結した文字列の引数としてクラス名を渡します。
-
-```javascript
-render: function() {
-  var cx = React.addons.classSet;
-  var importantModifier = 'message-important';
-  var readModifier = 'message-read';
-  var classes = cx('message', importantModifier, readModifier);
-  // 最終的な文字列は 'message message-important message-read'
-  return <div className={classes}>Great, I'll be there.</div>;
-}
-```
-
-文字列の連結を手で書くのはやめましょう！
diff --git a/docs/docs/10.3-class-name-manipulation.ko-KR.md b/docs/docs/10.3-class-name-manipulation.ko-KR.md
deleted file mode 100644
index 463d6a1dbdec..000000000000
--- a/docs/docs/10.3-class-name-manipulation.ko-KR.md
+++ /dev/null
@@ -1,62 +0,0 @@
----
-id: class-name-manipulation-ko-KR
-title: 클래스 이름 조작
-permalink: class-name-manipulation-ko-KR.html
-prev: two-way-binding-helpers-ko-KR.html
-next: test-utils-ko-KR.html
----
-
-> 주의:
->
-> 이 모듈은 폐기예정입니다. 대신 [JedWatson/classnames](https://github.com/JedWatson/classnames)를 사용하세요.
-
-`classSet()`은 간단히 DOM `class` 문자열을 조작하는 편리한 도구입니다.
-
-일반적으로 있을법한 경우와 `classSet()`을 사용하지 않았을 때의 처리법을 보시죠.
-
-```javascript
-// 어떤 `<Message />` React 컴포넌트의 안쪽
-render: function() {
-  var classString = 'message';
-  if (this.props.isImportant) {
-    classString += ' message-important';
-  }
-  if (this.props.isRead) {
-    classString += ' message-read';
-  }
-  // 'message message-important message-read'
-  return <div className={classString}>좋아요, 거기서 봅시다.</div>;
-}
-```
-
-이것은 순식간에 장황해질 수 있습니다. 클래스 이름 문자열은 읽기 어렵고 에러가 발생하기도 쉽죠. `classSet()`가 이 문제를 해결할 수 있습니다.
-
-```javascript
-render: function() {
-  var cx = React.addons.classSet;
-  var classes = cx({
-    'message': true,
-    'message-important': this.props.isImportant,
-    'message-read': this.props.isRead
-  });
-  // 최종 문자열은 동일하지만, 훨씬 깔끔함
-  return <div className={classes}>좋아요, 거기서 봅시다.</div>;
-}
-```
-
-`classSet()`을 사용할 때 사용할지 안할지 잘 모르는 CSS 클래스 이름 키와 함께 객체를 전달합니다. true로 간주되는(Truthy) 값은 키를 결과 문자열의 일부로 만듭니다.
-
-`classSet()`은 클래스 이름을 인자로 넘겨 연결되게 할 수도 있습니다.
-
-```javascript
-render: function() {
-  var cx = React.addons.classSet;
-  var importantModifier = 'message-important';
-  var readModifier = 'message-read';
-  var classes = cx('message', importantModifier, readModifier);
-  // 최종 문자열은 'message message-important message-read'
-  return <div className={classes}>좋아요, 거기서 봅시다.</div>;
-}
-```
-
-복잡한 문자열 연결은 이제 안하셔도 됩니다!
diff --git a/docs/docs/10.3-class-name-manipulation.md b/docs/docs/10.3-class-name-manipulation.md
deleted file mode 100644
index 4a3567d41045..000000000000
--- a/docs/docs/10.3-class-name-manipulation.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-id: class-name-manipulation
-title: Class Name Manipulation
-permalink: class-name-manipulation.html
-prev: two-way-binding-helpers.html
-next: test-utils.html
----
-
-> NOTE:
->
-> This module has been deprecated; use [JedWatson/classnames](https://github.com/JedWatson/classnames) instead.
diff --git a/docs/docs/10.3-class-name-manipulation.zh-CN.md b/docs/docs/10.3-class-name-manipulation.zh-CN.md
deleted file mode 100644
index 48b38d909066..000000000000
--- a/docs/docs/10.3-class-name-manipulation.zh-CN.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-id: class-name-manipulation-zh-CN
-title: 类名操纵
-permalink: class-name-manipulation-zh-CN.html
-prev: two-way-binding-helpers-zh-CN.html
-next: test-utils-zh-CN.html
----
-
-> NOTE:
->
-> 此模块已被弃用; 用 [JedWatson/classnames](https://github.com/JedWatson/classnames) 替代.
diff --git a/docs/docs/10.4-test-utils.it-IT.md b/docs/docs/10.4-test-utils.it-IT.md
deleted file mode 100644
index 2cf3262fd7eb..000000000000
--- a/docs/docs/10.4-test-utils.it-IT.md
+++ /dev/null
@@ -1,233 +0,0 @@
----
-id: test-utils-it-IT
-title: Utilità di Test
-permalink: test-utils-it-IT.html
-prev: two-way-binding-helpers-it-IT.html
-next: clone-with-props-it-IT.html
----
-
-`React.addons.TestUtils` semplifica la validazione dei componenti React nel framework di test di tua scelta (noi utilizziamo [Jest](https://facebook.github.io/jest/)).
-
-### Simulate
-
-```javascript
-Simulate.{eventName}(
-  DOMElement element,
-  [object eventData]
-)
-```
-
-Simula l'inoltro di un evento su un nodo DOM con dei dati dell'evento opzionali `eventData`. **Questa è probabilmente l'utilità più essenziale in `ReactTestUtils`.**
-
-**Cliccare un elemento**
-
-```javascript
-var node = ReactDOM.findDOMNode(this.refs.button);
-React.addons.TestUtils.Simulate.click(node);
-```
-
-**Cambiare il valore di un campo di input e in seguito premere INVIO**
-
-```javascript
-var node = ReactDOM.findDOMNode(this.refs.input);
-node.value = 'giraffe';
-React.addons.TestUtils.Simulate.change(node);
-React.addons.TestUtils.Simulate.keyDown(node, {key: "Enter", keyCode: 13, which: 13});
-```
-
-*nota che dovrai fornire tu stesso ciascuna proprietà dell'evento utilizzata nel tuo componente (ad es. keyCode, which, etc...) in quanto React non crea alcuna di esse per te*
-
-`Simulate` possiede un metodo per ciascun evento che React comprende.
-
-### renderIntoDocument
-
-```javascript
-ReactComponent renderIntoDocument(
-  ReactElement instance
-)
-```
-
-Effettua il rendering di un componente in un nodo DOM staccato dal documento. **Questa funzione richiede la presenza del DOM.**
-
-### mockComponent
-
-```javascript
-object mockComponent(
-  function componentClass,
-  [string mockTagName]
-)
-```
-
-Passa il mock di un componente a questo metodo per aumentarlo con metodi utili che gli permettono di essere utilizzato come un componente React fantoccio. Anziché essere visualizzato come al solito, il componente diventerà un semplice `<div>` (o qualsiasi altro tag se fornito come valore di `mockTagName`) contenente ciascun figlio fornito.
-
-### isElement
-
-```javascript
-boolean isElement(
-  ReactElement element
-)
-```
-
-Restituisce `true` se `element` è un qualunque ReactElement.
-
-### isElementOfType
-
-```javascript
-boolean isElementOfType(
-  ReactElement element,
-  function componentClass
-)
-```
-
-Restituisce `true` se `element` è un ReactElement il cui tipo è la classe React `componentClass`.
-
-### isDOMComponent
-
-```javascript
-boolean isDOMComponent(
-  ReactComponent instance
-)
-```
-
-Restituisce `true` se `instance` è un componente DOM (come ad esempio `<div>` o `<span>`).
-
-### isCompositeComponent
-
-```javascript
-boolean isCompositeComponent(
-  ReactComponent instance
-)
-```
-
-Restituisce `true` se `instance` è un componente composito (creato tramite `React.createClass()`).
-
-### isCompositeComponentWithType
-
-```javascript
-boolean isCompositeComponentWithType(
-  ReactComponent instance,
-  function componentClass
-)
-```
-
-Restituisce `true` se `instance` è un componente composito (creato tramite `React.createClass()`) il cui tipo è una classe React dal nome `componentClass`.
-
-### findAllInRenderedTree
-
-```javascript
-array findAllInRenderedTree(
-  ReactComponent tree,
-  function test
-)
-```
-
-Attraversa tutti i componenti in `tree` e accumula tutti i componenti per i quali `test(component)` è `true`. Non è molto utile usata da sola, ma diventa ptente se usata come primitiva per altre utilità di test.
-
-### scryRenderedDOMComponentsWithClass
-
-```javascript
-array scryRenderedDOMComponentsWithClass(
-  ReactComponent tree, string className
-)
-```
-
-Trova tutte le istanze di componenti nell'albero visualizzato che sono componenti DOM il cui nome di classe corrisponde a `className`.
-
-### findRenderedDOMComponentWithClass
-
-```javascript
-ReactComponent findRenderedDOMComponentWithClass(
-  ReactComponent tree,
-  string className
-)
-```
-
-Simile a `scryRenderedDOMComponentsWithClass()` ma si aspetta di trovare un solo risultato, e restituisce quel solo risultato, oppure lancia un'eccezione se viene trovato qualunque altro numero di occorrenze diverso da uno.
-
-### scryRenderedDOMComponentsWithTag
-
-```javascript
-array scryRenderedDOMComponentsWithTag(
-  ReactComponent tree,
-  string tagName
-)
-```
-
-Trova tutte le istanze di componenti nell'albero visualizzato che sono componenti DOM il cui nome di tag corrisponde a `tagName`.
-
-### findRenderedDOMComponentWithTag
-
-```javascript
-ReactComponent findRenderedDOMComponentWithTag(
-  ReactComponent tree,
-  string tagName
-)
-```
-
-Simile a `scryRenderedDOMComponentsWithTag()` ma si aspetta di trovare un solo risultato, e restituisce quel solo risultato, oppure lancia un'eccezione se viene trovato qualunque altro numero di occorrenze diverso da uno.
-
-### scryRenderedComponentsWithType
-
-```javascript
-array scryRenderedComponentsWithType(
-  ReactComponent tree,
-  function componentClass
-)
-```
-
-Trova tutte le istanze di componenti il cui tipo corrisponde a `componentClass`.
-
-### findRenderedComponentWithType
-
-```javascript
-ReactComponent findRenderedComponentWithType(
-  ReactComponent tree, function componentClass
-)
-```
-
-Simile a `scryRenderedComponentsWithType()` si aspetta di trovare un solo risultato, oppure lancia un'eccezione se viene trovato qualunque altro numero di occorrenze diverso da uno.
-
-
-## Rendering superficiale
-
-Il rendering superficiale è una caratteristica sperimentale che ti permette di effettuare il rendering di un componente "ad un livello di profondità" e asserire dei fatti su ciò che viene restituito dal suo metodo render, senza preoccuparti del comportamento dei componenti figli, i quali non sono né istanziati né viene effettuato il rendering. Questo non richiede la presenza di un DOM.
-
-```javascript
-ReactShallowRenderer createRenderer()
-```
-
-Chiama questo metodo nei tuoi test per creare un renderer superficiale. Puoi pensare ad esso come un "luogo" in cui effettuare il rendering del componente che stai validando, dove può rispondere ad eventi e aggiornarsi.
-
-```javascript
-shallowRenderer.render(
-  ReactElement element
-)
-```
-
-Simile a `ReactDOM.render`.
-
-```javascript
-ReactComponent shallowRenderer.getRenderOutput()
-```
-
-Dopo che `render` è stato chiamato, restituisce un output di cui è stato effettuato un rendering superficiale. Puoi quindi iniziare ad asserire fatti sull'output. Ad esempio, se il metodo render del tuo componente resituisce:
-
-```javascript
-<div>
-  <span className="heading">Titolo</span>
-  <Subcomponent foo="bar" />
-</div>
-```
-
-Allora puoi asserire:
-
-```javascript
-result = renderer.getRenderOutput();
-expect(result.type).toBe('div');
-expect(result.props.children).toEqual([
-  <span className="heading">Titolo</span>,
-  <Subcomponent foo="bar" />
-]);
-```
-
-La validazione superficiale ha al momento alcune limitazioni, in particolare non supporta i riferimenti. Stiamo rilasciando questa caratteristica in anticipo e gradiremmo ascoltare il parere della comunità React per la direzione in cui debba evolvere.
diff --git a/docs/docs/10.4-test-utils.ja-JP.md b/docs/docs/10.4-test-utils.ja-JP.md
deleted file mode 100644
index 81d0d16bea7d..000000000000
--- a/docs/docs/10.4-test-utils.ja-JP.md
+++ /dev/null
@@ -1,183 +0,0 @@
----
-id: test-utils
-title: テストユーティリティ
-permalink: test-utils-ja-JP.html
-prev: two-way-binding-helpers-ja-JP.html
-next: clone-with-props-ja-JP.html
----
-
-`React.addons.TestUtils` は選んだテストフレームワーク（私たちは[Jest](https://facebook.github.io/jest/)を使っています）において、Reactのコンポーネントをテストすることを簡単にします。
-
-### Simulate
-
-```javascript
-Simulate.{eventName}(DOMElement element, object eventData)
-```
-
-オプションの `eventData` であるイベントデータと共に、DOMノードの上でイベントのディスパッチをシミュレートします。 **これは `ReactTestUtils` の中で最も有用なユーティリティでしょう。**
-
-使用例:
-
-```javascript
-var node = ReactDOM.findDOMNode(this.refs.input);
-React.addons.TestUtils.Simulate.click(node);
-React.addons.TestUtils.Simulate.change(node, {target: {value: 'Hello, world'}});
-React.addons.TestUtils.Simulate.keyDown(node, {key: "Enter"});
-```
-
-`Simulate` はReactが理解出来る全てのイベントのためのメソッドを持っています。
-
-### renderIntoDocument
-
-```javascript
-ReactComponent renderIntoDocument(ReactElement instance)
-```
-
-コンポーネントをドキュメントの中で分離したDOMノードにレンダリングします。 **この関数はDOMを必要とします。**
-
-
-### mockComponent
-
-```javascript
-object mockComponent(function componentClass, string? mockTagName)
-```
-
-有効なダミーのReactのコンポーネントとして使われることを許可するメソッドと共にこれを増強させるためにモックとなったコンポーネントモジュールをこのメソッドに渡してください。いつものようにレンダリングされる代わりに、コンポーネントは単純で、提供された子要素はどんなものでも含む `<div>` （`mockTagName` が提供されている場合はそのタグ）になるでしょう。
-
-### isElement
-
-```javascript
-boolean isElement(ReactElement element)
-```
-
-`element` が何かしらのReactElementだった場合に `true` を返します。
-
-### isElementOfType
-
-```javascript
-boolean isElementOfType(ReactElement element, function componentClass)
-```
-
-`element` がReactの `componentClass` 型であるReactElementだった場合に `true` を返します。
-
-### isDOMComponent
-
-```javascript
-boolean isDOMComponent(ReactComponent instance)
-```
-
-`instance` がDOMのコンポーネントだった場合に `true` を返します( `<div>` や `<span>` のように)。
-
-### isCompositeComponent
-
-```javascript
-boolean isCompositeComponent(ReactComponent instance)`
-```
-
-`instance` が複合的なコンポーネントだった場合に `true` を返します（`React.createClass()` で作成されるような）。
-
-### isCompositeComponentWithType
-
-```javascript
-boolean isCompositeComponentWithType(ReactComponent instance, function componentClass)
-```
-
-`instance` が複合的なコンポーネントだった場合に `true` を返します（`React.createClass()` で作成され、型がReactの `componentClass` であるような）。
-
-### findAllInRenderedTree
-
-```javascript
-array findAllInRenderedTree(ReactComponent tree, function test)
-```
-
-`tree` の中の全てのコンポーネントや `test(component)` が `true` となる蓄積された全てのコンポーネントを検討します。これはこれだけでは有用ではありませんが、他のテストユーティリティの根本として使われます。
-
-### scryRenderedDOMComponentsWithClass
-
-```javascript
-array scryRenderedDOMComponentsWithClass(ReactComponent tree, string className)
-```
-
-レンダリングされたツリーの中で、DOMコンポーネントであり、クラス名が `className` にマッチする、コンポーネントの全てのインスタンスを見つけます。
-
-### findRenderedDOMComponentWithClass
-
-```javascript
-ReactComponent findRenderedDOMComponentWithClass(ReactComponent tree, string className)
-```
-
-`scryRenderedDOMComponentsWithClass()` に似ていますが、結果が1つであること、それを返すこと、またはマッチする個数が1個以外だった場合に例外を投げることを予期します。
-
-### scryRenderedDOMComponentsWithTag
-
-```javascript
-array scryRenderedDOMComponentsWithTag(ReactComponent tree, string tagName)
-```
-
-レンダリングされたツリーの中で、DOMコンポーネントであり、タグ名が `tagName` にマッチする、コンポーネントの全てのインスタンスを見つけます。
-
-### findRenderedDOMComponentWithTag
-
-```javascript
-ReactComponent findRenderedDOMComponentWithTag(ReactComponent tree, string tagName)
-```
-
-`scryRenderedDOMComponentsWithTag()` に似ていますが、結果が1つであること、それを返すこと、またはマッチする個数が1個以外だった場合に例外を投げることを予期します。
-
-### scryRenderedComponentsWithType
-
-```javascript
-array scryRenderedComponentsWithType(ReactComponent tree, function componentClass)
-```
-
-型名が `componentClass` と同様である、コンポーネントの全てのインスタンスを見つけます。
-
-### findRenderedComponentWithType
-
-```javascript
-ReactComponent findRenderedComponentWithType(ReactComponent tree, function componentClass)
-```
-
-`scryRenderedComponentsWithType()` と同じですが、結果が1つであること、それを返すこと、またはマッチする個数が1個以外だった場合に例外を投げることを予期します。
-
-## Shallow rendering
-
-シャローレンダリングは"第一段階の深さ"であるコンポーネントをレンダリングすることを強制し、レンダリングメソッドが返すものについての事実をアサートし、インスタンスを生成したり、レンダリングされたりしない子のコンポーネントの振る舞いについては関心しない実験的な特徴です。これはDOMを必要としません。
-
-```javascript
-ReactShallowRenderer createRenderer()
-```
-
-シャローレンダラーを作成するにはこれをテストの中で呼んでください。これをあなたがテストするコンポーネントをレンダリングする場所であると考えることができます。この場所はイベントに返答したり、これ自身を更新したりできます。
-
-```javascript
-shallowRenderer.render(ReactElement element)
-```
-
-`ReactDOM.render` に同様。
-
-```javascript
-ReactComponent shallowRenderer.getRenderOutput()
-```
-
-`render` が呼ばれた後、浅くレンダリングされた出力を返します。その後、その出力に関しての事実をアサートすることができます。例えば、以下のように、コンポーネントのレンダリングメソッドが返してきた場合は、
-
-```javascript
-<div>
-  <span className="heading">Title</span>
-  <Subcomponent foo="bar" />
-</div>
-```
-
-以下のように、アサートできます。
-
-```javascript
-result = renderer.getRenderOutput();
-expect(result.type).toBe('div');
-expect(result.props.children).toEqual([
-  <span className="heading">Title</span>,
-  <Subcomponent foo="bar" />
-]);
-```
-
-シャローテスティングは現在、制限があります。はっきり言うと、参照をサポートしていません。私たちは、この特徴を早めにリリースし、これが、どのように進化していくか、Reactのコミュニティのフィードバックを評価するつもりです。
diff --git a/docs/docs/10.4-test-utils.ko-KR.md b/docs/docs/10.4-test-utils.ko-KR.md
deleted file mode 100644
index ee44011bf148..000000000000
--- a/docs/docs/10.4-test-utils.ko-KR.md
+++ /dev/null
@@ -1,236 +0,0 @@
----
-id: test-utils-ko-KR
-title: 테스트 유틸리티
-permalink: test-utils-ko-KR.html
-prev: two-way-binding-helpers-ko-KR.html
-next: clone-with-props-ko-KR.html
----
-
-`ReactTestUtils`는 선택한 테스트 프레임워크(React는 [Jest](https://facebook.github.io/jest/)를 사용)에서 React 컴포넌트를 테스트하기 쉽게 합니다.
-
-```
-var ReactTestUtils = require('react-addons-test-utils');
-```
-
-### Simulate
-
-```javascript
-Simulate.{eventName}(
-  DOMElement element,
-  [object eventData]
-)
-```
-
-DOM 노드에 이벤트 디스패치하는 것을 시뮬레이트합니다. 선택적으로 `eventData`를 통해 이벤트 데이터도 처리할 수 있습니다. **아마 `ReactTestUtils`에서 가장 유용한 유틸리티일 것 입니다.**
-
-**엘리먼트 클릭**
-
-```javascript
-// <button ref="button">...</button>
-var node = this.refs.button;
-ReactTestUtils.Simulate.click(node);
-```
-
-**입력 필드의 값을 변경하고 엔터 누르기.**
-
-```javascript
-// <input ref="input" />
-var node = this.refs.input;
-node.value = 'giraffe';
-ReactTestUtils.Simulate.change(node);
-ReactTestUtils.Simulate.keyDown(node, {key: "Enter", keyCode: 13, which: 13});
-```
-
-*컴포넌트에서 사용할 이벤트 프로퍼티(예를 들어 keyCode, which, 등등...)는 React에서 만들어 주지 않으므로 직접 제공해야 합니다.*
-
-`Simulate`에는 React가 이해하는 모든 이벤트에 대해 메소드가 있습니다.
-
-### renderIntoDocument
-
-```javascript
-ReactComponent renderIntoDocument(
-  ReactElement instance
-)
-```
-
-문서의 detach된 DOM 노드에 컴포넌트를 렌더합니다. **이 기능은 DOM을 필요로 합니다.**
-
-> 주의:
->
-> React를 임포트하기 **전에** `window`, `window.document`, `window.document.createElement`을 전역적으로 사용가능하게 해두어야 합니다. 아니면 React는 DOM과 `setState`같은 메소드가 동작하지 않는다고 생각할 수 있습니다.
-
-### mockComponent
-
-```javascript
-object mockComponent(
-  function componentClass,
-  [string mockTagName]
-)
-```
-
-목 컴포넌트 모듈을 이 메소드에 넘겨 더미 React 컴포넌트로 사용할 수 있도록 합니다. 이 더미는 유용한 메소드와 함께 사용해 기능을 보강할 수 있습니다. 일반적인 렌더링과는 다르게, 컴포넌트는 제공된 자식을 포함하는 평범한  `<div>`가 됩니다. (`mockTagName`을 통해 div가 아닌 다른 태그를 지정해 줄 수도 있습니다.)
-
-### isElement
-
-```javascript
-boolean isElement(
-  ReactElement element
-)
-```
-
-`element`가 ReactElement면 `true`를 리턴합니다.
-
-### isElementOfType
-
-```javascript
-boolean isElementOfType(
-  ReactElement element,
-  function componentClass
-)
-```
-
-`element`가 React `componentClass` 타입인 ReactElement면 `true`를 리턴합니다.
-
-### isDOMComponent
-
-```javascript
-boolean isDOMComponent(
-  ReactComponent instance
-)
-```
-
-`instance`가 (`<div>`나 `<span>`같은) DOM 컴포넌트면 `true`를 리턴합니다.
-
-### isCompositeComponent
-
-```javascript
-boolean isCompositeComponent(ReactComponent instance)`
-```
-
-`instance`가 (`React.createClass()`로 생성된) 복합 컴포넌트면 `true`를 리턴합니다.
-
-### isCompositeComponentWithType
-
-```javascript
-boolean isCompositeComponentWithType(
-  ReactComponent instance,
-  function componentClass
-)
-```
-
-`instance`가 (`React.createClass()`로 생성된) 복합 컴포넌트고 React `componentClass` 타입이면 `true`를 리턴합니다.
-
-### findAllInRenderedTree
-
-```javascript
-array findAllInRenderedTree(
-  ReactComponent tree,
-  function test
-)
-```
-
-`tree`안의 모든 컴포넌트에서 `test(component)`가 `true`인 모든 컴포넌트를 모읍니다. 이것만으로는 그렇게 유용하지 않습니다만, 다른 테스트 유틸와 같이 사용합니다.
-
-### scryRenderedDOMComponentsWithClass
-
-```javascript
-array scryRenderedDOMComponentsWithClass(
-  ReactComponent tree, string className
-)
-```
-렌더된 트리의 모든 컴포넌트 인스턴스 중에서 클래스 이름이 `className`인 DOM 컴포넌트들을 찾습니다.
-
-### findRenderedDOMComponentWithClass
-
-```javascript
-ReactComponent findRenderedDOMComponentWithClass(ReactComponent tree, string className)
-```
-
-`scryRenderedDOMComponentsWithClass()`와 비슷하지만 하나의 결과만 기대될 때 사용합니다. 하나의 결과를 리턴하거나 한개 이상의 결과가 나온 경우에는 예외를 던집니다.
-
-### scryRenderedDOMComponentsWithTag
-
-```javascript
-array scryRenderedDOMComponentsWithTag(
-  ReactComponent tree,
-  string tagName
-)
-```
-
-렌더된 트리의 모든 컴포넌트 인스턴스중에서 태그 이름이 `tagName`인 DOM 컴포넌트들을 찾습니다.
-
-### findRenderedDOMComponentWithTag
-
-```javascript
-ReactComponent findRenderedDOMComponentWithTag(
-  ReactComponent tree,
-  string tagName
-)
-```
-
-`scryRenderedDOMComponentsWithTag()`와 비슷하지만 하나의 결과만 기대될 때 사용합니다. 하나의 결과를 리턴하거나 한개 이상의 결과가 나온 경우에는 예외를 던집니다.
-
-### scryRenderedComponentsWithType
-
-```javascript
-array scryRenderedComponentsWithType(
-  ReactComponent tree,
-  function componentClass
-)
-```
-
-타입이 `componentClass`인 모든 컴포넌트 인스턴스를 찾습니다.
-
-### findRenderedComponentWithType
-
-```javascript
-ReactComponent findRenderedComponentWithType(
-  ReactComponent tree, function componentClass
-)
-```
-
-`scryRenderedComponentsWithType()`와 비슷하지만 하나의 결과만 기대될 때 사용합니다. 하나의 결과를 리턴하거나 한개 이상의 결과가 나온 경우에는 예외를 던집니다.
-
-## 얕은 렌더링
-
-얕은 렌더링은 "한 단계 깊이의" 컴포넌트를 렌더할 수 있는 실험적인 기능입니다. 자식 컴포넌트가 인스턴스화 되거나 렌더되는 등의 동작에 대한 걱정 없이 렌더 메소드가 반환하는 것만 검증합니다. 이 기능은 DOM이 필요하지 않습니다.
-
-```javascript
-ReactShallowRenderer createRenderer()
-```
-
-테스트에서 얕은 렌더러를 생성하고자 할때 호출합니다. 이를 이벤트와 업데이트에 스스로 반응하는 컴포넌트를 렌더하기 위한 "장소"라고 생각할 수 있습니다.
-
-```javascript
-shallowRenderer.render(
-  ReactElement element
-)
-```
-
-`ReactDOM.render`와 유사합니다.
-
-```javascript
-ReactElement shallowRenderer.getRenderOutput()
-```
-
-`render`가 호출 된 후, 얕게 렌더된 결과물을 반환합니다. 그 후엔 결과물에 대한 검증을 시작할 수 있습니다. 예를 들어 컴포넌트의 렌더 메소드가 다음을 반환한다면:
-
-```javascript
-<div>
-  <span className="heading">Title</span>
-  <Subcomponent foo="bar" />
-</div>
-```
-
-그 후에는 검증할 수 있습니다:
-
-```javascript
-result = renderer.getRenderOutput();
-expect(result.type).toBe('div');
-expect(result.props.children).toEqual([
-  <span className="heading">Title</span>,
-  <Subcomponent foo="bar" />
-]);
-```
-
-현재 얕은 테스트는 refs를 지원하지 않는 등 몇가지 제약사항이 있습니다. 우리는 이 기능을 빠르게 먼저 배포하고 React 커뮤니티의 피드백을 받아 나아갈 방향을 찾고자 합니다.
diff --git a/docs/docs/10.4-test-utils.md b/docs/docs/10.4-test-utils.md
deleted file mode 100644
index 38b4e16f4b2a..000000000000
--- a/docs/docs/10.4-test-utils.md
+++ /dev/null
@@ -1,244 +0,0 @@
----
-id: test-utils
-title: Test Utilities
-permalink: test-utils.html
-prev: two-way-binding-helpers.html
-next: clone-with-props.html
----
-
-`ReactTestUtils` makes it easy to test React components in the testing framework of your choice (we use [Jest](https://facebook.github.io/jest/)).
-
-```
-var ReactTestUtils = require('react-addons-test-utils');
-```
-
-### Simulate
-
-```javascript
-Simulate.{eventName}(
-  DOMElement element,
-  [object eventData]
-)
-```
-
-Simulate an event dispatch on a DOM node with optional `eventData` event data. **This is possibly the single most useful utility in `ReactTestUtils`.**
-
-**Clicking an element**
-
-```javascript
-// <button ref="button">...</button>
-var node = this.refs.button;
-ReactTestUtils.Simulate.click(node);
-```
-
-**Changing the value of an input field and then pressing ENTER.**
-
-```javascript
-// <input ref="input" />
-var node = this.refs.input;
-node.value = 'giraffe';
-ReactTestUtils.Simulate.change(node);
-ReactTestUtils.Simulate.keyDown(node, {key: "Enter", keyCode: 13, which: 13});
-```
-
-*Note that you will have to provide any event property that you're using in your component (e.g. keyCode, which, etc...) as React is not creating any of these for you.*
-
-`Simulate` has a method for [every event that React understands](/react/docs/events.html#supported-events).
-
-### renderIntoDocument
-
-```javascript
-ReactComponent renderIntoDocument(
-  ReactElement instance
-)
-```
-
-Render a component into a detached DOM node in the document. **This function requires a DOM.**
-
-> Note:
->
-> You will need to have `window`, `window.document` and `window.document.createElement`
- globally available **before** you import React. Otherwise React will think it can't access the DOM and methods like `setState` won't work.
-
-### mockComponent
-
-```javascript
-object mockComponent(
-  function componentClass,
-  [string mockTagName]
-)
-```
-
-Pass a mocked component module to this method to augment it with useful methods that allow it to be used as a dummy React component. Instead of rendering as usual, the component will become a simple `<div>` (or other tag if `mockTagName` is provided) containing any provided children.
-
-### isElement
-
-```javascript
-boolean isElement(
-  ReactElement element
-)
-```
-
-Returns `true` if `element` is any ReactElement.
-
-### isElementOfType
-
-```javascript
-boolean isElementOfType(
-  ReactElement element,
-  function componentClass
-)
-```
-
-Returns `true` if `element` is a ReactElement whose type is of a React `componentClass`.
-
-### isDOMComponent
-
-```javascript
-boolean isDOMComponent(
-  ReactComponent instance
-)
-```
-
-Returns `true` if `instance` is a DOM component (such as a `<div>` or `<span>`).
-
-### isCompositeComponent
-
-```javascript
-boolean isCompositeComponent(
-  ReactComponent instance
-)
-```
-
-Returns `true` if `instance` is a composite component (created with `React.createClass()`).
-
-### isCompositeComponentWithType
-
-```javascript
-boolean isCompositeComponentWithType(
-  ReactComponent instance,
-  function componentClass
-)
-```
-
-Returns `true` if `instance` is a composite component (created with `React.createClass()`) whose type is of a React `componentClass`.
-
-### findAllInRenderedTree
-
-```javascript
-array findAllInRenderedTree(
-  ReactComponent tree,
-  function test
-)
-```
-
-Traverse all components in `tree` and accumulate all components where `test(component)` is `true`. This is not that useful on its own, but it's used as a primitive for other test utils.
-
-### scryRenderedDOMComponentsWithClass
-
-```javascript
-array scryRenderedDOMComponentsWithClass(
-  ReactComponent tree, string className
-)
-```
-
-Finds all instances of components in the rendered tree that are DOM components with the class name matching `className`.
-
-### findRenderedDOMComponentWithClass
-
-```javascript
-ReactComponent findRenderedDOMComponentWithClass(
-  ReactComponent tree,
-  string className
-)
-```
-
-Like `scryRenderedDOMComponentsWithClass()` but expects there to be one result, and returns that one result, or throws exception if there is any other number of matches besides one.
-
-### scryRenderedDOMComponentsWithTag
-
-```javascript
-array scryRenderedDOMComponentsWithTag(
-  ReactComponent tree,
-  string tagName
-)
-```
-
-Finds all instances of components in the rendered tree that are DOM components with the tag name matching `tagName`.
-
-### findRenderedDOMComponentWithTag
-
-```javascript
-ReactComponent findRenderedDOMComponentWithTag(
-  ReactComponent tree,
-  string tagName
-)
-```
-
-Like `scryRenderedDOMComponentsWithTag()` but expects there to be one result, and returns that one result, or throws exception if there is any other number of matches besides one.
-
-### scryRenderedComponentsWithType
-
-```javascript
-array scryRenderedComponentsWithType(
-  ReactComponent tree,
-  function componentClass
-)
-```
-
-Finds all instances of components with type equal to `componentClass`.
-
-### findRenderedComponentWithType
-
-```javascript
-ReactComponent findRenderedComponentWithType(
-  ReactComponent tree, function componentClass
-)
-```
-
-Same as `scryRenderedComponentsWithType()` but expects there to be one result and returns that one result, or throws exception if there is any other number of matches besides one.
-
-## Shallow rendering
-
-Shallow rendering is an experimental feature that lets you render a component "one level deep" and assert facts about what its render method returns, without worrying about the behavior of child components, which are not instantiated or rendered. This does not require a DOM.
-
-```javascript
-ReactShallowRenderer createRenderer()
-```
-
-Call this in your tests to create a shallow renderer. You can think of this as a "place" to render the component you're testing, where it can respond to events and update itself.
-
-```javascript
-shallowRenderer.render(
-  ReactElement element
-)
-```
-
-Similar to `ReactDOM.render`.
-
-```javascript
-ReactElement shallowRenderer.getRenderOutput()
-```
-
-After `render` has been called, returns shallowly rendered output. You can then begin to assert facts about the output. For example, if your component's render method returns:
-
-```javascript
-<div>
-  <span className="heading">Title</span>
-  <Subcomponent foo="bar" />
-</div>
-```
-
-Then you can assert:
-
-```javascript
-var renderer = ReactTestUtils.createRenderer();
-result = renderer.getRenderOutput();
-expect(result.type).toBe('div');
-expect(result.props.children).toEqual([
-  <span className="heading">Title</span>,
-  <Subcomponent foo="bar" />
-]);
-```
-
-Shallow testing currently has some limitations, namely not supporting refs. We're releasing this feature early and would appreciate the React community's feedback on how it should evolve.
diff --git a/docs/docs/10.4-test-utils.zh-CN.md b/docs/docs/10.4-test-utils.zh-CN.md
deleted file mode 100644
index 8a01890d9268..000000000000
--- a/docs/docs/10.4-test-utils.zh-CN.md
+++ /dev/null
@@ -1,244 +0,0 @@
----
-id: test-utils-zh-CN
-title: 测试工具
-permalink: test-utils-zh-CN.html
-prev: two-way-binding-helpers-zh-CN.html
-next: clone-with-props-zh-CN.html
----
-
-`ReactTestUtils` 使你在你选择的测试框架中 (我们使用 [Jest](https://facebook.github.io/jest/)) 测试 React 组件变得容易。
-
-```
-var ReactTestUtils = require('react-addons-test-utils');
-```
-
-### Simulate
-
-```javascript
-Simulate.{eventName}(
-  DOMElement element,
-  [object eventData]
-)
-```
-
-模拟一个在 DOM 节点上带有可选 `eventData` 事件数据的事件派遣（event dispatch）。**这可能是 `ReactTestUtils` 里单独最有用的工具。**
-
-**点击一个元素**
-
-```javascript
-// <button ref="button">...</button>
-var node = this.refs.button;
-ReactTestUtils.Simulate.click(node);
-```
-
-**改变 input 域的值然后点击 回车。**
-
-```javascript
-// <input ref="input" />
-var node = this.refs.input;
-node.value = 'giraffe';
-ReactTestUtils.Simulate.change(node);
-ReactTestUtils.Simulate.keyDown(node, {key: "Enter", keyCode: 13, which: 13});
-```
-
-*注意你将必须提供任何你在你的组件里使用的事件属性（例如 keyCode, which, 等等）因为React没有为你创建任何这类东西。*
-
-`Simulate` has a method for [every event that React understands](/react/docs/events.html#supported-events).
-
-### renderIntoDocument
-
-```javascript
-ReactComponent renderIntoDocument(
-  ReactElement instance
-)
-```
-
-渲染一个组件到 document 里的 detached DOM 节点。**这个函数需要一个 DOM。**
-
-> 注意:
->
-> 在你 import React **之前**，你需要让 `window`, `window.document` 和 `window.document.createElement` 全局可用。
-不然 React 会认为它不能访问 DOM 然后类似 `setState` 的方法会不工作。
-
-### mockComponent
-
-```javascript
-object mockComponent(
-  function componentClass,
-  [string mockTagName]
-)
-```
-
-传入一个 mocked 组件模块到这个方法来给它增加有用的方法，使它可以被用作 dummy React 组件。代替像通常一样的渲染，组件会成为一个简单的包含了任意被提供的子级的 `<div>` （或者其他 tag 名，如果提供了 `mockTagName`）
-
-### isElement
-
-```javascript
-boolean isElement(
-  ReactElement element
-)
-```
-
-返回 `true` 如果 `element` 是任意的 ReactElement。
-
-### isElementOfType
-
-```javascript
-boolean isElementOfType(
-  ReactElement element,
-  function componentClass
-)
-```
-
-返回 `true` 如果 `element` 是一个类型是 React `componentClass` 的 ReactElement。
-
-### isDOMComponent
-
-```javascript
-boolean isDOMComponent(
-  ReactComponent instance
-)
-```
-
-返回 `true` 如果 `instance` 是一个 DOM 组件 （比如一个 `<div>` 或者 `<span>`）。
-
-### isCompositeComponent
-
-```javascript
-boolean isCompositeComponent(
-  ReactComponent instance
-)
-```
-
-返回 `true` 如果 `instance` 是一个复合组件 （由 `React.createClass()` 创建）。
-
-### isCompositeComponentWithType
-
-```javascript
-boolean isCompositeComponentWithType(
-  ReactComponent instance,
-  function componentClass
-)
-```
-
-返回 `true` 如果 `instance` 是一个类型为 React `componentClass` 的复合组件 （由 `React.createClass()` 创建）。
-
-### findAllInRenderedTree
-
-```javascript
-array findAllInRenderedTree(
-  ReactComponent tree,
-  function test
-)
-```
-
-遍历 `tree` 里所有的组件，并累积所有 `test(component)` 为 `true` 的组件。它本身并没有什么用，但是它被用作其他测试工具的基本元素。
-
-### scryRenderedDOMComponentsWithClass
-
-```javascript
-array scryRenderedDOMComponentsWithClass(
-  ReactComponent tree, string className
-)
-```
-
-在渲染的树中查找所有 DOM组件的类名匹配`className` 的组件实例。
-
-### findRenderedDOMComponentWithClass
-
-```javascript
-ReactComponent findRenderedDOMComponentWithClass(
-  ReactComponent tree,
-  string className
-)
-```
-
-类似 `scryRenderedDOMComponentsWithClass()` 除了只有一个返回结果，并且要么返回这个结果，要么如果还有其他的匹配项就抛出一个异常。
-
-### scryRenderedDOMComponentsWithTag
-
-```javascript
-array scryRenderedDOMComponentsWithTag(
-  ReactComponent tree,
-  string tagName
-)
-```
-
-在渲染的树中查找所有 DOM 组件的 tag 名匹配 `tagName` 的组件实例。
-
-### findRenderedDOMComponentWithTag
-
-```javascript
-ReactComponent findRenderedDOMComponentWithTag(
-  ReactComponent tree,
-  string tagName
-)
-```
-
-类似 `scryRenderedDOMComponentsWithTag()` 除了只有一个返回结果，并且要么返回这个结果，要么如果还有其他的匹配项就抛出一个异常。
-
-### scryRenderedComponentsWithType
-
-```javascript
-array scryRenderedComponentsWithType(
-  ReactComponent tree,
-  function componentClass
-)
-```
-
-查找所有类型等于 `componentClass` 的组件实例。
-
-### findRenderedComponentWithType
-
-```javascript
-ReactComponent findRenderedComponentWithType(
-  ReactComponent tree, function componentClass
-)
-```
-
-类似 `scryRenderedComponentsWithType()` 除了只有一个返回结果，并且要么返回这个结果，要么如果还有其他的匹配项就抛出一个异常。
-
-## Shallow rendering（浅渲染）
-
-浅渲染是一个实验性特性，让你渲染一个组件为 "one level deep" 并且断言渲染方法返回的内容，不用担心子组件的行为，它们没有被实例化或者渲染。这个方式不需要一个 DOM。
-
-```javascript
-ReactShallowRenderer createRenderer()
-```
-
-在你的测试里调用它来创建一个浅渲染器。你可以把它想做是一个你渲染你要测试的组件的 "地方"，它可以自己响应事件并更新。
-
-```javascript
-shallowRenderer.render(
-  ReactElement element
-)
-```
-
-类似于 `ReactDOM.render`。
-
-```javascript
-ReactElement shallowRenderer.getRenderOutput()
-```
-
-在 `render` 被调用后，返回一个浅渲染的输出。你可以接着断言输出的内容。例如，如果你的组件的渲染方法返回：
-
-```javascript
-<div>
-  <span className="heading">Title</span>
-  <Subcomponent foo="bar" />
-</div>
-```
-
-然后你可以断言：
-
-```javascript
-var renderer = ReactTestUtils.createRenderer();
-result = renderer.getRenderOutput();
-expect(result.type).toBe('div');
-expect(result.props.children).toEqual([
-  <span className="heading">Title</span>,
-  <Subcomponent foo="bar" />
-]);
-```
-
-浅测试现在有一些限制，即不支持 refs。我们在早期发布这个特性，并感激 React 社区关于它应该如何演化的反馈。
diff --git a/docs/docs/10.5-clone-with-props.it-IT.md b/docs/docs/10.5-clone-with-props.it-IT.md
deleted file mode 100644
index 019af4ede578..000000000000
--- a/docs/docs/10.5-clone-with-props.it-IT.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-id: clone-with-props-it-IT
-title: Clonare ReactElements
-permalink: clone-with-props-it-IT.html
-prev: test-utils-it-IT.html
-next: create-fragment-it-IT.html
----
-
-> Nota:
-> `cloneWithProps` è deprecato. Usa [React.cloneElement](top-level-api.html#react.cloneelement) al suo posto.
-
-In rare condizioni, potresti voler creare una copia di un elemento React con proprietà diverse da quelle dell'elemento originale. Un esempio è clonare gli elementi passati come `this.props.children` ed effettuarne il rendering con proprietà diverse:
-
-```js
-var _makeBlue = function(element) {
-  return React.addons.cloneWithProps(element, {style: {color: 'blue'}});
-};
-
-var Blue = React.createClass({
-  render: function() {
-    var blueChildren = React.Children.map(this.props.children, _makeBlue);
-    return <div>{blueChildren}</div>;
-  }
-});
-
-ReactDOM.render(
-  <Blue>
-    <p>Questo testo è blu.</p>
-  </Blue>,
-  document.getElementById('container')
-);
-```
-
-`cloneWithProps` non trasferisce gli attributi `key` o `ref` agli elementi clonati. Le proprietà `className` e `style` sono automaticamente riunite.
diff --git a/docs/docs/10.5-clone-with-props.ja-JP.md b/docs/docs/10.5-clone-with-props.ja-JP.md
deleted file mode 100644
index 21b1c73b60ec..000000000000
--- a/docs/docs/10.5-clone-with-props.ja-JP.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-id: clone-with-props
-title: ReactElementsをクローンすること
-permalink: clone-with-props-ja-JP.html
-prev: test-utils-ja-JP.html
-next: create-fragment-ja-JP.html
----
-
-> 注意:
-> `cloneWithProps` は使用不可になりました。[React.cloneElement](top-level-api-ja-JP.html#react.cloneelement)を代わりに使用してください。
-
-元のReact要素とは異なるプロパティを持った要素のコピーを作成したいと考える稀なケースがあるかと思います。1つの例としては、以下のように、 `this.props.children` に渡すように要素をクローンし、異なるプロパティを持つようそれらをレンダリングするものです。
-
-```js
-var _makeBlue = function(element) {
-  return React.addons.cloneWithProps(element, {style: {color: 'blue'}});
-};
-
-var Blue = React.createClass({
-  render: function() {
-    var blueChildren = React.Children.map(this.props.children, _makeBlue);
-    return <div>{blueChildren}</div>;
-  }
-});
-
-ReactDOM.render(
-  <Blue>
-    <p>This text is blue.</p>
-  </Blue>,
-  document.getElementById('container')
-);
-```
-
-`cloneWithProps` は `key` や `ref` をクローンされた要素に渡すことはありません。 `className` や `style` は自動的にマージされます。
diff --git a/docs/docs/10.5-clone-with-props.ko-KR.md b/docs/docs/10.5-clone-with-props.ko-KR.md
deleted file mode 100644
index ebc0bd872659..000000000000
--- a/docs/docs/10.5-clone-with-props.ko-KR.md
+++ /dev/null
@@ -1,36 +0,0 @@
----
-id: clone-with-props-ko-KR
-title: ReactElement 클론하기
-permalink: clone-with-props-ko-KR.html
-prev: test-utils-ko-KR.html
-next: create-fragment-ko-KR.html
----
-
-> 주의:
-> `cloneWithProps`는 비추천입니다. 대신 [React.cloneElement](top-level-api.html#react.cloneelement)를 사용하세요.
-
-드문 경우긴 하지만 원래 엘리먼트와 다른 prop을 가진 React 엘리먼트의 복사본을 만들고 싶을 때가 있습니다. 예를 들면 `this.props.children`에 클론한 엘리먼트를 넘기고 다른 prop으로 렌더링하는 경우 입니다.
-
-```js
-var cloneWithProps = require('react-addons-clone-with-props');
-
-var _makeBlue = function(element) {
-  return cloneWithProps(element, {style: {color: 'blue'}});
-};
-
-var Blue = React.createClass({
-  render: function() {
-    var blueChildren = React.Children.map(this.props.children, _makeBlue);
-    return <div>{blueChildren}</div>;
-  }
-});
-
-ReactDOM.render(
-  <Blue>
-    <p>This text is blue.</p>
-  </Blue>,
-  document.getElementById('container')
-);
-```
-
-`cloneWithProps`는 `key`나 `ref`를 클론된 엘리먼트에 전달하지 않습니다. `className`, `style` prop은 자동으로 머지됩니다.
diff --git a/docs/docs/10.5-clone-with-props.md b/docs/docs/10.5-clone-with-props.md
deleted file mode 100644
index 279d04a98d9e..000000000000
--- a/docs/docs/10.5-clone-with-props.md
+++ /dev/null
@@ -1,36 +0,0 @@
----
-id: clone-with-props
-title: Cloning ReactElements
-permalink: clone-with-props.html
-prev: test-utils.html
-next: create-fragment.html
----
-
-> Note:
-> `cloneWithProps` is deprecated. Use [React.cloneElement](top-level-api.html#react.cloneelement) instead.
-
-In rare situations, you may want to create a copy of a React element with different props from those of the original element. One example is cloning the elements passed into `this.props.children` and rendering them with different props:
-
-```js
-var cloneWithProps = require('react-addons-clone-with-props');
-
-var _makeBlue = function(element) {
-  return cloneWithProps(element, {style: {color: 'blue'}});
-};
-
-var Blue = React.createClass({
-  render: function() {
-    var blueChildren = React.Children.map(this.props.children, _makeBlue);
-    return <div>{blueChildren}</div>;
-  }
-});
-
-ReactDOM.render(
-  <Blue>
-    <p>This text is blue.</p>
-  </Blue>,
-  document.getElementById('container')
-);
-```
-
-`cloneWithProps` does not transfer `key` or `ref` to the cloned element. `className` and `style` props are automatically merged.
diff --git a/docs/docs/10.5-clone-with-props.zh-CN.md b/docs/docs/10.5-clone-with-props.zh-CN.md
deleted file mode 100644
index ea970ad1bce5..000000000000
--- a/docs/docs/10.5-clone-with-props.zh-CN.md
+++ /dev/null
@@ -1,36 +0,0 @@
----
-id: clone-with-props-zh-CN
-title: 克隆 ReactElements
-permalink: clone-with-props-zh-CN.html
-prev: test-utils-zh-CN.html
-next: create-fragment-zh-CN.html
----
-
-> 注意:
-> `cloneWithProps` 被弃用了. 用 [React.cloneElement](top-level-api.html#react.cloneelement) 代替.
-
-在很罕见的情况下，你可能需要创建一个 React 元素的拷贝，它与初始的元素有不同的 props。一个例子是克隆这些传递到 `this.props.children` 的元素并用不同的 props 渲染他们。
-
-```js
-var cloneWithProps = require('react-addons-clone-with-props');
-
-var _makeBlue = function(element) {
-  return cloneWithProps(element, {style: {color: 'blue'}});
-};
-
-var Blue = React.createClass({
-  render: function() {
-    var blueChildren = React.Children.map(this.props.children, _makeBlue);
-    return <div>{blueChildren}</div>;
-  }
-});
-
-ReactDOM.render(
-  <Blue>
-    <p>This text is blue.</p>
-  </Blue>,
-  document.getElementById('container')
-);
-```
-
-`cloneWithProps` 不传递 `key` 或者 `ref` 到被克隆的元素。`className` 和 `style` props 被自动合并。
diff --git a/docs/docs/10.6-create-fragment.it-IT.md b/docs/docs/10.6-create-fragment.it-IT.md
deleted file mode 100644
index 11971643f254..000000000000
--- a/docs/docs/10.6-create-fragment.it-IT.md
+++ /dev/null
@@ -1,73 +0,0 @@
----
-id: create-fragment-it-IT
-title: Frammenti con Chiave
-permalink: create-fragment-it-IT.html
-prev: clone-with-props-it-IT.html
-next: update-it-IT.html
----
-
-In molti casi, puoi utilizzare la proprietà `key` per specificare chiavi sugli elementi che restituisci da `render`. Tuttavia, questo approccio fallisce in una situazione: se hai due insiemi di figli che devi riordinare, non esiste alcun modo di assegnare una chiave a ciascuno di essi senza aggiungere un elemento contenitore.
-
-Ovvero, se hai un componente come il seguente:
-
-```js
-var Swapper = React.createClass({
-  propTypes: {
-    // `leftChildren` e `rightChildren` possono essere una stringa, un elemento, un array, etc.
-    leftChildren: React.PropTypes.node,
-    rightChildren: React.PropTypes.node,
-
-    swapped: React.PropTypes.bool
-  }
-  render: function() {
-    var children;
-    if (this.props.swapped) {
-      children = [this.props.rightChildren, this.props.leftChildren];
-    } else {
-      children = [this.props.leftChildren, this.props.rightChildren];
-    }
-    return <div>{children}</div>;
-  }
-});
-```
-
-I figli saranno smontati e rimontati nel momento in cui cambi la proprietà `swapped` poiché non ci sono chiavi che marcano i due insiemi di figli.
-
-Per risolvere questo problema, puoi utilizzare `React.addons.createFragment` per dare una chiave a ciascun insieme di figli.
-
-#### `ReactFragment React.addons.createFragment(object children)`
-
-Anziché creare array, scriviamo:
-
-```js
-if (this.props.swapped) {
-  children = React.addons.createFragment({
-    right: this.props.rightChildren,
-    left: this.props.leftChildren
-  });
-} else {
-  children = React.addons.createFragment({
-    left: this.props.leftChildren,
-    right: this.props.rightChildren
-  });
-}
-```
-
-Le chiavi degli oggetti passati (ovvero, `left` e `right`) sono usate come chiavi per l'intero insieme di figli, e l'ordine delle chiavi dell'oggetto è utilizzato per determinare l'ordine dei figli visualizzati. Con questo cambiamento, i due insiemi di figli saranno correttamente riordinati nel DOM senza bisogno di smontaggio.
-
-Il valore di ritorno di `createFragment` deve essere trattato come un oggetto opaco; puoi usare gli helper `React.Children` per iterare su un frammento ma non dovresti accedervi direttamente. Nota anche che ci stiamo affidando al motore JavaScript per preservare l'ordine dell'enumerazione degli oggetti, che non viene garantito dalla specifica ma è implementato dai principali browser e macchine virtuali per oggetti con chiavi non numeriche.
-
-> **Nota:**
->
-> In un futuro, `createFragment` potrebbe essere sostituito da una API quale
->
-> ```js
-> return (
->   <div>
->     <x:frag key="right">{this.props.rightChildren}</x:frag>,
->     <x:frag key="left">{this.props.leftChildren}</x:frag>
->   </div>
-> );
-> ```
->
-> che ti permette di assegnare chiavi direttamente in JSX senza aggiungere elementi contenitore.
diff --git a/docs/docs/10.6-create-fragment.ja-JP.md b/docs/docs/10.6-create-fragment.ja-JP.md
deleted file mode 100644
index 11b6dd306755..000000000000
--- a/docs/docs/10.6-create-fragment.ja-JP.md
+++ /dev/null
@@ -1,72 +0,0 @@
----
-id: create-fragment
-title: キー付けされたフラグメント
-permalink: create-fragment-ja-JP.html
-prev: clone-with-props-ja-JP.html
-next: update-ja-JP.html
----
-
-多くの場合、 `render` から返された要素のキーを特定するために、 `key` プロパティを使用します。しかし、以下のような特定の状況では、こういったことを行うことはできません。何度も並び替える必要のある2つの子要素を持っているときには、ラッパーの要素を加える以外にそれぞれのセットのキーを追加する方法はありません。
-
-これは、以下のようなコンポーネントがある場合には、
-
-```js
-var Swapper = React.createClass({
-  propTypes: {
-    // `leftChildren` と `rightChildren` は文字列や、要素や、配列などになり得ます。
-    leftChildren: React.PropTypes.node,
-    rightChildren: React.PropTypes.node,
-
-    swapped: React.PropTypes.bool
-  }
-  render: function() {
-    var children;
-    if (this.props.swapped) {
-      children = [this.props.rightChildren, this.props.leftChildren];
-    } else {
-      children = [this.props.leftChildren, this.props.rightChildren];
-    }
-    return <div>{children}</div>;
-  }
-});
-```
-
-2つの子要素のセットを表すキーがないため、 `swapped` プロパティを変更するたびに子要素はアンマウントされ、再度マウントされます。
-
-この問題を解決するために、子要素のセットのキーを与える `React.addons.createFragment` を使用することができます。
-
-#### `ReactFragment React.addons.createFragment(object children)`
-
-配列を作成する代わりに、以下のように記述することができます。
-
-```js
-if (this.props.swapped) {
-  children = React.addons.createFragment({
-    right: this.props.rightChildren,
-    left: this.props.leftChildren
-  });
-} else {
-  children = React.addons.createFragment({
-    left: this.props.leftChildren,
-    right: this.props.rightChildren
-  });
-}
-```
-
-渡されたオブジェクトのキー（`left` や `right` のことです）は子要素のセット全体のキーとして使用され、そのオブジェクトのキーの順序はレンダリングされた子要素の順序を決める際に使用されます。この変更により、2つの子要素のセットはアンマウントされることなく、DOMの中で適切に順序立てられます。
-
-`createFragment` の戻り値は、不透明なオブジェクトとして扱われるべきです。つまり、 `React.Children` ヘルパーを、フラグメントのなかでループするために使用することはできますが、直接アクセスするべきではないということです。私たちはいまオブジェクトの一覧における順序を保存するのにJavaScriptのエンジンに頼っていることに注意してください。それは、仕様が保証されているわけではありませんが、数に関するものではないキーとオブジェクトは全てのメジャーなブラウザやVMで実行されます。
-
-> **注意:**
-> 将来、 `createFragment` は以下のようなAPIに変わるでしょう。
->
-> ```js
-> return (
->   <div>
->     <x:frag key="right">{this.props.rightChildren}</x:frag>,
->     <x:frag key="left">{this.props.leftChildren}</x:frag>
->   </div>
-> );
-> ```
->
-> ラッパーの要素を加えることなく、JSXの中に直接キーをアサインすることができます。
diff --git a/docs/docs/10.6-create-fragment.ko-KR.md b/docs/docs/10.6-create-fragment.ko-KR.md
deleted file mode 100644
index c2bae58ec690..000000000000
--- a/docs/docs/10.6-create-fragment.ko-KR.md
+++ /dev/null
@@ -1,75 +0,0 @@
----
-id: create-fragment-ko-KR
-title: 키가 할당된 프래그먼트
-permalink: create-fragment-ko-KR.html
-prev: clone-with-props-ko-KR.html
-next: update-ko-KR.html
----
-
-대부분의 경우는 `key` prop으로 `render`에서 반환된 엘리먼트에 키를 명시할 수 있습니다. 하지만 말썽을 부리는 경우가 한가지 있습니다: 재정렬을 할 두개의 자식 집합을 가지고 있는 경우, 감싸는 엘리먼트 없이 각각의 집합에 키를 부여하는 것은 불가능 합니다.
-
-이 말은, 만약 다음과 같은 컴포넌트가 있다면:
-
-```js
-var Swapper = React.createClass({
-  propTypes: {
-    // `leftChildren`과 `rightChildren`은 문자열, 엘리먼트, 배열 혹은 다른 무언가 일 수 있음.
-    leftChildren: React.PropTypes.node,
-    rightChildren: React.PropTypes.node,
-
-    swapped: React.PropTypes.bool
-  },
-  render: function() {
-    var children;
-    if (this.props.swapped) {
-      children = [this.props.rightChildren, this.props.leftChildren];
-    } else {
-      children = [this.props.leftChildren, this.props.rightChildren];
-    }
-    return <div>{children}</div>;
-  }
-});
-```
-
-`swapped` prop을 변경할 경우 자식은 마운트 해제되거나 다시 마운트 될 수 있습니다. 두 자식 집합에 키가 할당되지 않았기 때문입니다.
-
-이 문제를 해결하기 위해서 `createFragment`를 사용해 자식 집합에 키를 부여할 수 있습니다.
-
-#### `Array<ReactNode> createFragment(object children)`
-
-배열을 만드는 대신에 다음과 같이 해볼 수 있습니다:
-
-```js
-var createFragment = require('react-addons-create-fragment');
-
-if (this.props.swapped) {
-  children = createFragment({
-    right: this.props.rightChildren,
-    left: this.props.leftChildren
-  });
-} else {
-  children = createFragment({
-    left: this.props.leftChildren,
-    right: this.props.rightChildren
-  });
-}
-```
-
-전달된 객체의 키(`left`, `right`)는 모든 자식 집합의 키로 사용됩니다. 그리고 객체에서 키들의 순서는 렌더된 자식들의 순서를 결정하는데 사용됩니다. 이러한 변경으로 두 자식 집합은 언마운팅하지 않고도 DOM에서 적절하게 재정렬 됩니다.
-
-`createFragment`의 반환값은 불명확한 객체로 취급되어야 합니다; `React.Children` 헬퍼를 사용해 프래그먼트를 순환할 수 있지만 직접 접근해서는 안됩니다. 명세에는 없지만 모든 주요 브라우저와 VM들에서 JavaScript 엔진이 숫자가 아닌 키에 대해서도 객체 목록 순서를 보존한다는 점을 주의하세요.
-
-> **주의:**
->
-> 미래에 `createFragment`는 대략 다음과 같은 API로 교체될 것입니다
->
-> ```js
-> return (
->   <div>
->     <x:frag key="right">{this.props.rightChildren}</x:frag>,
->     <x:frag key="left">{this.props.leftChildren}</x:frag>
->   </div>
-> );
-> ```
->
-> JSX에서 엘리먼트로 감싸지 않고도 key를 바로 선언할 수 있게 될 것입니다.
diff --git a/docs/docs/10.6-create-fragment.md b/docs/docs/10.6-create-fragment.md
deleted file mode 100644
index 91879d4e0feb..000000000000
--- a/docs/docs/10.6-create-fragment.md
+++ /dev/null
@@ -1,75 +0,0 @@
----
-id: create-fragment
-title: Keyed Fragments
-permalink: create-fragment.html
-prev: clone-with-props.html
-next: update.html
----
-
-In most cases, you can use the `key` prop to specify keys on the elements you're returning from `render`. However, this breaks down in one situation: if you have two sets of children that you need to reorder, there's no way to put a key on each set without adding a wrapper element.
-
-That is, if you have a component such as:
-
-```js
-var Swapper = React.createClass({
-  propTypes: {
-    // `leftChildren` and `rightChildren` can be a string, element, array, etc.
-    leftChildren: React.PropTypes.node,
-    rightChildren: React.PropTypes.node,
-
-    swapped: React.PropTypes.bool
-  },
-  render: function() {
-    var children;
-    if (this.props.swapped) {
-      children = [this.props.rightChildren, this.props.leftChildren];
-    } else {
-      children = [this.props.leftChildren, this.props.rightChildren];
-    }
-    return <div>{children}</div>;
-  }
-});
-```
-
-The children will unmount and remount as you change the `swapped` prop because there aren't any keys marked on the two sets of children.
-
-To solve this problem, you can use the `createFragment` add-on to give keys to the sets of children.
-
-#### `Array<ReactNode> createFragment(object children)`
-
-Instead of creating arrays, we write:
-
-```js
-var createFragment = require('react-addons-create-fragment');
-
-if (this.props.swapped) {
-  children = createFragment({
-    right: this.props.rightChildren,
-    left: this.props.leftChildren
-  });
-} else {
-  children = createFragment({
-    left: this.props.leftChildren,
-    right: this.props.rightChildren
-  });
-}
-```
-
-The keys of the passed object (that is, `left` and `right`) are used as keys for the entire set of children, and the order of the object's keys is used to determine the order of the rendered children. With this change, the two sets of children will be properly reordered in the DOM without unmounting.
-
-The return value of `createFragment` should be treated as an opaque object; you can use the `React.Children` helpers to loop through a fragment but should not access it directly. Note also that we're relying on the JavaScript engine preserving object enumeration order here, which is not guaranteed by the spec but is implemented by all major browsers and VMs for objects with non-numeric keys.
-
-> **Note:**
->
-> In the future, `createFragment` may be replaced by an API such as
->
-> ```js
-> return (
->   <div>
->     <x:frag key="right">{this.props.rightChildren}</x:frag>,
->     <x:frag key="left">{this.props.leftChildren}</x:frag>
->   </div>
-> );
-> ```
->
-> allowing you to assign keys directly in JSX without adding wrapper elements.
diff --git a/docs/docs/10.6-create-fragment.zh-CN.md b/docs/docs/10.6-create-fragment.zh-CN.md
deleted file mode 100644
index 661cef570436..000000000000
--- a/docs/docs/10.6-create-fragment.zh-CN.md
+++ /dev/null
@@ -1,75 +0,0 @@
----
-id: create-fragment-zh-CN
-title: Keyed Fragments
-permalink: create-fragment-zh-CN.html
-prev: clone-with-props-zh-CN.html
-next: update-zh-CN.html
----
-
-在大多数情况下，你可以使用 `key` prop 指定你从 `render` 返回的元素的 keys。然而，这在一个情况下会失败：如果你有两组你需要记录的子级，将没有办法在不使用包裹元素的情况下放置一个 key 到每组上。
-
-即是，如果你有一个像这样的组件：
-
-```js
-var Swapper = React.createClass({
-  propTypes: {
-    // `leftChildren` and `rightChildren` can be a string, element, array, etc.
-    leftChildren: React.PropTypes.node,
-    rightChildren: React.PropTypes.node,
-
-    swapped: React.PropTypes.bool
-  },
-  render: function() {
-    var children;
-    if (this.props.swapped) {
-      children = [this.props.rightChildren, this.props.leftChildren];
-    } else {
-      children = [this.props.leftChildren, this.props.rightChildren];
-    }
-    return <div>{children}</div>;
-  }
-});
-```
-
-这些子级会在当你改变 `swapped` prop 时加载和卸载，因为没有任何的 key 标记在这两组子级上。
-
-要解决这个问题，你可以使用 `createFragment` 插件来给予这两组子级 keys.
-
-#### `Array<ReactNode> createFragment(object children)`
-
-代替创建数组，我们这样写：
-
-```js
-var createFragment = require('react-addons-create-fragment');
-
-if (this.props.swapped) {
-  children = createFragment({
-    right: this.props.rightChildren,
-    left: this.props.leftChildren
-  });
-} else {
-  children = createFragment({
-    left: this.props.leftChildren,
-    right: this.props.rightChildren
-  });
-}
-```
-
-被传入对象的 keys （即 `left` 和 `right`）被用作为整组子级的 keys，并且对象 keys 的顺序被用于决定渲染子级的顺序。通过这个改变，这两个子级将会恰当的在 DOM 里排序，而不被卸载。
-
-`createFragment` 的返回值应该被对待为一个不透明的对象;你可以使用 `React.Children` 来遍历一个 fragment 但是不应该直接访问它。同样注意，我们依赖于 JavaScript 引擎保留了对象的枚举顺序，这点在 spec 上是不保证的，但是所有主要的浏览器和 VMs 都对非数字键的对象实现了这个特性。
-
-> **注意:**
->
-> 将来，`createFragment` 也许会被替换为如下的API：
->
-> ```js
-> return (
->   <div>
->     <x:frag key="right">{this.props.rightChildren}</x:frag>,
->     <x:frag key="left">{this.props.leftChildren}</x:frag>
->   </div>
-> );
-> ```
->
-> 允许你直接在 JSX 里赋值 keys 而不用添加包裹元素。 
diff --git a/docs/docs/10.7-update.it-IT.md b/docs/docs/10.7-update.it-IT.md
deleted file mode 100644
index 3477f63cee58..000000000000
--- a/docs/docs/10.7-update.it-IT.md
+++ /dev/null
@@ -1,100 +0,0 @@
----
-id: update-it-IT
-title: Helper per l'Immutabilità
-permalink: update-it-IT.html
-prev: create-fragment-it-IT.html
-next: pure-render-mixin-it-IT.html
----
-
-React ti permette di usare qualunque stile per la gestione dei dati che desideri, incluso la mutazione. Tuttavia, se puoi usare dati immutabili in parti critiche per le prestazioni della tua applicazione è facile implementare rapidamente un metodo `shouldComponentUpdate()` che aumenta significativamente la velocità della tua applicazione.
-
-Avere a che fare con dati immutabili in JavaScript è più difficile che in linguaggi progettati a tale scopo, come [Clojure](http://clojure.org/). Tuttavia, abbiamo fornito un semplice helper per l'immutabilità, `update()`, che rende avere a che fare con questo tipo di dati molto più semplice, *senza* cambiare fondamentalmente la rappresentazione dei tuoi dati. Se puoi anche dare un'occhiata alla libreria [Immutable-js](https://facebook.github.io/immutable-js/docs/) di Facebook e la sezione [Prestazioni Avanzate](/react/docs/advanced-performance.html) per maggiori dettagli su Immutable-js.
-
-## L'idea fondamentale
-
-Se muti i tuoi dati nella seguente maniera:
-
-```js
-myData.x.y.z = 7;
-// oppure...
-myData.a.b.push(9);
-```
-
-non hai modo di determinare quali dati siano cambiati dal momento che la copia precedente è stata sovrascritta. Invece, devi creare una nuova copia di `myData` e cambiare solo le parti che vanno cambiate. Allora puoi confrontare la vecchia copia di `myData` con la nuova in `shouldComponentUpdate()` usando l'operatore di uguaglianza stretta `===`:
-
-```js
-var newData = deepCopy(myData);
-newData.x.y.z = 7;
-newData.a.b.push(9);
-```
-
-Sfortunatamente, le copie profonde sono costose, e a volte impossibili. Puoi alleviare questa limitazione copiando soltanto gli oggetti che devono essere cambiati e riutilizzando gli oggetti che nonsono cambiati. Sfortunatamente, nel JavaScript odierno questa può essere un'operazione difficoltosa:
-
-```js
-var newData = extend(myData, {
-  x: extend(myData.x, {
-    y: extend(myData.x.y, {z: 7}),
-  }),
-  a: extend(myData.a, {b: myData.a.b.concat(9)})
-});
-```
-
-Mentre questo codice ha prestazioni accettabili (dal momento che effettua soltanto una copia superficiale di `log n` oggetti e riutilizza i rimanenti), è una gran scocciatura da scrivere. Guarda quanta ripetizione! Questo non è soltanto fastidioso, ma offre una grande superficie di attacco per i bachi.
-
-`update()` fornisce un semplice zucchero sintattico attorno a questo pattern per rendere più semplice la scrittura di questo codice. Questo codice diventa:
-
-```js
-var newData = React.addons.update(myData, {
-  x: {y: {z: {$set: 7}}},
-  a: {b: {$push: [9]}}
-});
-```
-
-Mentre la sintassi richiede qualche tempo per abituarsi (anche se è ispirata dal [linguaggio di query di MongoDB](http://docs.mongodb.org/manual/core/crud-introduction/#query)) non c'è ridondanza, può essere analizzato staticamente e non richiede la scrittura di più codice della versione mutativa.
-
-Le chiavi con il prefisso `$` sono chiamate *comandi*. La struttura dati che stanno "mutando" viene chiamata *bersaglio*.
-
-## Comandi disponibili
-
-  * `{$push: array}` invoca `push()` sul bersagio passando ciascun elemento di `array`.
-  * `{$unshift: array}` invoca `unshift()` sul bersagio passando ciascun elemento di `array`.
-  * `{$splice: array of arrays}` per ogni elemento di `arrays` invoca `splice()` sul bersaglio con i parametri forniti dall'elemento.
-  * `{$set: any}` sostituisce l'intero bersaglio.
-  * `{$merge: object}` unisce le chiavi di `object` con il bersaglio.
-  * `{$apply: function}` passa il valore attuale alla funzione e lo aggiorna con il nuovo valore da essa restituito.
-
-## Esempi
-
-### Semplice inserimento in coda
-
-```js
-var initialArray = [1, 2, 3];
-var newArray = update(initialArray, {$push: [4]}); // => [1, 2, 3, 4]
-```
-`initialArray` is still `[1, 2, 3]`.
-
-### Collezioni annidate
-
-```js
-var collection = [1, 2, {a: [12, 17, 15]}];
-var newCollection = update(collection, {2: {a: {$splice: [[1, 1, 13, 14]]}}});
-// => [1, 2, {a: [12, 13, 14, 15]}]
-```
-Questo accede all'indice `2` di `collection`, alla chiave `a`, ed effettua lo splice di un elemento a partire dall'indice `1` (per rimuovere `17`) e al contempo inserisce `13` e `14`.
-
-### Aggiornare un valore basandosi sul suo valore attuale
-
-```js
-var obj = {a: 5, b: 3};
-var newObj = update(obj, {b: {$apply: function(x) {return x * 2;}}});
-// => {a: 5, b: 6}
-// Questa è una forma equivalente, ma diventa prolissa per profonde collezioni annidate:
-var newObj2 = update(obj, {b: {$set: obj.b * 2}});
-```
-
-### Unione (superficiale)
-
-```js
-var obj = {a: 5, b: 3};
-var newObj = update(obj, {$merge: {b: 6, c: 7}}); // => {a: 5, b: 6, c: 7}
-```
diff --git a/docs/docs/10.7-update.ja-JP.md b/docs/docs/10.7-update.ja-JP.md
deleted file mode 100644
index b472c7e5f130..000000000000
--- a/docs/docs/10.7-update.ja-JP.md
+++ /dev/null
@@ -1,101 +0,0 @@
----
-id: update
-title: 不変性のヘルパ
-permalink: update-ja-JP.html
-prev: create-fragment-ja-JP.html
-next: pure-render-mixin-ja-JP.html
----
-
-Reactは変化を含む、使用したいデータマネジメントのスタイルであればどういったものであっても使用することができます。しかし、アプリケーションの、パフォーマンスが重要な部分において不変なデータを使用できる場合は、速い `shouldComponentUpdate()` メソッドを実行して、簡単にアプリケーションのスピードを著しく速くすることができます。
-
-[Clojure](http://clojure.org/)のような、不変なデータの扱いのためにデザインされた言語よりも、JavaScriptでそれを行うことは難しいです。しかし、単純な不変性のヘルパである、 `update()` が提供されています。それは、データがどのように表されるかということを基本的には変更すること *なく* データのタイプを扱うことを簡単にします。Immutable-jsについての詳細は、Facebookの[Immutable-js](https://facebook.github.io/immutable-js/docs/#/)や[進歩したパフォーマンス](/react/docs/advanced-performance.html)をご覧ください。
-
-## 主要な考え
-
-もし変更する予定のデータが以下のようなものであれば、
-
-```js
-myData.x.y.z = 7;
-// または...
-myData.a.b.push(9);
-```
-
-以前のコピーが上書きされるので、どのデータが変更されたか判断する方法はありません。代わりに、 `myData` の新しいコピーを作成する必要があり、変更される必要がある部分のみを変更します。それから、 `myData` の古いコピーと新しいコピーを `shouldComponentUpdate()` の中で以下のように、3つのイコールを使用して比較することができます。
-
-```js
-var newData = deepCopy(myData);
-newData.x.y.z = 7;
-newData.a.b.push(9);
-```
-
-不幸なことに、ディープコピーはコストがかかり、不可能なときもあります。変更される必要があるオブジェクトをコピーすることと、変更されていないオブジェクトを再利用することによってのみ、これを代替することができます。不幸なことに、今日のJavaScriptでは、こういったことは面倒です。
-
-```js
-var newData = extend(myData, {
-  x: extend(myData.x, {
-    y: extend(myData.x.y, {z: 7}),
-  }),
-  a: extend(myData.a, {b: myData.a.b.concat(9)})
-});
-```
-
-動きが速い一方で（ `log n` オブジェクトのシャローコピーを作成し、残りを再利用するため）、記述するのには多くのコストがかかります。全てのコードの繰り返しを見てください。それらはつまらないものではなく、多くのバグの表面を提供します。
-
-`update()` はこのようなパターンにおいて、コードを簡単に記述するための単純な糖衣構文を提供します。そのコードは以下のようになります。
-
-```js
-var newData = React.addons.update(myData, {
-  x: {y: {z: {$set: 7}}},
-  a: {b: {$push: [9]}}
-});
-```
-
-シンタックスは少し慣れが必要ですが（[MongoDBのクエリ言語](http://docs.mongodb.org/manual/core/crud-introduction/#query)にインスパイアされているため）、冗長性はありません。静的に分析し、変更ができるバージョンと比べてタイプする量がすごく増えているわけではありません。
-
-`$` から始まるキーは *コマンド* と呼ばれます。それらが「変更する」データ構造は *ターゲット* と呼ばれます。
-
-## 使用できるコマンド
-
-  * `{$push: array}` ターゲットに `array` の全ての要素を `push()` します。
-  * `{$unshift: array}` ターゲットの `array` の全ての要素を `unshift()` します。
-  * `{$splice: array of arrays}` `arrays` の全ての要素について、その要素によって提供されるパラメータのターゲットにおいて、 `splice()` を呼び出します。
-  * `{$set: any}` ターゲットを完全に置き換えます。
-  * `{$merge: object}` `object` のキーをターゲットとマージします。
-  * `{$apply: function}` 現在の値を関数に渡し、返された新しい値によってそれを更新します。
-
-## 例
-
-### 単純なプッシュ
-
-```js
-var initialArray = [1, 2, 3];
-var newArray = update(initialArray, {$push: [4]}); // => [1, 2, 3, 4]
-```
-`initialArray` は `[1, 2, 3]` のままです。
-
-### ネストしたコレクション
-
-```js
-var collection = [1, 2, {a: [12, 17, 15]}];
-var newCollection = update(collection, {2: {a: {$splice: [[1, 1, 13, 14]]}}});
-// => [1, 2, {a: [12, 13, 14, 15]}]
-```
-
-これは、 `collection` のインデックスが `2` である要素にアクセスし、インデックスが `1` である要素に（ `17` を削除し）`13` と `14` を挿入することで繋ぎ合わせます。
-
-### 現在の値に基づいて値を更新すること
-
-```js
-var obj = {a: 5, b: 3};
-var newObj = update(obj, {b: {$apply: function(x) {return x * 2;}}});
-// => {a: 5, b: 6}
-// 以下は上と同義ですが、ネストが深いコレクションにとっては冗長になります。
-var newObj2 = update(obj, {b: {$set: obj.b * 2}});
-```
-
-### (シャロー)マージ
-
-```js
-var obj = {a: 5, b: 3};
-var newObj = update(obj, {$merge: {b: 6, c: 7}}); // => {a: 5, b: 6, c: 7}
-```
diff --git a/docs/docs/10.7-update.ko-KR.md b/docs/docs/10.7-update.ko-KR.md
deleted file mode 100644
index cc96b1c31245..000000000000
--- a/docs/docs/10.7-update.ko-KR.md
+++ /dev/null
@@ -1,103 +0,0 @@
----
-id: update-ko-KR
-title: 불변성 헬퍼들
-permalink: update-ko-KR.html
-prev: create-fragment-ko-KR.html
-next: pure-render-mixin-ko-KR.html
----
-
-React에서는 mutation을 포함해 어떤 데이터 관리 방식도 사용하실 수 있습니다. 하지만 애플리케이션의 성능이 중요한 부분에서 불변의(immutable) 데이터를 사용할 수 있다면, 쉽게 빠른 `shouldComponentUpdate()` 메소드를 구현해 애플리케이션의 속도를 크게 향상시킬 수 있습니다.
-
-JavaScript에서 불변성의 데이터를 다루는 것은 [Clojure](http://clojure.org/)같이 그것을 위해 디자인된 언어로 다루는 것보다는 어렵습니다. 하지만, React는 간단한 불변성 헬퍼를 제공합니다. `update()`는 이런 종류의 데이터를 근본적인 변화 *없이*  쉽게 다루도록 해줍니다. Immutable-js에 관한 좀 더 자세한 정보는 페이스북의 [Immutable-js](https://facebook.github.io/immutable-js/docs/)나 [성능 심화](/react/docs/advanced-performance-ko-KR.html)을 참조하세요.
-
-## 주요 아이디어
-
-만약 데이터를 이렇게 변화시킨다면:
-
-```js
-myData.x.y.z = 7;
-// or...
-myData.a.b.push(9);
-```
-
-이전의 카피가 덮어씌워진다면 어떤 자료가 바뀌었는지 알 방도가 없습니다. 대신에, `myData`의 새로운 카피를 만들고 오직 변화가 필요한 부분만 바꿀 필요가 있습니다. 그 다음 `shouldComponentUpdate()` 에서  `myData`의 이전 카피와 새로운 카피를 `===` 연산자를 사용하여 비교할 수 있습니다.
-
-```js
-var newData = deepCopy(myData);
-newData.x.y.z = 7;
-newData.a.b.push(9);
-```
-
-하지만 깊은 복사는 비싸고, 가끔은 불가능하기도 합니다. 변화가 필요한 객체만 복제하고, 변화가 없는 객체는 다시 사용하는 방법으로만 비용을 줄일 수 있습니다. 안타깝지만 오늘날의 JavaScript에서는 그 방법이 성가실 수 있습니다:
-
-```js
-var newData = extend(myData, {
-  x: extend(myData.x, {
-    y: extend(myData.x.y, {z: 7}),
-  }),
-  a: extend(myData.a, {b: myData.a.b.concat(9)})
-});
-```
-
-이것은 꽤 성능이 좋긴 하지만 (`log n`개의 객체만 얕은 복사하고, 나머지는 재사용하기 때문에), 일일히 쓰기엔 큰 고통이 따릅니다. 이 반복들을 보세요! 이건 짜증날 뿐만 아니라 버그들을 야기할수도 있습니다.
-
-`update()`는 이런 패턴 속에서 코드를 더 쉽게 쓸 수 있도록 편의 문법을 제공합니다. 코드는 이렇습니다:
-
-```js
-var update = require('react-addons-update');
-
-var newData = update(myData, {
-  x: {y: {z: {$set: 7}}},
-  a: {b: {$push: [9]}}
-});
-```
-
-([MongoDB 쿼리 언어](http://docs.mongodb.org/manual/core/crud-introduction/#query)에서 영감을 받은) 이 문법에 익숙해지기에는 시간이 조금 걸리긴 하지만, 쓸모 없는 반복이 없고 정적분석이 가능할 뿐더러 변할 수 있는(mutative) 버전보다 더 많은 타이핑이 필요하지도 않습니다.
-
-
-`$`가 앞에 붙어있는 키들은 *커맨드* 라고 불립니다. "변하는" 자료 구조는 *타겟* 이라고 불립니다.
-
-## 사용가능한 커맨드들
-
-  * `{$push: array}` 모든 아이템들을 타겟에 있는 `array`에 `push()`합니다.
-  * `{$unshift: array}` 타겟속 `array`에 있는 모든 아이템들을 `unshift()`합니다.
-  * `{$splice: array of arrays}` `arrays` 안의 각 아이템들이 `splice()`를 주어진 인자들을 사용해 호출하게 합니다.
-  * `{$set: any}` 타겟 전체를 대체합니다.
-  * `{$merge: object}` 타겟과 `object`의 키들을 병합합니다.
-  * `{$apply: function}` 는 지금 값을 함수에 전달하고 새로운 리턴 값으로 업데이트합니다.
-
-## 예제
-
-### 간단한 push
-
-```js
-var initialArray = [1, 2, 3];
-var newArray = update(initialArray, {$push: [4]}); // => [1, 2, 3, 4]
-```
-`initialArray` 은 여전히 `[1, 2, 3]` 입니다.
-
-### 중첩된 컬렉션
-
-```js
-var collection = [1, 2, {a: [12, 17, 15]}];
-var newCollection = update(collection, {2: {a: {$splice: [[1, 1, 13, 14]]}}});
-// => [1, 2, {a: [12, 13, 14, 15]}]
-```
-이것은 `collection`의 인덱스 `2`의 키 `a`에 접근해, 인덱스 `1`에 있는 한 아이템을 접합(splice)해서(`17`를 제거하고) `13`, `14`를 추가합니다.
-
-### 현재 상태에 의거해 값을 업데이트
-
-```js
-var obj = {a: 5, b: 3};
-var newObj = update(obj, {b: {$apply: function(x) {return x * 2;}}});
-// => {a: 5, b: 6}
-// 위의 것과 같은 동작을 합니다만, 깊게 중첩된 컬렉션들에서는 더 장황해 집니다.
-var newObj2 = update(obj, {b: {$set: obj.b * 2}});
-```
-
-### (얕은) 합병
-
-```js
-var obj = {a: 5, b: 3};
-var newObj = update(obj, {$merge: {b: 6, c: 7}}); // => {a: 5, b: 6, c: 7}
-```
diff --git a/docs/docs/10.7-update.md b/docs/docs/10.7-update.md
deleted file mode 100644
index a9dcdf7f60a8..000000000000
--- a/docs/docs/10.7-update.md
+++ /dev/null
@@ -1,102 +0,0 @@
----
-id: update
-title: Immutability Helpers
-permalink: update.html
-prev: create-fragment.html
-next: pure-render-mixin.html
----
-
-React lets you use whatever style of data management you want, including mutation. However, if you can use immutable data in performance-critical parts of your application it's easy to implement a fast `shouldComponentUpdate()` method to significantly speed up your app.
-
-Dealing with immutable data in JavaScript is more difficult than in languages designed for it, like [Clojure](http://clojure.org/). However, we've provided a simple immutability helper, `update()`, that makes dealing with this type of data much easier, *without* fundamentally changing how your data is represented. You can also take a look at Facebook's [Immutable-js](https://facebook.github.io/immutable-js/docs/) and the [Advanced Performance](/react/docs/advanced-performance.html) section for more detail on Immutable-js.
-
-## The main idea
-
-If you mutate data like this:
-
-```js
-myData.x.y.z = 7;
-// or...
-myData.a.b.push(9);
-```
-
-You have no way of determining which data has changed since the previous copy has been overwritten. Instead, you need to create a new copy of `myData` and change only the parts of it that need to be changed. Then you can compare the old copy of `myData` with the new one in `shouldComponentUpdate()` using triple-equals:
-
-```js
-var newData = deepCopy(myData);
-newData.x.y.z = 7;
-newData.a.b.push(9);
-```
-
-Unfortunately, deep copies are expensive, and sometimes impossible. You can alleviate this by only copying objects that need to be changed and by reusing the objects that haven't changed. Unfortunately, in today's JavaScript this can be cumbersome:
-
-```js
-var newData = extend(myData, {
-  x: extend(myData.x, {
-    y: extend(myData.x.y, {z: 7}),
-  }),
-  a: extend(myData.a, {b: myData.a.b.concat(9)})
-});
-```
-
-While this is fairly performant (since it only makes a shallow copy of `log n` objects and reuses the rest), it's a big pain to write. Look at all the repetition! This is not only annoying, but also provides a large surface area for bugs.
-
-`update()` provides simple syntactic sugar around this pattern to make writing this code easier. This code becomes:
-
-```js
-var update = require('react-addons-update');
-
-var newData = update(myData, {
-  x: {y: {z: {$set: 7}}},
-  a: {b: {$push: [9]}}
-});
-```
-
-While the syntax takes a little getting used to (though it's inspired by [MongoDB's query language](http://docs.mongodb.org/manual/core/crud-introduction/#query)) there's no redundancy, it's statically analyzable and it's not much more typing than the mutative version.
-
-The `$`-prefixed keys are called *commands*. The data structure they are "mutating" is called the *target*.
-
-## Available commands
-
-  * `{$push: array}` `push()` all the items in `array` on the target.
-  * `{$unshift: array}` `unshift()` all the items in `array` on the target.
-  * `{$splice: array of arrays}` for each item in `arrays` call `splice()` on the target with the parameters provided by the item.
-  * `{$set: any}` replace the target entirely.
-  * `{$merge: object}` merge the keys of `object` with the target.
-  * `{$apply: function}` passes in the current value to the function and updates it with the new returned value.
-
-## Examples
-
-### Simple push
-
-```js
-var initialArray = [1, 2, 3];
-var newArray = update(initialArray, {$push: [4]}); // => [1, 2, 3, 4]
-```
-`initialArray` is still `[1, 2, 3]`.
-
-### Nested collections
-
-```js
-var collection = [1, 2, {a: [12, 17, 15]}];
-var newCollection = update(collection, {2: {a: {$splice: [[1, 1, 13, 14]]}}});
-// => [1, 2, {a: [12, 13, 14, 15]}]
-```
-This accesses `collection`'s index `2`, key `a`, and does a splice of one item starting from index `1` (to remove `17`) while inserting `13` and `14`.
-
-### Updating a value based on its current one
-
-```js
-var obj = {a: 5, b: 3};
-var newObj = update(obj, {b: {$apply: function(x) {return x * 2;}}});
-// => {a: 5, b: 6}
-// This is equivalent, but gets verbose for deeply nested collections:
-var newObj2 = update(obj, {b: {$set: obj.b * 2}});
-```
-
-### (Shallow) merge
-
-```js
-var obj = {a: 5, b: 3};
-var newObj = update(obj, {$merge: {b: 6, c: 7}}); // => {a: 5, b: 6, c: 7}
-```
diff --git a/docs/docs/10.7-update.zh-CN.md b/docs/docs/10.7-update.zh-CN.md
deleted file mode 100644
index ea1b3b734984..000000000000
--- a/docs/docs/10.7-update.zh-CN.md
+++ /dev/null
@@ -1,102 +0,0 @@
----
-id: update-zh-CN
-title: immutability 助手
-permalink: update-zh-CN.html
-prev: create-fragment-zh-CN.html
-next: pure-render-mixin-zh-CN.html
----
-
-React 让你可以使用任何你想要的数据管理方式，包括 mutation。然而，如果你可以在你的应用的性能关键性部分里使用 immutable 数据，将会易于实现一个快速的 `shouldComponentUpdate()` 方法来显著加速你的 app。
-
-在 JavaScript 里处理 immutable 数据比在为此设计的语言中要难的多，比如 [Clojure](http://clojure.org/)。然而，我们提供了一个简单的 immutability 助手，`update()`，它使处理这类数据容易多了，*不用* 根本性的改变你的数据的表达方式。你也同样可以看一看 Facebook 的 [Immutable-js](https://facebook.github.io/immutable-js/docs/) 和[Advanced Performance](/react/docs/advanced-performance.html) 了解更多关于 Immutable-js 的信息。
-
-## 主要的思路
-
-如果你像这样变动数据：
-
-```js
-myData.x.y.z = 7;
-// or...
-myData.a.b.push(9);
-```
-
-你将没有任何办法决定哪个数据被改变了，因为之前的拷贝已经被覆盖。作为替代，你需要创建一个新的 `myData` 的拷贝并且只修改需要改变的地方。然后你可以用三个等于在 `shouldComponentUpdate()`  里比较旧的 `myData` 拷贝与新的拷贝：
-
-```js
-var newData = deepCopy(myData);
-newData.x.y.z = 7;
-newData.a.b.push(9);
-```
-
-不幸的是，深拷贝很昂贵，并且有时候不可能。你可以通过仅仅拷贝需要被改变和重用没有改变的对象来缓解这个情况。不幸的是，在当今的 JavaScript 里这会很笨重：
-
-```js
-var newData = extend(myData, {
-  x: extend(myData.x, {
-    y: extend(myData.x.y, {z: 7}),
-  }),
-  a: extend(myData.a, {b: myData.a.b.concat(9)})
-});
-```
-
-虽然这相当高性能（因为只对 `log n` 的对象进行了浅拷贝并重用了剩下的），但它写起来很痛苦。看看所有重复的代码！这不仅仅是烦人的，同时也提供了一大片 bugs 区域。
-
-`update()` 提供了这个模式的简单语法糖来使写这类代码更容易。上面的代码变成：
-
-```js
-var update = require('react-addons-update');
-
-var newData = update(myData, {
-  x: {y: {z: {$set: 7}}},
-  a: {b: {$push: [9]}}
-});
-```
-
-虽然这个语法需要花一些时间来适应（它的灵感来自于 [MongoDB's query language](http://docs.mongodb.org/manual/core/crud-introduction/#query)），但是没有冗余，它可静态分析并且没有 mutative 版本那么多键入。
-
-`$`-前缀的 keys 被称为 *命令*。被 "变动的" 数据结构被称为 *目标*。
-
-## 有效的命令
-
-  * `{$push: array}` 在目标上 `push()` 所有 `array` 里的项目。
-  * `{$unshift: array}` 在目标上 `unshift()` 所有 `array` 里的项目。
-  * `{$splice: array of arrays}` 在目标上对于每一个 `arrays` 里的项目使用项目提供的参数调用 `splice()`。
-  * `{$set: any}` 整个替换目标.
-  * `{$merge: object}` 合并 目标和 `object` 的 keys.
-  * `{$apply: function}` 传递当前的值给 function 并用返回值更新它。
-
-## 例子
-
-### 简单的 push
-
-```js
-var initialArray = [1, 2, 3];
-var newArray = update(initialArray, {$push: [4]}); // => [1, 2, 3, 4]
-```
-`initialArray` is still `[1, 2, 3]`.
-
-### 嵌套的 collections
-
-```js
-var collection = [1, 2, {a: [12, 17, 15]}];
-var newCollection = update(collection, {2: {a: {$splice: [[1, 1, 13, 14]]}}});
-// => [1, 2, {a: [12, 13, 14, 15]}]
-```
-本例访问了 `collection` 的`2`索引下的键`a`，并且拼接了一个从索引`1`开始（移除`17`）并插入`13`和`14`的项目。
-
-### 基于当前的值更新新值
-
-```js
-var obj = {a: 5, b: 3};
-var newObj = update(obj, {b: {$apply: function(x) {return x * 2;}}});
-// => {a: 5, b: 6}
-// This is equivalent, but gets verbose for deeply nested collections:
-var newObj2 = update(obj, {b: {$set: obj.b * 2}});
-```
-
-### (浅) 合并
-
-```js
-var obj = {a: 5, b: 3};
-var newObj = update(obj, {$merge: {b: 6, c: 7}}); // => {a: 5, b: 6, c: 7}
-```
diff --git a/docs/docs/10.8-pure-render-mixin.it-IT.md b/docs/docs/10.8-pure-render-mixin.it-IT.md
deleted file mode 100644
index bce1a42fa6d8..000000000000
--- a/docs/docs/10.8-pure-render-mixin.it-IT.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-id: pure-render-mixin-it-IT
-title: PureRenderMixin
-permalink: pure-render-mixin-it-IT.html
-prev: update-it-IT.html
-next: perf-it-IT.html
----
-
-Se la funzione render del tuo componente React è "pura" (in altre parole, visualizza lo stesso risultato a partire dagli stessi proprietà e stato), puoi usare questo mixin per un incremento di prestazioni in alcuni casi.
-
-Esempio:
-
-```js
-var PureRenderMixin = require('react/addons').addons.PureRenderMixin;
-React.createClass({
-  mixins: [PureRenderMixin],
-
-  render: function() {
-    return <div className={this.props.className}>foo</div>;
-  }
-});
-```
-
-Dietro le quinte, il mixin implementa [shouldComponentUpdate](/react/docs/component-specs.html#updating-shouldcomponentupdate), nel quale confronta i valori attuali di `this.props` e `this.state` con i successivi e restituisce  `false` se l'uguaglianza è verificata.
-
-> Nota:
->
-> Questo confronto tra gli oggetti è soltanto superficiale. Se questi contengono strutture dati complesse, può causare dei falsi negativi per differenze in profondità. Effettua il mix in componenti la cui struttura di `this.props` e  `this.state` sia semplice, oppure utilizza `forceUpdate()` quando si ha la certezza che le strutture dati siano cambiate in profondità. In alternativa, considera l'utilizzo di [oggetti immutabili](https://facebook.github.io/immutable-js/) per facilitare il confronto rapido di oggetti annidati.
->
-> Inoltre, `shouldComponentUpdate` rimanda gli aggiornamenti per l'intero sotto albero di componenti. Assicurati che tutti i componenti figli siano anch'essi "puri".
diff --git a/docs/docs/10.8-pure-render-mixin.ja-JP.md b/docs/docs/10.8-pure-render-mixin.ja-JP.md
deleted file mode 100644
index 967315164e01..000000000000
--- a/docs/docs/10.8-pure-render-mixin.ja-JP.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-id: pure-render-mixin
-title: PureRenderMixin
-permalink: pure-render-mixin-ja-JP.html
-prev: update-ja-JP.html
-next: perf-ja-JP.html
----
-
-Reactコンポーネントのrender関数が「ピュア」である（言い換えると、同じpropsやstateが与えられた時に同じ結果をレンダリングする）場合は、いくつかのケースでパフォーマンスをあげるためにこのミックスインを使用することができます。
-
-例:
-
-```js
-var PureRenderMixin = require('react/addons').addons.PureRenderMixin;
-React.createClass({
-  mixins: [PureRenderMixin],
-
-  render: function() {
-    return <div className={this.props.className}>foo</div>;
-  }
-});
-```
-
-内部で、このミックスインは[shouldComponentUpdate](/react/docs/component-specs-ja-JP.html#updating-shouldcomponentupdate)を実行します。現在のpropsとstateを次のものと比較し、同様のものであれば、 `false` を返します。
-
-> 注意:
-> このミックスインはオブジェクトの比較のみを行います。それらが複雑なデータ構造を持っていた場合、深い位置における違いは見逃されることがあります。単純なpropsやstateをコンポーネントが持っている場合にのみ、使用してください。深いデータ構造が変更されることが分かっている場合は、 `forceUpdate()` を使用してください。または、ネストされたデータの比較を速く行うために[不変オブジェクト](https://facebook.github.io/immutable-js/)の使用を考えてみてください。
-> 更に、 `shouldComponentUpdate` は全てのコンポーネントのサブツリーのアップデートをスキップします。全ての子要素のコンポーネントもまた、「ピュア」であることを確認してください。
diff --git a/docs/docs/10.8-pure-render-mixin.ko-KR.md b/docs/docs/10.8-pure-render-mixin.ko-KR.md
deleted file mode 100644
index 34fadd75d1c4..000000000000
--- a/docs/docs/10.8-pure-render-mixin.ko-KR.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-id: pure-render-mixin-ko-KR
-title: PureRenderMixin
-permalink: pure-render-mixin-ko-KR.html
-prev: update-ko-KR.html
-next: perf-ko-KR.html
----
-
-React 컴포넌트의 렌더 함수가 "pure"하다면 (다른 말로, props나 state에 같은 값이 주어질 때 같은 결과를 렌더한다면) 몇몇 경우엔 이 믹스인을 사용하여 성능을 향상시킬 수 있습니다.
-
-예제:
-
-```js
-var PureRenderMixin = require('react-addons-pure-render-mixin');
-React.createClass({
-  mixins: [PureRenderMixin],
-
-  render: function() {
-    return <div className={this.props.className}>foo</div>;
-  }
-});
-```
-
-내부적으로 믹스인은 현재의 props와 state를 다음 값과 비교하여 같다면 `false`를 반환하도록 [shouldComponentUpdate](/react/docs/component-specs-ko-KR.html#updating-shouldcomponentupdate)를 구현합니다.
-
-> 주의:
->
-> 여기서는 객체에 대한 얕은(shallow) 비교만 합니다. 복잡한 데이터 구조를 가진 경우에는 깊은 부분의 차이에 대해 잘못된 false를 반환 할 수도 있습니다. 간단한 props와 state를 사용하는 컴포넌트에만 적용하거나 깊은 데이터 구조가 변경 되었을때는 `forceUpdate()`를 사용하세요. 아니면 중첩 데이터의 비교를 빠르고 용이하게 하기 위해 [immutable 객체](https://facebook.github.io/immutable-js/)의 도입을 고려해보세요.
->
-> 또, `shouldComponentUpdate`는 컴포넌트 서브트리의 업데이트를 건너뜁니다. 모든 자식 컴포넌트들도 "pure"한지 확인하세요.
diff --git a/docs/docs/10.8-pure-render-mixin.md b/docs/docs/10.8-pure-render-mixin.md
deleted file mode 100644
index 5b8c4099f88a..000000000000
--- a/docs/docs/10.8-pure-render-mixin.md
+++ /dev/null
@@ -1,46 +0,0 @@
----
-id: pure-render-mixin
-title: PureRenderMixin
-permalink: pure-render-mixin.html
-prev: update.html
-next: perf.html
----
-
-If your React component's render function is "pure" (in other words, it renders the same result given the same props and state), you can use this mixin for a performance boost in some cases.
-
-Example:
-
-```js
-var PureRenderMixin = require('react-addons-pure-render-mixin');
-React.createClass({
-  mixins: [PureRenderMixin],
-
-  render: function() {
-    return <div className={this.props.className}>foo</div>;
-  }
-});
-```
-
-Example using ES6 class syntax:
-
-```js
-import PureRenderMixin from 'react-addons-pure-render-mixin';
-class FooComponent extends React.Component {
-  constructor(props) {
-    super(props);
-    this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);
-  }
-
-  render() {
-    return <div className={this.props.className}>foo</div>;
-  }
-}
-```
-
-Under the hood, the mixin implements [shouldComponentUpdate](/react/docs/component-specs.html#updating-shouldcomponentupdate), in which it compares the current props and state with the next ones and returns `false` if the equalities pass.
-
-> Note:
->
-> This only shallowly compares the objects. If these contain complex data structures, it may produce false-negatives for deeper differences. Only mix into components which have simple props and state, or use `forceUpdate()` when you know deep data structures have changed. Or, consider using [immutable objects](https://facebook.github.io/immutable-js/) to facilitate fast comparisons of nested data.
->
-> Furthermore, `shouldComponentUpdate` skips updates for the whole component subtree. Make sure all the children components are also "pure".
diff --git a/docs/docs/10.8-pure-render-mixin.zh-CN.md b/docs/docs/10.8-pure-render-mixin.zh-CN.md
deleted file mode 100644
index d37e927584c4..000000000000
--- a/docs/docs/10.8-pure-render-mixin.zh-CN.md
+++ /dev/null
@@ -1,46 +0,0 @@
----
-id: pure-render-mixin-zh-CN
-title: PureRenderMixin
-permalink: pure-render-mixin-zh-CN.html
-prev: update-zh-CN.html
-next: perf-zh-CN.html
----
-
-如果你的 React 组件的 render 函数是 "纯净" 的（换句话说，它的渲染在给定相同的 props 和 state 时返回相同的结果），你可以使用这个 mixin 在某些情况下进行性能加速。
-
-例子:
-
-```js
-var PureRenderMixin = require('react-addons-pure-render-mixin');
-React.createClass({
-  mixins: [PureRenderMixin],
-
-  render: function() {
-    return <div className={this.props.className}>foo</div>;
-  }
-});
-```
-
-使用 ES6 class 语法的例子:
-
-```js
-import PureRenderMixin from 'react-addons-pure-render-mixin';
-class FooComponent extends React.Component {
-  constructor(props) {
-    super(props);
-    this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);
-  }
-
-  render() {
-    return <div className={this.props.className}>foo</div>;
-  }
-}
-```
-
-在内部, mixin 实现了 [shouldComponentUpdate](/react/docs/component-specs.html#updating-shouldcomponentupdate), 它对当前及下一步的 props 和 state 进行比较，并当相等时返回 `false`。
-
-> 注意:
->
-> 它仅仅浅比较对象。如果包含了复杂的对象，可能会对于深层的不同产生 false-negatives。只 mix 到那些含有简单 props 和 state 的组件，或者在你知道深层对象改变时使用 `forceUpdate()` 。或者，考虑使用[immutable objects](https://facebook.github.io/immutable-js/) 来促进快速的嵌套数据比较。
->
-> 此外， `shouldComponentUpdate` 跳过了整个子树的更新。确保所有的子组件都是 "纯净" 的。
diff --git a/docs/docs/10.9-perf.it-IT.md b/docs/docs/10.9-perf.it-IT.md
deleted file mode 100644
index 3ef53e5e0802..000000000000
--- a/docs/docs/10.9-perf.it-IT.md
+++ /dev/null
@@ -1,74 +0,0 @@
----
-id: perf-it-IT
-title: Strumenti per la Performance
-permalink: perf-it-IT.html
-prev: pure-render-mixin-it-IT.html
-next: advanced-performance-it-IT.html
----
-
-React è solitamente assai veloce. Tuttavia, in situazioni nelle quali devi spremere fino all'ultima goccia di prestazioni dalla tua applicazione, fornisce un hook [shouldComponentUpdate](/react/docs/component-specs.html#updating-shouldcomponentupdate) nel quale puoi aggiungere controlli di ottimizzazione per l'algoritmo di confronto di React.
-
-Oltre a darti una panoramica sulle prestazioni generali della tua applicazione, ReactPerf è uno strumento di profilazione che ti dice esattamente dove è necessario aggiungere questi hook.
-
-> Nota:
->
-> La build di sviluppo di React è più lenta della build di produzione, per via di tutta la logica aggiuntiva per fornire, ad esempio, gli avvisi amichevoli di React nella console (eliminati dalla build di produzione). Pertanto, il profilatore serve soltanto ad indicare le parti _relativamente_ costose della tua applicazione.
-
-## API Generale
-
-L'oggetto `Perf` documentato di seguito è esposto come `React.addons.Perf` quando si usa la build `react-with-addons.js` in modalità di sviluppo.
-
-### `Perf.start()` and `Perf.stop()`
-Avvia/interrompe la misurazione. Le operazioni React intermedie sono registrate per analisi in seguito. Le operazioni che hanno impiegato un tempo trascurabile vengono ignorate.
-
-Dopo l'interruzione, dovrai chiamare `Perf.getLastMeasurements()` (descritta in seguito) per ottenere le misurazioni.
-
-### `Perf.printInclusive(measurements)`
-Stampa il tempo complessivo impiegato. Se non vengono passati argomenti, stampa tutte le misurazioni dall'ultima registrazione. Stampa una tabella gradevolmente formattata nella console, come segue:
-
-![](/react/img/docs/perf-inclusive.png)
-
-### `Perf.printExclusive(measurements)`
-I tempi "esclusivi" non includono il tempo impiegato a montare i componenti: processare le proprietà, `getInitialState`, chiamare `componentWillMount` e `componentDidMount`, etc.
-
-![](/react/img/docs/perf-exclusive.png)
-
-### `Perf.printWasted(measurements)`
-
-**La parte più utile in assoluto del profilatore**.
-
-Il tempo "sprecato" è impiegato nei componenti che non hanno di fatto visualizzato nulla, ad es. il rendering è rimasto inalterato, quindi il DOM non è stato toccato.
-
-![](/react/img/docs/perf-wasted.png)
-
-### `Perf.printDOM(measurements)`
-Stampa le manipolazioni sottostanti del DOM, ad es. "imposta innerHTML" e "rimuovi".
-
-![](/react/img/docs/perf-dom.png)
-
-## API Avanzata
-
-I metodi di stampa precedenti utilizzano `Perf.getLastMeasurements()` per effettuare una gradevole stampa dei risultati.
-
-### `Perf.getLastMeasurements()`
-Ottieni l'array delle misurazioni dall'ultima sessione di avvio-interruzione. L'array contiene oggetti, ciascuno dei quali assomiglia a quanto segue:
-
-```js
-{
-  // I termini "inclusive" ed "exclusive" sono spiegati in seguito
-  "exclusive": {},
-  // '.0.0' è l'identificativo React del nodo
-  "inclusive": {".0.0": 0.0670000008540228, ".0": 0.3259999939473346},
-  "render": {".0": 0.036999990697950125, ".0.0": 0.010000003385357559},
-  // Numero di istanze
-  "counts": {".0": 1, ".0.0": 1},
-  // Scritture sul DOM
-  "writes": {},
-  // Informazioni aggiuntive per il debug
-  "displayNames": {
-    ".0": {"current": "App", "owner": "<root>"},
-    ".0.0": {"current": "Box", "owner": "App"}
-  },
-  "totalTime": 0.48499999684281647
-}
-```
diff --git a/docs/docs/10.9-perf.ja-JP.md b/docs/docs/10.9-perf.ja-JP.md
deleted file mode 100644
index 7c7024a71184..000000000000
--- a/docs/docs/10.9-perf.ja-JP.md
+++ /dev/null
@@ -1,73 +0,0 @@
----
-id: perf
-title: パフォーマンスツール
-permalink: perf-ja-JP.html
-prev: pure-render-mixin-ja-JP.html
-next: advanced-performance-ja-JP.html
----
-
-Reactは普通、従来の枠を超えてとても速いです。しかし、アプリケーションにおいて、少しでもパフォーマンスを上げようという状況では、Reactの差分を取るアルゴリズムを最大限活用するヒントが得られる、[shouldComponentUpdate](/react/docs/component-specs-ja-JP.html#updating-shouldcomponentupdate)のフックを提供します。
-
-アプリケーション全体のパフォーマンスについての要約を得ることに加えて、ReactPerfはそれらのフックを実際にはどこに配置する必要があるか教えてくれるプロファイリングツールでもあります。
-
-> 注意:
-> Reactの開発版のビルドは与えられた外部ロジックのためにプロダクション版のビルドよりも遅くなります。例えば、Reactのフレンドリーコンソールの警告（プロダクション版のビルドにおいては警告が出ません）のように。それゆえ、プロファイラは *比較的* コストがかかっている箇所のみを指し示します。
-
-## 一般的なAPI
-
-ここに記述されている `Perf` オブジェクトは `react-with-addons.js` を開発版でビルドしたものを使用する際に `React.addons.Perf` として表されます。
-
-### `Perf.start()` と `Perf.stop()`
-測定の開始/終了です。その間のReactの操作は以下のような分析のために記録されます。あまり時間を使わない操作は無視されます。
-
-停止した後、あなたは、測定結果を得るために `Perf.getLastMeasurements()` （後述）が必要になります。
-
-### `Perf.printInclusive(measurements)`
-かかった全ての時間を出力します。引数が渡されなかった場合は、デフォルトで最後の測定から全ての測定が行われます。これは以下のように、コンソールに綺麗にフォーマットされたテーブルを出力します。
-
-![](/react/img/docs/perf-inclusive.png)
-
-### `Perf.printExclusive(measurements)`
-「占有」時間はコンポーネントをマウントするのにかかった時間を含みません。プロパティの処理、 `getInitialState` , `componentWillMount` や `componentDidMount` の呼び出しなどは含みます。
-
-![](/react/img/docs/perf-exclusive.png)
-
-### `Perf.printWasted(measurements)`
-
-**プロファイラの最も有用な箇所です**。
-
-「無駄な」時間はコンポーネントが実際には何もレンダリングしていないのにかかっている時間です。例えば、同じものをレンダリングしたので、DOMが触られなかったような場合です。
-
-![](/react/img/docs/perf-wasted.png)
-
-### `Perf.printDOM(measurements)`
-以下のような、DOMの操作を出力します。例えば、"set innerHTML"や"remove"といったものです。
-
-![](/react/img/docs/perf-dom.png)
-
-## 先進的なAPI
-
-上記の出力メソッドは結果をプリティプリントするのに `Perf.getLastMeasurements()` を使用しています。
-
-### `Perf.getLastMeasurements()`
-最後の開始と終了のセッションから測定の配列を取得します。配列は以下のようなオブジェクトを含みます。
-
-```js
-{
-  // "inclusive"と"exclusive"の期間は以下で説明されています
-  "exclusive": {},
-  // '.0.0' はノードのReact ID
-  "inclusive": {".0.0": 0.0670000008540228, ".0": 0.3259999939473346},
-  "render": {".0": 0.036999990697950125, ".0.0": 0.010000003385357559},
-  // インスタンスの数
-  "counts": {".0": 1, ".0.0": 1},
-  // 触ったDOM
-  "writes": {},
-  // 追加のデバッグ情報
-  "displayNames": {
-    ".0": {"current": "App", "owner": "<root>"},
-    ".0.0": {"current": "Box", "owner": "App"}
-  },
-  "totalTime": 0.48499999684281647
-}
-```
diff --git a/docs/docs/10.9-perf.ko-KR.md b/docs/docs/10.9-perf.ko-KR.md
deleted file mode 100644
index 62e679b0f646..000000000000
--- a/docs/docs/10.9-perf.ko-KR.md
+++ /dev/null
@@ -1,74 +0,0 @@
----
-id: perf-ko-KR
-title: 성능 도구
-permalink: perf-ko-KR.html
-prev: pure-render-mixin-ko-KR.html
-next: advanced-performance-ko-KR.html
----
-
-React는 보통 처음에는 꽤 빠릅니다. 하지만 모든 성능을 짜내야 하는 상황일 때를 위해, React는 [shouldComponentUpdate](/react/docs/component-specs.html#updating-shouldcomponentupdate) 훅을 제공해 React의 diff 알고리즘을 위한 최적화 힌트를 추가할 수 있습니다.
-
-덧붙여 앱의 전반적인 성능의 개요도 제공합니다. ReactPerf는 프로파일링 도구로 정확히 어디에 훅이 필요한지 알려줍니다.
-
-> 주의:
->
-> React의 개발 빌드는 제공되는 추가 기능으로 인해 프로덕션 빌드보다 느립니다. 추가 기능에는 React의 친절한 콘솔 경고같은 것이 있습니다.(이는 프로덕션 빌드에서는 제거 됩니다) 따라서, 프로파일러는 앱의 _상대적으로_ 비싼 부분만 표시하도록 합니다.
-
-## 일반 API
-
-여기에서 설명하는 `Perf` 객체는 `require('react-addons-perf')`로 노출되고 React 개발 모드에서만 사용할 수 있습니다. 이 번들을 프로덕션에서 앱과 같이 빌드하시면 안됩니다.
-
-### `Perf.start()`와 `Perf.stop()`
-측정을 시작/정지합니다. 그 사이의 React 연산은 밑에 있는 분석을 하기위해 기록됩니다. 미미한 양의 연산은 무시됩니다.
-
-종료 후, 측정을 하기위해서는 이후에 설명할 `Perf.getLastMeasurements()`가 필요합니다.
-
-### `Perf.printInclusive(measurements)`
-전 수행 시간을 출력합니다. 인자가 넘겨지지 않으면, 기본값은 지난 기록부터의 모든 측정이 됩니다. 이 출력은 밑에 있는 것처럼 콘솔에서 깔끔한 테이블로 그려집니다.
-
-![](/react/img/docs/perf-inclusive.png)
-
-### `Perf.printExclusive(measurements)`
-컴포넌트를 마운트하는 시간을 포함하지 않은 "exclusive" 시간입니다. 여기에는 props 연산, `getInitialState`, `componentWillMount` 호출, `componentDidMount`등이 포함됩니다.
-
-![](/react/img/docs/perf-exclusive.png)
-
-### `Perf.printWasted(measurements)`
-
-**프로파일러에서 가장 유용한 부분입니다**.
-
-렌더가 같아서, DOM을 변경(touch)하지 않는 경우같은 실제로는 아무것도 렌더하지 않는 컴포넌트가 사용하는 "낭비되는" 시간을 출력합니다.
-
-![](/react/img/docs/perf-wasted.png)
-
-### `Perf.printDOM(measurements)`
-"set innerHTML"이나 "remove"같은 기저의 DOM 조작을 출력합니다.
-
-![](/react/img/docs/perf-dom.png)
-
-## 고급 API
-
-위의 출력 메소드에 `Perf.getLastMeasurements()`를 사용해 결과를 이쁘게 출력합니다.
-
-### `Perf.getLastMeasurements()`
-마지막 start-stop 세션에서 측정들의 배열을 가져옵니다. 이 배열은 이런 객체들을 가지고 있습니다.
-
-```js
-{
-  // 용어 "inclusive"와 "exclusive"는 위에서 설명했음
-  "exclusive": {},
-  // '.0.0'는 노드의 React ID
-  "inclusive": {".0.0": 0.0670000008540228, ".0": 0.3259999939473346},
-  "render": {".0": 0.036999990697950125, ".0.0": 0.010000003385357559},
-  // 인스턴스의 수
-  "counts": {".0": 1, ".0.0": 1},
-  // DOM 변경(touch)
-  "writes": {},
-  // 추가 디버깅 정보
-  "displayNames": {
-    ".0": {"current": "App", "owner": "<root>"},
-    ".0.0": {"current": "Box", "owner": "App"}
-  },
-  "totalTime": 0.48499999684281647
-}
-```
diff --git a/docs/docs/10.9-perf.md b/docs/docs/10.9-perf.md
deleted file mode 100644
index 8b8da062584a..000000000000
--- a/docs/docs/10.9-perf.md
+++ /dev/null
@@ -1,62 +0,0 @@
----
-id: perf
-title: Performance Tools
-permalink: perf.html
-prev: pure-render-mixin.html
-next: shallow-compare.html
----
-
-React is usually quite fast out of the box. However, in situations where you need to squeeze every ounce of performance out of your app, it provides a [shouldComponentUpdate](/react/docs/component-specs.html#updating-shouldcomponentupdate) hook where you can add optimization hints to React's diff algorithm.
-
-In addition to giving you an overview of your app's overall performance, ReactPerf is a profiling tool that tells you exactly where you need to put these hooks.
-
-See these two articles by the [Benchling Engineering Team](http://benchling.engineering) for a in-depth introduction to performance tooling: ["Performance Engineering with React"](http://benchling.engineering/performance-engineering-with-react/) and ["A Deep Dive into React Perf Debugging"](http://benchling.engineering/deep-dive-react-perf-debugging/)!
-
-## General API
-
-The `Perf` object documented here is exposed as `require('react-addons-perf')` and can be used with React in development mode only. You should not include this bundle when building your app for production.
-
-> Note:
->
-> The dev build of React is slower than the prod build, due to all the extra logic for providing, for example, React's friendly console warnings (stripped away in the prod build). Therefore, the profiler only serves to indicate the _relatively_ expensive parts of your app.
-
-### `Perf.start()` and `Perf.stop()`
-Start/stop the measurement. The React operations in-between are recorded for analyses below. Operations that took an insignificant amount of time are ignored.
-
-After stopping, you will need `Perf.getLastMeasurements()` (described below) to get the measurements.
-
-### `Perf.printInclusive(measurements)`
-Prints the overall time taken. If no argument's passed, defaults to all the measurements from the last recording. This prints a nicely formatted table in the console, like so:
-
-![](/react/img/docs/perf-inclusive.png)
-
-### `Perf.printExclusive(measurements)`
-"Exclusive" times don't include the times taken to mount the components: processing props, `getInitialState`, call `componentWillMount` and `componentDidMount`, etc.
-
-![](/react/img/docs/perf-exclusive.png)
-
-### `Perf.printWasted(measurements)`
-
-**The most useful part of the profiler**.
-
-"Wasted" time is spent on components that didn't actually render anything, e.g. the render stayed the same, so the DOM wasn't touched.
-
-![](/react/img/docs/perf-wasted.png)
-
-### `Perf.printOperations(measurements)`
-Prints the underlying DOM manipulations, e.g. "set innerHTML" and "remove".
-
-![](/react/img/docs/perf-dom.png)
-
-### `Perf.printDOM(measurements)`
-
-This method has been renamed to `printOperations()` which is described in the previous paragraph. Currently `printDOM()` still exists as an alias but it prints a deprecation warning and will eventually be removed.
-
-## Advanced API
-
-The above print methods use `Perf.getLastMeasurements()` to pretty-print the result.
-
-### `Perf.getLastMeasurements()`
-Get the opaque data structure describing measurements from the last start-stop session. You can save it and pass it to the methods above to analyze past measurements.
-
-Don't rely on the exact format of the return value because it may change in minor releases. We will update the documentation if the return value format becomes a supported part of the public API.
diff --git a/docs/docs/10.9-perf.zh-CN.md b/docs/docs/10.9-perf.zh-CN.md
deleted file mode 100644
index b4f314bc37bd..000000000000
--- a/docs/docs/10.9-perf.zh-CN.md
+++ /dev/null
@@ -1,74 +0,0 @@
----
-id: perf-zh-CN
-title: 性能工具
-permalink: perf-zh-CN.html
-prev: pure-render-mixin-zh-CN.html
-next: shallow-compare-zh-CN.html
----
-
-React 通常是相当快的。然而，在你需要压榨你的 app 的每一分性能的情况下，它提供了一个[shouldComponentUpdate](/react/docs/component-specs.html#updating-shouldcomponentupdate) 钩子，在此你可以添加优化提示到 React 的 diff 算法里。
-
-除了给予你一个你的 app 的整体性能概览外，ReactPerf 还是一个准确告诉你，你需要在哪里放置这些钩子的分析工具。
-
-## General API
-
-这里陈述的 `Perf` 对象被用 `require('react-addons-perf')` 暴露，并且只能被使用在 React 的开发模式。你不应在生产环境下在你的 app 包含这个包。
-
-> 注意:
->
-> 开发版的 React 慢于生产版，因为所有额外提供的逻辑，例如，React 的友好的控制台警告 （在生产版中被除去）。因此，分析工具仅服务于指示你的 app _相对_ 昂贵的部分。
-
-### `Perf.start()` and `Perf.stop()`
-开始/停止测量。其间的React操作被记录用于之后的分析。产生无关紧要时间的操作被忽略。
-
-在停止以后，你将需要 `Perf.getLastMeasurements()` （下面将介绍）来获取测量结果。
-
-### `Perf.printInclusive(measurements)`
-打印总体花费的时间。如果没有传入参数，默认是从上次记录的所有测量数据。它在控制台里打印良好格式化的结果，像这样：
-
-![](/react/img/docs/perf-inclusive.png)
-
-### `Perf.printExclusive(measurements)`
-"独占的"时间不包括花费于加载组件的时间： 处理 props, `getInitialState`, 调用 `componentWillMount` 及 `componentDidMount`, 等等。
-
-![](/react/img/docs/perf-exclusive.png)
-
-### `Perf.printWasted(measurements)`
-
-**分析工具里最有用的部分**.
-
-"垃圾"时间是花费在组件上实际没有绘制任何东西的时间，例如渲染结果总是相同，所以 DOM 没有被触碰到。
-
-![](/react/img/docs/perf-wasted.png)
-
-### `Perf.printDOM(measurements)`
-打印底层的 DOM 操纵，例如 "set innerHTML" 和 "remove".
-
-![](/react/img/docs/perf-dom.png)
-
-## Advanced API
-
-以上的打印方法使用 `Perf.getLastMeasurements()` 来美观的打印结果。
-
-### `Perf.getLastMeasurements()`
-从最后的 start-stop 会话获取测量数据数据。这个数组包含对象，每个看起来像这样：
-
-```js
-{
-  // The term "inclusive" and "exclusive" are explained below
-  "exclusive": {},
-  // '.0.0' is the React ID of the node
-  "inclusive": {".0.0": 0.0670000008540228, ".0": 0.3259999939473346},
-  "render": {".0": 0.036999990697950125, ".0.0": 0.010000003385357559},
-  // Number of instances
-  "counts": {".0": 1, ".0.0": 1},
-  // DOM touches
-  "writes": {},
-  // Extra debugging info
-  "displayNames": {
-    ".0": {"current": "App", "owner": "<root>"},
-    ".0.0": {"current": "Box", "owner": "App"}
-  },
-  "totalTime": 0.48499999684281647
-}
-```
diff --git a/docs/docs/11-advanced-performance.it-IT.md b/docs/docs/11-advanced-performance.it-IT.md
deleted file mode 100644
index 625b48a3cb8b..000000000000
--- a/docs/docs/11-advanced-performance.it-IT.md
+++ /dev/null
@@ -1,207 +0,0 @@
----
-id: advanced-performance-it-IT
-title: Performance Avanzata
-permalink: advanced-performance-it-IT.html
-prev: perf-it-IT.html
----
-
-Una tra le prime domande che la gente si pone quando considera React per un progetto è se l'applicazione sarà altrettanto veloce e scattante di una versione equivalente non basata su React. L'idea di ripetere il rendering di un intero sottoalbero di componenti in risposta a ciascun cambiamento dello stato rende la gente curiosa se questo processo influisce negativamente sulle prestazioni. React utilizza diverse tecniche intelligenti per minimizzare il numero di operazioni costose sul DOM richieste dall'aggiornamento della UI.
-
-## Evitare di riconciliare il DOM
-
-React fa uso di un *DOM virtuale*, che è un descrittore di un sottoalbero DOM visualizzato nel browser. Questa rappresentazione parallela permette a React di evitare di creare nodi DOM e accedere nodi esistenti, che è di gran lunga più lento di operazioni su oggetti JavaScript. Quando le proprietà di un componente o il suo stato cambiano, React decide se un'aggiornamento effettivo del DOM sia necessario costruendo un nuovo virtual DOM e confrontandolo con quello vecchio. Solo nel caso in cui non siano uguali, React [riconcilierà](/react/docs/reconciliation.html) il DOM, applicando il minor numero di mutamenti possibile.
-
-In aggiunta a questo, React offre una funzione per il ciclo di vita del componente, `shouldComponentUpdate`, che viene scatenata prima che il processo di ri-rendering cominci (il confronto del DOM virtuale e una possibile eventuale riconciliazione del DOM), dando allo sviluppatore la possibilità di cortocircuitare questo processo. L'implementazione predefinita di questa funzione restituisce `true`, lasciando che React effettui l'aggiornamento:
-
-```javascript
-shouldComponentUpdate: function(nextProps, nextState) {
-  return true;
-}
-```
-
-Tieni in mente che React invocherà questa funzione abbastanza spesso, quindi l'implementazione deve essere veloce.
-
-Supponiamo che hai un'applicazione di messaggistica con parecchi thread di conversazioni. Supponi che solo uno dei thread sia cambiato.  Se implementassimo `shouldComponentUpdate` sul componente `ChatThread`, React potrebbe saltare la fase di rendering per gli altri thread:
-
-```javascript
-shouldComponentUpdate: function(nextProps, nextState) {
-  // TODO: restituisci true se il thread attuale è diverso
-  // da quello precedente.
-}
-```
-
-Quindi, riassumendo, React evita di effettuare operazioni costose sul DOM richieste a riconciliare sottoalberi del DOM, permettendo all'utente di cortocircuitare il processo usando `shouldComponentUpdate`, e, per i casi in cui si debba aggiornare, confrontando i DOM virtuali.
-
-## shouldComponentUpdate in azione
-
-Ecco un sottoalbero di componenti. Per ciascuno di essi viene indicato cosa `shouldComponentUpdate` ha restituito e se i DOM virtuali siano equivalenti o meno. Infine, il colore del cerchio indica se il componente sia stato riconciliato o meno.
-
-<figure><img src="/react/img/docs/should-component-update.png" /></figure>
-
-Nell'esempio precedente, dal momento che `shouldComponentUpdate` ha restituito `false` per il sottoalbero di radice C2, React non ha avuto bisogno di generare il nuovo DOM virtuale, e quindi non ha nemmeno avuto bisogno di riconciliare il DOM. Nota che React non ha nemmeno avuto bisogno di invocare `shouldComponentUpdate` su C4 e C5.
-
-Per C1 e C3, `shouldComponentUpdate` ha restituito `true`, quindi React è dovuto scendere giù fino alle foglie e controllarle. Per C6 ha restituito `true`; dal momento che i DOM virtuali non erano equivalenti, ha dovuto riconciliare il DOM.
-L'ultimo caso interessante è C8. Per questo nodo React ha dovuto calcolare il DOM virtuale, ma dal momento che era uguale al vecchio, non ha dovuto riconciliare il suo DOM.
-
-Nota che React ha dovuto effettuare mutazioni del DOM soltanto per C6, che era inevitabile. Per C8, lo ha evitato confrontando i DOM virtuali, e per il sottoalbero di C2 e C7, non ha neppure dovuto calcolare il DOM virtuale in quanto è stato esonerato da `shouldComponentUpdate`.
-
-Quindi, come dovremmo implementare `shouldComponentUpdate`? Supponiamo di avere un componente che visualizza soltanto un valore stringa:
-
-```javascript
-React.createClass({
-  propTypes: {
-    value: React.PropTypes.string.isRequired
-  },
-
-  render: function() {
-    return <div>{this.props.value}</div>;
-  }
-});
-```
-
-Potremmo facilmente implementare `shouldComponentUpdate` come segue:
-
-```javascript
-shouldComponentUpdate: function(nextProps, nextState) {
-  return this.props.value !== nextProps.value;
-}
-```
-
-Finora tutto a posto, maneggiare queste semplici strutture proprietà e stato è molto facile. Potremmo anche generalizzare un'implementazione basata sull'uguaglianza superficiale e farne il mix dentro i componenti. Infatti, React fornisce già una tale implementazione: [PureRenderMixin](/react/docs/pure-render-mixin.html).
-
-Ma che succede se le proprietà o lo stato del tuo componente sono strutture dati mutevoli? Supponiamo che la proprietà che il componente riceve sia, anziché una stringa come `'bar'`, un oggetto JavaScript che contiene una stringa, come `{ foo: 'bar' }`:
-
-```javascript
-React.createClass({
-  propTypes: {
-    value: React.PropTypes.object.isRequired
-  },
-
-  render: function() {
-    return <div>{this.props.value.foo}</div>;
-  }
-});
-```
-
-L'implementazione di `shouldComponentUpdate` che avevamo prima non funzionerebbe sempre come ci aspettiamo:
-
-```javascript
-// assumiamo che this.props.value sia { foo: 'bar' }
-// assumiamo che nextProps.value sia { foo: 'bar' },
-// ma questo riferimento è diverso da this.props.value
-this.props.value !== nextProps.value; // true
-```
-
-Il problema è che `shouldComponentUpdate` restituirà `true` quando la proprietà non è in realtà cambiata. Per risolvere questo problema, potremmo proporre questa implementazione alternativa:
-
-```javascript
-shouldComponentUpdate: function(nextProps, nextState) {
-  return this.props.value.foo !== nextProps.value.foo;
-}
-```
-
-In breve, abbiamo finito per effettuare un confronto in profondità per assicurarci di accorgerci correttamente dei cambiamenti. In termini di prestazioni, questo approccio è molto costoso. Non scala in quanto dovremmo scrivere codice diverso per valutare l'uguaglianza in profondità per ciascun modello. Inoltre, potrebbe anche non funzionare per nulla se non gestiamo correttamente i riferimenti agli oggetti. Supponiamo che il componente sia usato da un genitore:
-
-```javascript
-React.createClass({
-  getInitialState: function() {
-    return { value: { foo: 'bar' } };
-  },
-
-  onClick: function() {
-    var value = this.state.value;
-    value.foo += 'bar'; // ANTI-PATTERN!
-    this.setState({ value: value });
-  },
-
-  render: function() {
-    return (
-      <div>
-        <InnerComponent value={this.state.value} />
-        <a onClick={this.onClick}>Click me</a>
-      </div>
-    );
-  }
-});
-```
-
-La prima volta che viene effettuato il rendering del componente interno, la sua proprietà value avrà il valore `{ foo: 'bar' }`. Se l'utente clicca l'ancora, lo stato del componente genitore sarà aggiornato a `{ value: { foo: 'barbar' } }`, scatenando il processo di ri-rendering sul componente interno, il quale riceverà `{ foo: 'barbar' }` come il nuovo valore della proprietà.
-
-Il problema è che, dal momento che il genitore e il componente interno condividono un riferimento allo stesso oggetto, quando l'oggetto viene modificato nella riga 2 della funzione `onClick`, la proprietà che il componente interno possedeva cambierà anch'essa. Quindi, quando il processo di ri-rendering inizia, e `shouldComponentUpdate` viene invocato, `this.props.value.foo` sarà uguale a `nextProps.value.foo`, perché infatti, `this.props.value` si riferisce allo stesso oggetto di `nextProps.value`.
-
-Di conseguenza, dal momento che non ci accorgiamo del cambiamento della proprietà e cortocircuitiamo il processo di ri-rendering, la UI non sarà aggiornata da `'bar'` a `'barbar'`.
-
-## Immutable-js viene in nostro soccorso
-
-[Immutable-js](https://github.com/facebook/immutable-js) è una libreria di collezioni JavaScript scritta da Lee Byron, che Facebook ha recentemente rilasciato come open source. Fornisce collezioni *immutabili e persistenti* attraverso *condivisione strutturale*. Vediamo cosa significano queste proprietà:
-
-* *Immutabile*: una volta creata, una collezione non può essere alterata in un momento successivo.
-* *Persistente*: nuove collezioni possono essere create da una collezione precedente e una mutazione come un assegnamento. La collezione originale è ancora valida dopo che la nuova collezione è stata creata.
-* *Condivisione Strutturale*: nuove collezioni sono create riutilizzando quanto più possibile della stessa struttura della collezione originale, riducendo le operazioni di copia al minimo, per ottenere efficienza spaziale e prestazioni accettabili. Se la nuova collezione è identica all'originale, l'originale è spesso restituita.
-
-L'immutabilità ci permette di tenere traccia dei cambiamenti in modo economico; un cambiamento risulterà sempre in un nuovo oggetto, quindi dobbiamo soltanto controllare se il riferimento all'oggeto sia cambiato. Ad esempio, in questo codice regolare JavaScript:
-
-```javascript
-var x = { foo: "bar" };
-var y = x;
-y.foo = "baz";
-x === y; // true
-```
-
-Sebbene `y` sia stato modificato, dal momento che si tratta di un riferimento allo stesso oggetto di `x`, questo confronto restituisce `true`. Tuttavia, questo codice potrebbe essere scritto usando immutable-js come segue:
-
-```javascript
-var SomeRecord = Immutable.Record({ foo: null });
-var x = new SomeRecord({ foo: 'bar'  });
-var y = x.set('foo', 'baz');
-x === y; // false
-```
-
-In questo caso, poiché un nuovo riferimento è restituito quando si modifica `x`, possiamo assumere in tutta sicurezza che `x` sia cambiato.
-
-Un'altra maniera possibile di tener traccia dei cambiamenti potrebbe essere il dirty checking, ovvero usare un flag impostato dai metodi setter. Un problema con questo approccio è che ti forza ad usare i setter e scrivere un sacco di codice aggiuntivo, oppure instrumentare in qualche modo le tue classi. In alternativa, puoi effettuare una copia profonda dell'oggetto immediatamente prima della mutazione ed effettuare un confronto in profondità per determinare se vi è stato un cambiamento oppure no. Un problema con questo approccio è che sia deepCopy che deepCompare sono operazioni costose.
-
-Quindi, le strutture dati Immutable ti forniscono una maniera economica e concisa di osservare i cambiamenti degli oggetti, che è tutto ciò che ci serve per implementare `shouldComponentUpdate`. Pertanto, se modelliamo gli attributi delle proprietà e dello stato usando le astrazioni fornite da immutable-js saremo in grado di usare `PureRenderMixin` e ottenere un grande aumento di prestazioni.
-
-## Immutable-js e Flux
-
-Se stai usando [Flux](https://facebook.github.io/flux/), dovresti cominciare a scrivere i tuoi store usando immutable-js. Dài un'occhiata alla [API completa](https://facebook.github.io/immutable-js/docs/#/).
-
-Vediamo una delle possibili maniere di modellare l'esempio dei thread usando strutture dati Immutable. Anzitutto, dobbiamo definire un  `Record` per ciascuna delle entità che desideriamo modellare. I Record sono semplicemente contenitori immutabili che contengono valori per un insieme specifico di campi:
-
-```javascript
-var User = Immutable.Record({
-  id: undefined,
-  name: undefined,
-  email: undefined
-});
-
-var Message = Immutable.Record({
-  timestamp: new Date(),
-  sender: undefined,
-  text: ''
-});
-```
-
-La funzione `Record` riceve un oggetto che definisce i campi che l'oggetto possiede e i loro valori predefiniti.
-
-Lo *store* dei messaggi potrebbe tenere traccia degli utenti e dei messaggi usando due liste:
-
-```javascript
-this.users = Immutable.List();
-this.messages = Immutable.List();
-```
-
-Dovrebbe essere abbastanza banale implementare funzioni che gestiscono ciascun tipo di *payload*. Ad esempio, quando lo store vede un payload che rappresenta un messaggio, possiamo semplicemente creare un nuovo record e metterlo in coda alla lista di messaggi:
-
-```javascript
-this.messages = this.messages.push(new Message({
-  timestamp: payload.timestamp,
-  sender: payload.sender,
-  text: payload.text
-});
-```
-
-Nota che dal momento che le strutture dati sono immutabili, dobbiamo assegnare il valore di ritorno del metodo push a `this.messages`.
-
-Dal punto di vista di React, se usiamo strutture dati immutable-js anche per contenere lo stato del componente, possiamo fare il mix di `PureRenderMixin` in tutti i nostri componenti e cortocircuitare il processo di ri-rendering.
diff --git a/docs/docs/11-advanced-performance.ja-JP.md b/docs/docs/11-advanced-performance.ja-JP.md
deleted file mode 100644
index a17b28f82d1c..000000000000
--- a/docs/docs/11-advanced-performance.ja-JP.md
+++ /dev/null
@@ -1,205 +0,0 @@
----
-id: advanced-performance
-title: 先進的なパフォーマンス
-permalink: advanced-performance-ja-JP.html
-prev: perf-ja-JP.html
----
-
-Reactをプロジェクトで使用しようとする際にまず最初に気になるのは、アプリケーションがReactを使用しないバージョンと比べて、同じくらい速くてレスポンシブであるかどうかということです。ステータスの変更毎にレスポンスでコンポーネントのサブツリーの全てを再度レンダリングするという考え方によって、このプロセスがパフォーマンスにネガティブな影響を与えるのではないかと人々は不安に思います。ReactはUIを更新するのに必要な、コストのかかる多くのDOMの操作を最小限にするためのいくつかの賢い技術を使用します。
-
-## DOMを一致させることを防ぐこと
-
-ReactはブラウザでレンダリングされるDOMのサブツリーの記述語である *virtual DOM* を使用しています。この2つの表現によってReactは、JavaScriptのオブジェクトの操作よりも遅い、DOMノードを作成したり存在しているDOMノードにアクセスすることを防いでいます。コンポーネントの `props` や `state` が変更された時、Reactは新しいvirtual DOMを構成して、それを古いものと比較することによって、実際のDOMの更新が必要かどうか決定します。それらが同じものでなかった場合にのみ、ReactはDOMを[一致](/react/docs/reconciliation.html)させ、最小限の変更を適用します。
-この最上位で、Reactはコンポーネントライフサイクルファンクションである `shouldComponentUpdate` を提供します。これは、再度レンダリングを行うプロセス（virtual DOMの比較と起こり得る最終的なDOMの一致）が始まる前に誘発されます。そして、開発者にこのプロセスの循環を短くすることを可能にします。デフォルトのこの関数の実行時にはReactが更新を行って、以下のように `true` が返ります。
-
-```javascript
-shouldComponentUpdate: function(nextProps, nextState) {
-  return true;
-}
-```
-
-Reactがとても頻繁にこの関数を呼び出すので、実行が速いものである必要があることを頭に置いておいてください。
-
-いくつかのチャットのスレッドを持つメッセージングのアプリケーションを持っていると仮定してください。そして、スレッドのうち1つだけが変更されたと考えてください。 `ChatThread` コンポーネントで `shouldComponentUpdate` を実行した際には、Reactは以下のように、他のスレッドのレンダリングステップをスキップできます。
-
-```javascript
-shouldComponentUpdate: function(nextProps, nextState) {
-  // TODO: 現在のチャットスレッドが以前のものと
-  // 異なっているかどうかをリターンする。
-}
-```
-
-つまり、要約すると、ReactはDOMのサブツリーを一致させる必要があるためにコストのかかるDOMの操作を実行するのを避けます。 `shouldComponentUpdate` を使用して、このプロセスを短縮することができます。そして、virtual DOMを比較して、更新すべきDOMだけを更新します。
-
-## shouldComponentUpdate の実行
-
-以下はコンポーネントのサブツリーです。1つ1つは `shouldComponentUpdate` が何をリターンするかとvirtual DOMが同じものであるかどうかを示しています。最終的には、円の色が、コンポーネントを一致させる必要があるかどうかを示しています。
-
-<figure><img src="/react/img/docs/should-component-update.png" /></figure>
-
-上記の例では、C2の上の `shouldComponentUpdate` が `false` を返しているので、Reactは新しいvirtual DOMを生成する必要はありません。そして、それゆえ、DOMを一致させる必要もありません。C4とC5についても、Reactが `shouldComponentUpdate` を実行する必要がないことに注意してください。
-
-C1とC3の `shouldComponentUpdate` は `true` を返すので、Reactは葉の部分まで降りてそれらのチェックを行います。C6が `true` を返すので、virtual DOMが同じものではなくなり、DOMを一致させる必要があります。最後の興味深いケースはC8です。このノードについては、Reactはvirtual DOMを計算する必要がありますが、古いものと同じであるため、DOMと一致させる必要はありません。
-
-ReactがDOMを変化させるのはC6だけであることに注意してください。これは避けられません。C8は、virtual DOMの比較から解放されています。C2のサブツリーとC7も同様です。`shouldComponentUpdate` から解放されているので、virtual DOMの比較を行う必要はありません。
-
-それでは、私たちはどのように `shouldComponentUpdate` を実行すべきでしょうか？ある文字列の値をただレンダリングするコンポーネントの場合について見てみましょう。
-
-```javascript
-React.createClass({
-  propTypes: {
-    value: React.PropTypes.string.isRequired
-  },
-
-  render: function() {
-    return <div>this.props.value</div>;
-  }
-});
-```
-
-以下のように簡単に `shouldComponentUpdate` を実行することができます。
-
-```javascript
-shouldComponentUpdate: function(nextProps, nextState) {
-  return this.props.value !== nextProps.value;
-}
-```
-
-これまでは順調でした。以上のような、単純なpropsやstateの構造を扱うことは簡単です。浅い同一性に基づいて実行したり、コンポーネントに組み込んだりもできます。実際、Reactはそのような実行のためのMixinを既に提供しています。[PureRenderMixin](/react/docs/pure-render-mixin-ja-JP.html)です。
-
-しかし、コンポーネントのpropsやstateが変更される可能性がある場合はどうでしょうか？propが `bar` のような文字列ではなく、コンポーネント受け取ったものであると考えてみると、 `{ foo: 'bar' }` のような文字列を含んだJavaScriptのオブジェクトになります。
-
-```javascript
-React.createClass({
-  propTypes: {
-    value: React.PropTypes.object.isRequired
-  },
-
-  render: function() {
-    return <div>this.props.value.foo</div>;
-  }
-});
-```
-
-今までに述べてきた `shouldComponentUpdate` の実行は常に想定した通りに動くとは限りません。
-
-```javascript
-// this.props.value が { foo: 'bar' } であると仮定
-// nextProps.value が { foo: 'bar' } であると仮定
-// しかし、この参照は this.props.value とは異なります。
-this.props.value !== nextProps.value; // true
-```
-
-問題は、 `shouldComponentUpdate` が、propが実際には変化していない場合にも `true` を返すことです。これを修正するために、以下のような代替の実行を行うことができます。
-
-```javascript
-shouldComponentUpdate: function(nextProps, nextState) {
-  return this.props.value.foo !== nextProps.value.foo;
-}
-```
-
-基本的には、厳密に変更を追跡することを明確にするために、深い比較を行うことになります。パフォーマンスの点では、このアプローチはとてもコストがかかります。これは、それぞれのモデルに対して間違った深い同一性のコードを書いているであろうときには、スケールしません。その最上部では、オブジェクトの参照を注意深く見ていなければ、動作しさえしません。以下のコンポーネントが親から使用されていると考えてください。
-
-```javascript
-React.createClass({
-  getInitialState: function() {
-    return { value: { foo: 'bar' } };
-  },
-
-  onClick: function() {
-    var value = this.state.value;
-    value.foo += 'bar'; // アンチパターン！
-    this.setState({ value: value });
-  },
-
-  render: function() {
-    return (
-      <div>
-        <InnerComponent value={this.state.value} />
-        <a onClick={this.onClick}>Click me</a>
-      </div>
-    );
-  }
-});
-```
-
-はじめに、内部のコンポーネントがレンダリングされます。それは、valueというプロパティとして `{ foo: 'bar' }` を保有します。ユーザがアンカーをクリックした際には、親のコンポーネントのstateが `{ value: { foo: 'barbar' } }` にアップデートされるでしょう。そして、新しいvalueのプロパティとして、 `{ foo: 'barbar' }` を受け取る、内部のコンポーネントの再レンダリングのプロセスのトリガーとなります。
-
-問題は、親と内部のコンポーネントが同じオブジェクトへの参照を共有していることです。オブジェクトが `onClick` 関数の2行目で変更された時には、内部のコンポーネントが保有しているプロパティが変更されるでしょう。そのため、再レンダリングのプロセスが始まった時と、 `shouldComponentUpdate` が呼び出された時には、 `this.props.value.foo` は `nextProps.value.foo` と同じものになるでしょう。そのため、実際は、 `this.props.value` は `nextProps.value` と同じオブジェクトを参照します。
-
-結果として、プロパティの変更と再レンダリングのプロセスを省略ができなかったので、UIは `'bar'` から `'barbar'` にアップデートされないでしょう。
-
-## 助けとなるImmutable-js
-
-[Immutable-js](https://github.com/facebook/immutable-js)はLee Byronによって作成されたJavaScriptのコレクションのライブラリです。Facebookが最近オープンソース化しました。これは、 *構造の共有* を通して、*不変の状態を保ち続ける* コレクションを提供します。以下のプロパティが何を意味するか見ていきましょう。
-
-* *Immutable*: 一度作成されたら、コレクションは変更できません。
-* *Persistent*: 新しいコレクションは以前のコレクションかsetのような変化によってのみ作成されます。元となるコレクションは新しいコレクションが作成された後も使用可能です。
-* *Structural Sharing*: 新しいコレクションは元のコレクションとなるべく同じ構造を持って作成されます。パフォーマンスが効率的で許容できるものであるように、コピーを少なくします。新しいコレクションが元のものと同じである場合は、多くの場合元のものがリターンされます。
-
-不変性によって、変更を追跡するコストが下がります。変更は常に新しいオブジェクトを生むので、オブジェクトの参照が変更されたかどうかを確認しさえすればよいのです。例えば、以下のような一般的なJavaScriptのコードにおいては、
-
-```javascript
-var x = { foo: "bar" };
-var y = x;
-y.foo = "baz";
-x === y; // true
-```
-
-`y` は編集されていますが、`x` と同じオブジェクトを参照しているので、それらの比較は `true` を返します。しかし、以下のコードはimmutable-jsを使用すると以下のように記述されます。
-
-```javascript
-var SomeRecord = Immutable.Record({ foo: null });
-var x = new SomeRecord({ foo: 'bar'  });
-var y = x.set('foo', 'baz');
-x === y; // false
-```
-
-このケースでは、 `x` を変更する時に新しい参照が返されているので、 `x` が変更されたことを安全に認識することができます。
-
-変更を追跡する他の方法は、セッタによるフラグセットを保持することでダーティーチェックを行うことです。このアプローチの問題は、追加のコードを多く書いた場合やクラスの編集をいくつか行った場合でもセッタの使用が強制されることです。代わりに、変化の直前にオブジェクトをディープコピーし、変更が有ろうと無かろうと、その特定のために深い比較を行うことができます。このアプローチの問題は、ディープコピーと深い比較の両方とも、コストの高い操作であることです。
-
-そのため、不変なデータ構造によって、オブジェクトの変更を追跡するためのコストの低く、冗長ではない方法が提供されます。私たちがすべきなのは `shouldComponentUpdate` を実行することだけです。それゆえ、immutable-jsに提供される抽象化を使用して、propsやstate属性を形作る場合は、 `PureRenderMixin` を使用して、パフォーマンスの向上を行うことができます。
-
-## Immutable-js と Flux
-
-[Flux](https://facebook.github.io/flux/)を使用している場合には、immutable-jsを使用して書き直すべきです。[API一覧](https://facebook.github.io/immutable-js/docs/#/)をご覧ください。
-
-不変のデータ構造を使用したスレッドの例を形作る、ある方法を見ていきましょう。はじめに、形作ろうとしているエンティティのそれぞれに `Record` を定義する必要が有ります。Record はあるフィールドのセットの値を保持している、ただの不変なコンテナです。
-
-```javascript
-var User = Immutable.Record({
-  id: undefined,
-  name: undefined,
-  email: undefined
-});
-
-var Message = Immutable.Record({
-  timestamp: new Date(),
-  sender: undefined,
-  text: ''
-});
-```
-
-`Record` 関数はオブジェクトが保有しているフィールドとデフォルトの値を定義するオブジェクトを受け取ります。
-
-メッセージの *ストア* は以下のように2つのリストを使用して users と messages を追跡し続けることができます。
-
-```javascript
-this.users = Immutable.List();
-this.messages = Immutable.List();
-```
-
-それぞれの *ペイロードの* 型を調査することはとても単純で、関数を実行するだけです。例えば、ストアが新しいメッセージを代表するペイロードを調べるときには、新しいレコードを作成し、それを以下のような messages のリストとして適用するだけです。
-
-```javascript
-this.messages = this.messages.push(new Message({
-  timestamp: payload.timestamp,
-  sender: payload.sender,
-  text: payload.text
-});
-```
-
-データ構造が不変であることで、push関数の結果を `this.messages` にアサインする必要があることに注意してください。
-
-Reactの側では、 immutable-js のデータ構造をコンポーネントの state を保持するために使用する場合は、 `PureRenderMixin` をコンポーネントにミックスし、再レンダリングのプロセスを短縮することもできます。
diff --git a/docs/docs/11-advanced-performance.ko-KR.md b/docs/docs/11-advanced-performance.ko-KR.md
deleted file mode 100644
index 413c1eb232fd..000000000000
--- a/docs/docs/11-advanced-performance.ko-KR.md
+++ /dev/null
@@ -1,206 +0,0 @@
----
-id: advanced-performance-ko-KR
-title: 성능 심화
-permalink: advanced-performance-ko-KR.html
-prev: perf-ko-KR.html
-next: context-ko-KR.html
----
-
-React를 도입하려 할 때 많은 사람이 묻는 첫 번째 질문은 React를 사용하지 않을 때처럼 애플리케이션이 빠르고 반응성도 좋을 것이냐는 것입니다. 모든 상태변화에 대해 컴포넌트의 하위 트리를 전부 다시 렌더링하는 아이디어에 대해 사람들은 이 프로세스가 성능에 부정적인 영향을 줄 것으로 생각하지만, React는 여러 가지 영리한 방법을 통해 UI를 업데이트하는데 필요한 비싼 DOM 조작을 최소화합니다.
-
-## DOM 조정 회피
-
-React는 브라우저에서 렌더된 DOM 하위 트리의 서술자 개념인 *가상의 DOM*을 사용합니다. 이 병렬적인 서술체는 React가 DOM 노드를 생성하거나 이미 존재하는 DOM 노드에 접근하는 것(JavaScript 객체를 조작하는 것보다 느리죠)을 피하게 해 줍니다. 컴포넌트의 props나 state가 변경되면 React는 새로운 가상의 DOM을 구성해 이전의 것과 비교해서 실제 DOM 업데이트가 필요한지 결정합니다. 가능한 적게 변화를 적용하기 위해, React는 둘이 다를 경우에만 DOM을 [조정](/react/docs/reconciliation-ko-KR.html)할 것입니다.
-
-이에 더해, React는 컴포넌트 생명주기 함수인 `shouldComponentUpdate`를 제공합니다. 이는 다시 렌더링하는 프로세스(가상 DOM 비교와 어쩌면 일어날 DOM 조정)가 일어나기 직전에 일어나며 개발자가 프로세스를 중단할 수 있게 합니다. 이 함수의 기본구현은 `true`를 반환해 React가 업데이트를 수행하도록 합니다.
-
-```javascript
-shouldComponentUpdate: function(nextProps, nextState) {
-  return true;
-}
-```
-
-React가 이 함수를 자주 호출한다는 것을 명심하십시오. 따라서 구현체는 빨라야 합니다.
-
-대화 스레드가 여럿 돌고 있는 메시지처리 애플리케이션을 생각해 봅시다. 오직 하나의 스레드만이 변경되었다고 가정해 보죠. `ChatThread`에 `shouldComponentUpdate`를 구현했다면 React는 다른 스레드의 렌더링 프로세스를 건너뛸 수 있습니다.
-
-```javascript
-shouldComponentUpdate: function(nextProps, nextState) {
-  // TODO: 현재의 대화 스레드가 이전의 것과 다른지 아닌지를 반환한다
-}
-```
-
-정리하자면, React는 사용자가 `shouldComponentUpdate`를 사용해 렌더링 프로세스를 중단하고 가상의 DOM과 비교해 업데이트 여부를 결정해서 DOM의 하위 트리를 조정하는 비싼 DOM 조작을 피하도록 합니다.
-
-## shouldComponentUpdate 실전
-
-다음은 컴포넌트의 하위 트리입니다. 각각은 `shouldComponentUpdate`의 반환값(SCU)과 가상의 DOM과의 동일성(vDOMEq)을 표시합니다. 마지막으로, 원의 색은 컴포넌트가 조정되었는지를 표시합니다.
-
-<figure><img src="/react/img/docs/should-component-update.png" /></figure>
-
-위의 예시에서, C2를 루트로 하는 하위 트리에 대해 `shouldComponentUpdate`가 `false`를 반환했기 때문에 React는 새로운 가상의 DOM을 만들 필요가 없습니다. 따라서 DOM을 조정할 필요도 없습니다. React가 C4와 C5에는 `shouldComponentUpdate`를 요청하지도 않은 것을 확인하세요.
-
-C1과 C3의 `shouldComponentUpdate`가 `true`를 반환했기 때문에 React는 하위 노드로 내려가 그들을 확인합니다. C6는 `true`를 반환했네요; 이는 가상의 DOM과 같지 않기 때문에 DOM의 조정이 일어났습니다. 마지막으로 흥미로운 사례는 C8입니다. React가 이 노드를 위해 가상의 DOM을 작동했지만, 노드가 이전의 것과 일치했기 때문에 DOM의 조정을 일어나지 않았습니다.
-
-React가 C6에만 DOM 변경을 수행한 것을 확인하세요. 이는 필연적이었습니다. C8의 경우는, 가상의 DOM과 비교를 해 제외되었고, C2의 하위 트리와 C7은 `shouldComponentUpdate` 단계에서 제외되어 가상의 DOM은 구동조차 되지 않았습니다.
-
-자 그럼, 어떻게 `shouldComponentUpdate`를 구현해야 할까요? 문자열 값을 렌더하는 컴포넌트를 생각해보죠.
-
-```javascript
-React.createClass({
-  propTypes: {
-    value: React.PropTypes.string.isRequired
-  },
-
-  render: function() {
-    return <div>{this.props.value}</div>;
-  }
-});
-```
-
-다음과 같이 간단히 `shouldComponentUpdate`를 구현해 볼 수 있습니다:
-
-```javascript
-shouldComponentUpdate: function(nextProps, nextState) {
-  return this.props.value !== nextProps.value;
-}
-```
-
-여기까지는 좋습니다. 간단한 props/state 구조를 다루기는 쉽습니다. 단순한 등식비교 구현을 일반화하고 이를 컴포넌트에 혼합할 수도 있습니다. 사실, React는 이미 그런 구현을 제공합니다: [PureRenderMixin](/react/docs/pure-render-mixin-ko-KR.html).
-
-하지만 만약 컴포넌트의 props나 state가 가변적인 데이터 구조로 되어 있다면 어떨까요? 컴포넌트의 prop으로 `'bar'`같은 문자열 대신에 `{ foo: 'bar' }`처럼 문자열을 포함한 JavaScript 객체를 전달받는다고 해봅시다.
-
-```javascript
-React.createClass({
-  propTypes: {
-    value: React.PropTypes.object.isRequired
-  },
-
-  render: function() {
-    return <div>{this.props.value.foo}</div>;
-  }
-});
-```
-
-전에 구현했던 `shouldComponentUpdate`는 언제나 예상대로 작동하지 않을 것입니다:
-
-```javascript
-// this.props.value가 { foo: 'bar' }라고 가정합니다
-// nextProps.value도 { foo: 'bar' }라고 가정하지만,
-// 이 참조는 this.props.value와 다른 것입니다
-this.props.value !== nextProps.value; // true
-```
-
-문제는 prop이 실제로 변경되지 않았을 때도 `shouldComponentUpdate`가 `true`를 반환할 거라는 겁니다. 이를 해결하기 위한 대안으로, 아래와 같이 구현해 볼 수 있습니다:
-
-```javascript
-shouldComponentUpdate: function(nextProps, nextState) {
-  return this.props.value.foo !== nextProps.value.foo;
-}
-```
-
-기본적으로, 우리는 변경을 정확히 추적하기 위해서 깊은 비교를 해야 했습니다. 이 방법은 성능 면에서 제법 비쌉니다. 각각의 모델마다 다른 깊은 등식 코드를 작성해야 하므로 확장이 힘들어 집니다. 심지어 객체 참조를 신중히 관리하지 않는다면 작동하지도 않을 수 있습니다. 컴포넌트가 부모에 의해 다뤄지는 경우를 살펴보죠:
-
-```javascript
-React.createClass({
-  getInitialState: function() {
-    return { value: { foo: 'bar' } };
-  },
-
-  onClick: function() {
-    var value = this.state.value;
-    value.foo += 'bar'; // 안티패턴 입니다!
-    this.setState({ value: value });
-  },
-
-  render: function() {
-    return (
-      <div>
-        <InnerComponent value={this.state.value} />
-        <a onClick={this.onClick}>클릭하세요</a>
-      </div>
-    );
-  }
-});
-```
-
-처음엔 내부 컴포넌트(`<InnerComponent />`)가 `{ foo: 'bar' }`를 value prop으로 가진 채 렌더될 것입니다. 사용자가 앵커(`<a>`)를 클릭한다면 부모 컴포넌트의 state는 `{ value: { foo: 'barbar' } }`로 업데이트되고, 내부 컴포넌트 또한 `{ foo: 'barbar' }`를 새로운 value prop으로 전달받아 다시 렌더링 되는 프로세스가 일어날 것입니다.
-
-이 문제는 부모와 내부 컴포넌트가 같은 객체에 대한 참조를 공유하기 때문에 발생합니다. `onClick` 함수의 두 번째 줄에서 객체에 대한 변경이 일어날 때, 내부 컴포넌트의 prop도 변경될 것입니다. 따라서 다시 렌더링 되는 프로세스가 시작될 때 `shouldComponentUpdate`가 호출되고 `this.props.value.foo`가 `nextProps.value.foo`와 같게 됩니다. 실제로 `this.props.value`는 `nextProps.value`와 같은 객체이기 때문입니다.
-
-그에따라 prop의 변경을 놓치게 되어 다시 렌더링하는 프로세스가 중단되고, UI는 `'bar'`에서 `'barbar'`로 업데이트되지 않습니다.
-
-## 구원자 Immutable-js
-
-[Immutable-js](https://github.com/facebook/immutable-js)는 Lee Byron이 만들고 Facebook이 오픈소스화 한 JavaScript 컬렉션 라이브러리입니다. 이는 *구조의 공유(structural sharing)*를 통해 *불변의 영속적인(immutable persistent)* 컬렉션을 제공합니다. 이러한 속성이 무엇을 의미하는지 살펴보죠:
-
-* *불변성(Immutable)*: 컬렉션이 한번 생성되면, 이 후 다른 시점에 변경될 수 없습니다.
-* *영속성(Persistent)*: 새로운 컬렉션이 이전의 컬렉션이나 셋(set) 같은 뮤테이션(mutation)에서 생성될 수 있습니다. 기존의 컬렉션은 새로운 컬렉션이 생성된 후에도 여전히 유효합니다.
-* *구조의 공유(Structural Sharing)*: 새로운 컬렉션은 가능한 한 원래의 컬렉션과 같은 구조를 사용해 생성됩니다. 공간 효율성과 적절한 성능을 위해 복사를 최소화합니다.
-
-불변성은 변경의 추적을 비용을 줄여줍니다; 변경은 항상 새로운 객체에만 발생하기 때문에 객체에 대한 참조가 변경될 때만 확인하면 됩니다. 예를 들어 일반적인 이 JavaScript 코드에서는:
-
-```javascript
-var x = { foo: "bar" };
-var y = x;
-y.foo = "baz";
-x === y; // true
-```
-
-`y`가 수정되더라도 여전히 같은 객체인 `x`를 참조하고 있기 때문에, 이 비교는 `true`를 반환합니다. 하지만 이 코드를 immutable-js를 사용해 다음과 같이 작성할 수 있습니다:
-
-```javascript
-var SomeRecord = Immutable.Record({ foo: null });
-var x = new SomeRecord({ foo: 'bar' });
-var y = x.set('foo', 'baz');
-x === y; // false
-```
-
-이 경우, `x`가 변경되면 새로운 참조가 반환되기 때문에, 우리는 안전하게 `x`가 변경되었을 것으로 추정할 수 있습니다.
-
-변경을 탐지할 수 있는 또 다른 방법은 세터(setter)에 의해 설정된 플래그를 더티 체킹(dirty checking)하는 것입니다. 이 방식의 문제는 당신이 세터를 사용할 뿐만 아니라 수많은 추가 코드를 작성하거나 어떻게든 클래스들을 인스트루먼트(instrument) 하도록 강요한다는 것입니다. 혹은 변경(mutations) 직전에 객체를 깊은 복사(deep copy) 한 뒤 깊은 비교(deep compare)를 수행해 변경 여부를 판단할 수 있습니다. 이 방식의 문제점은 deepCopy와 deepCompare 둘 다 비용이 많이 드는 연산이라는 것입니다.
-
-그래서 Immutable 자료구조는 `shouldComponentUpdate`의 구현에 필요한 객체의 변경사항을 추적할 수 있는 덜 자세하지만 저렴한 방법을 제공합니다. 그에 따라 immutable-js가 제공하는 추상화를 사용해 props와 state 어트리뷰트를 모델링한다면, `PureRenderMixin`을 사용해 성능을 향상할 수 있습니다.
-
-## Immutable-js와 Flux
-
-[Flux](https://facebook.github.io/flux/)를 사용한다면 immutable-js를 사용해 stores를 작성해야 합니다. [전체 API](https://facebook.github.io/immutable-js/docs/#/)를 살펴보세요.
-
-Immutable 자료구조를 이용해 스레드를 모델링하는 예제를 살펴봅시다. 먼저 모델링하려는 엔티티마다 `Record`를 정의해야 합니다. Record는 특정 필드들의 값을 유지하기 위한 불변의 컨테이너입니다:
-
-```javascript
-var User = Immutable.Record({
-  id: undefined,
-  name: undefined,
-  email: undefined
-});
-
-var Message = Immutable.Record({
-  timestamp: new Date(),
-  sender: undefined,
-  text: ''
-});
-```
-
-`Record` 함수는 필드별로 기본값이 선언된 객체에 대한 정의를 넘겨받습니다.
-
-메시지 store는 두 개의 List를 통해 users와 messages를 추적할 수 있습니다:
-
-```javascript
-this.users = Immutable.List();
-this.messages = Immutable.List();
-```
-
-각각의 *페이로드* 타입을 처리하는 기능을 구현하는 것은 꽤 간단합니다. 예를 들면, store가 새 메시지를 나타내는 페이로드를 확인할 때 레코드를 새로 생성하고 메시지 리스트에 추가할 수 있습니다.
-
-```javascript
-this.messages = this.messages.push(new Message({
-  timestamp: payload.timestamp,
-  sender: payload.sender,
-  text: payload.text
-});
-```
-
-자료구조가 불변이기 때문에 push 함수의 결과를 `this.messages`에 할당할 필요가 있으니 주의하세요.
-
-React 측에서는, 컴포넌트의 state를 보존하기 위해 immutable-js 자료구조를 사용한다면, 모든 컴포넌트에 `PureRenderMixin`을 혼합해 다시 렌더링하는 프로세스를 중단할 수 있습니다.
diff --git a/docs/docs/11-advanced-performance.md b/docs/docs/11-advanced-performance.md
deleted file mode 100644
index 0d15756564c8..000000000000
--- a/docs/docs/11-advanced-performance.md
+++ /dev/null
@@ -1,208 +0,0 @@
----
-id: advanced-performance
-title: Advanced Performance
-permalink: advanced-performance.html
-prev: shallow-compare.html
-next: context.html
----
-
-One of the first questions people ask when considering React for a project is whether their application will be as fast and responsive as an equivalent non-React version. The idea of re-rendering an entire subtree of components in response to every state change makes people wonder whether this process negatively impacts performance. React uses several clever techniques to minimize the number of costly DOM operations required to update the UI.
-
-## Avoiding reconciling the DOM
-
-React makes use of a *virtual DOM*, which is a descriptor of a DOM subtree rendered in the browser. This parallel representation allows React to avoid creating DOM nodes and accessing existing ones, which is slower than operations on JavaScript objects. When a component's props or state change, React decides whether an actual DOM update is necessary by constructing a new virtual DOM and comparing it to the old one. Only in the case they are not equal, will React [reconcile](/react/docs/reconciliation.html) the DOM, applying as few mutations as possible.
-
-On top of this, React provides a component lifecycle function, `shouldComponentUpdate`, which is triggered before the re-rendering process starts (virtual DOM comparison and possible eventual DOM reconciliation), giving the developer the ability to short circuit this process. The default implementation of this function returns `true`, leaving React to perform the update:
-
-```javascript
-shouldComponentUpdate: function(nextProps, nextState) {
-  return true;
-}
-```
-
-Keep in mind that React will invoke this function pretty often, so the implementation has to be fast.
-
-Say you have a messaging application with several chat threads. Suppose only one of the threads has changed. If we implement `shouldComponentUpdate` on the `ChatThread` component, React can skip the rendering step for the other threads:
-
-```javascript
-shouldComponentUpdate: function(nextProps, nextState) {
-  // TODO: return whether or not current chat thread is
-  // different to former one.
-}
-```
-
-So, in summary, React avoids carrying out expensive DOM operations required to reconcile subtrees of the DOM by allowing the user to short circuit the process using `shouldComponentUpdate`, and, for those which should update, by comparing virtual DOMs.
-
-## shouldComponentUpdate in action
-
-Here's a subtree of components. For each one is indicated what `shouldComponentUpdate` returned and whether or not the virtual DOMs were equivalent. Finally, the circle's color indicates whether the component had to be reconciled or not.
-
-<figure><img src="/react/img/docs/should-component-update.png" /></figure>
-
-In the example above, since `shouldComponentUpdate` returned `false` for the subtree rooted at C2, React had no need to generate the new virtual DOM, and therefore, it neither needed to reconcile the DOM. Note that React didn't even have to invoke `shouldComponentUpdate` on C4 and C5.
-
-For C1 and C3 `shouldComponentUpdate` returned `true`, so React had to go down to the leaves and check them. For C6 it returned `true`; since the virtual DOMs weren't equivalent it had to reconcile the DOM.
-The last interesting case is C8. For this node React had to compute the virtual DOM, but since it was equal to the old one, it didn't have to reconcile it's DOM.
-
-Note that React only had to do DOM mutations for C6, which was inevitable. For C8, it bailed out by comparing the virtual DOMs, and for C2's subtree and C7, it didn't even have to compute the virtual DOM as we bailed out on `shouldComponentUpdate`.
-
-So, how should we implement `shouldComponentUpdate`? Say that you have a component that just renders a string value:
-
-```javascript
-React.createClass({
-  propTypes: {
-    value: React.PropTypes.string.isRequired
-  },
-
-  render: function() {
-    return <div>{this.props.value}</div>;
-  }
-});
-```
-
-We could easily implement `shouldComponentUpdate` as follows:
-
-```javascript
-shouldComponentUpdate: function(nextProps, nextState) {
-  return this.props.value !== nextProps.value;
-}
-```
-
-So far so good, dealing with such simple props/state structures is easy. We could even generalize an implementation based on shallow equality and mix it into components. In fact, React already provides such implementation: [PureRenderMixin](/react/docs/pure-render-mixin.html).
-
-But what if your components' props or state are mutable data structures? Say the prop the component receives, instead of being a string like `'bar'`, is a JavaScript object that contains a string such as, `{ foo: 'bar' }`:
-
-```javascript
-React.createClass({
-  propTypes: {
-    value: React.PropTypes.object.isRequired
-  },
-
-  render: function() {
-    return <div>{this.props.value.foo}</div>;
-  }
-});
-```
-
-The implementation of `shouldComponentUpdate` we had before wouldn't always work as expected:
-
-```javascript
-// assume this.props.value is { foo: 'bar' }
-// assume nextProps.value is { foo: 'bar' },
-// but this reference is different to this.props.value
-this.props.value !== nextProps.value; // true
-```
-
-The problem is `shouldComponentUpdate` will return `true` when the prop actually didn't change. To fix this, we could come up with this alternative implementation:
-
-```javascript
-shouldComponentUpdate: function(nextProps, nextState) {
-  return this.props.value.foo !== nextProps.value.foo;
-}
-```
-
-Basically, we ended up doing a deep comparison to make sure we properly track changes. In terms of performance, this approach is pretty expensive. It doesn't scale as we would have to write different deep equality code for each model. On top of that, it might not even work if we don't carefully manage object references. Say this component is used by a parent:
-
-```javascript
-React.createClass({
-  getInitialState: function() {
-    return { value: { foo: 'bar' } };
-  },
-
-  onClick: function() {
-    var value = this.state.value;
-    value.foo += 'bar'; // ANTI-PATTERN!
-    this.setState({ value: value });
-  },
-
-  render: function() {
-    return (
-      <div>
-        <InnerComponent value={this.state.value} />
-        <a onClick={this.onClick}>Click me</a>
-      </div>
-    );
-  }
-});
-```
-
-The first time the inner component gets rendered, it will have `{ foo: 'bar' }` as the value prop. If the user clicks on the anchor, the parent component's state will get updated to `{ value: { foo: 'barbar' } }`, triggering the re-rendering process of the inner component, which will receive `{ foo: 'barbar' }` as the new value for the prop.
-
-The problem is that since the parent and inner components share a reference to the same object, when the object gets mutated on line 2 of the `onClick` function, the prop the inner component had will change. So, when the re-rendering process starts, and `shouldComponentUpdate` gets invoked, `this.props.value.foo` will be equal to `nextProps.value.foo`, because in fact, `this.props.value` references the same object as `nextProps.value`.
-
-Consequently, since we'll miss the change on the prop and short circuit the re-rendering process, the UI won't get updated from `'bar'` to `'barbar'`.
-
-## Immutable-js to the rescue
-
-[Immutable-js](https://github.com/facebook/immutable-js) is a JavaScript collections library written by Lee Byron, which Facebook recently open-sourced. It provides *immutable persistent* collections via *structural sharing*. Let's see what these properties mean:
-
-* *Immutable*: once created, a collection cannot be altered at another point in time.
-* *Persistent*: new collections can be created from a previous collection and a mutation such as set. The original collection is still valid after the new collection is created.
-* *Structural Sharing*: new collections are created using as much of the same structure as the original collection as possible, reducing copying to a minimum to achieve space efficiency and acceptable performance. If the new collection is equal to the original, the original is often returned.
-
-Immutability makes tracking changes cheap; a change will always result in a new object so we only need to check if the reference to the object has changed. For example, in this regular JavaScript code:
-
-```javascript
-var x = { foo: "bar" };
-var y = x;
-y.foo = "baz";
-x === y; // true
-```
-
-Although `y` was edited, since it's a reference to the same object as `x`, this comparison returns `true`. However, this code could be written using immutable-js as follows:
-
-```javascript
-var SomeRecord = Immutable.Record({ foo: null });
-var x = new SomeRecord({ foo: 'bar'  });
-var y = x.set('foo', 'baz');
-x === y; // false
-```
-
-In this case, since a new reference is returned when mutating `x`, we can safely assume that `x` has changed.
-
-Another possible way to track changes could be doing dirty checking by having a flag set by setters. A problem with this approach is that it forces you to use setters and, either write a lot of additional code, or somehow instrument your classes. Alternatively, you could deep copy the object just before the mutations and deep compare to determine whether there was a change or not. A problem with this approach is both deepCopy and deepCompare are expensive operations.
-
-So, Immutable data structures provides you a cheap and less verbose way to track changes on objects, which is all we need to implement `shouldComponentUpdate`. Therefore, if we model props and state attributes using the abstractions provided by immutable-js we'll be able to use `PureRenderMixin` and get a nice boost in perf.
-
-## Immutable-js and Flux
-
-If you're using [Flux](https://facebook.github.io/flux/), you should start writing your stores using immutable-js. Take a look at the [full API](https://facebook.github.io/immutable-js/docs/#/).
-
-Let's see one possible way to model the thread example using Immutable data structures. First, we need to define a `Record` for each of the entities we're trying to model. Records are just immutable containers that hold values for a specific set of fields:
-
-```javascript
-var User = Immutable.Record({
-  id: undefined,
-  name: undefined,
-  email: undefined
-});
-
-var Message = Immutable.Record({
-  timestamp: new Date(),
-  sender: undefined,
-  text: ''
-});
-```
-
-The `Record` function receives an object that defines the fields the object has and its default values.
-
-The messages *store* could keep track of the users and messages using two lists:
-
-```javascript
-this.users = Immutable.List();
-this.messages = Immutable.List();
-```
-
-It should be pretty straightforward to implement functions to process each *payload* type. For instance, when the store sees a payload representing a new message,  we can just create a new record and append it to the messages list:
-
-```javascript
-this.messages = this.messages.push(new Message({
-  timestamp: payload.timestamp,
-  sender: payload.sender,
-  text: payload.text
-});
-```
-
-Note that since the data structures are immutable, we need to assign the result of the push function to `this.messages`.
-
-On the React side, if we also use immutable-js data structures to hold the components' state, we could mix `PureRenderMixin` into all our components and short circuit the re-rendering process.
diff --git a/docs/docs/12-context.ko-KR.md b/docs/docs/12-context.ko-KR.md
deleted file mode 100644
index a15d5397d82f..000000000000
--- a/docs/docs/12-context.ko-KR.md
+++ /dev/null
@@ -1,174 +0,0 @@
----
-id: context
-title: 컨텍스트
-permalink: context-ko-KR.html
-prev: advanced-performance-ko-KR.html
----
-
-React의 가장 큰 장점 중 하나는 React 컴포넌트를 통해 데이터의 흐름을 추적하기 쉽다는 것입니다. 컴포넌트를 보면 각각의 프로퍼티가 어떻게 전달되었는지 쉽게 파악할 수 있습니다. 
-
-때때로 컴포넌트 트리를 통해 props을 전단하는 대신 수동으로 모든 레벨에서 데이터를 전달하고 싶은 경우가 있습니다. React의 "컨텍스트" 기능은 이를 가능하게 해줍니다.
-
-
-> 주의:
->
-> 컨텍스트는 실험적인 고급 기능입니다. 향후 릴리즈에서 API가 변경될 수 있습니다.
->
-> 대부분은 애플리켄이션은 컨텍스트가 필요하지 않을겁니다. 특히 React로 시작한 경우에는 컨텍스트를 사용하지 않을겁니다. 컨텍스트의 사용은 데이터 흐름을 명확하지 않게 만들기 때문에 코드를 이해하기 어려워 집니다. 이는 마치 앱에서 전역 변수를 state로 전달하는 경우와 유사합니다.
->
-> **만약 컨텍스트를 사용해야 하는 경우에도, 가능한 아껴 사용하세요.**
->
-> 구축하는것이 애플리케이션이든 라이브러리든간에, 가능한 컨텍스트의 사용은 작은 영역으로 격리하고 직접적으로 컨텍스트 API를 사용하는 것을 피하세요. 그렇게 하면 API가 변경 되더라도 쉽게 업데이트 할 수 있습니다. 
-
-## 트리를 통해 정보를 자동으로 전달하기
-
-아래와 같은 구조가 있다고 가정해 봅시다:
-
-```javascript
-var Button = React.createClass({
-  render: function() {
-    return (
-      <button style={{'{{'}}background: this.props.color}}>
-        {this.props.children}
-      </button>
-    );
-  }
-});
-
-var Message = React.createClass({
-  render: function() {
-    return (
-      <div>
-        {this.props.text} <Button color={this.props.color}>삭제</Button>
-      </div>
-    );
-  }
-});
-
-var MessageList = React.createClass({
-  render: function() {
-    var color = "purple";
-    var children = this.props.messages.map(function(message) {
-      return <Message text={message.text} color={color} />;
-    });
-    return <div>{children}</div>;
-  }
-});
-```
-
-이 예제에서, 우리는 스타일을 주기 위해 수동으로 적절하게 `Button`과 `Messages` 컴포넌트에 `color` 프로퍼티를 엮어서 전달했습니다. 테마는 서브트리가 정보 조각의 일부(여기선 color)에 접근하기 원하는 좋은 예제입니다. 컨텍스트를 사용하면 우리는 이를 자동으로 트리로 전달할 수 있습니다:
-
-```javascript{2-4,7,18,25-30,33}
-var Button = React.createClass({
-  contextTypes: {
-    color: React.PropTypes.string
-  },
-  render: function() {
-    return (
-      <button style={{'{{'}}background: this.context.color}}>
-        {this.props.children}
-      </button>
-    );
-  }
-});
-
-var Message = React.createClass({
-  render: function() {
-    return (
-      <div>
-        {this.props.text} <Button>Delete</Button>
-      </div>
-    );
-  }
-});
-
-var MessageList = React.createClass({
-  childContextTypes: {
-    color: React.PropTypes.string
-  },
-  getChildContext: function() {
-    return {color: "purple"};
-  },
-  render: function() {
-    var children = this.props.messages.map(function(message) {
-      return <Message text={message.text} />;
-    });
-    return <div>{children}</div>;
-  }
-});
-```
-
-`childContextTypes`와 `getChildContext`를 `MessageList`(context provider)에 추가함으로써, React는 정보를 자동으로 아래로 전달하며 서브트리내의 어떤 컴포넌트든 (여기선 `Button`) `contextTypes`를 정의함으로써 이에 접근할 수 있습니다.
-
-`contextTypes`가 정의되지 않은 경우, `this.context`는 빈 오브젝트가 됩니다.
-
-## 부모-자식 커플링
-
-컨텍스트는 다음과 같은 API를 구성할 수 있게 해줍니다:
-
-```javascript
-<Menu>
-  <MenuItem>가지</MenuItem>
-  <MenuItem>땅콩호박</MenuItem>
-  <MenuItem>클레멘타인</MenuItem>
-</Menu>
-```
-
-`Menu` 컴포넌트에서 관련 정보를 전달함으로써 각각의 `MenuItem`가 부모인 `Menu` 컴포넌트와 통신할 수 있습니다.
-
-**이 API를 이용해 컴포넌트를 구성하기 전에, 깔끔한 대안이 있는지 먼저 고려해 보세요.** 다음과 같이 간단히 아이템을 배열로 넘겨 보겠습니다:
-
-```javascript
-<Menu items={['가지', '땅콩호박', '클레멘타인']} />
-```
-
-원한다면 전체 React 컴포넌트를 프로퍼티로 전달할 수도 있습니다. 
-
-## Referencing context in lifecycle methods
-
-If `contextTypes` is defined within a component, the following lifecycle methods will receive an additional parameter, the `context` object:
-
-```javascript
-void componentWillReceiveProps(
-  object nextProps, object nextContext
-)
-
-boolean shouldComponentUpdate(
-  object nextProps, object nextState, object nextContext
-)
-
-void componentWillUpdate(
-  object nextProps, object nextState, object nextContext
-)
-
-void componentDidUpdate(
-  object prevProps, object prevState, object prevContext
-)
-```
-
-## Referencing context in stateless functional components
-
-Stateless functional components are also able to reference `context` if `contextTypes` is defined as a property of the function. The following code shows the `Button` component above written as a stateless functional component.
-
-```javascript
-function Button(props, context) {
-  return (
-    <button style={{'{{'}}background: context.color}}>
-      {props.children}
-    </button>
-  );
-}
-Button.contextTypes = {color: React.PropTypes.string};
-```
-
-## 컨텍스트를 사용하지 말아야 하는 경우
-
-대부분의 경우, 깔끔한 코드를 위해 전역 변수를 피하는 것과 마찬가지로 컨텍스트의 사용을 피해야 합니다. 특히 "타이핑을 줄이거나" 명시적인 프로퍼티 전달 대신 이를 사용하려는 경우 다시 한번 생각해 보세요.
-
-컨텍스트의 가장 적절한 사용 사례는 로그인한 유저, 언어 설정, 테마 정보 등을 암시적으로 전달하는 것입니다. 컨텍스트를 사용함으로써 이런 정보들을 전역으로 다루는 대신 단일 React 서브트리 내에서 다룰 수 있습니다. 
-
-모델 데이터를 컴포넌트로 전달하는데 컨텍스트를 사용하지 마세요. 트리를 통해 명시적으로 데이터를 엮어 전달하는 것이 훨씬 이해하기 쉽습니다. 컨텍스트는 렌더되는 위치에 따라 다르게 작동하기 때문에 컴포넌트를 더욱 연결되고(coupled) 재사용성이 떨어지게 만듭니다. 
-
-## 알려진 한계점
-
-컴포넌트에 의해 제공되는 컨텍스트의 값이 변경될 때, 중간 부모가 `shouldComponentUpdate`에서`false`을 반환한다면 그 값을 사용하는 자손은 업데이트되지 않습니다. 자세한 내용은 [#2517](https://github.com/facebook/react/issues/2517) 이슈를 확인하세요.
diff --git a/docs/docs/12-context.md b/docs/docs/12-context.md
deleted file mode 100644
index d85d7c2fd695..000000000000
--- a/docs/docs/12-context.md
+++ /dev/null
@@ -1,205 +0,0 @@
----
-id: context
-title: Context
-permalink: context.html
-prev: advanced-performance.html
----
-
-One of React's biggest strengths is that it's easy to track the flow of data through your React components. When you look at a component, you can easily see exactly which props are being passed in which makes your apps easy to reason about.
-
-Occasionally, you want to pass data through the component tree without having to pass the props down manually at every level. React's "context" feature lets you do this.
-
-> Note:
->
-> Context is an advanced and experimental feature. The API is likely to change in future releases.
->
-> Most applications will never need to use context. Especially if you are just getting started with React, you likely do not want to use context. Using context will make your code harder to understand because it makes the data flow less clear. It is similar to using global variables to pass state through your application.
->
-> **If you have to use context, use it sparingly.**
->
-> Regardless of whether you're building an application or a library, try to isolate your use of context to a small area and avoid using the context API directly when possible so that it's easier to upgrade when the API changes.
-
-## Passing info automatically through a tree
-
-Suppose you have a structure like:
-
-```javascript
-var Button = React.createClass({
-  render: function() {
-    return (
-      <button style={{'{{'}}background: this.props.color}}>
-        {this.props.children}
-      </button>
-    );
-  }
-});
-
-var Message = React.createClass({
-  render: function() {
-    return (
-      <div>
-        {this.props.text} <Button color={this.props.color}>Delete</Button>
-      </div>
-    );
-  }
-});
-
-var MessageList = React.createClass({
-  render: function() {
-    var color = "purple";
-    var children = this.props.messages.map(function(message) {
-      return <Message text={message.text} color={color} />;
-    });
-    return <div>{children}</div>;
-  }
-});
-```
-
-In this example, we manually thread through a `color` prop in order to style the `Button` and `Message` components appropriately. Theming is a good example of when you might want an entire subtree to have access to some piece of information (a color). Using context, we can pass this through the tree automatically:
-
-```javascript{2-4,7,18,25-30,33}
-var Button = React.createClass({
-  contextTypes: {
-    color: React.PropTypes.string
-  },
-  render: function() {
-    return (
-      <button style={{'{{'}}background: this.context.color}}>
-        {this.props.children}
-      </button>
-    );
-  }
-});
-
-var Message = React.createClass({
-  render: function() {
-    return (
-      <div>
-        {this.props.text} <Button>Delete</Button>
-      </div>
-    );
-  }
-});
-
-var MessageList = React.createClass({
-  childContextTypes: {
-    color: React.PropTypes.string
-  },
-  getChildContext: function() {
-    return {color: "purple"};
-  },
-  render: function() {
-    var children = this.props.messages.map(function(message) {
-      return <Message text={message.text} />;
-    });
-    return <div>{children}</div>;
-  }
-});
-```
-
-By adding `childContextTypes` and `getChildContext` to `MessageList` (the context provider), React passes the information down automatically and any component in the subtree (in this case, `Button`) can access it by defining `contextTypes`.
-
-If `contextTypes` is not defined, then `this.context` will be an empty object.
-
-## Parent-child coupling
-
-Context can also let you build an API such as:
-
-```javascript
-<Menu>
-  <MenuItem>aubergine</MenuItem>
-  <MenuItem>butternut squash</MenuItem>
-  <MenuItem>clementine</MenuItem>
-</Menu>
-```
-
-By passing down the relevant info in the `Menu` component, each `MenuItem` can communicate back to the containing `Menu` component.
-
-**Before you build components with this API, consider if there are cleaner alternatives.** We're fond of simply passing the items as an array in cases like this:
-
-```javascript
-<Menu items={['aubergine', 'butternut squash', 'clementine']} />
-```
-
-Recall that you can also pass entire React components in props if you'd like to.
-
-## Referencing context in lifecycle methods
-
-If `contextTypes` is defined within a component, the following lifecycle methods will receive an additional parameter, the `context` object:
-
-```javascript
-void componentWillReceiveProps(
-  object nextProps, object nextContext
-)
-
-boolean shouldComponentUpdate(
-  object nextProps, object nextState, object nextContext
-)
-
-void componentWillUpdate(
-  object nextProps, object nextState, object nextContext
-)
-
-void componentDidUpdate(
-  object prevProps, object prevState, object prevContext
-)
-```
-
-## Referencing context in stateless functional components
-
-Stateless functional components are also able to reference `context` if `contextTypes` is defined as a property of the function. The following code shows the `Button` component above written as a stateless functional component.
-
-```javascript
-function Button(props, context) {
-  return (
-    <button style={{'{{'}}background: context.color}}>
-      {props.children}
-    </button>
-  );
-}
-Button.contextTypes = {color: React.PropTypes.string};
-```
-
-## Updating context
-
-The `getChildContext` function will be called when the state or props changes. In order to update data in the context, trigger a local state update with `this.setState`. This will trigger a new context and changes will be received by the children.
-
-```javascript
-var MediaQuery = React.createClass({
-  getInitialState: function(){
-    return {type:'desktop'};
-  },
-  childContextTypes: {
-    type: React.PropTypes.string
-  },
-  getChildContext: function() {
-    return {type: this.state.type};
-  },
-  componentDidMount: function(){
-    var checkMediaQuery = function(){
-      var type = window.matchMedia("(min-width: 1025px)").matches ? 'desktop' : 'mobile';
-      if (type !== this.state.type){
-        this.setState({type:type}); 
-      }
-    };
-    
-    window.addEventListener('resize', checkMediaQuery);
-    checkMediaQuery();
-  },
-  render: function(){
-    return this.props.children;
-  }
-});
-```
-
-## When not to use context
-
-Just as global variables are best avoided when writing clear code, you should avoid using context in most cases. In particular, think twice before using it to "save typing" and using it instead of passing explicit props.
-
-The best use cases for context are for implicitly passing down the logged-in user, the current language, or theme information. All of these might otherwise be true globals, but context lets you scope them to a single React subtree.
-
-Do not use context to pass your model data through components. Threading your data through the tree explicitly is much easier to understand. Using context makes your components more coupled and less reusable, because they behave differently depending on where they're rendered.
-
-## Known limitations
-
-If a context value provided by a component changes, descendants that use that value won't update if an intermediate parent returns `false` from `shouldComponentUpdate`. See issue [#2517](https://github.com/facebook/react/issues/2517) for more details.
diff --git a/docs/docs/12-context.zh-CN.md b/docs/docs/12-context.zh-CN.md
deleted file mode 100644
index 601c8b1b12d7..000000000000
--- a/docs/docs/12-context.zh-CN.md
+++ /dev/null
@@ -1,205 +0,0 @@
----
-id: context-zh-CN
-title: Context
-permalink: context-zh-CN.html
-prev: advanced-performance-zh-CN.html
----
-
-React最大的优势之一是很容易从你的React组件里跟踪数据流动。当你看着一个组件，你可以很容易准确看出哪个props被传入，这让你的APP很容易推断。
-
-偶尔，你想通过组件树传递数据，而不在每一级上手工下传prop，React的 "context" 让你做到这点。
-
-＞　注意：
-＞　
-＞　Context是一个先进的实验性特性．这个 API 很可能在未来版本变化.
->
-> 大多数应用将不会需要用到 context. 尤其是如果你刚开始用React,你很可能不会想用 context.使用 context 将会使你的代码很难理解因为它让数据流不清晰.它类似于在你的应用里使用全局变量传递state.
->
-> **如果你必须使用 context ,保守的使用它**
->
-> 不论你正在创建一个应用或者是库,试着分离你对 context 的使用到一个小区域,并尽可能避免直接使用 context API,以便在API变动时容易升级.
-
-## 从树里自动传递info
-
-假设你有一个这样的结构:
-
-```javascript
-var Button = React.createClass({
-  render: function() {
-    return (
-      <button style={{'{{'}}background: this.props.color}}>
-        {this.props.children}
-      </button>
-    );
-  }
-});
-
-var Message = React.createClass({
-  render: function() {
-    return (
-      <div>
-        {this.props.text} <Button color={this.props.color}>Delete</Button>
-      </div>
-    );
-  }
-});
-
-var MessageList = React.createClass({
-  render: function() {
-    var color = "purple";
-    var children = this.props.messages.map(function(message) {
-      return <Message text={message.text} color={color} />;
-    });
-    return <div>{children}</div>;
-  }
-});
-```
-
-在这里例子里,我们手工穿透一个 `color` prop 以便于恰当格式化 `Button` 和 `Message` 组件.主题是一个很好的例子,当你可能想整个子树都可以访问一部分信息时(比如color). 使用 context 我们可以自动传过这个树:
-
-```javascript{2-4,7,18,25-30,33}
-var Button = React.createClass({
-  contextTypes: {
-    color: React.PropTypes.string
-  },
-  render: function() {
-    return (
-      <button style={{'{{'}}background: this.context.color}}>
-        {this.props.children}
-      </button>
-    );
-  }
-});
-
-var Message = React.createClass({
-  render: function() {
-    return (
-      <div>
-        {this.props.text} <Button>Delete</Button>
-      </div>
-    );
-  }
-});
-
-var MessageList = React.createClass({
-  childContextTypes: {
-    color: React.PropTypes.string
-  },
-  getChildContext: function() {
-    return {color: "purple"};
-  },
-  render: function() {
-    var children = this.props.messages.map(function(message) {
-      return <Message text={message.text} />;
-    });
-    return <div>{children}</div>;
-  }
-});
-```
-
-通过添加 `childContextTypes` 和 `getChildContext` 到 `MessageList` ( context 提供),React下传信息到子树中的任何组件(在这个例子中, `Button`可以由定义 `contextTypes`来访问它).
-
-如果 `contextTypes` 没有定义,那么 `this.context` 将是一个空对象.
-
-## 父子耦合
-
-Context 同样可以使你构建这样的 APT:
-
-```javascript
-<Menu>
-  <MenuItem>aubergine</MenuItem>
-  <MenuItem>butternut squash</MenuItem>
-  <MenuItem>clementine</MenuItem>
-</Menu>
-```
-
-通过在 `Menu` 组件下传相关的信息,每个 `MenuItem` 可以与包含他们的 `Menu` 组件沟通.
-
-**在你用这个API构建组件以前,考虑一下是否有清晰的替代方案** 我们 喜欢像这样简单的用数组传递items:
-
-```javascript
-<Menu items={['aubergine', 'butternut squash', 'clementine']} />
-```
-
-记住你同样可以在props里传递整个React组件,如果你想.
-
-## 在生命周期方法里引用 context
-
-如果 `contextTypes` 在一个组件中定义,接下来的生命周期方法会收到一个额外的参数, `context` 对象:
-
-```javascript
-void componentWillReceiveProps(
-  object nextProps, object nextContext
-)
-
-boolean shouldComponentUpdate(
-  object nextProps, object nextState, object nextContext
-)
-
-void componentWillUpdate(
-  object nextProps, object nextState, object nextContext
-)
-
-void componentDidUpdate(
-  object prevProps, object prevState, object prevContext
-)
-```
-
-## 在无状态函数组件里引用 context
-
-无状态函数同样能够引用 `context` 如果 `contextTypes` 被定义为函数的属性.下面的代码展示了被写为无状态函数组件的 `Button` 组件.
-
-```javascript
-function Button(props, context) {
-  return (
-    <button style={{'{{'}}background: context.color}}>
-      {props.children}
-    </button>
-  );
-}
-Button.contextTypes = {color: React.PropTypes.string};
-```
-
-## Updating context
-
-当 state 或者 props 变化时 `getChildContext` 函数会被调用。为了更新context里的数据，用 `this.setState` 触发一个本地的state更新。这将会触发一个新的 context 并且子级将收到变化。
-
-```javascript
-var MediaQuery = React.createClass({
-  getInitialState: function(){
-    return {type:'desktop'};
-  },
-  childContextTypes: {
-    type: React.PropTypes.string
-  },
-  getChildContext: function() {
-    return {type: this.state.type};
-  },
-  componentDidMount: function(){
-    var checkMediaQuery = function(){
-      var type = window.matchMedia("(min-width: 1025px)").matches ? 'desktop' : 'mobile';
-      if (type !== this.state.type){
-        this.setState({type:type}); 
-      }
-    };
-    
-    window.addEventListener('resize', checkMediaQuery);
-    checkMediaQuery();
-  },
-  render: function(){
-    return this.props.children;
-  }
-});
-```
-
-## 什么时候不用 context
-
-正像全局变量是在写清晰代码时最好要避免的,你应该在大多数情况下避免使用context. 特别是,在用它来"节省输入"和代替显示传入props时要三思.
-
-context最好的使用场景是隐式的传入登录的用户,当前的语言,或者主题信息.要不然所有这些可能就是全局变量,但是context让你限定他们到一个单独的React树里.
-
-不要用context在组件里传递你的模型数据.通过树显示的传递你的数据更容易理解.使用context使你的组件更耦合和不可复用,因为  依赖于他们在哪里渲染,他们会表现不同的行为.
-
-## 已知的限制
-
-如果一个由组件提供的context值变动,使用那个值的子级不会更新,如果一个直接的父级从 `shouldComponentUpdate` 返回 `false` .详见 issue [#2517](https://github.com/facebook/react/issues/2517) . 
diff --git a/docs/docs/addons-animation.md b/docs/docs/addons-animation.md
new file mode 100644
index 000000000000..ebf1b27a8a03
--- /dev/null
+++ b/docs/docs/addons-animation.md
@@ -0,0 +1,349 @@
+---
+id: animation
+title: Animation Add-Ons
+permalink: docs/animation.html
+layout: docs
+category: Add-Ons
+redirect_from:
+  - "docs/animation-ja-JP.html"
+  - "docs/animation-ko-KR.html"
+  - "docs/animation-zh-CN.html"
+---
+
+> Note:
+>
+> `ReactTransitionGroup` and `ReactCSSTransitionGroup` have been moved to the [`react-transition-group`](https://github.com/reactjs/react-transition-group/tree/v1-stable) package that is maintained by the community. Its 1.x branch is completely API-compatible with the existing addons. Please file bugs and feature requests in the [new repository](https://github.com/reactjs/react-transition-group/tree/v1-stable).
+
+The [`ReactTransitionGroup`](#low-level-api-reacttransitiongroup) add-on component is a low-level API for animation, and [`ReactCSSTransitionGroup`](#high-level-api-reactcsstransitiongroup) is an add-on component for easily implementing basic CSS animations and transitions.
+
+## High-level API: ReactCSSTransitionGroup
+
+`ReactCSSTransitionGroup` is a high-level API based on [`ReactTransitionGroup`](#low-level-api-reacttransitiongroup) and is an easy way to perform CSS transitions and animations when a React component enters or leaves the DOM. It's inspired by the excellent [ng-animate](https://docs.angularjs.org/api/ngAnimate) library.
+
+**Importing**
+
+```javascript
+import ReactCSSTransitionGroup from 'react-addons-css-transition-group'; // ES6
+var ReactCSSTransitionGroup = require('react-addons-css-transition-group'); // ES5 with npm
+```
+
+```javascript{31-36}
+class TodoList extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {items: ['hello', 'world', 'click', 'me']};
+    this.handleAdd = this.handleAdd.bind(this);
+  }
+
+  handleAdd() {
+    const newItems = this.state.items.concat([
+      prompt('Enter some text')
+    ]);
+    this.setState({items: newItems});
+  }
+
+  handleRemove(i) {
+    let newItems = this.state.items.slice();
+    newItems.splice(i, 1);
+    this.setState({items: newItems});
+  }
+
+  render() {
+    const items = this.state.items.map((item, i) => (
+      <div key={item} onClick={() => this.handleRemove(i)}>
+        {item}
+      </div>
+    ));
+
+    return (
+      <div>
+        <button onClick={this.handleAdd}>Add Item</button>
+        <ReactCSSTransitionGroup
+          transitionName="example"
+          transitionEnterTimeout={500}
+          transitionLeaveTimeout={300}>
+          {items}
+        </ReactCSSTransitionGroup>
+      </div>
+    );
+  }
+}
+```
+
+> Note:
+>
+> You must provide [the `key` attribute](/react/docs/multiple-components.html#dynamic-children) for all children of `ReactCSSTransitionGroup`, even when only rendering a single item. This is how React will determine which children have entered, left, or stayed.
+
+In this component, when a new item is added to `ReactCSSTransitionGroup` it will get the `example-enter` CSS class and the `example-enter-active` CSS class added in the next tick. This is a convention based on the `transitionName` prop.
+
+You can use these classes to trigger a CSS animation or transition. For example, try adding this CSS and adding a new list item:
+
+```css
+.example-enter {
+  opacity: 0.01;
+}
+
+.example-enter.example-enter-active {
+  opacity: 1;
+  transition: opacity 500ms ease-in;
+}
+
+.example-leave {
+  opacity: 1;
+}
+
+.example-leave.example-leave-active {
+  opacity: 0.01;
+  transition: opacity 300ms ease-in;
+}
+```
+
+You'll notice that animation durations need to be specified in both the CSS and the render method; this tells React when to remove the animation classes from the element and -- if it's leaving -- when to remove the element from the DOM.
+
+### Animate Initial Mounting
+
+`ReactCSSTransitionGroup` provides the optional prop `transitionAppear`, to add an extra transition phase at the initial mount of the component. There is generally no transition phase at the initial mount as the default value of `transitionAppear` is `false`. The following is an example which passes the prop `transitionAppear` with the value `true`.
+
+```javascript{5-6}
+render() {
+  return (
+    <ReactCSSTransitionGroup
+      transitionName="example"
+      transitionAppear={true}
+      transitionAppearTimeout={500}
+      transitionEnter={false}
+      transitionLeave={false}>
+      <h1>Fading at Initial Mount</h1>
+    </ReactCSSTransitionGroup>
+  );
+}
+```
+
+During the initial mount `ReactCSSTransitionGroup` will get the `example-appear` CSS class and the `example-appear-active` CSS class added in the next tick.
+
+```css
+.example-appear {
+  opacity: 0.01;
+}
+
+.example-appear.example-appear-active {
+  opacity: 1;
+  transition: opacity .5s ease-in;
+}
+```
+
+At the initial mount, all children of the `ReactCSSTransitionGroup` will `appear` but not `enter`. However, all children later added to an existing `ReactCSSTransitionGroup` will `enter` but not `appear`.
+
+> Note:
+>
+> The prop `transitionAppear` was added to `ReactCSSTransitionGroup` in version `0.13`. To maintain backwards compatibility, the default value is set to `false`.
+>
+> However, the default values of `transitionEnter` and `transitionLeave` are `true` so you must specify `transitionEnterTimeout` and `transitionLeaveTimeout` by default. If you don't need either enter or leave animations, pass `transitionEnter={false}` or `transitionLeave={false}`.
+
+### Custom Classes
+
+It is also possible to use custom class names for each of the steps in your transitions. Instead of passing a string into transitionName you can pass an object containing either the `enter` and `leave` class names, or an object containing the `enter`, `enter-active`, `leave-active`, and `leave` class names. If only the enter and leave classes are provided, the enter-active and leave-active classes will be determined by appending '-active' to the end of the class name. Here are two examples using custom classes:
+
+```javascript
+// ...
+<ReactCSSTransitionGroup
+  transitionName={ {
+    enter: 'enter',
+    enterActive: 'enterActive',
+    leave: 'leave',
+    leaveActive: 'leaveActive',
+    appear: 'appear',
+    appearActive: 'appearActive'
+  } }>
+  {item}
+</ReactCSSTransitionGroup>
+
+<ReactCSSTransitionGroup
+  transitionName={ {
+    enter: 'enter',
+    leave: 'leave',
+    appear: 'appear'
+  } }>
+  {item2}
+</ReactCSSTransitionGroup>
+// ...
+```
+
+### Animation Group Must Be Mounted To Work
+
+In order for it to apply transitions to its children, the `ReactCSSTransitionGroup` must already be mounted in the DOM or the prop `transitionAppear` must be set to `true`.
+
+The example below would **not** work, because the `ReactCSSTransitionGroup` is being mounted along with the new item, instead of the new item being mounted within it. Compare this to the [Getting Started](#getting-started) section above to see the difference.
+
+```javascript{4,6,13}
+render() {
+  const items = this.state.items.map((item, i) => (
+    <div key={item} onClick={() => this.handleRemove(i)}>
+      <ReactCSSTransitionGroup transitionName="example">
+        {item}
+      </ReactCSSTransitionGroup>
+    </div>
+  ));
+
+  return (
+    <div>
+      <button onClick={this.handleAdd}>Add Item</button>
+      {items}
+    </div>
+  );
+}
+```
+
+### Animating One or Zero Items
+
+In the example above, we rendered a list of items into `ReactCSSTransitionGroup`. However, the children of `ReactCSSTransitionGroup` can also be one or zero items. This makes it possible to animate a single element entering or leaving. Similarly, you can animate a new element replacing the current element. For example, we can implement a simple image carousel like this:
+
+```javascript{10}
+import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
+
+function ImageCarousel(props) {
+  return (
+    <div>
+      <ReactCSSTransitionGroup
+        transitionName="carousel"
+        transitionEnterTimeout={300}
+        transitionLeaveTimeout={300}>
+        <img src={props.imageSrc} key={props.imageSrc} />
+      </ReactCSSTransitionGroup>
+    </div>
+  );
+}
+```
+
+### Disabling Animations
+
+You can disable animating `enter` or `leave` animations if you want. For example, sometimes you may want an `enter` animation and no `leave` animation, but `ReactCSSTransitionGroup` waits for an animation to complete before removing your DOM node. You can add `transitionEnter={false}` or `transitionLeave={false}` props to `ReactCSSTransitionGroup` to disable these animations.
+
+> Note:
+>
+> When using `ReactCSSTransitionGroup`, there's no way for your components to be notified when a transition has ended or to perform any more complex logic around animation. If you want more fine-grained control, you can use the lower-level `ReactTransitionGroup` API which provides the hooks you need to do custom transitions.
+
+* * *
+
+## Low-level API: ReactTransitionGroup
+
+**Importing**
+
+```javascript
+import ReactTransitionGroup from 'react-addons-transition-group' // ES6
+var ReactTransitionGroup = require('react-addons-transition-group') // ES5 with npm
+```
+
+`ReactTransitionGroup` is the basis for animations. When children are declaratively added or removed from it (as in the [example above](#getting-started)), special lifecycle hooks are called on them.
+
+ - [`componentWillAppear()`](#componentwillappear)
+ - [`componentDidAppear()`](#componentdidappear)
+ - [`componentWillEnter()`](#componentwillenter)
+ - [`componentDidEnter()`](#componentdidenter)
+ - [`componentWillLeave()`](#componentwillleave)
+ - [`componentDidLeave()`](#componentdidleave)
+
+#### Rendering a Different Component
+
+`ReactTransitionGroup` renders as a `span` by default. You can change this behavior by providing a `component` prop. For example, here's how you would render a `<ul>`:
+
+```javascript{1}
+<ReactTransitionGroup component="ul">
+  {/* ... */}
+</ReactTransitionGroup>
+```
+
+Any additional, user-defined, properties will become properties of the rendered component. For example, here's how you would render a `<ul>` with CSS class:
+
+```javascript{1}
+<ReactTransitionGroup component="ul" className="animated-list">
+  {/* ... */}
+</ReactTransitionGroup>
+```
+
+Every DOM component that React can render is available for use. However, `component` does not need to be a DOM component. It can be any React component you want; even ones you've written yourself! Just write `component={List}` and your component will receive `this.props.children`.
+
+#### Rendering a Single Child
+
+People often use `ReactTransitionGroup` to animate mounting and unmounting of a single child such as a collapsible panel. Normally `ReactTransitionGroup` wraps all its children in a `span` (or a custom `component` as described above). This is because any React component has to return a single root element, and `ReactTransitionGroup` is no exception to this rule.
+
+However if you only need to render a single child inside `ReactTransitionGroup`, you can completely avoid wrapping it in a `<span>` or any other DOM component. To do this, create a custom component that renders the first child passed to it directly:
+
+```javascript
+function FirstChild(props) {
+  const childrenArray = React.Children.toArray(props.children);
+  return childrenArray[0] || null;
+}
+```
+
+Now you can specify `FirstChild` as the `component` prop in `<ReactTransitionGroup>` props and avoid any wrappers in the result DOM:
+
+```javascript
+<ReactTransitionGroup component={FirstChild}>
+  {someCondition ? <MyComponent /> : null}
+</ReactTransitionGroup>
+```
+
+This only works when you are animating a single child in and out, such as a collapsible panel. This approach wouldn't work when animating multiple children or replacing the single child with another child, such as an image carousel. For an image carousel, while the current image is animating out, another image will animate in, so `<ReactTransitionGroup>` needs to give them a common DOM parent. You can't avoid the wrapper for multiple children, but you can customize the wrapper with the `component` prop as described above.
+
+* * *
+
+## Reference
+
+### `componentWillAppear()`
+
+```javascript
+componentWillAppear(callback)
+```
+
+This is called at the same time as `componentDidMount()` for components that are initially mounted in a `TransitionGroup`. It will block other animations from occurring until `callback` is called. It is only called on the initial render of a `TransitionGroup`.
+
+* * *
+
+### `componentDidAppear()`
+
+```javascript
+componentDidAppear()
+```
+
+This is called after the `callback` function that was passed to `componentWillAppear` is called.
+
+* * *
+
+### `componentWillEnter()`
+
+```javascript
+componentWillEnter(callback)
+```
+
+This is called at the same time as `componentDidMount()` for components added to an existing `TransitionGroup`. It will block other animations from occurring until `callback` is called. It will not be called on the initial render of a `TransitionGroup`.
+
+* * *
+
+### `componentDidEnter()`
+
+```javascript
+componentDidEnter()
+```
+
+This is called after the `callback` function that was passed to [`componentWillEnter()`](#componentwillenter) is called.
+
+* * *
+
+### `componentWillLeave()`
+
+```javascript
+componentWillLeave(callback)
+```
+
+This is called when the child has been removed from the `ReactTransitionGroup`. Though the child has been removed, `ReactTransitionGroup` will keep it in the DOM until `callback` is called.
+
+* * *
+
+### `componentDidLeave()`
+
+```javascript
+componentDidLeave()
+```
+
+This is called when the `willLeave` `callback` is called (at the same time as `componentWillUnmount()`).
diff --git a/docs/docs/addons-create-fragment.md b/docs/docs/addons-create-fragment.md
new file mode 100644
index 000000000000..aaeea0cd3fce
--- /dev/null
+++ b/docs/docs/addons-create-fragment.md
@@ -0,0 +1,64 @@
+---
+id: create-fragment
+title: Keyed Fragments
+permalink: docs/create-fragment.html
+layout: docs
+category: Add-Ons
+---
+
+**Importing**
+
+```javascript
+import createFragment from 'react-addons-create-fragment'; // ES6
+var createFragment = require('react-addons-create-fragment'); // ES5 with npm
+```
+
+## Overview
+
+In most cases, you can use the `key` prop to specify keys on the elements you're returning from `render`. However, this breaks down in one situation: if you have two sets of children that you need to reorder, there's no way to put a key on each set without adding a wrapper element.
+
+That is, if you have a component such as:
+
+```js
+function Swapper(props) {
+  let children;
+  if (props.swapped) {
+    children = [props.rightChildren, props.leftChildren];
+  } else {
+    children = [props.leftChildren, props.rightChildren];
+  }
+  return <div>{children}</div>;
+}
+```
+
+The children will unmount and remount as you change the `swapped` prop because there aren't any keys marked on the two sets of children.
+
+To solve this problem, you can use the `createFragment` add-on to give keys to the sets of children.
+
+#### `Array<ReactNode> createFragment(object children)`
+
+Instead of creating arrays, we write:
+
+```javascript
+import createFragment from 'react-addons-create-fragment';
+
+function Swapper(props) {
+  let children;
+  if (props.swapped) {
+    children = createFragment({
+      right: props.rightChildren,
+      left: props.leftChildren
+    });
+  } else {
+    children = createFragment({
+      left: props.leftChildren,
+      right: props.rightChildren
+    });
+  }
+  return <div>{children}</div>;
+}
+```
+
+The keys of the passed object (that is, `left` and `right`) are used as keys for the entire set of children, and the order of the object's keys is used to determine the order of the rendered children. With this change, the two sets of children will be properly reordered in the DOM without unmounting.
+
+The return value of `createFragment` should be treated as an opaque object; you can use the [`React.Children`](https://facebook.github.io/react/docs/react-api.html#react.children) helpers to loop through a fragment but should not access it directly. Note also that we're relying on the JavaScript engine preserving object enumeration order here, which is not guaranteed by the spec but is implemented by all major browsers and VMs for objects with non-numeric keys.
diff --git a/docs/docs/addons-perf.md b/docs/docs/addons-perf.md
new file mode 100644
index 000000000000..762c75a3e4e7
--- /dev/null
+++ b/docs/docs/addons-perf.md
@@ -0,0 +1,144 @@
+---
+id: perf
+title: Performance Tools
+permalink: docs/perf.html
+layout: docs
+category: Add-Ons
+---
+
+**Importing**
+
+```javascript
+import Perf from 'react-addons-perf'; // ES6
+var Perf = require('react-addons-perf'); // ES5 with npm
+```
+
+
+## Overview
+
+React is usually quite fast out of the box. However, in situations where you need to squeeze every ounce of performance out of your app, it provides a [shouldComponentUpdate()](/react/docs/react-component.html#shouldcomponentupdate) hook where you can add optimization hints to React's diff algorithm.
+
+In addition to giving you an overview of your app's overall performance, `Perf` is a profiling tool that tells you exactly where you need to put these hooks.
+
+See these articles for an introduction to React performance tooling:
+
+ - ["How to Benchmark React Components"](https://medium.com/code-life/how-to-benchmark-react-components-the-quick-and-dirty-guide-f595baf1014c)
+ - ["Performance Engineering with React"](http://benchling.engineering/performance-engineering-with-react/)
+ - ["A Deep Dive into React Perf Debugging"](http://benchling.engineering/deep-dive-react-perf-debugging/) 
+
+### Development vs. Production Builds
+
+If you're benchmarking or seeing performance problems in your React apps, make sure you're testing with the [minified production build](/react/downloads.html). The development build includes extra warnings that are helpful when building your apps, but it is slower due to the extra bookkeeping it does.
+
+However, the perf tools described on this page only work when using the development build of React. Therefore, the profiler only serves to indicate the _relatively_ expensive parts of your app.
+
+### Using Perf
+
+The `Perf` object can be used with React in development mode only. You should not include this bundle when building your app for production.
+
+#### Getting Measurements
+
+ - [`start()`](#start)
+ - [`stop()`](#stop)
+ - [`getLastMeasurements()`](#getlastmeasurements)
+
+#### Printing Results
+
+The following methods use the measurements returned by [`Perf.getLastMeasurements()`](#getlastmeasurements) to pretty-print the result.
+
+ - [`printInclusive()`](#printinclusive)
+ - [`printExclusive()`](#printexclusive)
+ - [`printWasted()`](#printwasted)
+ - [`printOperations()`](#printoperations)
+ - [`printDOM()`](#printdom)
+
+* * *
+
+## Reference
+
+### `start()`
+### `stop()`
+
+```javascript
+Perf.start()
+// ...
+Perf.stop()
+```
+
+Start/stop the measurement. The React operations in-between are recorded for analyses below. Operations that took an insignificant amount of time are ignored.
+
+After stopping, you will need [`Perf.getLastMeasurements()`](#getlastmeasurements) to get the measurements.
+
+* * *
+
+### `getLastMeasurements()`
+
+```javascript
+Perf.getLastMeasurements()
+```
+
+Get the opaque data structure describing measurements from the last start-stop session. You can save it and pass it to the other print methods in [`Perf`](#printing-results) to analyze past measurements.
+
+> Note
+>
+> Don't rely on the exact format of the return value because it may change in minor releases. We will update the documentation if the return value format becomes a supported part of the public API.
+
+* * *
+
+### `printInclusive()`
+
+```javascript
+Perf.printInclusive(measurements)
+```
+
+Prints the overall time taken. If no argument's passed, defaults to all the measurements from the last recording. This prints a nicely formatted table in the console, like so:
+
+![](/react/img/docs/perf-inclusive.png)
+
+* * *
+
+### `printExclusive()`
+
+```javascript
+Perf.printExclusive(measurements)
+```
+
+"Exclusive" times don't include the times taken to mount the components: processing props, calling `componentWillMount` and `componentDidMount`, etc.
+
+![](/react/img/docs/perf-exclusive.png)
+
+* * *
+
+### `printWasted()`
+
+```javascript
+Perf.printWasted(measurements)
+```
+
+**The most useful part of the profiler**.
+
+"Wasted" time is spent on components that didn't actually render anything, e.g. the render stayed the same, so the DOM wasn't touched.
+
+![](/react/img/docs/perf-wasted.png)
+
+* * *
+
+### `printOperations()`
+
+```javascript
+Perf.printOperations(measurements)
+```
+
+Prints the underlying DOM manipulations, e.g. "set innerHTML" and "remove".
+
+![](/react/img/docs/perf-dom.png)
+
+* * *
+
+### `printDOM()`
+
+```javascript
+Perf.printDOM(measurements)
+```
+
+This method has been renamed to [`printOperations()`](#printoperations). Currently `printDOM()` still exists as an alias but it prints a deprecation warning and will eventually be removed.
diff --git a/docs/docs/addons-pure-render-mixin.md b/docs/docs/addons-pure-render-mixin.md
new file mode 100644
index 000000000000..cb71ec52ad19
--- /dev/null
+++ b/docs/docs/addons-pure-render-mixin.md
@@ -0,0 +1,44 @@
+---
+id: pure-render-mixin
+title: PureRenderMixin
+permalink: docs/pure-render-mixin.html
+layout: docs
+category: Add-Ons
+---
+
+> Note:
+>
+> `PureRenderMixin` is a legacy add-on. Use [`React.PureComponent`](/react/docs/react-api.html#react.purecomponent) instead.
+
+**Importing**
+
+```javascript
+import PureRenderMixin from 'react-addons-pure-render-mixin'; // ES6
+var PureRenderMixin = require('react-addons-pure-render-mixin'); // ES5 with npm
+```
+
+## Overview
+
+If your React component's render function renders the same result given the same props and state, you can use this mixin for a performance boost in some cases.
+
+Example:
+
+```js
+const createReactClass = require('create-react-class');
+
+createReactClass({
+  mixins: [PureRenderMixin],
+
+  render: function() {
+    return <div className={this.props.className}>foo</div>;
+  }
+});
+```
+
+Under the hood, the mixin implements [shouldComponentUpdate](/react/docs/component-specs.html#updating-shouldcomponentupdate), in which it compares the current props and state with the next ones and returns `false` if the equalities pass.
+
+> Note:
+>
+> This only shallowly compares the objects. If these contain complex data structures, it may produce false-negatives for deeper differences. Only mix into components which have simple props and state, or use `forceUpdate()` when you know deep data structures have changed. Or, consider using [immutable objects](https://facebook.github.io/immutable-js/) to facilitate fast comparisons of nested data.
+>
+> Furthermore, `shouldComponentUpdate` skips updates for the whole component subtree. Make sure all the children components are also "pure".
diff --git a/docs/docs/addons-shallow-compare.md b/docs/docs/addons-shallow-compare.md
new file mode 100644
index 000000000000..79de40d4823a
--- /dev/null
+++ b/docs/docs/addons-shallow-compare.md
@@ -0,0 +1,44 @@
+---
+id: shallow-compare
+title: Shallow Compare
+permalink: docs/shallow-compare.html
+layout: docs
+category: Reference
+---
+
+> Note:
+>
+> `shallowCompare` is a legacy add-on. Use [`React.PureComponent`](/react/docs/react-api.html#react.purecomponent) instead.
+
+**Importing**
+
+```javascript
+import shallowCompare from 'react-addons-shallow-compare'; // ES6
+var shallowCompare = require('react-addons-shallow-compare'); // ES5 with npm
+```
+
+## Overview
+
+Before [`React.PureComponent`](/react/docs/react-api.html#react.purecomponent) was introduced, `shallowCompare` was commonly used to achieve the same functionality as [`PureRenderMixin`](pure-render-mixin.html) while using ES6 classes with React.
+
+If your React component's render function is "pure" (in other words, it renders the same result given the same props and state), you can use this helper function for a performance boost in some cases.
+
+Example:
+
+```js
+export class SampleComponent extends React.Component {
+  shouldComponentUpdate(nextProps, nextState) {
+    return shallowCompare(this, nextProps, nextState);
+  }
+
+  render() {
+    return <div className={this.props.className}>foo</div>;
+  }
+}
+```
+
+`shallowCompare` performs a shallow equality check on the current `props` and `nextProps` objects as well as the current `state` and `nextState` objects.  
+It does this by iterating on the keys of the objects being compared and returning true when the values of a key in each object are not strictly equal.
+
+`shallowCompare` returns `true` if the shallow comparison for props or state fails and therefore the component should update.  
+`shallowCompare` returns `false` if the shallow comparison for props and state both pass and therefore the component does not need to update.
diff --git a/docs/docs/addons-shallow-renderer.md b/docs/docs/addons-shallow-renderer.md
new file mode 100644
index 000000000000..c69ea5c48e03
--- /dev/null
+++ b/docs/docs/addons-shallow-renderer.md
@@ -0,0 +1,68 @@
+---
+id: shallow-renderer
+title: Shallow Renderer
+permalink: docs/shallow-renderer.html
+layout: docs
+category: Reference
+---
+
+**Importing**
+
+```javascript
+import ShallowRenderer from 'react-test-renderer/shallow'; // ES6
+var ShallowRenderer = require('react-test-renderer/shallow'); // ES5 with npm
+```
+
+## Overview
+
+When writing unit tests for React, shallow rendering can be helpful. Shallow rendering lets you render a component "one level deep" and assert facts about what its render method returns, without worrying about the behavior of child components, which are not instantiated or rendered. This does not require a DOM.
+
+For example, if you have the following component:
+
+```javascript
+function MyComponent() {
+  return (
+    <div>
+      <span className="heading">Title</span>
+      <Subcomponent foo="bar" />
+    </div>
+  );
+}
+```
+
+Then you can assert:
+
+```javascript
+import ShallowRenderer from 'react-test-renderer/shallow';
+
+// in your test:
+const renderer = new ShallowRenderer();
+renderer.render(<MyComponent />);
+const result = renderer.getRenderOutput();
+
+expect(result.type).toBe('div');
+expect(result.props.children).toEqual([
+  <span className="heading">Title</span>,
+  <Subcomponent foo="bar" />
+]);
+```
+
+Shallow testing currently has some limitations, namely not supporting refs.
+
+> Note:
+>
+> We also recommend checking out Enzyme's [Shallow Rendering API](http://airbnb.io/enzyme/docs/api/shallow.html). It provides a nicer higher-level API over the same functionality.
+
+## Reference
+
+### `shallowRenderer.render()`
+
+You can think of the shallowRenderer as a "place" to render the component you're testing, and from which you can extract the component's output.
+
+`shallowRenderer.render()` is similar to [`ReactDOM.render()`](/react/docs/react-dom.html#render) but it doesn't require DOM and only renders a single level deep. This means you can test components isolated from how their children are implemented.
+
+### `shallowRenderer.getRenderOutput()`
+
+After `shallowRenderer.render()` has been called, you can use `shallowRenderer.getRenderOutput()` to get the shallowly rendered output.
+
+You can then begin to assert facts about the output.
diff --git a/docs/docs/addons-test-utils.md b/docs/docs/addons-test-utils.md
new file mode 100644
index 000000000000..bf689464f8bb
--- /dev/null
+++ b/docs/docs/addons-test-utils.md
@@ -0,0 +1,263 @@
+---
+id: test-utils
+title: Test Utilities
+permalink: docs/test-utils.html
+layout: docs
+category: Reference
+---
+
+**Importing**
+
+```javascript
+import ReactTestUtils from 'react-dom/test-utils'; // ES6
+var ReactTestUtils = require('react-dom/test-utils'); // ES5 with npm
+```
+
+## Overview
+
+`ReactTestUtils` makes it easy to test React components in the testing framework of your choice. At Facebook we use [Jest](https://facebook.github.io/jest/) for painless JavaScript testing. Learn how to get started with Jest through the Jest website's [React Tutorial](http://facebook.github.io/jest/docs/tutorial-react.html#content).
+
+> Note:
+>
+> Airbnb has released a testing utility called Enzyme, which makes it easy to assert, manipulate, and traverse your React Components' output. If you're deciding on a unit testing utility to use together with Jest, or any other test runner, it's worth checking out: [http://airbnb.io/enzyme/](http://airbnb.io/enzyme/)
+
+ - [`Simulate`](#simulate)
+ - [`renderIntoDocument()`](#renderintodocument)
+ - [`mockComponent()`](#mockcomponent)
+ - [`isElement()`](#iselement)
+ - [`isElementOfType()`](#iselementoftype)
+ - [`isDOMComponent()`](#isdomcomponent)
+ - [`isCompositeComponent()`](#iscompositecomponent)
+ - [`isCompositeComponentWithType()`](#iscompositecomponentwithtype)
+ - [`findAllInRenderedTree()`](#findallinrenderedtree)
+ - [`scryRenderedDOMComponentsWithClass()`](#scryrendereddomcomponentswithclass)
+ - [`findRenderedDOMComponentWithClass()`](#findrendereddomcomponentwithclass)
+ - [`scryRenderedDOMComponentsWithTag()`](#scryrendereddomcomponentswithtag)
+ - [`findRenderedDOMComponentWithTag()`](#findrendereddomcomponentwithtag)
+ - [`scryRenderedComponentsWithType()`](#scryrenderedcomponentswithtype)
+ - [`findRenderedComponentWithType()`](#findrenderedcomponentwithtype)
+
+## Reference
+
+## Shallow Rendering
+
+When writing unit tests for React, shallow rendering can be helpful. Shallow rendering lets you render a component "one level deep" and assert facts about what its render method returns, without worrying about the behavior of child components, which are not instantiated or rendered. This does not require a DOM.
+
+> Note:
+>
+> The shallow renderer has moved to `react-test-renderer/shallow`.<br>
+> [Learn more about shallow rendering on its reference page.](/react/docs/shallow-renderer.html)
+
+## Other Utilities
+
+### `Simulate`
+
+```javascript
+Simulate.{eventName}(
+  element,
+  [eventData]
+)
+```
+
+Simulate an event dispatch on a DOM node with optional `eventData` event data.
+
+`Simulate` has a method for [every event that React understands](/react/docs/events.html#supported-events).
+
+**Clicking an element**
+
+```javascript
+// <button ref="button">...</button>
+const node = this.refs.button;
+ReactTestUtils.Simulate.click(node);
+```
+
+**Changing the value of an input field and then pressing ENTER.**
+
+```javascript
+// <input ref="input" />
+const node = this.refs.input;
+node.value = 'giraffe';
+ReactTestUtils.Simulate.change(node);
+ReactTestUtils.Simulate.keyDown(node, {key: "Enter", keyCode: 13, which: 13});
+```
+
+> Note
+>
+> You will have to provide any event property that you're using in your component (e.g. keyCode, which, etc...) as React is not creating any of these for you.
+
+* * *
+
+### `renderIntoDocument()`
+
+```javascript
+renderIntoDocument(element)
+```
+
+Render a React element into a detached DOM node in the document. **This function requires a DOM.**
+
+> Note:
+>
+> You will need to have `window`, `window.document` and `window.document.createElement` globally available **before** you import `React`. Otherwise React will think it can't access the DOM and methods like `setState` won't work.
+
+* * *
+
+### `mockComponent()`
+
+```javascript
+mockComponent(
+  componentClass,
+  [mockTagName]
+)
+```
+
+Pass a mocked component module to this method to augment it with useful methods that allow it to be used as a dummy React component. Instead of rendering as usual, the component will become a simple `<div>` (or other tag if `mockTagName` is provided) containing any provided children.
+
+* * *
+
+### `isElement()`
+
+```javascript
+isElement(element)
+```
+
+Returns `true` if `element` is any React element.
+
+* * *
+
+### `isElementOfType()`
+
+```javascript
+isElementOfType(
+  element,
+  componentClass
+)
+```
+
+Returns `true` if `element` is a React element whose type is of a React `componentClass`.
+
+* * *
+
+### `isDOMComponent()`
+
+```javascript
+isDOMComponent(instance)
+```
+
+Returns `true` if `instance` is a DOM component (such as a `<div>` or `<span>`).
+
+* * *
+
+### `isCompositeComponent()`
+
+```javascript
+isCompositeComponent(instance)
+```
+
+Returns `true` if `instance` is a user-defined component, such as a class or a function.
+
+* * *
+
+### `isCompositeComponentWithType()`
+
+```javascript
+isCompositeComponentWithType(
+  instance,
+  componentClass
+)
+```
+
+Returns `true` if `instance` is a component whose type is of a React `componentClass`.
+
+* * *
+
+### `findAllInRenderedTree()`
+
+```javascript
+findAllInRenderedTree(
+  tree,
+  test
+)
+```
+
+Traverse all components in `tree` and accumulate all components where `test(component)` is `true`. This is not that useful on its own, but it's used as a primitive for other test utils.
+
+* * *
+
+### `scryRenderedDOMComponentsWithClass()`
+
+```javascript
+scryRenderedDOMComponentsWithClass(
+  tree,
+  className
+)
+```
+
+Finds all DOM elements of components in the rendered tree that are DOM components with the class name matching `className`.
+
+* * *
+
+### `findRenderedDOMComponentWithClass()`
+
+```javascript
+findRenderedDOMComponentWithClass(
+  tree,
+  className
+)
+```
+
+Like [`scryRenderedDOMComponentsWithClass()`](#scryrendereddomcomponentswithclass) but expects there to be one result, and returns that one result, or throws exception if there is any other number of matches besides one.
+
+* * *
+
+### `scryRenderedDOMComponentsWithTag()`
+
+```javascript
+scryRenderedDOMComponentsWithTag(
+  tree,
+  tagName
+)
+```
+
+Finds all DOM elements of components in the rendered tree that are DOM components with the tag name matching `tagName`.
+
+* * *
+
+### `findRenderedDOMComponentWithTag()`
+
+```javascript
+findRenderedDOMComponentWithTag(
+  tree,
+  tagName
+)
+```
+
+Like [`scryRenderedDOMComponentsWithTag()`](#scryrendereddomcomponentswithtag) but expects there to be one result, and returns that one result, or throws exception if there is any other number of matches besides one.
+
+* * *
+
+### `scryRenderedComponentsWithType()`
+
+```javascript
+scryRenderedComponentsWithType(
+  tree,
+  componentClass
+)
+```
+
+Finds all instances of components with type equal to `componentClass`.
+
+* * *
+
+### `findRenderedComponentWithType()`
+
+```javascript
+findRenderedComponentWithType(
+  tree,
+  componentClass
+)
+```
+
+Same as [`scryRenderedComponentsWithType()`](#scryrenderedcomponentswithtype) but expects there to be one result and returns that one result, or throws exception if there is any other number of matches besides one.
+
+* * *
+
diff --git a/docs/docs/addons-two-way-binding-helpers.md b/docs/docs/addons-two-way-binding-helpers.md
new file mode 100644
index 000000000000..1441803960c4
--- /dev/null
+++ b/docs/docs/addons-two-way-binding-helpers.md
@@ -0,0 +1,131 @@
+---
+id: two-way-binding-helpers
+title: Two-way Binding Helpers
+permalink: docs/two-way-binding-helpers.html
+layout: docs
+category: Add-Ons
+---
+
+> Note:
+>
+> `LinkedStateMixin` is deprecated as of React v15. The recommendation is to explicitly set the value and change handler, instead of using `LinkedStateMixin`.
+
+**Importing**
+
+```javascript
+import LinkedStateMixin from 'react-addons-linked-state-mixin'; // ES6
+var LinkedStateMixin = require('react-addons-linked-state-mixin'); // ES5 with npm
+```
+
+## Overview
+
+`LinkedStateMixin` is an easy way to express two-way binding with React.
+
+In React, data flows one way: from owner to child. This is because data only flows one direction in [the Von Neumann model of computing](https://en.wikipedia.org/wiki/Von_Neumann_architecture). You can think of it as "one-way data binding."
+
+However, there are lots of applications that require you to read some data and flow it back into your program. For example, when developing forms, you'll often want to update some React `state` when you receive user input. Or perhaps you want to perform layout in JavaScript and react to changes in some DOM element size.
+
+In React, you would implement this by listening to a "change" event, read from your data source (usually the DOM) and call `setState()` on one of your components. "Closing the data flow loop" explicitly leads to more understandable and easier-to-maintain programs. See [our forms documentation](/react/docs/forms.html) for more information.
+
+Two-way binding -- implicitly enforcing that some value in the DOM is always consistent with some React `state` -- is concise and supports a wide variety of applications. We've provided `LinkedStateMixin`: syntactic sugar for setting up the common data flow loop pattern described above, or "linking" some data source to React `state`.
+
+> Note:
+>
+> `LinkedStateMixin` is just a thin wrapper and convention around the `onChange`/`setState()` pattern. It doesn't fundamentally change how data flows in your React application.
+
+## LinkedStateMixin: Before and After
+
+Here's a simple form example without using `LinkedStateMixin`:
+
+```javascript
+var createReactClass = require('create-react-class');
+
+var NoLink = createReactClass({
+  getInitialState: function() {
+    return {message: 'Hello!'};
+  },
+  handleChange: function(event) {
+    this.setState({message: event.target.value});
+  },
+  render: function() {
+    var message = this.state.message;
+    return <input type="text" value={message} onChange={this.handleChange} />;
+  }
+});
+```
+
+This works really well and it's very clear how data is flowing, however, with a lot of form fields it could get a bit verbose. Let's use `LinkedStateMixin` to save us some typing:
+
+```javascript{4,9}
+var createReactClass = require('create-react-class');
+
+var WithLink = createReactClass({
+  mixins: [LinkedStateMixin],
+  getInitialState: function() {
+    return {message: 'Hello!'};
+  },
+  render: function() {
+    return <input type="text" valueLink={this.linkState('message')} />;
+  }
+});
+```
+
+`LinkedStateMixin` adds a method to your React component called `linkState()`. `linkState()` returns a `valueLink` object which contains the current value of the React state and a callback to change it.
+
+`valueLink` objects can be passed up and down the tree as props, so it's easy (and explicit) to set up two-way binding between a component deep in the hierarchy and state that lives higher in the hierarchy.
+
+Note that checkboxes have a special behavior regarding their `value` attribute, which is the value that will be sent on form submit if the checkbox is checked (defaults to `on`). The `value` attribute is not updated when the checkbox is checked or unchecked. For checkboxes, you should use `checkedLink` instead of `valueLink`:
+```
+<input type="checkbox" checkedLink={this.linkState('booleanValue')} />
+```
+
+## Under the Hood
+
+There are two sides to `LinkedStateMixin`: the place where you create the `valueLink` instance and the place where you use it. To prove how simple `LinkedStateMixin` is, let's rewrite each side separately to be more explicit.
+
+### valueLink Without LinkedStateMixin
+
+```javascript{7-9,11-14}
+var createReactClass = require('create-react-class');
+
+var WithoutMixin = createReactClass({
+  getInitialState: function() {
+    return {message: 'Hello!'};
+  },
+  handleChange: function(newValue) {
+    this.setState({message: newValue});
+  },
+  render: function() {
+    var valueLink = {
+      value: this.state.message,
+      requestChange: this.handleChange
+    };
+    return <input type="text" valueLink={valueLink} />;
+  }
+});
+```
+
+As you can see, `valueLink` objects are very simple objects that just have a `value` and `requestChange` prop. And `LinkedStateMixin` is similarly simple: it just populates those fields with a value from `this.state` and a callback that calls `this.setState()`.
+
+### LinkedStateMixin Without valueLink
+
+```javascript
+var LinkedStateMixin = require('react-addons-linked-state-mixin');
+var createReactClass = require('create-react-class');
+
+var WithoutLink = createReactClass({
+  mixins: [LinkedStateMixin],
+  getInitialState: function() {
+    return {message: 'Hello!'};
+  },
+  render: function() {
+    var valueLink = this.linkState('message');
+    var handleChange = function(e) {
+      valueLink.requestChange(e.target.value);
+    };
+    return <input type="text" value={valueLink.value} onChange={handleChange} />;
+  }
+});
+```
+
+The `valueLink` prop is also quite simple. It simply handles the `onChange` event and calls `this.props.valueLink.requestChange()` and also uses `this.props.valueLink.value` instead of `this.props.value`. That's it!
diff --git a/docs/docs/addons-update.md b/docs/docs/addons-update.md
new file mode 100644
index 000000000000..51b1295b32ec
--- /dev/null
+++ b/docs/docs/addons-update.md
@@ -0,0 +1,117 @@
+---
+id: update
+title: Immutability Helpers
+permalink: docs/update.html
+layout: docs
+category: Add-Ons
+---
+
+> Note:
+>
+> `update` is a legacy add-on. Use [`immutability-helper`](https://github.com/kolodny/immutability-helper) instead.
+
+**Importing**
+
+```javascript
+import update from 'react-addons-update'; // ES6
+var update = require('react-addons-update'); // ES5 with npm
+```
+
+## Overview
+
+React lets you use whatever style of data management you want, including mutation. However, if you can use immutable data in performance-critical parts of your application it's easy to implement a fast [`shouldComponentUpdate()`](/react/docs/react-component.html#shouldcomponentupdate) method to significantly speed up your app.
+
+Dealing with immutable data in JavaScript is more difficult than in languages designed for it, like [Clojure](http://clojure.org/). However, we've provided a simple immutability helper, `update()`, that makes dealing with this type of data much easier, *without* fundamentally changing how your data is represented. You can also take a look at Facebook's [Immutable-js](https://facebook.github.io/immutable-js/docs/) and the [Advanced Performance](/react/docs/advanced-performance.html) section for more detail on Immutable-js.
+
+### The Main Idea
+
+If you mutate data like this:
+
+```js
+myData.x.y.z = 7;
+// or...
+myData.a.b.push(9);
+```
+
+You have no way of determining which data has changed since the previous copy has been overwritten. Instead, you need to create a new copy of `myData` and change only the parts of it that need to be changed. Then you can compare the old copy of `myData` with the new one in `shouldComponentUpdate()` using triple-equals:
+
+```js
+const newData = deepCopy(myData);
+newData.x.y.z = 7;
+newData.a.b.push(9);
+```
+
+Unfortunately, deep copies are expensive, and sometimes impossible. You can alleviate this by only copying objects that need to be changed and by reusing the objects that haven't changed. Unfortunately, in today's JavaScript this can be cumbersome:
+
+```js
+const newData = extend(myData, {
+  x: extend(myData.x, {
+    y: extend(myData.x.y, {z: 7}),
+  }),
+  a: extend(myData.a, {b: myData.a.b.concat(9)})
+});
+```
+
+While this is fairly performant (since it only makes a shallow copy of `log n` objects and reuses the rest), it's a big pain to write. Look at all the repetition! This is not only annoying, but also provides a large surface area for bugs.
+
+## `update()`
+
+`update()` provides simple syntactic sugar around this pattern to make writing this code easier. This code becomes:
+
+```js
+import update from 'react-addons-update';
+
+const newData = update(myData, {
+  x: {y: {z: {$set: 7}}},
+  a: {b: {$push: [9]}}
+});
+```
+
+While the syntax takes a little getting used to (though it's inspired by [MongoDB's query language](http://docs.mongodb.org/manual/core/crud-introduction/#query)) there's no redundancy, it's statically analyzable and it's not much more typing than the mutative version.
+
+The `$`-prefixed keys are called *commands*. The data structure they are "mutating" is called the *target*.
+
+## Available Commands
+
+  * `{$push: array}` `push()` all the items in `array` on the target.
+  * `{$unshift: array}` `unshift()` all the items in `array` on the target.
+  * `{$splice: array of arrays}` for each item in `arrays` call `splice()` on the target with the parameters provided by the item.
+  * `{$set: any}` replace the target entirely.
+  * `{$merge: object}` merge the keys of `object` with the target.
+  * `{$apply: function}` passes in the current value to the function and updates it with the new returned value.
+
+## Examples
+
+### Simple push
+
+```js
+const initialArray = [1, 2, 3];
+const newArray = update(initialArray, {$push: [4]}); // => [1, 2, 3, 4]
+```
+`initialArray` is still `[1, 2, 3]`.
+
+### Nested collections
+
+```js
+const collection = [1, 2, {a: [12, 17, 15]}];
+const newCollection = update(collection, {2: {a: {$splice: [[1, 1, 13, 14]]}}});
+// => [1, 2, {a: [12, 13, 14, 15]}]
+```
+This accesses `collection`'s index `2`, key `a`, and does a splice of one item starting from index `1` (to remove `17`) while inserting `13` and `14`.
+
+### Updating a value based on its current one
+
+```js
+const obj = {a: 5, b: 3};
+const newObj = update(obj, {b: {$apply: function(x) {return x * 2;}}});
+// => {a: 5, b: 6}
+// This is equivalent, but gets verbose for deeply nested collections:
+const newObj2 = update(obj, {b: {$set: obj.b * 2}});
+```
+
+### (Shallow) Merge
+
+```js
+const obj = {a: 5, b: 3};
+const newObj = update(obj, {$merge: {b: 6, c: 7}}); // => {a: 5, b: 6, c: 7}
+```
diff --git a/docs/docs/addons.md b/docs/docs/addons.md
new file mode 100644
index 000000000000..b9575b3fa38f
--- /dev/null
+++ b/docs/docs/addons.md
@@ -0,0 +1,48 @@
+---
+id: addons
+title: Add-Ons
+permalink: docs/addons.html
+---
+
+>Note:
+> `React.addons` is deprecated as of React v15.5. The add-ons have now all either been deprecated or moved to separate modules.
+
+The React add-ons are a collection of useful utility modules for building React apps. **These should be considered experimental** and tend to change more often than the core.
+
+- [`createFragment`](create-fragment.html), to create a set of externally-keyed children.
+
+The add-ons below are in the development (unminified) version of React only:
+
+- [`Perf`](perf.html), a performance profiling tool for finding optimization opportunities.
+- [`ReactTestUtils`](test-utils.html), simple helpers for writing test cases.
+
+### Legacy Add-ons
+
+The add-ons below are considered legacy and their use is discouraged.
+
+- [`PureRenderMixin`](pure-render-mixin.html). Use [`React.PureComponent`](/react/docs/react-api.html#react.purecomponent) instead.
+- [`shallowCompare`](shallow-compare.html), a helper function that performs a shallow comparison for props and state in a component to decide if a component should update.
+- [`update`](update.html). Use [`kolodny/immutability-helper`](https://github.com/kolodny/immutability-helper) instead.
+- [`ReactDOMFactories`](dom-factories.html), pre-configured DOM factories to make React easier to use without JSX.
+
+### Deprecated Add-ons
+
+- [`LinkedStateMixin`](two-way-binding-helpers.html) has been deprecated.
+- [`TransitionGroup` and `CSSTransitionGroup`](animation.html) have been deprecated.
+
+## Using React with Add-ons
+
+You can install the add-ons individually from npm (e.g. `npm install react-addons-create-fragment`) and import them:
+
+```javascript
+import createFragment from 'react-addons-create-fragment'; // ES6
+var createFragment = require('react-addons-create-fragment'); // ES5 with npm
+```
+
+When using a CDN, you can use `react-with-addons.js` instead of `react.js`:
+
+```html
+<script src="https://unpkg.com/react@15/dist/react-with-addons.js"></script>
+```
+
+The add-ons will be available via the `React.addons` global (e.g. `React.addons.TestUtils`).
diff --git a/docs/docs/complementary-tools.it-IT.md b/docs/docs/complementary-tools.it-IT.md
deleted file mode 100644
index ce1fc965b7d4..000000000000
--- a/docs/docs/complementary-tools.it-IT.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-permalink: complementary-tools-it-IT.html
-layout: redirect
-dest_url: https://github.com/facebook/react/wiki/Complementary-Tools
----
diff --git a/docs/docs/complementary-tools.ko-KR.md b/docs/docs/complementary-tools.ko-KR.md
deleted file mode 100644
index 9807bf0799ee..000000000000
--- a/docs/docs/complementary-tools.ko-KR.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-permalink: complementary-tools-ko-KR.html
-layout: redirect
-dest_url: https://github.com/facebook/react/wiki/Complementary-Tools
----
diff --git a/docs/docs/complementary-tools.md b/docs/docs/complementary-tools.md
deleted file mode 100644
index 10e8dba553cd..000000000000
--- a/docs/docs/complementary-tools.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-permalink: complementary-tools.html
-layout: redirect
-dest_url: https://github.com/facebook/react/wiki/Complementary-Tools
----
diff --git a/docs/docs/complementary-tools.zh-CN.md b/docs/docs/complementary-tools.zh-CN.md
deleted file mode 100644
index 797700c15e82..000000000000
--- a/docs/docs/complementary-tools.zh-CN.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-permalink: complementary-tools-zh-CN.html
-layout: redirect
-dest_url: https://github.com/facebook/react/wiki/Complementary-Tools
----
diff --git a/docs/docs/components-and-props.md b/docs/docs/components-and-props.md
new file mode 100644
index 000000000000..150138fb91b6
--- /dev/null
+++ b/docs/docs/components-and-props.md
@@ -0,0 +1,266 @@
+---
+id: components-and-props
+title: Components and Props
+permalink: docs/components-and-props.html
+redirect_from:
+  - "docs/reusable-components.html"
+  - "docs/reusable-components-zh-CN.html"
+  - "docs/transferring-props.html"
+  - "docs/transferring-props-it-IT.html"
+  - "docs/transferring-props-ja-JP.html"
+  - "docs/transferring-props-ko-KR.html"
+  - "docs/transferring-props-zh-CN.html"
+  - "tips/props-in-getInitialState-as-anti-pattern.html"
+  - "tips/communicate-between-components.html"
+prev: rendering-elements.html
+next: state-and-lifecycle.html
+---
+
+Components let you split the UI into independent, reusable pieces, and think about each piece in isolation.
+
+Conceptually, components are like JavaScript functions. They accept arbitrary inputs (called "props") and return React elements describing what should appear on the screen.
+
+## Functional and Class Components
+
+The simplest way to define a component is to write a JavaScript function:
+
+```js
+function Welcome(props) {
+  return <h1>Hello, {props.name}</h1>;
+}
+```
+
+This function is a valid React component because it accepts a single "props" object argument with data and returns a React element. We call such components "functional" because they are literally JavaScript functions.
+
+You can also use an [ES6 class](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes) to define a component:
+
+```js
+class Welcome extends React.Component {
+  render() {
+    return <h1>Hello, {this.props.name}</h1>;
+  }
+}
+```
+
+The above two components are equivalent from React's point of view.
+
+Classes have some additional features that we will discuss in the [next sections](/react/docs/state-and-lifecycle.html). Until then, we will use functional components for their conciseness.
+
+## Rendering a Component
+
+Previously, we only encountered React elements that represent DOM tags:
+
+```js
+const element = <div />;
+```
+
+However, elements can also represent user-defined components:
+
+```js
+const element = <Welcome name="Sara" />;
+```
+
+When React sees an element representing a user-defined component, it passes JSX attributes to this component as a single object. We call this object "props".
+
+For example, this code renders "Hello, Sara" on the page:
+
+```js{1,5}
+function Welcome(props) {
+  return <h1>Hello, {props.name}</h1>;
+}
+
+const element = <Welcome name="Sara" />;
+ReactDOM.render(
+  element,
+  document.getElementById('root')
+);
+```
+
+[Try it on CodePen.](http://codepen.io/gaearon/pen/YGYmEG?editors=0010)
+
+Let's recap what happens in this example:
+
+1. We call `ReactDOM.render()` with the `<Welcome name="Sara" />` element.
+2. React calls the `Welcome` component with `{name: 'Sara'}` as the props.
+3. Our `Welcome` component returns a `<h1>Hello, Sara</h1>` element as the result.
+4. React DOM efficiently updates the DOM to match `<h1>Hello, Sara</h1>`.
+
+>**Caveat:**
+>
+>Always start component names with a capital letter.
+>
+>For example, `<div />` represents a DOM tag, but `<Welcome />` represents a component and requires `Welcome` to be in scope.
+
+## Composing Components
+
+Components can refer to other components in their output. This lets us use the same component abstraction for any level of detail. A button, a form, a dialog, a screen: in React apps, all those are commonly expressed as components.
+
+For example, we can create an `App` component that renders `Welcome` many times:
+
+```js{8-10}
+function Welcome(props) {
+  return <h1>Hello, {props.name}</h1>;
+}
+
+function App() {
+  return (
+    <div>
+      <Welcome name="Sara" />
+      <Welcome name="Cahal" />
+      <Welcome name="Edite" />
+    </div>
+  );
+}
+
+ReactDOM.render(
+  <App />,
+  document.getElementById('root')
+);
+```
+
+[Try it on CodePen.](http://codepen.io/gaearon/pen/KgQKPr?editors=0010)
+
+Typically, new React apps have a single `App` component at the very top. However, if you integrate React into an existing app, you might start bottom-up with a small component like `Button` and gradually work your way to the top of the view hierarchy.
+
+>**Caveat:**
+>
+>Components must return a single root element. This is why we added a `<div>` to contain all the `<Welcome />` elements.
+
+## Extracting Components
+
+Don't be afraid to split components into smaller components.
+
+For example, consider this `Comment` component:
+
+```js
+function Comment(props) {
+  return (
+    <div className="Comment">
+      <div className="UserInfo">
+        <img className="Avatar"
+          src={props.author.avatarUrl}
+          alt={props.author.name}
+        />
+        <div className="UserInfo-name">
+          {props.author.name}
+        </div>
+      </div>
+      <div className="Comment-text">
+        {props.text}
+      </div>
+      <div className="Comment-date">
+        {formatDate(props.date)}
+      </div>
+    </div>
+  );
+}
+```
+
+[Try it on CodePen.](http://codepen.io/gaearon/pen/VKQwEo?editors=0010)
+
+It accepts `author` (an object), `text` (a string), and `date` (a date) as props, and describes a comment on a social media website.
+
+This component can be tricky to change because of all the nesting, and it is also hard to reuse individual parts of it. Let's extract a few components from it.
+
+First, we will extract `Avatar`:
+
+```js{3-6}
+function Avatar(props) {
+  return (
+    <img className="Avatar"
+      src={props.user.avatarUrl}
+      alt={props.user.name}
+    />
+  );
+}
+```
+
+The `Avatar` doesn't need to know that it is being rendered inside a `Comment`. This is why we have given its prop a more generic name: `user` rather than `author`.
+
+We recommend naming props from the component's own point of view rather than the context in which it is being used.
+
+We can now simplify `Comment` a tiny bit:
+
+```js{5}
+function Comment(props) {
+  return (
+    <div className="Comment">
+      <div className="UserInfo">
+        <Avatar user={props.author} />
+        <div className="UserInfo-name">
+          {props.author.name}
+        </div>
+      </div>
+      <div className="Comment-text">
+        {props.text}
+      </div>
+      <div className="Comment-date">
+        {formatDate(props.date)}
+      </div>
+    </div>
+  );
+}
+```
+
+Next, we will extract a `UserInfo` component that renders an `Avatar` next to user's name:
+
+```js{3-8}
+function UserInfo(props) {
+  return (
+    <div className="UserInfo">
+      <Avatar user={props.user} />
+      <div className="UserInfo-name">
+        {props.user.name}
+      </div>
+    </div>
+  );
+}
+```
+
+This lets us simplify `Comment` even further:
+
+```js{4}
+function Comment(props) {
+  return (
+    <div className="Comment">
+      <UserInfo user={props.author} />
+      <div className="Comment-text">
+        {props.text}
+      </div>
+      <div className="Comment-date">
+        {formatDate(props.date)}
+      </div>
+    </div>
+  );
+}
+```
+
+[Try it on CodePen.](http://codepen.io/gaearon/pen/rrJNJY?editors=0010)
+
+Extracting components might seem like grunt work at first, but having a palette of reusable components pays off in larger apps. A good rule of thumb is that if a part of your UI is used several times (`Button`, `Panel`, `Avatar`), or is complex enough on its own (`App`, `FeedStory`, `Comment`), it is a good candidate to be a reusable component.
+
+## Props are Read-Only
+
+Whether you declare a component [as a function or a class](#functional-and-class-components), it must never modify its own props. Consider this `sum` function:
+
+```js
+function sum(a, b) {
+  return a + b;
+}
+```
+
+Such functions are called ["pure"](https://en.wikipedia.org/wiki/Pure_function) because they do not attempt to change their inputs, and always return the same result for the same inputs.
+
+In contrast, this function is impure because it changes its own input:
+
+```js
+function withdraw(account, amount) {
+  account.total -= amount;
+}
+```
+
+React is pretty flexible but it has a single strict rule:
+
+**All React components must act like pure functions with respect to their props.**
+
+Of course, application UIs are dynamic and change over time. In the [next section](/react/docs/state-and-lifecycle.html), we will introduce a new concept of "state". State allows React components to change their output over time in response to user actions, network responses, and anything else, without violating this rule.
diff --git a/docs/docs/composition-vs-inheritance.md b/docs/docs/composition-vs-inheritance.md
new file mode 100644
index 000000000000..0ac5cd45b21c
--- /dev/null
+++ b/docs/docs/composition-vs-inheritance.md
@@ -0,0 +1,171 @@
+---
+id: composition-vs-inheritance
+title: Composition vs Inheritance
+permalink: docs/composition-vs-inheritance.html
+redirect_from: "docs/multiple-components.html"
+prev: lifting-state-up.html
+next: thinking-in-react.html
+---
+
+React has a powerful composition model, and we recommend using composition instead of inheritance to reuse code between components.
+
+In this section, we will consider a few problems where developers new to React often reach for inheritance, and show how we can solve them with composition.
+
+## Containment
+
+Some components don't know their children ahead of time. This is especially common for components like `Sidebar` or `Dialog` that represent generic "boxes".
+
+We recommend that such components use the special `children` prop to pass children elements directly into their output:
+
+```js{4}
+function FancyBorder(props) {
+  return (
+    <div className={'FancyBorder FancyBorder-' + props.color}>
+      {props.children}
+    </div>
+  );
+}
+```
+
+This lets other components pass arbitrary children to them by nesting the JSX:
+
+```js{4-9}
+function WelcomeDialog() {
+  return (
+    <FancyBorder color="blue">
+      <h1 className="Dialog-title">
+        Welcome
+      </h1>
+      <p className="Dialog-message">
+        Thank you for visiting our spacecraft!
+      </p>
+    </FancyBorder>
+  );
+}
+```
+
+[Try it on CodePen.](http://codepen.io/gaearon/pen/ozqNOV?editors=0010)
+
+Anything inside the `<FancyBorder>` JSX tag gets passed into the `FancyBorder` component as a `children` prop. Since `FancyBorder` renders `{props.children}` inside a `<div>`, the passed elements appear in the final output.
+
+While this is less common, sometimes you might need multiple "holes" in a component. In such cases you may come up with your own convention instead of using `children`:
+
+```js{5,8,18,21}
+function SplitPane(props) {
+  return (
+    <div className="SplitPane">
+      <div className="SplitPane-left">
+        {props.left}
+      </div>
+      <div className="SplitPane-right">
+        {props.right}
+      </div>
+    </div>
+  );
+}
+
+function App() {
+  return (
+    <SplitPane
+      left={
+        <Contacts />
+      }
+      right={
+        <Chat />
+      } />
+  );
+}
+```
+
+[Try it on CodePen.](http://codepen.io/gaearon/pen/gwZOJp?editors=0010)
+
+React elements like `<Contacts />` and `<Chat />` are just objects, so you can pass them as props like any other data.
+
+## Specialization
+
+Sometimes we think about components as being "special cases" of other components. For example, we might say that a `WelcomeDialog` is a special case of `Dialog`.
+
+In React, this is also achieved by composition, where a more "specific" component renders a more "generic" one and configures it with props:
+
+```js{5,8,16-18}
+function Dialog(props) {
+  return (
+    <FancyBorder color="blue">
+      <h1 className="Dialog-title">
+        {props.title}
+      </h1>
+      <p className="Dialog-message">
+        {props.message}
+      </p>
+    </FancyBorder>
+  );
+}
+
+function WelcomeDialog() {
+  return (
+    <Dialog
+      title="Welcome"
+      message="Thank you for visiting our spacecraft!" />
+  );
+}
+```
+
+[Try it on CodePen.](http://codepen.io/gaearon/pen/kkEaOZ?editors=0010)
+
+Composition works equally well for components defined as classes:
+
+```js{10,27-31}
+function Dialog(props) {
+  return (
+    <FancyBorder color="blue">
+      <h1 className="Dialog-title">
+        {props.title}
+      </h1>
+      <p className="Dialog-message">
+        {props.message}
+      </p>
+      {props.children}
+    </FancyBorder>
+  );
+}
+
+class SignUpDialog extends React.Component {
+  constructor(props) {
+    super(props);
+    this.handleChange = this.handleChange.bind(this);
+    this.handleSignUp = this.handleSignUp.bind(this);
+    this.state = {login: ''};
+  }
+
+  render() {
+    return (
+      <Dialog title="Mars Exploration Program"
+              message="How should we refer to you?">
+        <input value={this.state.login}
+               onChange={this.handleChange} />
+        <button onClick={this.handleSignUp}>
+          Sign Me Up!
+        </button>
+      </Dialog>
+    );
+  }
+
+  handleChange(e) {
+    this.setState({login: e.target.value});
+  }
+
+  handleSignUp() {
+    alert(`Welcome aboard, ${this.state.login}!`);
+  }
+}
+```
+
+[Try it on CodePen.](http://codepen.io/gaearon/pen/gwZbYa?editors=0010)
+
+## So What About Inheritance?
+
+At Facebook, we use React in thousands of components, and we haven't found any use cases where we would recommend creating component inheritance hierarchies.
+
+Props and composition give you all the flexibility you need to customize a component's look and behavior in an explicit and safe way. Remember that components may accept arbitrary props, including primitive values, React elements, or functions.
+
+If you want to reuse non-UI functionality between components, we suggest extracting it into a separate JavaScript module. The components may import it and use that function, object, or a class, without extending it.
diff --git a/docs/docs/conditional-rendering.md b/docs/docs/conditional-rendering.md
new file mode 100644
index 000000000000..ea1be02a4c85
--- /dev/null
+++ b/docs/docs/conditional-rendering.md
@@ -0,0 +1,242 @@
+---
+id: conditional-rendering
+title: Conditional Rendering
+permalink: docs/conditional-rendering.html
+prev: handling-events.html
+next: lists-and-keys.html
+redirect_from: "tips/false-in-jsx.html"
+---
+
+In React, you can create distinct components that encapsulate behavior you need. Then, you can render only some of them, depending on the state of your application.
+
+Conditional rendering in React works the same way conditions work in JavaScript. Use JavaScript operators like [`if`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else) or the [conditional operator](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) to create elements representing the current state, and let React update the UI to match them.
+
+Consider these two components:
+
+```js
+function UserGreeting(props) {
+  return <h1>Welcome back!</h1>;
+}
+
+function GuestGreeting(props) {
+  return <h1>Please sign up.</h1>;
+}
+```
+
+We'll create a `Greeting` component that displays either of these components depending on whether a user is logged in:
+
+```javascript{3-7,11,12}
+function Greeting(props) {
+  const isLoggedIn = props.isLoggedIn;
+  if (isLoggedIn) {
+    return <UserGreeting />;
+  }
+  return <GuestGreeting />;
+}
+
+ReactDOM.render(
+  // Try changing to isLoggedIn={true}:
+  <Greeting isLoggedIn={false} />,
+  document.getElementById('root')
+);
+```
+
+[Try it on CodePen.](https://codepen.io/gaearon/pen/ZpVxNq?editors=0011)
+
+This example renders a different greeting depending on the value of `isLoggedIn` prop.
+
+### Element Variables
+
+You can use variables to store elements. This can help you conditionally render a part of the component while the rest of the output doesn't change.
+
+Consider these two new components representing Logout and Login buttons:
+
+```js
+function LoginButton(props) {
+  return (
+    <button onClick={props.onClick}>
+      Login
+    </button>
+  );
+}
+
+function LogoutButton(props) {
+  return (
+    <button onClick={props.onClick}>
+      Logout
+    </button>
+  );
+}
+```
+
+In the example below, we will create a [stateful component](/react/docs/state-and-lifecycle.html#adding-local-state-to-a-class) called `LoginControl`.
+
+It will render either `<LoginButton />` or `<LogoutButton />` depending on its current state. It will also render a `<Greeting />` from the previous example:
+
+```javascript{20-25,29,30}
+class LoginControl extends React.Component {
+  constructor(props) {
+    super(props);
+    this.handleLoginClick = this.handleLoginClick.bind(this);
+    this.handleLogoutClick = this.handleLogoutClick.bind(this);
+    this.state = {isLoggedIn: false};
+  }
+
+  handleLoginClick() {
+    this.setState({isLoggedIn: true});
+  }
+
+  handleLogoutClick() {
+    this.setState({isLoggedIn: false});
+  }
+
+  render() {
+    const isLoggedIn = this.state.isLoggedIn;
+
+    let button = null;
+    if (isLoggedIn) {
+      button = <LogoutButton onClick={this.handleLogoutClick} />;
+    } else {
+      button = <LoginButton onClick={this.handleLoginClick} />;
+    }
+
+    return (
+      <div>
+        <Greeting isLoggedIn={isLoggedIn} />
+        {button}
+      </div>
+    );
+  }
+}
+
+ReactDOM.render(
+  <LoginControl />,
+  document.getElementById('root')
+);
+```
+
+[Try it on CodePen.](https://codepen.io/gaearon/pen/QKzAgB?editors=0010)
+
+While declaring a variable and using an `if` statement is a fine way to conditionally render a component, sometimes you might want to use a shorter syntax. There are a few ways to inline conditions in JSX, explained below.
+
+### Inline If with Logical && Operator
+
+You may [embed any expressions in JSX](/react/docs/introducing-jsx.html#embedding-expressions-in-jsx) by wrapping them in curly braces. This includes the JavaScript logical `&&` operator. It can be handy for conditionally including an element:
+
+```js{6-10}
+function Mailbox(props) {
+  const unreadMessages = props.unreadMessages;
+  return (
+    <div>
+      <h1>Hello!</h1>
+      {unreadMessages.length > 0 &&
+        <h2>
+          You have {unreadMessages.length} unread messages.
+        </h2>
+      }
+    </div>
+  );
+}
+
+const messages = ['React', 'Re: React', 'Re:Re: React'];
+ReactDOM.render(
+  <Mailbox unreadMessages={messages} />,
+  document.getElementById('root')
+);
+```
+
+[Try it on CodePen.](https://codepen.io/gaearon/pen/ozJddz?editors=0010)
+
+It works because in JavaScript, `true && expression` always evaluates to `expression`, and `false && expression` always evaluates to `false`.
+
+Therefore, if the condition is `true`, the element right after `&&` will appear in the output. If it is `false`, React will ignore and skip it.
+
+### Inline If-Else with Conditional Operator
+
+Another method for conditionally rendering elements inline is to use the JavaScript conditional operator [`condition ? true : false`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Conditional_Operator).
+
+In the example below, we use it to conditionally render a small block of text.
+
+```javascript{5}
+render() {
+  const isLoggedIn = this.state.isLoggedIn;
+  return (
+    <div>
+      The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
+    </div>
+  );
+}
+```
+
+It can also be used for larger expressions although it is less obvious what's going on:
+
+```js{5,7,9}
+render() {
+  const isLoggedIn = this.state.isLoggedIn;
+  return (
+    <div>
+      {isLoggedIn ? (
+        <LogoutButton onClick={this.handleLogoutClick} />
+      ) : (
+        <LoginButton onClick={this.handleLoginClick} />
+      )}
+    </div>
+  );
+}
+```
+
+Just like in JavaScript, it is up to you to choose an appropriate style based on what you and your team consider more readable. Also remember that whenever conditions become too complex, it might be a good time to [extract a component](/react/docs/components-and-props.html#extracting-components).
+
+### Preventing Component from Rendering
+
+In rare cases you might want a component to hide itself even though it was rendered by another component. To do this return `null` instead of its render output.
+
+In the example below, the `<WarningBanner />` is rendered depending on the value of the prop called `warn`. If the value of the prop is `false`, then the component does not render:
+
+```javascript{2-4,29}
+function WarningBanner(props) {
+  if (!props.warn) {
+    return null;
+  }
+
+  return (
+    <div className="warning">
+      Warning!
+    </div>
+  );
+}
+
+class Page extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {showWarning: true}
+    this.handleToggleClick = this.handleToggleClick.bind(this);
+  }
+
+  handleToggleClick() {
+    this.setState(prevState => ({
+      showWarning: !prevState.showWarning
+    }));
+  }
+
+  render() {
+    return (
+      <div>
+        <WarningBanner warn={this.state.showWarning} />
+        <button onClick={this.handleToggleClick}>
+          {this.state.showWarning ? 'Hide' : 'Show'}
+        </button>
+      </div>
+    );
+  }
+}
+
+ReactDOM.render(
+  <Page />,
+  document.getElementById('root')
+);
+```
+
+[Try it on CodePen.](https://codepen.io/gaearon/pen/Xjoqwm?editors=0010)
+
+Returning `null` from a component's `render` method does not affect the firing of the component's lifecycle methods. For instance, `componentWillUpdate` and `componentDidUpdate` will still be called.
diff --git a/docs/docs/conferences.it-IT.md b/docs/docs/conferences.it-IT.md
deleted file mode 100644
index 9a38a6c79f59..000000000000
--- a/docs/docs/conferences.it-IT.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-id: conferences-it-IT
-title: Conferenze
-permalink: conferences-it-IT.html
-prev: thinking-in-react-it-IT.html
-next: videos-it-IT.html
----
-
-### React.js Conf 2015
-28 e 29 Gennaio
-
-[Sito web](http://conf.reactjs.com/) - [Agenda](http://conf.reactjs.com/schedule.html) - [Video](https://www.youtube-nocookie.com/playlist?list=PLb0IAmt7-GS1cbw4qonlQztYV1TAW0sCr)
-
-<iframe width="650" height="315" src="//www.youtube-nocookie.com/embed/KVZ-P-ZI6W4?list=PLb0IAmt7-GS1cbw4qonlQztYV1TAW0sCr" frameborder="0" allowfullscreen></iframe>
-
-### ReactEurope 2015
-2 e 3 Luglio
-
-[Sito web](http://www.react-europe.org/) - [Agenda](http://www.react-europe.org/#schedule)
diff --git a/docs/docs/conferences.ko-KR.md b/docs/docs/conferences.ko-KR.md
deleted file mode 100644
index 56502080a60e..000000000000
--- a/docs/docs/conferences.ko-KR.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-id: conferences-ko-KR
-title: 컨퍼런스들
-permalink: conferences-ko-KR.html
-prev: thinking-in-react-ko-KR.html
-next: videos-ko-KR.html
----
-
-### React.js Conf 2015
-1월 28일 & 29일
-
-[웹사이트](http://conf.reactjs.com/) - [스케줄](http://conf.reactjs.com/schedule.html) - [비디오들](https://www.youtube-nocookie.com/playlist?list=PLb0IAmt7-GS1cbw4qonlQztYV1TAW0sCr)
-
-<iframe width="650" height="315" src="//www.youtube-nocookie.com/embed/KVZ-P-ZI6W4?list=PLb0IAmt7-GS1cbw4qonlQztYV1TAW0sCr" frameborder="0" allowfullscreen></iframe>
-
-### ReactEurope 2015
-7월 2일 & 3일
-
-[웹사이트](http://www.react-europe.org/) - [스케줄](http://www.react-europe.org/#schedule)
diff --git a/docs/docs/conferences.md b/docs/docs/conferences.md
deleted file mode 100644
index 3556f933c130..000000000000
--- a/docs/docs/conferences.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-id: conferences
-title: Conferences
-permalink: conferences.html
-prev: thinking-in-react.html
-next: videos.html
----
-
-### React.js Conf 2015
-January 28 & 29
-
-[Website](http://conf2015.reactjs.org/) - [Schedule](http://conf2015.reactjs.org/schedule.html) - [Videos](https://www.youtube.com/playlist?list=PLb0IAmt7-GS1cbw4qonlQztYV1TAW0sCr)
-
-<iframe width="650" height="315" src="//www.youtube-nocookie.com/embed/KVZ-P-ZI6W4?list=PLb0IAmt7-GS1cbw4qonlQztYV1TAW0sCr" frameborder="0" allowfullscreen></iframe>
-
-### ReactEurope 2015
-July 2 & 3
-
-[Website](http://www.react-europe.org/) - [Schedule](http://www.react-europe.org/#schedule)
-
-### Reactive 2015
-November 2-4
-
-[Website](https://reactive2015.com/) - [Schedule](https://reactive2015.com/schedule_speakers.html#schedule)
-
-### React.js Conf 2016
-February 22 & 23
-
-[Website](http://conf.reactjs.com/) - [Schedule](http://conf.reactjs.com/schedule.html) - [Videos](https://www.youtube.com/playlist?list=PLb0IAmt7-GS0M8Q95RIc2lOM6nc77q1IY)
-
-### ReactEurope 2016
-June 2 & 3
-
-[Website](http://www.react-europe.org/) - [Schedule](http://www.react-europe.org/#schedule)
diff --git a/docs/docs/context.md b/docs/docs/context.md
new file mode 100644
index 000000000000..718e941a0641
--- /dev/null
+++ b/docs/docs/context.md
@@ -0,0 +1,213 @@
+---
+id: context
+title: Context
+permalink: docs/context.html
+---
+
+>Note:
+> As of React v15.5 the `React.PropTypes` helper is deprecated, and we recommend using the [`prop-types` library](https://www.npmjs.com/package/prop-types) to define `contextTypes`.
+
+With React, it's easy to track the flow of data through your React components. When you look at a component, you can see which props are being passed, which makes your apps easy to reason about.
+
+In some cases, you want to pass data through the component tree without having to pass the props down manually at every level.
+You can do this directly in React with the powerful "context" API.
+
+
+## Why Not To Use Context
+
+The vast majority of applications do not need to use context.
+
+If you want your application to be stable, don't use context. It is an experimental API and it is likely to break in future releases of React.
+
+If you aren't familiar with state management libraries like [Redux](https://github.com/reactjs/redux) or [MobX](https://github.com/mobxjs/mobx), don't use context. For many practical applications, these libraries and their React bindings are a good choice for managing state that is relevant to many components. It is far more likely that Redux is the right solution to your problem than that context is the right solution.
+
+If you aren't an experienced React developer, don't use context. There is usually a better way to implement functionality just using props and state.
+
+If you insist on using context despite these warnings, try to isolate your use of context to a small area and avoid using the context API directly when possible so that it's easier to upgrade when the API changes.
+
+## How To Use Context
+
+Suppose you have a structure like:
+
+```javascript
+class Button extends React.Component {
+  render() {
+    return (
+      <button style={{'{{'}}background: this.props.color}}>
+        {this.props.children}
+      </button>
+    );
+  }
+}
+
+class Message extends React.Component {
+  render() {
+    return (
+      <div>
+        {this.props.text} <Button color={this.props.color}>Delete</Button>
+      </div>
+    );
+  }
+}
+
+class MessageList extends React.Component {
+  render() {
+    const color = "purple";
+    const children = this.props.messages.map((message) =>
+      <Message text={message.text} color={color} />
+    );
+    return <div>{children}</div>;
+  }
+}
+```
+
+In this example, we manually thread through a `color` prop in order to style the `Button` and `Message` components appropriately. Using context, we can pass this through the tree automatically:
+
+```javascript{6,13-15,21,28-30,40-42}
+const PropTypes = require('prop-types');
+
+class Button extends React.Component {
+  render() {
+    return (
+      <button style={{'{{'}}background: this.context.color}}>
+        {this.props.children}
+      </button>
+    );
+  }
+}
+
+Button.contextTypes = {
+  color: PropTypes.string
+};
+
+class Message extends React.Component {
+  render() {
+    return (
+      <div>
+        {this.props.text} <Button>Delete</Button>
+      </div>
+    );
+  }
+}
+
+class MessageList extends React.Component {
+  getChildContext() {
+    return {color: "purple"};
+  }
+
+  render() {
+    const children = this.props.messages.map((message) =>
+      <Message text={message.text} />
+    );
+    return <div>{children}</div>;
+  }
+}
+
+MessageList.childContextTypes = {
+  color: PropTypes.string
+};
+```
+
+By adding `childContextTypes` and `getChildContext` to `MessageList` (the context provider), React passes the information down automatically and any component in the subtree (in this case, `Button`) can access it by defining `contextTypes`.
+
+If `contextTypes` is not defined, then `context` will be an empty object.
+
+## Parent-Child Coupling
+
+Context can also let you build an API where parents and children communicate. For example, one library that works this way is [React Router V4](https://reacttraining.com/react-router):
+
+```javascript
+import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
+
+const BasicExample = () => (
+  <Router>
+    <div>
+      <ul>
+        <li><Link to="/">Home</Link></li>
+        <li><Link to="/about">About</Link></li>
+        <li><Link to="/topics">Topics</Link></li>
+      </ul>
+
+      <hr />
+
+      <Route exact path="/" component={Home} />
+      <Route path="/about" component={About} />
+      <Route path="/topics" component={Topics} />
+    </div>
+  </Router>
+);
+```
+
+By passing down some information from the `Router` component, each `Link` and `Route` can communicate back to the containing `Router`.
+
+Before you build components with an API similar to this, consider if there are cleaner alternatives. For example, you can pass entire React component as props if you'd like to.
+
+## Referencing Context in Lifecycle Methods
+
+If `contextTypes` is defined within a component, the following [lifecycle methods](/react/docs/react-component.html#the-component-lifecycle) will receive an additional parameter, the `context` object:
+
+- [`constructor(props, context)`](/react/docs/react-component.html#constructor)
+- [`componentWillReceiveProps(nextProps, nextContext)`](/react/docs/react-component.html#componentwillreceiveprops)
+- [`shouldComponentUpdate(nextProps, nextState, nextContext)`](/react/docs/react-component.html#shouldcomponentupdate)
+- [`componentWillUpdate(nextProps, nextState, nextContext)`](/react/docs/react-component.html#componentwillupdate)
+- [`componentDidUpdate(prevProps, prevState, prevContext)`](/react/docs/react-component.html#componentdidupdate)
+
+## Referencing Context in Stateless Functional Components
+
+Stateless functional components are also able to reference `context` if `contextTypes` is defined as a property of the function. The following code shows a `Button` component written as a stateless functional component.
+
+```javascript
+const PropTypes = require('prop-types');
+
+const Button = ({children}, context) =>
+  <button style={{'{{'}}background: context.color}}>
+    {children}
+  </button>;
+
+Button.contextTypes = {color: PropTypes.string};
+```
+
+## Updating Context
+
+Don't do it.
+
+React has an API to update context, but it is fundamentally broken and you should not use it.
+
+The `getChildContext` function will be called when the state or props changes. In order to update data in the context, trigger a local state update with `this.setState`. This will trigger a new context and changes will be received by the children.
+
+```javascript
+const PropTypes = require('prop-types');
+
+class MediaQuery extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {type:'desktop'};
+  }
+
+  getChildContext() {
+    return {type: this.state.type};
+  }
+
+  componentDidMount() {
+    const checkMediaQuery = () => {
+      const type = window.matchMedia("(min-width: 1025px)").matches ? 'desktop' : 'mobile';
+      if (type !== this.state.type) {
+        this.setState({type});
+      }
+    };
+
+    window.addEventListener('resize', checkMediaQuery);
+    checkMediaQuery();
+  }
+
+  render() {
+    return this.props.children;
+  }
+}
+
+MediaQuery.childContextTypes = {
+  type: PropTypes.string
+};
+```
+
+The problem is, if a context value provided by component changes, descendants that use that value won't update if an intermediate parent returns `false` from `shouldComponentUpdate`. This is totally out of control of the components using context, so there's basically no way to reliably update the context. [This blog post](https://medium.com/@mweststrate/how-to-safely-use-react-context-b7e343eff076) has a good explanation of why this is a problem and how you might get around it.
diff --git a/docs/docs/error-decoder.md b/docs/docs/error-decoder.md
new file mode 100644
index 000000000000..8623bf5e1c35
--- /dev/null
+++ b/docs/docs/error-decoder.md
@@ -0,0 +1,13 @@
+---
+id: error-decoder
+title: Error Decoder
+permalink: docs/error-decoder.html
+---
+
+In the minified production build of React, we avoid sending down full error messages in order to reduce the number of bytes sent over the wire.
+
+We highly recommend using the development build locally when debugging your app since it tracks additional debug info and provides helpful warnings about potential problems in your apps, but if you encounter an exception while using the production build, this page will reassemble the original text of the error.
+
+<script src="/react/js/errorMap.js"></script>
+<div class="error-decoder-container"></div>
+<script src="/react/js/ErrorDecoderComponent.js"></script>
diff --git a/docs/docs/examples.it-IT.md b/docs/docs/examples.it-IT.md
deleted file mode 100644
index 7166c57bbe70..000000000000
--- a/docs/docs/examples.it-IT.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-permalink: examples-it-IT.html
-layout: redirect
-dest_url: https://github.com/facebook/react/wiki/Examples
----
diff --git a/docs/docs/examples.ko-KR.md b/docs/docs/examples.ko-KR.md
deleted file mode 100644
index 3b46fa57d203..000000000000
--- a/docs/docs/examples.ko-KR.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-permalink: examples-ko-KR.html
-layout: redirect
-dest_url: https://github.com/facebook/react/wiki/Examples
----
diff --git a/docs/docs/examples.md b/docs/docs/examples.md
deleted file mode 100644
index c697ffdf5f41..000000000000
--- a/docs/docs/examples.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-permalink: examples.html
-layout: redirect
-dest_url: https://github.com/facebook/react/wiki/Examples
----
diff --git a/docs/docs/examples.zh-CN.md b/docs/docs/examples.zh-CN.md
deleted file mode 100644
index 057bedb9e63a..000000000000
--- a/docs/docs/examples.zh-CN.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-permalink: examples-zh-CN.html
-layout: redirect
-dest_url: https://github.com/facebook/react/wiki/Examples
----
diff --git a/docs/docs/flux-overview.it-IT.md b/docs/docs/flux-overview.it-IT.md
deleted file mode 100644
index 7e437de5dfdc..000000000000
--- a/docs/docs/flux-overview.it-IT.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-id: flux-overview-it-IT
-title: Architettura di un'Applicazione Flux
-permalink: flux-overview-it-IT.html
----
-
-Questa pagina è stata spostata sul sito di Flux. [Leggila qui](https://facebook.github.io/flux/docs/overview.html).
diff --git a/docs/docs/flux-overview.ko-KR.md b/docs/docs/flux-overview.ko-KR.md
deleted file mode 100644
index 6129d9655662..000000000000
--- a/docs/docs/flux-overview.ko-KR.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-id: flux-overview-ko-KR
-title: Flux 애플리케이션 아키텍쳐
-permalink: flux-overview-ko-KR.html
----
-
-이 페이지는 Flux 웹사이트로 이동되었습니다. [거기서 보세요](https://facebook.github.io/flux/docs/overview.html).
diff --git a/docs/docs/flux-overview.md b/docs/docs/flux-overview.md
deleted file mode 100644
index aa62b4772115..000000000000
--- a/docs/docs/flux-overview.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-id: flux-overview
-title: Flux Application Architecture
-permalink: flux-overview.html
----
-
-This page has been moved to the Flux website. [View it there](https://facebook.github.io/flux/docs/overview.html).
diff --git a/docs/docs/flux-overview.zh-CN.md b/docs/docs/flux-overview.zh-CN.md
deleted file mode 100644
index fe3287c96186..000000000000
--- a/docs/docs/flux-overview.zh-CN.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-id: flux-overview-zh-CN
-title: Flux 应用架构
-permalink: flux-overview-zh-CN.html
----
-
-本页被移到了 Flux 网站。[点击访问](https://facebook.github.io/flux/docs/overview.html)。
diff --git a/docs/docs/flux-todo-list.it-IT.md b/docs/docs/flux-todo-list.it-IT.md
deleted file mode 100644
index 376f6c91d306..000000000000
--- a/docs/docs/flux-todo-list.it-IT.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-id: flux-todo-list-it-IT
-title: Tutorial TodoMVC Flux
-permalink: flux-todo-list-it-IT.html
----
-
-Questa pagina è stata spostata sul sito di Flux. [Leggila qui](https://facebook.github.io/flux/docs/todo-list.html).
diff --git a/docs/docs/flux-todo-list.ko-KR.md b/docs/docs/flux-todo-list.ko-KR.md
deleted file mode 100644
index 327be3889763..000000000000
--- a/docs/docs/flux-todo-list.ko-KR.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-id: flux-todo-list-ko-KR
-title: Flux TodoMVC 튜토리얼
-permalink: flux-todo-list-ko-KR.html
----
-
-이 페이지는 Flux 웹사이트로 이동되었습니다. [거기서 보세요](https://facebook.github.io/flux/docs/todo-list.html).
diff --git a/docs/docs/flux-todo-list.md b/docs/docs/flux-todo-list.md
deleted file mode 100644
index 8c7827f26de5..000000000000
--- a/docs/docs/flux-todo-list.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-id: flux-todo-list
-title: Flux TodoMVC Tutorial
-permalink: flux-todo-list.html
----
-
-This page has been moved to the Flux website. [View it there](https://facebook.github.io/flux/docs/todo-list.html).
diff --git a/docs/docs/flux-todo-list.zh-CN.md b/docs/docs/flux-todo-list.zh-CN.md
deleted file mode 100644
index 076e4af9fb6a..000000000000
--- a/docs/docs/flux-todo-list.zh-CN.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-id: flux-todo-list-zh-CN
-title: Flux TodoMVC 教程
-permalink: flux-todo-list-zh-CN.html
----
-
-本页被移到了 Flux 网站。[点击访问](https://facebook.github.io/flux/docs/todo-list.html)。
diff --git a/docs/docs/forms.md b/docs/docs/forms.md
new file mode 100644
index 000000000000..c806a97a6528
--- /dev/null
+++ b/docs/docs/forms.md
@@ -0,0 +1,261 @@
+---
+id: forms
+title: Forms
+permalink: docs/forms.html
+prev: lists-and-keys.html
+next: lifting-state-up.html
+redirect_from:
+  - "tips/controlled-input-null-value.html"
+  - "docs/forms-zh-CN.html"
+---
+
+HTML form elements work a little bit differently from other DOM elements in React, because form elements naturally keep some internal state. For example, this form in plain HTML accepts a single name:
+
+```html
+<form>
+  <label>
+    Name:
+    <input type="text" name="name" />
+  </label>
+  <input type="submit" value="Submit" />
+</form>
+```
+
+This form has the default HTML form behavior of browsing to a new page when the user submits the form. If you want this behavior in React, it just works. But in most cases, it's convenient to have a JavaScript function that handles the submission of the form and has access to the data that the user entered into the form. The standard way to achieve this is with a technique called "controlled components".
+
+## Controlled Components
+
+In HTML, form elements such as `<input>`, `<textarea>`, and `<select>` typically maintain their own state and update it based on user input. In React, mutable state is typically kept in the state property of components, and only updated with [`setState()`](/react/docs/react-component.html#setstate).
+
+We can combine the two by making the React state be the "single source of truth". Then the React component that renders a form also controls what happens in that form on subsequent user input. An input form element whose value is controlled by React in this way is called a "controlled component".
+
+For example, if we want to make the previous example log the name when it is submitted, we can write the form as a controlled component:
+
+```javascript{4,10-12,24}
+class NameForm extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {value: ''};
+
+    this.handleChange = this.handleChange.bind(this);
+    this.handleSubmit = this.handleSubmit.bind(this);
+  }
+
+  handleChange(event) {
+    this.setState({value: event.target.value});
+  }
+
+  handleSubmit(event) {
+    alert('A name was submitted: ' + this.state.value);
+    event.preventDefault();
+  }
+
+  render() {
+    return (
+      <form onSubmit={this.handleSubmit}>
+        <label>
+          Name:
+          <input type="text" value={this.state.value} onChange={this.handleChange} />
+        </label>
+        <input type="submit" value="Submit" />
+      </form>
+    );
+  }
+}
+```
+
+[Try it on CodePen.](https://codepen.io/gaearon/pen/VmmPgp?editors=0010)
+
+Since the `value` attribute is set on our form element, the displayed value will always be `this.state.value`, making the React state the source of truth. Since `handleChange` runs on every keystroke to update the React state, the displayed value will update as the user types.
+
+With a controlled component, every state mutation will have an associated handler function. This makes it straightforward to modify or validate user input. For example, if we wanted to enforce that names are written with all uppercase letters, we could write `handleChange` as:
+
+```javascript{2}
+handleChange(event) {
+  this.setState({value: event.target.value.toUpperCase()});
+}
+```
+
+## The textarea Tag
+
+In HTML, a `<textarea>` element defines its text by its children:
+
+```html
+<textarea>
+  Hello there, this is some text in a text area
+</textarea>
+```
+
+In React, a `<textarea>` uses a `value` attribute instead. This way, a form using a `<textarea>` can be written very similarly to a form that uses a single-line input:
+
+```javascript{4-6,12-14,26}
+class EssayForm extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      value: 'Please write an essay about your favorite DOM element.'
+    };
+
+    this.handleChange = this.handleChange.bind(this);
+    this.handleSubmit = this.handleSubmit.bind(this);
+  }
+
+  handleChange(event) {
+    this.setState({value: event.target.value});
+  }
+
+  handleSubmit(event) {
+    alert('An essay was submitted: ' + this.state.value);
+    event.preventDefault();
+  }
+
+  render() {
+    return (
+      <form onSubmit={this.handleSubmit}>
+        <label>
+          Name:
+          <textarea value={this.state.value} onChange={this.handleChange} />
+        </label>
+        <input type="submit" value="Submit" />
+      </form>
+    );
+  }
+}
+```
+
+Notice that `this.state.value` is initialized in the constructor, so that the text area starts off with some text in it.
+
+## The select Tag
+
+In HTML, `<select>` creates a drop-down list. For example, this HTML creates a drop-down list of flavors:
+
+```html
+<select>
+  <option value="grapefruit">Grapefruit</option>
+  <option value="lime">Lime</option>
+  <option selected value="coconut">Coconut</option>
+  <option value="mango">Mango</option>
+</select>
+```
+
+Note that the Coconut option is initially selected, because of the `selected` attribute. React, instead of using this `selected` attribute, uses a `value` attribute on the root `select` tag. This is more convenient in a controlled component because you only need to update it in one place. For example:
+
+```javascript{4,10-12,24}
+class FlavorForm extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {value: 'coconut'};
+
+    this.handleChange = this.handleChange.bind(this);
+    this.handleSubmit = this.handleSubmit.bind(this);
+  }
+
+  handleChange(event) {
+    this.setState({value: event.target.value});
+  }
+
+  handleSubmit(event) {
+    alert('Your favorite flavor is: ' + this.state.value);
+    event.preventDefault();
+  }
+
+  render() {
+    return (
+      <form onSubmit={this.handleSubmit}>
+        <label>
+          Pick your favorite La Croix flavor:
+          <select value={this.state.value} onChange={this.handleChange}>
+            <option value="grapefruit">Grapefruit</option>
+            <option value="lime">Lime</option>
+            <option value="coconut">Coconut</option>
+            <option value="mango">Mango</option>
+          </select>
+        </label>
+        <input type="submit" value="Submit" />
+      </form>
+    );
+  }
+}
+```
+
+[Try it on CodePen.](https://codepen.io/gaearon/pen/JbbEzX?editors=0010)
+
+Overall, this makes it so that `<input type="text">`, `<textarea>`, and `<select>` all work very similarly - they all accept a `value` attribute that you can use to implement a controlled component.
+
+## Handling Multiple Inputs
+
+When you need to handle multiple controlled `input` elements, you can add a `name` attribute to each element and let the handler function choose what to do based on the value of `event.target.name`.
+
+For example:
+
+```javascript{15,18,28,37}
+class Reservation extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      isGoing: true,
+      numberOfGuests: 2
+    };
+
+    this.handleInputChange = this.handleInputChange.bind(this);
+  }
+
+  handleInputChange(event) {
+    const target = event.target;
+    const value = target.type === 'checkbox' ? target.checked : target.value;
+    const name = target.name;
+
+    this.setState({
+      [name]: value
+    });
+  }
+
+  render() {
+    return (
+      <form>
+        <label>
+          Is going:
+          <input
+            name="isGoing"
+            type="checkbox"
+            checked={this.state.isGoing}
+            onChange={this.handleInputChange} />
+        </label>
+        <br />
+        <label>
+          Number of guests:
+          <input
+            name="numberOfGuests"
+            type="number"
+            value={this.state.numberOfGuests}
+            onChange={this.handleInputChange} />
+        </label>
+      </form>
+    );
+  }
+}
+```
+
+[Try it on CodePen.](https://codepen.io/gaearon/pen/wgedvV?editors=0010)
+
+Note how we used the ES6 [computed property name](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Object_initializer#Computed_property_names) syntax to update the state key corresponding to the given input name:
+
+```js{2}
+this.setState({
+  [name]: value
+});
+```
+
+It is equivalent to this ES5 code:
+
+```js{2}
+var partialState = {};
+partialState[name] = value;
+this.setState(partialState);
+```
+
+Also, since `setState()` automatically [merges a partial state into the current state](/react/docs/state-and-lifecycle.html#state-updates-are-merged), we only needed to call it with the changed parts.
+
+## Alternatives to Controlled Components
+
+It can sometimes be tedious to use controlled components, because you need to write an event handler for every way your data can change and pipe all of the input state through a React component. This can become particularly annoying when you are converting a preexisting codebase to React, or integrating a React application with a non-React library. In these situations, you might want to check out [uncontrolled components](/react/docs/uncontrolled-components.html), an alternative technique for implementing input forms.
diff --git a/docs/docs/getting-started.it-IT.md b/docs/docs/getting-started.it-IT.md
deleted file mode 100644
index 1c572cbfe1c9..000000000000
--- a/docs/docs/getting-started.it-IT.md
+++ /dev/null
@@ -1,123 +0,0 @@
----
-id: getting-started-it-IT
-title: Primi Passi
-permalink: getting-started-it-IT.html
-next: tutorial-it-IT.html
-redirect_from: "docs/index.html"
----
-
-## JSFiddle
-
-La maniera più semplice di cominciare ad hackerare con React è usare i seguenti esempi di Hello World su JSFiddle:
-
- * **[React JSFiddle](https://jsfiddle.net/reactjs/69z2wepo/)**
- * [React JSFiddle senza JSX](https://jsfiddle.net/reactjs/5vjqabv3/)
-
-## Starter Kit
-
-Scarica lo starter kit per cominciare.
-
-<div class="buttons-unit downloads">
-  <a href="/react/downloads/react-{{site.react_version}}.zip" class="button">
-    Scarica lo Starter Kit {{site.react_version}}
-  </a>
-</div>
-
-Nella directory principale dello starter kit, crea `helloworld.html` con il seguente contenuto.
-
-```html
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="UTF-8" />
-    <title>Ciao React!</title>
-    <script src="build/react.js"></script>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
-  </head>
-  <body>
-    <div id="example"></div>
-    <script type="text/babel">
-      ReactDOM.render(
-        <h1>Cial, mondo!</h1>,
-        document.getElementById('example')
-      );
-    </script>
-  </body>
-</html>
-```
-
-La sintassi XML all'interno di JavaScript è chiamata JSX; dài un'occhiata alla [sintassi JSX](/react/docs/jsx-in-depth.html) per saperne di più. Allo scopo di tradurla in puro JavaScript usiamo `<script type="text/babel">` e includiamo Babel per effettuare la trasformazione effettiva nel browser.
-
-### File Separato
-
-Il tuo codice React JSX può trovarsi in un file a parte. Crea il seguente `src/helloworld.js`.
-
-```javascript
-ReactDOM.render(
-  <h1>Ciao, mondo!</h1>,
-  document.getElementById('example')
-);
-```
-
-Quindi fai riferimento ad esso da `helloworld.html`:
-
-```html{10}
-<script type="text/babel" src="src/helloworld.js"></script>
-```
-
-Nota che in alcuni browsers (Chrome, ad esempio) falliranno nel caricamento del file a meno che non sia servito tramite HTTP.
-
-### Trasformazione Offline
-
-Anzitutto installa gli strumenti da riga di comando di [Babel](http://babeljs.io/) (è richiesto [npm](https://www.npmjs.com/)):
-
-```
-npm install --global babel
-```
-
-Quindi, traduci il tuo file `src/helloworld.js` a semplice JavaScript:
-
-```
-babel src --watch --out-dir build
-
-```
-
-Il file `build/helloworld.js` è generato automaticamente ogni qualvolta effettui un cambiamento. Leggi la [documentazione di Babel CLI](http://babeljs.io/docs/usage/cli/) per un uso più avanzato.
-
-```javascript{2}
-ReactDOM.render(
-  React.createElement('h1', null, 'Ciao, mondo!'),
-  document.getElementById('example')
-);
-```
-
-
-Aggiorna il tuo file HTML come segue:
-
-```html{7,11}
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="UTF-8" />
-    <title>Ciao React!</title>
-    <script src="build/react.js"></script>
-    <!-- Non c'è bisogno di Babel! -->
-  </head>
-  <body>
-    <div id="example"></div>
-    <script src="build/helloworld.js"></script>
-  </body>
-</html>
-```
-
-## Vuoi CommonJS?
-
-Se vuoi usare React con [browserify](http://browserify.org/), [webpack](https://webpack.github.io/), o un altro sistema modulare compatibile con CommonJS, usa il [pacchetto npm `react`](https://www.npmjs.com/package/react). In aggiunta, lo strumento di build `jsx` può essere integrato in quasi tutti i sistemi di packaging (non soltanto CommonJS) assai facilmente.
-
-## Passi Successivi
-
-Dài un'occhiata [al tutorial](/react/docs/tutorial-it-IT.html) e agli altri esempi nella directory `examples` dello starter kit per saperne di più.
-
-Abbiamo anche un wiki al quale la comunità contribuisce con [flussi di lavoro, componenti UI, routing, gestione dati etc.](https://github.com/facebook/react/wiki/Complementary-Tools)
-
-In bocca al lupo, e benvenuto/a!
diff --git a/docs/docs/getting-started.ja-JP.md b/docs/docs/getting-started.ja-JP.md
deleted file mode 100644
index b5b8e5f81eeb..000000000000
--- a/docs/docs/getting-started.ja-JP.md
+++ /dev/null
@@ -1,121 +0,0 @@
----
-id: getting-started-ja-JP
-title: 始めてみましょう
-permalink: getting-started-ja-JP.html
-next: tutorial-ja-JP.html
-redirect_from: "docs/index-ja-JP.html"
----
-
-## JSFiddle
-
-React でのハッキングを始めるにあたり、一番簡単なものとして次の JSFiddle で動いている Hello World の例を取り上げます。
-
- * **[React JSFiddle](https://jsfiddle.net/reactjs/69z2wepo/)**
- * [React JSFiddle without JSX](https://jsfiddle.net/reactjs/5vjqabv3/)
-
-## スターターキット
-
-始めるためにスターターキットをダウンロードしましょう。
-
-<div class="buttons-unit downloads">
-  <a href="/react/downloads/react-{{site.react_version}}.zip" class="button">
-    Download Starter Kit {{site.react_version}}
-  </a>
-</div>
-
-スターターキットのルートディレクトリに `helloworld.html` を作り、次のように書いてみましょう。
-
-```html
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="UTF-8" />
-    <title>Hello React!</title>
-    <script src="build/react.js"></script>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
-  </head>
-  <body>
-    <div id="example"></div>
-    <script type="text/babel">
-      ReactDOM.render(
-        <h1>Hello, world!</h1>,
-        document.getElementById('example')
-      );
-    </script>
-  </body>
-</html>
-```
-
-JavaScript の中に書かれた XML シンタックスは JSX と呼ばれるものです（JSX の詳しいことについては [JSX syntax](/react/docs/jsx-in-depth.html) を読んでください）。ここでは JSX から vanilla JavaScript への変換をブラウザ内で行わせるため、先程のコードには `<script type="text/jsx">` と書いており、加えて `JSXTransformer.js` を読み込ませています。
-
-### ファイルの分割
-
-React の JSX コードは別ファイルに分離することができます。 次のような `src/helloworld.js` を作ってみましょう。
-
-```javascript
-ReactDOM.render(
-  <h1>Hello, world!</h1>,
-  document.getElementById('example')
-);
-```
-
-それが終わったら、`helloworld.js` への参照を `helloworld.html` に書き込みましょう。
-
-```html{10}
-<script type="text/babel" src="src/helloworld.js"></script>
-```
-
-### オフラインでの変換
-
-まずはコマンドラインツールをインストールしましょう（[npm](https://www.npmjs.com/) が必要です）。
-
-```
-npm install -g react-tools
-```
-
-インストールが終わったら、先程書いた `src/helloworld.js` ファイルを生の JavaScript に変換してみましょう。
-
-```
-jsx --watch src/ build/
-
-```
-
-すると、`src/helloword.js` に変更を加えるごとに `build/helloworld.js` が自動で生成されるようになります。
-
-```javascript{2}
-ReactDOM.render(
-  React.createElement('h1', null, 'Hello, world!'),
-  document.getElementById('example')
-);
-```
-
-
-最後に HTML ファイルを以下のように書き換えましょう。
-
-```html{7,11}
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="UTF-8" />
-    <title>Hello React!</title>
-    <script src="build/react.js"></script>
-    <!-- Babel は必要ありません！ -->
-  </head>
-  <body>
-    <div id="example"></div>
-    <script src="build/helloworld.js"></script>
-  </body>
-</html>
-```
-
-## CommonJS を使うには
-
-React を [browserify](http://browserify.org/) や [webpack](https://webpack.github.io/)、または CommonJS 準拠の他のモジュールシステムと一緒に使いたい場合、 [`react` npm package](https://www.npmjs.com/package/react) を使ってみてください。また、`jsx` ビルドツールをパッケージングシステム（CommonJS に限らず）に導入することも非常に簡単です。
-
-## 次にすること
-
-[チュートリアル](/react/docs/tutorial-ja-JP.html) や、スターターキットの `examples` ディレクトリに入っている他の例を読んでみてください。
-
-また、[ワークフロー、UIコンポーネント、ルーティング、データマネジメントなど](https://github.com/facebook/react/wiki/Complementary-Tools)の方面で貢献しているコミュニティの wiki もあります。
-
-幸運を祈ります！React へようこそ！
diff --git a/docs/docs/getting-started.ko-KR.md b/docs/docs/getting-started.ko-KR.md
deleted file mode 100644
index 7a8eb4750354..000000000000
--- a/docs/docs/getting-started.ko-KR.md
+++ /dev/null
@@ -1,150 +0,0 @@
----
-id: getting-started-ko-KR
-title: 시작해보기
-permalink: getting-started-ko-KR.html
-next: tutorial-ko-KR.html
-redirect_from: "docs/index-ko-KR.html"
----
-
-## JSFiddle
-
-React를 시작하는 가장 빠른 방법은 다음의 Hello World JSFiddle 예제를 따라 해 보는 것입니다.
-
- * **[React JSFiddle](https://jsfiddle.net/reactjs/69z2wepo/)**
- * [React JSFiddle without JSX](https://jsfiddle.net/reactjs/5vjqabv3/)
-
-## npm으로 React 사용하기
-
-[browserify](http://browserify.org/), [webpack](https://webpack.github.io/) 같은 CommonJS 모듈 시스템과 함께 React를 사용하시는 것을 권장합니다. [`react`](https://www.npmjs.com/package/react), [`react-dom`](https://www.npmjs.com/package/react-dom) npm 패키지를 사용하세요.
-
-```js
-// main.js
-var React = require('react');
-var ReactDOM = require('react-dom');
-
-ReactDOM.render(
-  <h1>Hello, world!</h1>,
-  document.getElementById('example')
-);
-```
-
-browserify를 설치한 후에 React DOM을 설치하고 bundle을 빌드합니다.
-
-```sh
-$ npm install --save react react-dom babelify babel-preset-react
-$ browserify -t [ babelify --presets [ react ] ] main.js -o bundle.js
-```
-
-> 주의:
->
-> ES2015를 사용하고 있다면, `babel-preset-es2015` 패키지도 설치할 필요가 있습니다.
-
-## npm 없이 Quick Start 하기
-
-만약 당신이 npm을 사용할 준비가 아직 안되었다면, 미리빌드된 React와 React DOM 파일이 포함된 초심자용 키트를 다운로드 받을 수 있습니다.
-
-<div class="buttons-unit downloads">
-  <a href="/react/downloads/react-{{site.react_version}}.zip" class="button">
-   초심자용 키트 내려받기 {{site.react_version}}
-  </a>
-</div>
-
-초심자용 키트의 최상위 디렉터리에 아래의 내용대로 `helloworld.html` 파일을 생성합니다.
-
-```html
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="UTF-8" />
-    <title>Hello React!</title>
-    <script src="build/react.js"></script>
-    <script src="build/react-dom.js"></script>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
-  </head>
-  <body>
-    <div id="example"></div>
-    <script type="text/babel">
-      ReactDOM.render(
-        <h1>Hello, world!</h1>,
-        document.getElementById('example')
-      );
-    </script>
-  </body>
-</html>
-```
-
-JavaScript 안에 보이는 XML 구문은 JSX라고 합니다; 더 자세한 내용은 [JSX syntax](/react/docs/jsx-in-depth-ko-KR.html)을 확인하세요. 일반적인 JavaScript로 번역하기 위해 `<script type="text/babel">`를 사용하고 Babel을 포함하는 것으로 실제로 브라우저에서 변환작업을 수행합니다.
-
-### 파일의 분리
-
-React JSX 코드는 분리된 파일로 존재할 수 있습니다. 다음 내용으로 `src/helloworld.js`를 생성해보세요.
-
-```javascript
-ReactDOM.render(
-  <h1>Hello, world!</h1>,
-  document.getElementById('example')
-);
-```
-
-그다음 `helloworld.html`에서 참조합니다:
-
-```html{10}
-<script type="text/babel" src="src/helloworld.js"></script>
-```
-
-크롬 같은 몇몇 브라우저에서는 HTTP를 통해 제공되는 파일이 아니면 로드에 실패하므로 주의하세요.
-
-### 오프라인 변환
-
-먼저 [Babel](http://babeljs.io/) 커맨드라인 도구를 설치합니다. ([npm](https://www.npmjs.com/) 필요):
-
-```
-npm install --global babel-cli
-npm install babel-preset-react
-```
-
-그다음, `src/helloworld.js` 파일을 일반 JavaScript 파일로 변환합니다:
-
-```
-babel --presets react src --watch --out-dir build
-```
-
-> 주의:
->
-> ES2015를 사용하고 있다면, `babel-preset-es2015` 패키지도 설치할 필요가 있습니다.
-
-수정할 때마다 `build/helloworld.js` 파일이 자동생성됩니다. 더 자세한 사용법은 [Babel CLI 문서](http://babeljs.io/docs/usage/cli/)를 읽어보세요.
-
-```javascript{2}
-ReactDOM.render(
-  React.createElement('h1', null, 'Hello, world!'),
-  document.getElementById('example')
-);
-```
-
-아래의 내용대로 HTML 파일을 업데이트합니다:
-
-```html{8,12}
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="UTF-8" />
-    <title>Hello React!</title>
-    <script src="build/react.js"></script>
-    <script src="build/react-dom.js"></script>
-    <!-- Babel은 이제 불필요합니다! -->
-  </head>
-  <body>
-    <div id="example"></div>
-    <script src="build/helloworld.js"></script>
-  </body>
-</html>
-```
-
-## 다음 단계로
-
-더 알아보려면 [튜토리얼](/react/docs/tutorial-ko-KR.html)과 초심자용 키트의 `examples` 디렉터리에서 다른 예제들을 확인해 보세요.
-
-커뮤니티의 기여로 운영되는 Wiki도 있습니다: [워크플로우, UI 컴포넌트, 라우팅, 데이터 관리 등](https://github.com/facebook/react/wiki/Complementary-Tools)
-
-React의 세계에 오신 것을 환영합니다. 행운을 빌어요!
diff --git a/docs/docs/getting-started.md b/docs/docs/getting-started.md
deleted file mode 100644
index cd93f379dd5e..000000000000
--- a/docs/docs/getting-started.md
+++ /dev/null
@@ -1,167 +0,0 @@
----
-id: getting-started
-title: Getting Started
-next: tutorial.html
-redirect_from: "docs/index.html"
----
-
-## JSFiddle
-
-The easiest way to start hacking on React is using the following JSFiddle Hello World examples:
-
- * **[React JSFiddle](https://jsfiddle.net/reactjs/69z2wepo/)**
- * [React JSFiddle without JSX](https://jsfiddle.net/reactjs/5vjqabv3/)
-
-## Using React from npm
-
-We recommend using React with a CommonJS module system like [browserify](http://browserify.org/) or [webpack](https://webpack.github.io/). Use the [`react`](https://www.npmjs.com/package/react) and [`react-dom`](https://www.npmjs.com/package/react-dom) npm packages.
-
-```js
-// main.js
-var React = require('react');
-var ReactDOM = require('react-dom');
-
-ReactDOM.render(
-  <h1>Hello, world!</h1>,
-  document.getElementById('example')
-);
-```
-
-To install React DOM and build your bundle with browserify:
-
-```sh
-$ npm install --save react react-dom babelify babel-preset-react
-$ browserify -t [ babelify --presets [ react ] ] main.js -o bundle.js
-```
-
-To install React DOM and build your bundle with webpack:
-
-```sh
-$ npm install --save react react-dom babel-preset-react
-$ webpack
-```
-
-> Note:
->
-> If you are using ES2015, you will want to also use the `babel-preset-es2015` package.
-
-**Note:** by default, React will be in development mode, which is slower, and not advised for production. To use React in production mode, set the environment variable `NODE_ENV` to `production` (using envify or webpack's DefinePlugin). For example:
-
-```js
-new webpack.DefinePlugin({
-  "process.env": {
-    NODE_ENV: JSON.stringify("production")
-  }
-});
-```
-
-## Quick Start Without npm
-
-If you're not ready to use npm yet, you can download the starter kit which includes prebuilt copies of React and React DOM.
-
-<div class="buttons-unit downloads">
-  <a href="/react/downloads/react-{{site.react_version}}.zip" class="button">
-    Download Starter Kit {{site.react_version}}
-  </a>
-</div>
-
-In the root directory of the starter kit, create a `helloworld.html` with the following contents.
-
-```html
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="UTF-8" />
-    <title>Hello React!</title>
-    <script src="build/react.js"></script>
-    <script src="build/react-dom.js"></script>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
-  </head>
-  <body>
-    <div id="example"></div>
-    <script type="text/babel">
-      ReactDOM.render(
-        <h1>Hello, world!</h1>,
-        document.getElementById('example')
-      );
-    </script>
-  </body>
-</html>
-```
-
-The XML syntax inside of JavaScript is called JSX; check out the [JSX syntax](/react/docs/jsx-in-depth.html) to learn more about it. In order to translate it to vanilla JavaScript we use `<script type="text/babel">` and include Babel to actually perform the transformation in the browser. Open the html from a browser and you should already be able to see the greeting!
-
-### Separate File
-
-Your React JSX code can live in a separate file. Create the following `src/helloworld.js`.
-
-```javascript
-ReactDOM.render(
-  <h1>Hello, world!</h1>,
-  document.getElementById('example')
-);
-```
-
-Then reference it from `helloworld.html`:
-
-```html{10}
-<script type="text/babel" src="src/helloworld.js"></script>
-```
-
-Note that some browsers (Chrome, e.g.) will fail to load the file unless it's served via HTTP.
-
-### Offline Transform
-
-First install the [Babel](http://babeljs.io/) command-line tools (requires [npm](https://www.npmjs.com/)):
-
-```
-npm install --global babel-cli
-npm install babel-preset-react
-```
-
-Then, translate your `src/helloworld.js` file to plain JavaScript:
-
-```
-babel --presets react src --watch --out-dir build
-```
-
-> Note:
->
-> If you are using ES2015, you will want to also use the `babel-preset-es2015` package.
-
-The file `build/helloworld.js` is autogenerated whenever you make a change. Read the [Babel CLI documentation](http://babeljs.io/docs/usage/cli/) for more advanced usage.
-
-```javascript{2}
-ReactDOM.render(
-  React.createElement('h1', null, 'Hello, world!'),
-  document.getElementById('example')
-);
-```
-
-
-Update your HTML file as below:
-
-```html{8,12}
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="UTF-8" />
-    <title>Hello React!</title>
-    <script src="build/react.js"></script>
-    <script src="build/react-dom.js"></script>
-    <!-- No need for Babel! -->
-  </head>
-  <body>
-    <div id="example"></div>
-    <script src="build/helloworld.js"></script>
-  </body>
-</html>
-```
-
-## Next Steps
-
-Check out [the tutorial](/react/docs/tutorial.html) and the other examples in the starter kit's `examples` directory to learn more.
-
-We also have a wiki where the community contributes with [workflows, UI-components, routing, data management etc.](https://github.com/facebook/react/wiki/Complementary-Tools)
-
-Good luck, and welcome!
diff --git a/docs/docs/getting-started.zh-CN.md b/docs/docs/getting-started.zh-CN.md
deleted file mode 100644
index db427f414b0b..000000000000
--- a/docs/docs/getting-started.zh-CN.md
+++ /dev/null
@@ -1,168 +0,0 @@
----
-id: getting-started-zh-CN
-title: 入门教程
-permalink: getting-started-zh-CN.html
-next: tutorial-zh-CN.html
-redirect_from: "docs/index-zh-CN.html"
----
-
-## JSFiddle
-
-开始 Hack React 的最简单的方法是用下面 JSFiddle 的Hello Worlds：
-
- * **[React JSFiddle](https://jsfiddle.net/reactjs/69z2wepo/)**
- * [React JSFiddle without JSX](https://jsfiddle.net/reactjs/5vjqabv3/)
-
-## 通过 npm 使用 React
-
-我们建议在 React 中使用 CommonJS 模块系统，比如 [browserify](http://browserify.org/) 或 [webpack](https://webpack.github.io/)。使用 [`react`](https://www.npmjs.com/package/react) 和 [`react-dom`](https://www.npmjs.com/package/react-dom) npm 包.
-
-```js
-// main.js
-var React = require('react');
-var ReactDOM = require('react-dom');
-
-ReactDOM.render(
-  <h1>Hello, world!</h1>,
-  document.getElementById('example')
-);
-```
-
-要用 browserify 安装 React DOM 和构建你的包。
-
-```sh
-$ npm install --save react react-dom babelify babel-preset-react
-$ browserify -t [ babelify --presets [ react ] ] main.js -o bundle.js
-```
-
-要用 webpack 安装 React DOM 和构建你的包:  
-
-```sh
-$ npm install --save react react-dom babel-preset-react
-$ webpack
-```
-
-> 注意:
->
-> 如果你正在使用 ES2015, 你将要使用 `babel-preset-es2015` 包.
-
-**注意:** 默认情况下，React 将会在开发模式，很缓慢，不建议用于生产。要在生产模式下使用 React，设置环境变量 `NODE_ENV` 为 `production` （使用 envify 或者 webpack's DefinePlugin）。例如：
-
-```js
-new webpack.DefinePlugin({
-  "process.env": {
-    NODE_ENV: JSON.stringify("production")
-  }
-});
-```
-
-## 不用 npm 的快速开始
-
-如果你现在还没准备要使用npm,你可以下载这个已经包含了预构建的 React 和 React DOM 拷贝的入门套件. 
-
-<div class="buttons-unit downloads">
-  <a href="/react/downloads/react-{{site.react_version}}.zip" class="button">
-    下载入门套件 {{site.react_version}}
-  </a>
-</div>
-
-在入门教程包的根目录，创建一个含有如下代码的 `helloworld.html`。
-
-```html
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="UTF-8" />
-    <title>Hello React!</title>
-    <script src="build/react.js"></script>
-    <script src="build/react-dom.js"></script>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
-  </head>
-  <body>
-    <div id="example"></div>
-    <script type="text/babel">
-      ReactDOM.render(
-        <h1>Hello, world!</h1>,
-        document.getElementById('example')
-      );
-    </script>
-  </body>
-</html>
-```
-
-在 JavaScript 代码里写着 XML 格式的代码称为 JSX；可以去 [JSX 语法](/react/docs/jsx-in-depth.html) 里学习更多 JSX 相关的知识。为了把 JSX 转成标准的 JavaScript，我们用 `<script type="text/babel">` 标签，并引入 Babel 来完成在浏览器里的代码转换。在浏览器里打开这个html，你应该可以看到成功的消息！
-
-### 分离文件
-
-你的 React JSX 代码文件可以写在另外的文件里。新建下面的 `src/helloworld.js`。
-
-```javascript
-ReactDOM.render(
-  <h1>Hello, world!</h1>,
-  document.getElementById('example')
-);
-```
-
-然后在 `helloworld.html` 引用该文件：
-
-```html{10}
-<script type="text/babel" src="src/helloworld.js"></script>
-```
-
-注意一些浏览器（比如 Chrome ）会在使用 HTTP 以外的协议加载文件时失败。
-
-### 离线转换
-
-先安装[Babel](http://babeljs.io/)命令行工具（需要 [npm](https://www.npmjs.com/)）：
-
-```
-npm install --global babel-cli
-npm install babel-preset-react
-```
-
-然后把你的 `src/helloworld.js` 文件转成标准的 JavaScript:
-
-```
-babel --presets react src --watch --out-dir build
-```
-
-> 注意:
->
-> 如果你正在使用 ES2015, 你将需要使用 `babel-preset-es2015` 包.
-
-`build/helloworld.js` 会在你对文件进行修改时自动生成。 阅读 [Babel CLI 文档](http://babeljs.io/docs/usage/cli/) 了解高级用法。
-
-```javascript{2}
-ReactDOM.render(
-  React.createElement('h1', null, 'Hello, world!'),
-  document.getElementById('example')
-);
-```
-
-
-对照下面更新你的 HTML 代码
-
-```html{8,12}
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="UTF-8" />
-    <title>Hello React!</title>
-    <script src="build/react.js"></script>
-    <script src="build/react-dom.js"></script>
-    <!-- 不需要 Babel! -->
-  </head>
-  <body>
-    <div id="example"></div>
-    <script src="build/helloworld.js"></script>
-  </body>
-</html>
-```
-
-## 下一步
-
-去看看[入门教程](/react/docs/tutorial.html) 和入门教程包 `examples` 目录下的其它例子学习更多。
-
-我们还有一个社区开发者共建的 Wiki：[workflows, UI-components, routing, data management etc.](https://github.com/facebook/react/wiki/Complementary-Tools)
-
-恭喜你，欢迎来到 React 的世界。
diff --git a/docs/docs/handling-events.md b/docs/docs/handling-events.md
new file mode 100644
index 000000000000..27683bf88731
--- /dev/null
+++ b/docs/docs/handling-events.md
@@ -0,0 +1,141 @@
+---
+id: handling-events
+title: Handling Events
+permalink: docs/handling-events.html
+prev: state-and-lifecycle.html
+next: conditional-rendering.html
+redirect_from:
+  - "docs/events-ko-KR.html"
+---
+
+Handling events with React elements is very similar to handling events on DOM elements. There are some syntactic differences:
+
+* React events are named using camelCase, rather than lowercase.
+* With JSX you pass a function as the event handler, rather than a string.
+
+For example, the HTML:
+
+```html
+<button onclick="activateLasers()">
+  Activate Lasers
+</button>
+```
+
+is slightly different in React:
+
+```js{1}
+<button onClick={activateLasers}>
+  Activate Lasers
+</button>
+```
+
+Another difference is that you cannot return `false` to prevent default behavior in React. You must call `preventDefault` explicitly. For example, with plain HTML, to prevent the default link behavior of opening a new page, you can write:
+
+```html
+<a href="#" onclick="console.log('The link was clicked.'); return false">
+  Click me
+</a>
+```
+
+In React, this could instead be:
+
+```js{2-5,8}
+function ActionLink() {
+  function handleClick(e) {
+    e.preventDefault();
+    console.log('The link was clicked.');
+  }
+
+  return (
+    <a href="#" onClick={handleClick}>
+      Click me
+    </a>
+  );
+}
+```
+
+Here, `e` is a synthetic event. React defines these synthetic events according to the [W3C spec](https://www.w3.org/TR/DOM-Level-3-Events/), so you don't need to worry about cross-browser compatibility. See the [`SyntheticEvent`](/react/docs/events.html) reference guide to learn more.
+
+When using React you should generally not need to call `addEventListener` to add listeners to a DOM element after it is created. Instead, just provide a listener when the element is initially rendered.
+
+When you define a component using an [ES6 class](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes), a common pattern is for an event handler to be a method on the class. For example, this `Toggle` component renders a button that lets the user toggle between "ON" and "OFF" states:
+
+```js{6,7,10-14,18}
+class Toggle extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {isToggleOn: true};
+
+    // This binding is necessary to make `this` work in the callback
+    this.handleClick = this.handleClick.bind(this);
+  }
+
+  handleClick() {
+    this.setState(prevState => ({
+      isToggleOn: !prevState.isToggleOn
+    }));
+  }
+
+  render() {
+    return (
+      <button onClick={this.handleClick}>
+        {this.state.isToggleOn ? 'ON' : 'OFF'}
+      </button>
+    );
+  }
+}
+
+ReactDOM.render(
+  <Toggle />,
+  document.getElementById('root')
+);
+```
+
+[Try it on CodePen.](http://codepen.io/gaearon/pen/xEmzGg?editors=0010)
+
+You have to be careful about the meaning of `this` in JSX callbacks. In JavaScript, class methods are not [bound](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind) by default. If you forget to bind `this.handleClick` and pass it to `onClick`, `this` will be `undefined` when the function is actually called.
+
+This is not React-specific behavior; it is a part of [how functions work in JavaScript](https://www.smashingmagazine.com/2014/01/understanding-javascript-function-prototype-bind/). Generally, if you refer to a method without `()` after it, such as `onClick={this.handleClick}`, you should bind that method.
+
+If calling `bind` annoys you, there are two ways you can get around this. If you are using the experimental [property initializer syntax](https://babeljs.io/docs/plugins/transform-class-properties/), you can use property initializers to correctly bind callbacks:
+
+```js{2-6}
+class LoggingButton extends React.Component {
+  // This syntax ensures `this` is bound within handleClick.
+  // Warning: this is *experimental* syntax.
+  handleClick = () => {
+    console.log('this is:', this);
+  }
+
+  render() {
+    return (
+      <button onClick={this.handleClick}>
+        Click me
+      </button>
+    );
+  }
+}
+```
+
+This syntax is enabled by default in [Create React App](https://github.com/facebookincubator/create-react-app).
+
+If you aren't using property initializer syntax, you can use an [arrow function](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions) in the callback:
+
+```js{7-9}
+class LoggingButton extends React.Component {
+  handleClick() {
+    console.log('this is:', this);
+  }
+
+  render() {
+    // This syntax ensures `this` is bound within handleClick
+    return (
+      <button onClick={(e) => this.handleClick(e)}>
+        Click me
+      </button>
+    );
+  }
+}
+```
+
+The problem with this syntax is that a different callback is created each time the `LoggingButton` renders. In most cases, this is fine. However, if this callback is passed as a prop to lower components, those components might do an extra re-rendering. We generally recommend binding in the constructor or using the property initializer syntax, to avoid this sort of performance problem.
diff --git a/docs/docs/hello-world.md b/docs/docs/hello-world.md
new file mode 100644
index 000000000000..6e2897147120
--- /dev/null
+++ b/docs/docs/hello-world.md
@@ -0,0 +1,33 @@
+---
+id: hello-world
+title: Hello World
+permalink: docs/hello-world.html
+prev: installation.html
+next: introducing-jsx.html
+redirect_from:
+  - "docs/index.html"
+  - "docs/getting-started.html"
+  - "docs/getting-started-ko-KR.html"
+  - "docs/getting-started-zh-CN.html"
+---
+
+The easiest way to get started with React is to use [this Hello World example code on CodePen](http://codepen.io/gaearon/pen/ZpvBNJ?editors=0010). You don't need to install anything; you can just open it in another tab and follow along as we go through examples. If you'd rather use a local development environment, check out the [Installation](/react/docs/installation.html) page.
+
+The smallest React example looks like this:
+
+```js
+ReactDOM.render(
+  <h1>Hello, world!</h1>,
+  document.getElementById('root')
+);
+```
+
+It renders a header saying "Hello World" on the page.
+
+The next few sections will gradually introduce you to using React. We will examine the building blocks of React apps: elements and components. Once you master them, you can create complex apps from small reusable pieces.
+
+## A Note on JavaScript
+
+React is a JavaScript library, and so it assumes you have a basic understanding of the JavaScript language. If you don't feel very confident, we recommend [refreshing your JavaScript knowledge](https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript) so you can follow along more easily.
+
+We also use some of the ES6 syntax in the examples. We try to use it sparingly because it's still relatively new, but we encourage you to get familiar with [arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions), [classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes), [template literals](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Template_literals), [`let`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let), and [`const`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const) statements. You can use <a href="http://babeljs.io/repl/#?babili=false&evaluate=true&lineWrap=false&presets=es2015%2Creact&experimental=false&loose=false&spec=false&code=const%20element%20%3D%20%3Ch1%3EHello%2C%20world!%3C%2Fh1%3E%3B%0Aconst%20container%20%3D%20document.getElementById('root')%3B%0AReactDOM.render(element%2C%20container)%3B%0A">Babel REPL</a> to check what ES6 code compiles to.
diff --git a/docs/docs/higher-order-components.md b/docs/docs/higher-order-components.md
new file mode 100644
index 000000000000..0593436bfabd
--- /dev/null
+++ b/docs/docs/higher-order-components.md
@@ -0,0 +1,423 @@
+---
+id: higher-order-components
+title: Higher-Order Components
+permalink: docs/higher-order-components.html
+---
+
+A higher-order component (HOC) is an advanced technique in React for reusing component logic. HOCs are not part of the React API, per se. They are a pattern that emerges from React's compositional nature.
+
+Concretely, **a higher-order component is a function that takes a component and returns a new component.**
+
+```js
+const EnhancedComponent = higherOrderComponent(WrappedComponent);
+```
+
+Whereas a component transforms props into UI, a higher-order component transforms a component into another component.
+
+HOCs are common in third-party React libraries, such as Redux's [`connect`](https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options) and Relay's [`createContainer`](https://facebook.github.io/relay/docs/api-reference-relay.html#createcontainer-static-method).
+
+In this document, we'll discuss why higher-order components are useful, and how to write your own.
+
+## Use HOCs For Cross-Cutting Concerns
+
+> **Note**
+>
+> We previously recommended mixins as a way to handle cross-cutting concerns. We've since realized that mixins create more trouble than they are worth. [Read more](/react/blog/2016/07/13/mixins-considered-harmful.html) about why we've moved away from mixins and how you can transition your existing components.
+
+Components are the primary unit of code reuse in React. However, you'll find that some patterns aren't a straightforward fit for traditional components.
+
+For example, say you have a `CommentList` component that subscribes to an external data source to render a list of comments:
+
+```js
+class CommentList extends React.Component {
+  constructor() {
+    super();
+    this.handleChange = this.handleChange.bind(this);
+    this.state = {
+      // "DataSource" is some global data source
+      comments: DataSource.getComments()
+    };
+  }
+
+  componentDidMount() {
+    // Subscribe to changes
+    DataSource.addChangeListener(this.handleChange);
+  }
+
+  componentWillUnmount() {
+    // Clean up listener
+    DataSource.removeChangeListener(this.handleChange);
+  }
+
+  handleChange() {
+    // Update component state whenever the data source changes
+    this.setState({
+      comments: DataSource.getComments()
+    });
+  }
+
+  render() {
+    return (
+      <div>
+        {this.state.comments.map((comment) => (
+          <Comment comment={comment} key={comment.id} />
+        ))}
+      </div>
+    );
+  }
+}
+```
+
+Later, you write a component for subscribing to a single blog post, which follows a similar pattern:
+
+```js
+class BlogPost extends React.Component {
+  constructor(props) {
+    super(props);
+    this.handleChange = this.handleChange.bind(this);
+    this.state = {
+      blogPost: DataSource.getBlogPost(props.id)
+    };
+  }
+
+  componentDidMount() {
+    DataSource.addChangeListener(this.handleChange);
+  }
+
+  componentWillUnmount() {
+    DataSource.removeChangeListener(this.handleChange);
+  }
+
+  handleChange() {
+    this.setState({
+      blogPost: DataSource.getBlogPost(this.props.id)
+    });
+  }
+
+  render() {
+    return <TextBlock text={this.state.blogPost} />;
+  }
+}
+```
+
+`CommentList` and `BlogPost` aren't identical — they call different methods on `DataSource`, and they render different output. But much of their implementation is the same:
+
+- On mount, add a change listener to `DataSource`.
+- Inside the listener, call `setState` whenever the data source changes.
+- On unmount, remove the change listener.
+
+You can imagine that in a large app, this same pattern of subscribing to `DataSource` and calling `setState` will occur over and over again. We want an abstraction that allows us to define this logic in a single place and share them across many components. This is where higher-order components excel.
+
+We can write a function that creates components, like `CommentList` and `BlogPost`, that subscribe to `DataSource`. The function will accept as one of its arguments a child component that receives the subscribed data as a prop. Let's call the function `withSubscription`:
+
+```js
+const CommentListWithSubscription = withSubscription(
+  CommentList,
+  (DataSource) => DataSource.getComments()
+);
+
+const BlogPostWithSubscription = withSubscription(
+  BlogPost,
+  (DataSource, props) => DataSource.getBlogPost(props.id)
+);
+```
+
+The first parameter is the wrapped component. The second parameter retrieves the data we're interested in, given a `DataSource` and the current props.
+
+When `CommentListWithSubscription` and `BlogPostWithSubscription` are rendered, `CommentList` and `BlogPost` will be passed a `data` prop with the most current data retrieved from `DataSource`:
+
+```js
+// This function takes a component...
+function withSubscription(WrappedComponent, selectData) {
+  // ...and returns another component...
+  return class extends React.Component {
+    constructor(props) {
+      super(props);
+      this.handleChange = this.handleChange.bind(this);
+      this.state = {
+        data: selectData(DataSource, props)
+      };
+    }
+
+    componentDidMount() {
+      // ... that takes care of the subscription...
+      DataSource.addChangeListener(this.handleChange);
+    }
+
+    componentWillUnmount() {
+      DataSource.removeChangeListener(this.handleChange);
+    }
+
+    handleChange() {
+      this.setState({
+        data: selectData(DataSource, this.props)
+      });
+    }
+
+    render() {
+      // ... and renders the wrapped component with the fresh data!
+      // Notice that we pass through any additional props
+      return <WrappedComponent data={this.state.data} {...this.props} />;
+    }
+  };
+}
+```
+
+Note that an HOC doesn't modify the input component, nor does it use inheritance to copy its behavior. Rather, an HOC *composes* the original component by *wrapping* it in a container component. An HOC is a pure function with zero side-effects.
+
+And that's it! The wrapped component receives all the props of the container, along with a new prop, `data`, which it uses to render its output. The HOC isn't concerned with how or why the data is used, and the wrapped component isn't concerned with where the data came from.
+
+Because `withSubscription` is a normal function, you can add as many or as few arguments as you like. For example, you may want to make the name of the `data` prop configurable, to further isolate the HOC from the wrapped component. Or you could accept an argument that configures `shouldComponentUpdate`, or one that configures the data source. These are all possible because the HOC has full control over how the component is defined.
+
+Like components, the contract between `withSubscription` and the wrapped component is entirely props-based. This makes it easy to swap one HOC for a different one, as long as they provide the same props to the wrapped component. This may be useful if you change data-fetching libraries, for example.
+
+## Don't Mutate the Original Component. Use Composition.
+
+Resist the temptation to modify a component's prototype (or otherwise mutate it) inside an HOC.
+
+```js
+function logProps(InputComponent) {
+  InputComponent.prototype.componentWillReceiveProps(nextProps) {
+    console.log('Current props: ', this.props);
+    console.log('Next props: ', nextProps);
+  }
+  // The fact that we're returning the original input is a hint that it has
+  // been mutated.
+  return InputComponent;
+}
+
+// EnhancedComponent will log whenever props are received
+const EnhancedComponent = logProps(InputComponent);
+```
+
+There are a few problems with this. One is that the input component cannot be reused separately from the enhanced component. More crucially, if you apply another HOC to `EnhancedComponent` that *also* mutates `componentWillReceiveProps`, the first HOC's functionality will be overridden! This HOC also won't work with function components, which do not have lifecycle methods.
+
+Mutating HOCs are a leaky abstraction—the consumer must know how they are implemented in order to avoid conflicts with other HOCs.
+
+Instead of mutation, HOCs should use composition, by wrapping the input component in a container component:
+
+```js
+function logProps(WrappedComponent) {
+  return class extends React.Component {
+    componentWillReceiveProps(nextProps) {
+      console.log('Current props: ', this.props);
+      console.log('Next props: ', nextProps);
+    }
+    render() {
+      // Wraps the input component in a container, without mutating it. Good!
+      return <WrappedComponent {...this.props} />;
+    }
+  }
+}
+```
+
+This HOC has the same functionality as the mutating version while avoiding the potential for clashes. It works equally well with class and functional components. And because it's a pure function, it's composable with other HOCs, or even with itself.
+
+You may have noticed similarities between HOCs and a pattern called **container components**. Container components are part of a strategy of separating responsibility between high-level and low-level concerns. Containers manage things like subscriptions and state, and pass props to components that handle things like rendering UI. HOCs use containers as part of their implementation. You can think of HOCs as parameterized container component definitions.
+
+## Convention: Pass Unrelated Props Through to the Wrapped Component
+
+HOCs add features to a component. They shouldn't drastically alter its contract. It's expected that the component returned from an HOC has a similar interface to the wrapped component.
+
+HOCs should pass through props that are unrelated to its specific concern. Most HOCs contain a render method that looks something like this:
+
+```js
+render() {
+  // Filter out extra props that are specific to this HOC and shouldn't be
+  // passed through
+  const { extraProp, ...passThroughProps } = this.props;
+
+  // Inject props into the wrapped component. These are usually state values or
+  // instance methods.
+  const injectedProp = someStateOrInstanceMethod;
+
+  // Pass props to wrapped component
+  return (
+    <WrappedComponent
+      injectedProp={injectedProp}
+      {...passThroughProps}
+    />
+  );
+}
+```
+
+This convention helps ensure that HOCs are as flexible and reusable as possible.
+
+## Convention: Maximizing Composability
+
+Not all HOCs look the same. Sometimes they accept only a single argument, the wrapped component:
+
+```js
+const NavbarWithRouter = withRouter(Navbar);
+```
+
+Usually, HOCs accept additional arguments. In this example from Relay, a config object is used to specify a component's data dependencies:
+
+```js
+const CommentWithRelay = Relay.createContainer(Comment, config);
+```
+
+The most common signature for HOCs looks like this:
+
+```js
+// React Redux's `connect`
+const ConnectedComment = connect(commentSelector, commentActions)(Comment);
+```
+
+*What?!* If you break it apart, it's easier to see what's going on.
+
+```js
+// connect is a function that returns another function
+const enhance = connect(commentListSelector, commentListActions);
+// The returned function is an HOC, which returns a component that is connected
+// to the Redux store
+const ConnectedComment = enhance(CommentList);
+```
+In other words, `connect` is a higher-order function that returns a higher-order component!
+
+This form may seem confusing or unnecessary, but it has a useful property. Single-argument HOCs like the one returned by the `connect` function have the signature `Component => Component`. Functions whose output type is the same as its input type are really easy to compose together.
+
+```js
+// Instead of doing this...
+const EnhancedComponent = connect(commentSelector)(withRouter(WrappedComponent))
+
+// ... you can use a function composition utility
+// compose(f, g, h) is the same as (...args) => f(g(h(...args)))
+const enhance = compose(
+  // These are both single-argument HOCs
+  connect(commentSelector),
+  withRouter
+)
+const EnhancedComponent = enhance(WrappedComponent)
+```
+
+(This same property also allows `connect` and other enhancer-style HOCs to be used as decorators, an experimental JavaScript proposal.)
+
+The `compose` utility function is provided by many third-party libraries including lodash (as [`lodash.flowRight`](https://lodash.com/docs/#flowRight)), [Redux](http://redux.js.org/docs/api/compose.html), and [Ramda](http://ramdajs.com/docs/#compose).
+
+## Convention: Wrap the Display Name for Easy Debugging
+
+The container components created by HOCs show up in the [React Developer Tools](https://github.com/facebook/react-devtools) like any other component. To ease debugging, choose a display name that communicates that it's the result of an HOC.
+
+The most common technique is to wrap the display name of the wrapped component. So if your higher-order component is named `withSubscription`, and the wrapped component's display name is `CommentList`, use the display name `WithSubscription(CommentList)`:
+
+```js
+function withSubscription(WrappedComponent) {
+  class WithSubscription extends React.Component {/* ... */}
+  WithSubscription.displayName = `WithSubscription(${getDisplayName(WrappedComponent)})`;
+  return WithSubscription;
+}
+
+function getDisplayName(WrappedComponent) {
+  return WrappedComponent.displayName || WrappedComponent.name || 'Component';
+}
+```
+
+
+## Caveats
+
+Higher-order components come with a few caveats that aren't immediately obvious if you're new to React.
+
+### Don't Use HOCs Inside the render Method
+
+React's diffing algorithm (called reconciliation) uses component identity to determine whether it should update the existing subtree or throw it away and mount a new one. If the component returned from `render` is identical (`===`) to the component from the previous render, React recursively updates the subtree by diffing it with the new one. If they're not equal, the previous subtree is unmounted completely.
+
+Normally, you shouldn't need to think about this. But it matters for HOCs because it means you can't apply an HOC to a component within the render method of a component:
+
+```js
+render() {
+  // A new version of EnhancedComponent is created on every render
+  // EnhancedComponent1 !== EnhancedComponent2
+  const EnhancedComponent = enhance(MyComponent);
+  // That causes the entire subtree to unmount/remount each time!
+  return <EnhancedComponent />;
+}
+```
+
+The problem here isn't just about performance — remounting a component causes the state of that component and all of its children to be lost.
+
+Instead, apply HOCs outside the component definition so that the resulting component is created only once. Then, its identity will be consistent across renders. This is usually what you want, anyway.
+
+In those rare cases where you need to apply an HOC dynamically, you can also do it inside a component's lifecycle methods or its constructor.
+
+### Static Methods Must Be Copied Over
+
+Sometimes it's useful to define a static method on a React component. For example, Relay containers expose a static method `getFragment` to facilitate the composition of GraphQL fragments.
+
+When you apply an HOC to a component, though, the original component is wrapped with a container component. That means the new component does not have any of the static methods of the original component.
+
+```js
+// Define a static method
+WrappedComponent.staticMethod = function() {/*...*/}
+// Now apply an HOC
+const EnhancedComponent = enhance(WrappedComponent);
+
+// The enhanced component has no static method
+typeof EnhancedComponent.staticMethod === 'undefined' // true
+```
+
+To solve this, you could copy the methods onto the container before returning it:
+
+```js
+function enhance(WrappedComponent) {
+  class Enhance extends React.Component {/*...*/}
+  // Must know exactly which method(s) to copy :(
+  Enhance.staticMethod = WrappedComponent.staticMethod;
+  return Enhance;
+}
+```
+
+However, this requires you to know exactly which methods need to be copied. You can use [hoist-non-react-statics](https://github.com/mridgway/hoist-non-react-statics) to automatically copy all non-React static methods:
+
+```js
+import hoistNonReactStatic from 'hoist-non-react-statics';
+function enhance(WrappedComponent) {
+  class Enhance extends React.Component {/*...*/}
+  hoistNonReactStatic(Enhance, WrappedComponent);
+  return Enhance;
+}
+```
+
+Another possible solution is to export the static method separately from the component itself.
+
+```js
+// Instead of...
+MyComponent.someFunction = someFunction;
+export default MyComponent;
+
+// ...export the method separately...
+export { someFunction };
+
+// ...and in the consuming module, import both
+import MyComponent, { someFunction } from './MyComponent.js';
+```
+
+### Refs Aren't Passed Through
+
+While the convention for higher-order components is to pass through all props to the wrapped component, it's not possible to pass through refs. That's because `ref` is not really a prop — like `key`, it's handled specially by React. If you add a ref to an element whose component is the result of an HOC, the ref refers to an instance of the outermost container component, not the wrapped component.
+
+If you find yourself facing this problem, the ideal solution is to figure out how to avoid using `ref` at all. Occasionally, users who are new to the React paradigm rely on refs in situations where a prop would work better.
+
+That said, there are times when refs are a necessary escape hatch — React wouldn't support them otherwise. Focusing an input field is an example where you may want imperative control of a component. In that case, one solution is to pass a ref callback as a normal prop, by giving it a different name:
+
+```js
+function Field({ inputRef, ...rest }) {
+  return <input ref={inputRef} {...rest} />;
+}
+
+// Wrap Field in a higher-order component
+const EnhancedField = enhance(Field);
+
+// Inside a class component's render method...
+<EnhancedField
+  inputRef={(inputEl) => {
+    // This callback gets passed through as a regular prop
+    this.inputEl = inputEl
+  }}
+/>
+
+// Now you can call imperative methods
+this.inputEl.focus();
+```
+
+This is not a perfect solution by any means. We prefer that refs remain a library concern, rather than require you to manually handle them. We are exploring ways to solve this problem so that using an HOC is unobservable.
diff --git a/docs/docs/installation.md b/docs/docs/installation.md
new file mode 100644
index 000000000000..7b51694d3260
--- /dev/null
+++ b/docs/docs/installation.md
@@ -0,0 +1,327 @@
+---
+id: installation
+title: Installation
+permalink: docs/installation.html
+redirect_from:
+  - "download.html"
+  - "downloads.html"
+  - "docs/tooling-integration.html"
+  - "docs/package-management.html"
+  - "docs/language-tooling.html"
+  - "docs/environments.html"
+next: hello-world.html
+---
+<style>
+  .tab-hidden {
+    display: none;
+  }
+</style>
+
+React is flexible and can be used in a variety of projects. You can create new apps with it, but you can also gradually introduce it into an existing codebase without doing a rewrite.
+
+<div class="toggler">
+  <style>
+    .toggler li {
+       display: inline-block;
+       position: relative;
+       top: 1px;
+       padding: 10px;
+       margin: 0px 2px 0px 2px;
+       border: 1px solid #05A5D1;
+       border-bottom-color: transparent;
+       border-radius: 3px 3px 0px 0px;
+       color: #05A5D1;
+       background-color: transparent;
+       font-size: 0.99em;
+       cursor: pointer;
+    }
+    .toggler li:first-child {
+      margin-left: 0;
+    }
+    .toggler li:last-child {
+      margin-right: 0;
+    }
+    .toggler ul {
+      display: inline-block;
+      list-style-type: none;
+      margin: 0;
+      border-bottom: 1px solid #05A5D1;
+      cursor: default;
+    }
+    @media screen and (max-width: 960px) {
+      .toggler li,
+      .toggler li:first-child,
+      .toggler li:last-child {
+        display: block;
+        border-bottom-color: #05A5D1;
+        border-radius: 3px;
+        margin: 2px 0px 2px 0px;
+      }
+      .toggler ul {
+        border-bottom: 0;
+      }
+    }
+    .display-target-fiddle .toggler .button-fiddle:focus,
+    .display-target-newapp .toggler .button-newapp:focus,
+    .display-target-existingapp .toggler .button-existingapp:focus {
+      background-color: #046E8B;
+      color: white;
+    }
+    .display-target-fiddle .toggler .button-fiddle,
+    .display-target-newapp .toggler .button-newapp,
+    .display-target-existingapp .toggler .button-existingapp {
+      background-color: #05A5D1;
+      color: white;
+    }
+    block {
+      display: none;
+    }
+    .display-target-fiddle .fiddle,
+    .display-target-newapp .newapp,
+    .display-target-existingapp .existingapp {
+      display: block;
+    }
+  </style>
+  <script>
+    document.querySelector('.toggler').parentElement.className += ' display-target-fiddle';
+  </script>
+  <span>Which of these options best describes what you want to do?</span>
+  <br />
+  <br />
+   <ul role="tablist" >
+      <li id="fiddle" class="button-fiddle" aria-selected="false" role="tab" tabindex="0" aria-controls="fiddletab"
+          onclick="display('target', 'fiddle')" onkeyup="keyToggle(event, 'fiddle', 'existingapp', 'newapp')">
+        Try React
+      </li>
+      <li id="newapp" class="button-newapp" aria-selected="false" role="tab" tabindex="-1" aria-controls="newapptab"
+          onclick="display('target', 'newapp')" onkeyup="keyToggle(event, 'newapp', 'fiddle', 'existingapp')">
+        Create a New App
+      </li>
+      <li id="existingapp" class="button-existingapp" aria-selected="false" role="tab" tabindex="-1" aria-controls="existingapptab"
+          onclick="display('target', 'existingapp')" onkeyup="keyToggle(event, 'existingapp', 'newapp', 'fiddle')">
+        Add React to an Existing App
+      </li>
+    </ul>
+</div>
+
+<block id="fiddletab" role="tabpanel" class="fiddle"  />
+
+## Trying Out React
+
+If you're just interested in playing around with React, you can use CodePen. Try starting from [this Hello World example code](http://codepen.io/gaearon/pen/rrpgNB?editors=0010). You don't need to install anything; you can just modify the code and see if it works.
+
+If you prefer to use your own text editor, you can also <a href="/react/downloads/single-file-example.html" download="hello.html">download this HTML file</a>, edit it, and open it from the local filesystem in your browser. It does a slow runtime code transformation, so don't use it in production.
+
+If you want to use it for a full application, there are two popular ways to get started with React: using Create React App, or adding it to an existing application.
+
+<block id="newapptab" role="tabpanel" class="newapp" />
+
+## Creating a New Application
+
+[Create React App](http://github.com/facebookincubator/create-react-app) is the best way to start building a new React single page application. It sets up your development environment so that you can use the latest JavaScript features, provides a nice developer experience, and optimizes your app for production.
+
+```bash
+npm install -g create-react-app
+create-react-app my-app
+
+cd my-app
+npm start
+```
+
+Create React App doesn't handle backend logic or databases; it just creates a frontend build pipeline, so you can use it with any backend you want. It uses build tools like Babel and webpack under the hood, but works with zero configuration.
+
+When you're ready to deploy to production, running `npm run build` will create an optimized build of your app in the `build` folder. You can learn more about Create React App [from its README](https://github.com/facebookincubator/create-react-app#create-react-app-) and the [User Guide](https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md#table-of-contents).
+
+<block id="existingapptab" role="tabpanel" class="existingapp" />
+
+## Adding React to an Existing Application
+
+You don't need to rewrite your app to start using React.
+
+We recommend adding React to a small part of your application, such as an individual widget, so you can see if it works well for your use case.
+
+While React [can be used](/react/docs/react-without-es6.html) without a build pipeline, we recommend setting it up so you can be more productive. A modern build pipeline typically consists of:
+
+* A **package manager**, such as [Yarn](https://yarnpkg.com/) or [npm](https://www.npmjs.com/). It lets you take advantage of a vast ecosystem of third-party packages, and easily install or update them.
+* A **bundler**, such as [webpack](https://webpack.js.org/) or [Browserify](http://browserify.org/). It lets you write modular code and bundle it together into small packages to optimize load time.
+* A **compiler** such as [Babel](http://babeljs.io/). It lets you write modern JavaScript code that still works in older browsers.
+
+### Installing React
+
+>**Note:**
+>
+>Once installed, we strongly recommend setting up a [production build process](/react/docs/optimizing-performance.html#use-the-production-build) to ensure you're using the fast version of React in production.
+
+We recommend using [Yarn](https://yarnpkg.com/) or [npm](https://www.npmjs.com/) for managing front-end dependencies. If you're new to package managers, the [Yarn documentation](https://yarnpkg.com/en/docs/getting-started) is a good place to get started.
+
+To install React with Yarn, run:
+
+```bash
+yarn init
+yarn add react react-dom
+```
+
+To install React with npm, run:
+
+```bash
+npm init
+npm install --save react react-dom
+```
+
+Both Yarn and npm download packages from the [npm registry](http://npmjs.com/).
+
+### Enabling ES6 and JSX
+
+We recommend using React with [Babel](http://babeljs.io/) to let you use ES6 and JSX in your JavaScript code. ES6 is a set of modern JavaScript features that make development easier, and JSX is an extension to the JavaScript language that works nicely with React.
+
+The [Babel setup instructions](https://babeljs.io/docs/setup/) explain how to configure Babel in many different build environments. Make sure you install [`babel-preset-react`](http://babeljs.io/docs/plugins/preset-react/#basic-setup-with-the-cli-) and [`babel-preset-es2015`](http://babeljs.io/docs/plugins/preset-es2015/#basic-setup-with-the-cli-) and enable them in your [`.babelrc` configuration](http://babeljs.io/docs/usage/babelrc/), and you're good to go.
+
+### Hello World with ES6 and JSX
+
+We recommend using a bundler like [webpack](https://webpack.js.org/) or [Browserify](http://browserify.org/) so you can write modular code and bundle it together into small packages to optimize load time.
+
+The smallest React example looks like this:
+
+```js
+import React from 'react';
+import ReactDOM from 'react-dom';
+
+ReactDOM.render(
+  <h1>Hello, world!</h1>,
+  document.getElementById('root')
+);
+```
+
+This code renders into a DOM element with the id of `root` so you need `<div id="root"></div>` somewhere in your HTML file.
+
+Similarly, you can render a React component inside a DOM element somewhere inside your existing app written with any other JavaScript UI library.
+
+[Learn more about integrating React with existing code.](/react/docs/integrating-with-other-libraries.html#integrating-with-other-view-libraries)
+
+### Development and Production Versions
+
+By default, React includes many helpful warnings. These warnings are very useful in development.
+
+**However, they make the development version of React larger and slower so you should use the production version when you deploy the app.**
+
+Learn [how to tell if your website is serving the right version of React](/react/docs/optimizing-performance.html#use-the-production-build), and how to configure the production build process most efficiently:
+
+* [Creating a Production Build with Create React App](/react/docs/optimizing-performance.html#create-react-app)
+* [Creating a Production Build with Single-File Builds](/react/docs/optimizing-performance.html#single-file-builds)
+* [Creating a Production Build with Brunch](/react/docs/optimizing-performance.html#brunch)
+* [Creating a Production Build with Browserify](/react/docs/optimizing-performance.html#browserify)
+* [Creating a Production Build with Rollup](/react/docs/optimizing-performance.html#rollup)
+* [Creating a Production Build with webpack](/react/docs/optimizing-performance.html#webpack)
+
+### Using a CDN
+
+If you don't want to use npm to manage client packages, the `react` and `react-dom` npm packages also provide single-file distributions in `dist` folders, which are hosted on a CDN:
+
+```html
+<script src="https://unpkg.com/react@15/dist/react.js"></script>
+<script src="https://unpkg.com/react-dom@15/dist/react-dom.js"></script>
+```
+
+The versions above are only meant for development, and are not suitable for production. Minified and optimized production versions of React are available at:
+
+```html
+<script src="https://unpkg.com/react@15/dist/react.min.js"></script>
+<script src="https://unpkg.com/react-dom@15/dist/react-dom.min.js"></script>
+```
+
+To load a specific version of `react` and `react-dom`, replace `15` with the version number.
+
+If you use Bower, React is available via the `react` package.
+
+<script>
+/**
+ * The code below is based on a snippet from React Native Getting Started page.
+ */
+
+// Convert <div>...<span><block /></span>...</div>
+// Into <div>...<block />...</div>
+var blocks = document.getElementsByTagName('block');
+for (var i = 0; i < blocks.length; ++i) {
+  var block = blocks[i];
+  var span = blocks[i].parentNode;
+  var container = span.parentNode;
+  container.insertBefore(block, span);
+  container.removeChild(span);
+}
+// Convert <div>...<block />content<block />...</div>
+// Into <div>...<block>content</block><block />...</div>
+blocks = document.getElementsByTagName('block');
+for (var i = 0; i < blocks.length; ++i) {
+  var block = blocks[i];
+  while (block.nextSibling && block.nextSibling.tagName !== 'BLOCK') {
+    block.appendChild(block.nextSibling);
+  }
+}
+
+function setSelected(value){
+  var tabs = document.querySelectorAll('li[role="tab"]');
+  for (var i = 0; i < tabs.length; ++i) {
+    var tab = tabs[i];
+    if (tab.className === 'button-' + value) {
+      tabs[i].setAttribute('aria-selected', 'true');
+      tabs[i].setAttribute('tabindex', '0');
+    } else {
+      tabs[i].setAttribute('aria-selected', 'false');
+      tabs[i].setAttribute('tabindex', '-1');
+    }
+  }
+}
+
+function keyToggle(e, value, prevTab, nextTab){
+  if (e.keyCode === 37) {
+    document.getElementById(prevTab).focus();
+    display('target', prevTab);
+  }
+  if (e.keyCode === 39) {
+    document.getElementById(nextTab).focus();
+    display('target', nextTab);
+  }
+}
+
+function display(type, value) {
+  setSelected(value);
+  var container = document.getElementsByTagName('block')[0].parentNode;
+  container.className = 'display-' + type + '-' + value + ' ' +
+    container.className.replace(RegExp('display-' + type + '-[a-z]+ ?'), '');
+}
+
+// If we are coming to the page with a hash in it (i.e. from a search, for example), try to get
+// us as close as possible to the correct platform and dev os using the hashtag and block walk up.
+var foundHash = false;
+if (window.location.hash !== '' && window.location.hash !== 'content') { // content is default
+  // Hash links are added a bit later so we wait for them.
+  window.addEventListener('DOMContentLoaded', selectTabForHashLink);
+}
+
+function selectTabForHashLink() {
+  var hashLinks = document.querySelectorAll('a.hash-link');
+  for (var i = 0; i < hashLinks.length && !foundHash; ++i) {
+    if (hashLinks[i].hash === window.location.hash) {
+      var parent = hashLinks[i].parentElement;
+      while (parent) {
+        if (parent.tagName === 'BLOCK') {
+          var target = null;
+          if (parent.className.indexOf('fiddle') > -1) {
+            target = 'fiddle';
+          } else if (parent.className.indexOf('newapp') > -1) {
+            target = 'newapp';
+          } else if (parent.className.indexOf('existingapp') > -1) {
+            target = 'existingapp';
+          } else {
+            break; // assume we don't have anything.
+          }
+          display('target', target);
+          foundHash = true;
+          break;
+        }
+        parent = parent.parentElement;
+      }
+    }
+  }
+}
+</script>
diff --git a/docs/docs/integrating-with-other-libraries.md b/docs/docs/integrating-with-other-libraries.md
new file mode 100644
index 000000000000..85704ab53b18
--- /dev/null
+++ b/docs/docs/integrating-with-other-libraries.md
@@ -0,0 +1,439 @@
+---
+id: integrating-with-other-libraries
+title: Integrating with Other Libraries
+permalink: docs/integrating-with-other-libraries.html
+---
+
+React can be used in any web application. It can be embedded in other applications and, with a little care, other applications can be embedded in React. This guide will examine some of the more common use cases, focusing on integration with [jQuery](https://jquery.com/) and [Backbone](http://backbonejs.org/), but the same ideas can be applied to integrating components with any existing code.
+
+## Integrating with DOM Manipulation Plugins
+
+React is unaware of changes made to the DOM outside of React. It determines updates based on its own internal representation, and if the same DOM nodes are manipulated by another library, React gets confused and has no way to recover.
+
+This does not mean it is impossible or even necessarily difficult to combine React with other ways of affecting the DOM, you just have to be mindful of what each are doing.
+
+The easiest way to avoid conflicts is to prevent the React component from updating. You can do this by rendering elements that React has no reason to update, like an empty `<div />`.
+
+### How to Approach the Problem
+
+To demonstrate this, let's sketch out a wrapper for a generic jQuery plugin.
+
+We will attach a [ref](/react/docs/refs-and-the-dom.html) to the root DOM element. Inside `componentDidMount`, we will get a reference to it so we can pass it to the jQuery plugin.
+
+To prevent React from touching the DOM after mounting, we will return an empty `<div />` from the `render()` method. The `<div />` element has no properties or children, so React has no reason to update it, leaving the jQuery plugin free to manage that part of the DOM:
+
+```js{3,4,8,12}
+class SomePlugin extends React.Component {
+  componentDidMount() {
+    this.$el = $(this.el);
+    this.$el.somePlugin();
+  }
+
+  componentWillUnmount() {
+    this.$el.somePlugin('destroy');
+  }
+
+  render() {
+    return <div ref={el => this.el = el} />;
+  }
+}
+```
+
+Note that we defined both `componentDidMount` and `componentWillUnmount` [lifecycle hooks](/react/docs/react-component.html#the-component-lifecycle). Many jQuery plugins attach event listeners to the DOM so it's important to detach them in `componentWillUnmount`. If the plugin does not provide a method for cleanup, you will probably have to provide your own, remembering to remove any event listeners the plugin registered to prevent memory leaks.
+
+### Integrating with jQuery Chosen Plugin
+
+For a more concrete example of these concepts, let's write a minimal wrapper for the plugin [Chosen](https://harvesthq.github.io/chosen/), which augments `<select>` inputs.
+
+>**Note:**
+>
+>Just because it's possible, doesn't mean that it's the best approach for React apps. We encourage you to use React components when you can. React components are easier to reuse in React applications, and often provide more control over their behavior and appearance.
+
+First, let's look at what Chosen does to the DOM.
+
+If you call it on a `<select>` DOM node, it reads the attributes off of the original DOM node, hides it with an inline style, and then appends a separate DOM node with its own visual representation right after the `<select>`. Then it fires jQuery events to notify us about the changes.
+
+Let's say that this is the API we're striving for with our `<Chosen>` wrapper React component:
+
+```js
+function Example() {
+  return (
+    <Chosen onChange={value => console.log(value)}>
+      <option>vanilla</option>
+      <option>chocolate</option>
+      <option>strawberry</option>
+    </Chosen>
+  );
+}
+```
+
+We will implement it as an [uncontrolled component](/react/docs/uncontrolled-components.html) for simplicity.
+
+First, we will create an empty component with a `render()` method where we return `<select>` wrapped in a `<div>`:
+
+```js{4,5}
+class Chosen extends React.Component {
+  render() {
+    return (
+      <div>
+        <select className="Chosen-select" ref={el => this.el = el}>
+          {this.props.children}
+        </select>
+      </div>
+    );
+  }
+}
+```
+
+Notice how we wrapped `<select>` in an extra `<div>`. This is necessary because Chosen will append another DOM element right after the `<select>` node we passed to it. However, as far as React is concerned, `<div>` always only has a single child. This is how we ensure that React updates won't conflict with the extra DOM node appended by Chosen. It is important that if you modify the DOM outside of React flow, you must ensure React doesn't have a reason to touch those DOM nodes.
+
+Next, we will implement the lifecycle hooks. We need to initialize Chosen with the ref to the `<select>` node in `componentDidMount`, and tear it down in `componentWillUnmount`:
+
+```js{2,3,7}
+componentDidMount() {
+  this.$el = $(this.el);
+  this.$el.chosen();
+}
+
+componentWillUnmount() {
+  this.$el.chosen('destroy');
+}
+```
+
+[Try it on CodePen.](http://codepen.io/gaearon/pen/qmqeQx?editors=0010)
+
+Note that React assigns no special meaning to the `this.el` field. It only works because we have previously assigned this field from a `ref` in the `render()` method:
+
+```js
+<select className="Chosen-select" ref={el => this.el = el}>
+```
+
+This is enough to get our component to render, but we also want to be notified about the value changes. To do this, we will subscribe to the jQuery `change` event on the `<select>` managed by Chosen.
+
+We won't pass `this.props.onChange` directly to Chosen because component's props might change over time, and that includes event handlers. Instead, we will declare a `handleChange()` method that calls `this.props.onChange`, and subscribe it to the jQuery `change` event:
+
+```js{5,6,10,14-16}
+componentDidMount() {
+  this.$el = $(this.el);
+  this.$el.chosen();
+
+  this.handleChange = this.handleChange.bind(this);
+  this.$el.on('change', this.handleChange);
+}
+
+componentWillUnmount() {
+  this.$el.off('change', this.handleChange);
+  this.$el.chosen('destroy');
+}
+
+handleChange(e) {
+  this.props.onChange(e.target.value);
+}
+```
+
+[Try it on CodePen.](http://codepen.io/gaearon/pen/bWgbeE?editors=0010)
+
+Finally, there is one more thing left to do. In React, props can change over time. For example, the `<Chosen>` component can get different children if parent component's state changes. This means that at integration points it is important that we manually update the DOM in response to prop updates, since we no longer let React manage the DOM for us.
+
+Chosen's documentation suggests that we can use jQuery `trigger()` API to notify it about changes to the original DOM element. We will let React take care of updating `this.props.children` inside `<select>`, but we will also add a `componentDidUpdate()` lifecycle hook that notifies Chosen about changes in the children list:
+
+```js{2,3}
+componentDidUpdate(prevProps) {
+  if (prevProps.children !== this.props.children) {
+    this.$el.trigger("chosen:updated");
+  }
+}
+```
+
+This way, Chosen will know to update its DOM element when the `<select>` children managed by React change.
+
+The complete implementation of the `Chosen` component looks like this:
+
+```js
+class Chosen extends React.Component {
+  componentDidMount() {
+    this.$el = $(this.el);
+    this.$el.chosen();
+
+    this.handleChange = this.handleChange.bind(this);
+    this.$el.on('change', this.handleChange);
+  }
+  
+  componentDidUpdate(prevProps) {
+    if (prevProps.children !== this.props.children) {
+      this.$el.trigger("chosen:updated");
+    }
+  }
+
+  componentWillUnmount() {
+    this.$el.off('change', this.handleChange);
+    this.$el.chosen('destroy');
+  }
+  
+  handleChange(e) {
+    this.props.onChange(e.target.value);
+  }
+
+  render() {
+    return (
+      <div>
+        <select className="Chosen-select" ref={el => this.el = el}>
+          {this.props.children}
+        </select>
+      </div>
+    );
+  }
+}
+```
+
+[Try it on CodePen.](http://codepen.io/gaearon/pen/xdgKOz?editors=0010)
+
+## Integrating with Other View Libraries
+
+React can be embedded into other applications thanks to the flexibility of [`ReactDOM.render()`](/react/docs/react-dom.html#render).
+
+Although React is commonly used at startup to load a single root React component into the DOM, `ReactDOM.render()` can also be called multiple times for independent parts of the UI which can be as small as a button, or as large as an app.
+
+In fact, this is exactly how React is used at Facebook. This lets us write applications in React piece by piece, and combine it with our existing server-generated templates and other client-side code.
+
+### Replacing String-Based Rendering with React
+
+A common pattern in older web applications is to describe chunks of the DOM as a string and insert it into the DOM like so: `$el.html(htmlString)`. These points in a codebase are perfect for introducing React. Just rewrite the string based rendering as a React component.
+
+So the following jQuery implementation...
+
+```js
+$('#container').html('<button id="btn">Say Hello</button>');
+$('#btn').click(function() {
+  alert('Hello!');
+});
+```
+
+...could be rewritten using a React component:
+
+```js
+function Button() {
+  return <button id="btn">Say Hello</button>;
+}
+
+ReactDOM.render(
+  <Button />,
+  document.getElementById('container'),
+  function() {
+    $('#btn').click(function() {
+      alert('Hello!');
+    });
+  }
+);
+```
+
+From here you could start moving more logic into the component and begin adopting more common React practices. For example, in components it is best not to rely on IDs because the same component can be rendered multiple times. Instead, we will use the [React event system](/react/docs/handling-events.html) and register the click handler directly on the React `<button>` element:
+
+```js{2,6,9}
+function Button(props) {
+  return <button onClick={props.onClick}>Say Hello</button>;
+}
+
+function HelloButton() {
+  function handleClick() {
+    alert('Hello!');
+  }
+  return <Button onClick={handleClick} />;
+}
+
+ReactDOM.render(
+  <HelloButton />,
+  document.getElementById('container')
+);
+```
+
+[Try it on CodePen.](http://codepen.io/gaearon/pen/RVKbvW?editors=1010)
+
+You can have as many such isolated components as you like, and use `ReactDOM.render()` to render them to different DOM containers. Gradually, as you convert more of your app to React, you will be able to combine them into larger components, and move some of the `ReactDOM.render()` calls up the hierarchy.
+
+### Embedding React in a Backbone View
+
+[Backbone](http://backbonejs.org/) views typically use HTML strings, or string-producing template functions, to create the content for their DOM elements. This process, too, can be replaced with rendering a React component.
+
+Below, we will create a Backbone view called `ParagraphView`. It will override Backbone's `render()` function to render a React `<Paragraph>` component into the DOM element provided by Backbone (`this.el`). Here, too, we are using [`ReactDOM.render()`](/react/docs/react-dom.html#render):
+
+```js{1,5,8,12}
+function Paragraph(props) {
+  return <p>{props.text}</p>;
+}
+
+const ParagraphView = Backbone.View.extend({
+  render() {
+    const text = this.model.get('text');
+    ReactDOM.render(<Paragraph text={text} />, this.el);
+    return this;
+  },
+  remove() {
+    ReactDOM.unmountComponentAtNode(this.el);
+    Backbone.View.prototype.remove.call(this);
+  }
+});
+```
+
+[Try it on CodePen.](http://codepen.io/gaearon/pen/gWgOYL?editors=0010)
+
+It is important that we also call `ReactDOM.unmountComponentAtNode()` in the `remove` method so that React unregisters event handlers and other resources associated with the component tree when it is detached.
+
+When a component is removed *from within* a React tree, the cleanup is performed automatically, but because we are removing the entire tree by hand, we must call it this method.
+
+## Integrating with Model Layers
+
+While it is generally recommended to use unidirectional data flow such as [React state](/react/docs/lifting-state-up.html), [Flux](http://facebook.github.io/flux/), or [Redux](http://redux.js.org/), React components can use a model layer from other frameworks and libraries.
+
+### Using Backbone Models in React Components
+
+The simplest way to consume [Backbone](http://backbonejs.org/) models and collections from a React component is to listen to the various change events and manually force an update.
+
+Components responsible for rendering models would listen to `'change'` events, while components responsible for rendering collections would listen for `'add'` and `'remove'` events. In both cases, call [`this.forceUpdate()`](/react/docs/react-component.html#forceupdate) to rerender the component with the new data.
+
+In the example below, the `List` component renders a Backbone collection, using the `Item` component to render individual items.
+
+```js{1,7-9,12,16,24,30-32,35,39,46}
+class Item extends React.Component {
+  constructor(props) {
+    super(props);
+    this.handleChange = this.handleChange.bind(this);
+  }
+
+  handleChange() {
+    this.forceUpdate();
+  }
+
+  componentDidMount() {
+    this.props.model.on('change', this.handleChange);
+  }
+
+  componentWillUnmount() {
+    this.props.model.off('change', this.handleChange);
+  }
+
+  render() {
+    return <li>{this.props.model.get('text')}</li>;
+  }
+}
+
+class List extends React.Component {
+  constructor(props) {
+    super(props);
+    this.handleChange = this.handleChange.bind(this);
+  }
+
+  handleChange() {
+    this.forceUpdate();
+  }
+
+  componentDidMount() {
+    this.props.collection.on('add', 'remove', this.handleChange);
+  }
+
+  componentWillUnmount() {
+    this.props.collection.off('add', 'remove', this.handleChange);
+  }
+
+  render() {
+    return (
+      <ul>
+        {this.props.collection.map(model => (
+          <Item key={model.cid} model={model} />
+        ))}
+      </ul>
+    );
+  }
+}
+```
+
+[Try it on CodePen.](http://codepen.io/gaearon/pen/GmrREm?editors=0010)
+
+### Extracting Data from Backbone Models
+
+The approach above requires your React components to be aware of the Backbone models and collections. If you later plan to migrate to another data management solution, you might want to concentrate the knowledge about Backbone in as few parts of the code as possible.
+
+One solution to this is to extract the model's attributes as plain data whenever it changes, and keep this logic in a single place. The following is [a higher-order component](/react/docs/higher-order-components.html) that extracts all attributes of a Backbone model into state, passing the data to the wrapped component.
+
+This way, only the higher-order component needs to know about Backbone model internals, and most components in the app can stay agnostic of Backbone.
+
+In the example below, we will make a copy of the model's attributes to form the initial state. We subscribe to the `change` event (and unsubscribe on unmounting), and when it happens, we update the state with the model's current attributes. Finally, we make sure that if the `model` prop itself changes, we don't forget to unsubscribe from the old model, and subscribe to the new one.
+
+Note that this example is not meant to be exhaustive with regards to working with Backbone, but it should give you an idea for how to approach this in a generic way:
+
+```js{1,5,10,14,16,17,22,26,32}
+function connectToBackboneModel(WrappedComponent) {
+  return class BackboneComponent extends React.Component {
+    constructor(props) {
+      super(props);
+      this.state = Object.assign({}, props.model.attributes);
+      this.handleChange = this.handleChange.bind(this);
+    }
+
+    componentDidMount() {
+      this.props.model.on('change', this.handleChange);
+    }
+
+    componentWillReceiveProps(nextProps) {
+      this.setState(Object.assign({}, nextProps.model.attributes));
+      if (nextProps.model !== this.props.model) {
+        this.props.model.off('change', this.handleChange);
+        nextProps.model.on('change', this.handleChange);
+      }
+    }
+
+    componentWillUnmount() {
+      this.props.model.off('change', this.handleChange);
+    }
+
+    handleChange(model) {
+      this.setState(model.changedAttributes());
+    }
+
+    render() {
+      const propsExceptModel = Object.assign({}, this.props);
+      delete propsExceptModel.model;
+      return <WrappedComponent {...propsExceptModel} {...this.state} />;
+    }
+  }
+}
+```
+
+To demonstrate how to use it, we will connect a `NameInput` React component to a Backbone model, and update its `firstName` attribute every time the input changes:
+
+```js{4,6,11,15,19-21}
+function NameInput(props) {
+  return (
+    <p>
+      <input value={props.firstName} onChange={props.handleChange} />
+      <br />
+      My name is {props.firstName}.
+    </p>
+  );
+}
+
+const BackboneNameInput = connectToBackboneModel(NameInput);
+
+function Example(props) {
+  function handleChange(e) {
+    model.set('firstName', e.target.value);
+  }
+
+  return (
+    <BackboneNameInput
+      model={props.model}
+      handleChange={handleChange}
+    />
+  );
+}
+
+const model = new Backbone.Model({ firstName: 'Frodo' });
+ReactDOM.render(
+  <Example model={model} />,
+  document.getElementById('root')
+);
+```
+
+[Try it on CodePen.](http://codepen.io/gaearon/pen/PmWwwa?editors=0010)
+
+This technique is not limited to Backbone. You can use React with any model library by subscribing to its changes in the lifecycle hooks and, optionally, copying the data into the local React state.
diff --git a/docs/docs/introducing-jsx.md b/docs/docs/introducing-jsx.md
new file mode 100644
index 000000000000..d83a8e84a914
--- /dev/null
+++ b/docs/docs/introducing-jsx.md
@@ -0,0 +1,162 @@
+---
+id: introducing-jsx
+title: Introducing JSX
+permalink: docs/introducing-jsx.html
+prev: hello-world.html
+next: rendering-elements.html
+---
+
+Consider this variable declaration:
+
+```js
+const element = <h1>Hello, world!</h1>;
+```
+
+This funny tag syntax is neither a string nor HTML.
+
+It is called JSX, and it is a syntax extension to JavaScript. We recommend using it with React to describe what the UI should look like. JSX may remind you of a template language, but it comes with the full power of JavaScript.
+
+JSX produces React "elements". We will explore rendering them to the DOM in the [next section](/react/docs/rendering-elements.html). Below, you can find the basics of JSX necessary to get you started.
+
+### Embedding Expressions in JSX
+
+You can embed any [JavaScript expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Expressions) in JSX by wrapping it in curly braces.
+
+For example, `2 + 2`, `user.firstName`, and `formatName(user)` are all valid expressions:
+
+```js{12}
+function formatName(user) {
+  return user.firstName + ' ' + user.lastName;
+}
+
+const user = {
+  firstName: 'Harper',
+  lastName: 'Perez'
+};
+
+const element = (
+  <h1>
+    Hello, {formatName(user)}!
+  </h1>
+);
+
+ReactDOM.render(
+  element,
+  document.getElementById('root')
+);
+```
+
+[Try it on CodePen.](http://codepen.io/gaearon/pen/PGEjdG?editors=0010)
+
+We split JSX over multiple lines for readability. While it isn't required, when doing this, we also recommend wrapping it in parentheses to avoid the pitfalls of [automatic semicolon insertion](http://stackoverflow.com/q/2846283).
+
+### JSX is an Expression Too
+
+After compilation, JSX expressions become regular JavaScript objects.
+
+This means that you can use JSX inside of `if` statements and `for` loops, assign it to variables, accept it as arguments, and return it from functions:
+
+```js{3,5}
+function getGreeting(user) {
+  if (user) {
+    return <h1>Hello, {formatName(user)}!</h1>;
+  }
+  return <h1>Hello, Stranger.</h1>;
+}
+```
+
+### Specifying Attributes with JSX
+
+You may use quotes to specify string literals as attributes:
+
+```js
+const element = <div tabIndex="0"></div>;
+```
+
+You may also use curly braces to embed a JavaScript expression in an attribute:
+
+```js
+const element = <img src={user.avatarUrl}></img>;
+```
+
+Don't put quotes around curly braces when embedding a JavaScript expression in an attribute. Otherwise JSX will treat the attribute as a string literal rather than an expression. You should either use quotes (for string values) or curly braces (for expressions), but not both in the same attribute.
+
+### Specifying Children with JSX
+
+If a tag is empty, you may close it immediately with `/>`, like XML:
+
+```js
+const element = <img src={user.avatarUrl} />;
+```
+
+JSX tags may contain children:
+
+```js
+const element = (
+  <div>
+    <h1>Hello!</h1>
+    <h2>Good to see you here.</h2>
+  </div>
+);
+```
+
+>**Caveat:**
+>
+>Since JSX is closer to JavaScript than HTML, React DOM uses `camelCase` property naming convention instead of HTML attribute names.
+>
+>For example, `class` becomes [`className`](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) in JSX, and `tabindex` becomes [`tabIndex`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/tabIndex).
+
+### JSX Prevents Injection Attacks
+
+It is safe to embed user input in JSX:
+
+```js
+const title = response.potentiallyMaliciousInput;
+// This is safe:
+const element = <h1>{title}</h1>;
+```
+
+By default, React DOM [escapes](http://stackoverflow.com/questions/7381974/which-characters-need-to-be-escaped-on-html) any values embedded in JSX before rendering them. Thus it ensures that you can never inject anything that's not explicitly written in your application. Everything is converted to a string before being rendered. This helps prevent [XSS (cross-site-scripting)](https://en.wikipedia.org/wiki/Cross-site_scripting) attacks.
+
+### JSX Represents Objects
+
+Babel compiles JSX down to `React.createElement()` calls.
+
+These two examples are identical:
+
+```js
+const element = (
+  <h1 className="greeting">
+    Hello, world!
+  </h1>
+);
+```
+
+```js
+const element = React.createElement(
+  'h1',
+  {className: 'greeting'},
+  'Hello, world!'
+);
+```
+
+`React.createElement()` performs a few checks to help you write bug-free code but essentially it creates an object like this:
+
+```js
+// Note: this structure is simplified
+const element = {
+  type: 'h1',
+  props: {
+    className: 'greeting',
+    children: 'Hello, world'
+  }
+};
+```
+
+These objects are called "React elements". You can think of them as descriptions of what you want to see on the screen. React reads these objects and uses them to construct the DOM and keep it up to date.
+
+We will explore rendering React elements to the DOM in the next section.
+
+>**Tip:**
+>
+>We recommend searching for a "Babel" syntax scheme for your editor of choice so that both ES6 and JSX code is properly highlighted.
diff --git a/docs/docs/jsx-in-depth.md b/docs/docs/jsx-in-depth.md
new file mode 100644
index 000000000000..282c199d5573
--- /dev/null
+++ b/docs/docs/jsx-in-depth.md
@@ -0,0 +1,426 @@
+---
+id: jsx-in-depth
+title: JSX In Depth
+permalink: docs/jsx-in-depth.html
+redirect_from:
+  - "docs/jsx-spread.html"
+  - "docs/jsx-gotchas.html"
+  - "tips/if-else-in-JSX.html"
+  - "tips/self-closing-tag.html"
+  - "tips/maximum-number-of-jsx-root-nodes.html"
+  - "tips/children-props-type.html"
+  - "docs/jsx-in-depth-zh-CN.html"
+  - "docs/jsx-in-depth-ko-KR.html"
+---
+
+Fundamentally, JSX just provides syntactic sugar for the `React.createElement(component, props, ...children)` function. The JSX code:
+
+```js
+<MyButton color="blue" shadowSize={2}>
+  Click Me
+</MyButton>
+```
+
+compiles into:
+
+```js
+React.createElement(
+  MyButton,
+  {color: 'blue', shadowSize: 2},
+  'Click Me'
+)
+```
+
+You can also use the self-closing form of the tag if there are no children. So:
+
+```js
+<div className="sidebar" />
+```
+
+compiles into:
+
+```js
+React.createElement(
+  'div',
+  {className: 'sidebar'},
+  null
+)
+```
+
+If you want to test out how some specific JSX is converted into JavaScript, you can try out [the online Babel compiler](https://babeljs.io/repl/#?babili=false&evaluate=true&lineWrap=false&presets=es2015%2Creact%2Cstage-0&code=function%20hello()%20%7B%0A%20%20return%20%3Cdiv%3EHello%20world!%3C%2Fdiv%3E%3B%0A%7D).
+
+## Specifying The React Element Type
+
+The first part of a JSX tag determines the type of the React element.
+
+Capitalized types indicate that the JSX tag is referring to a React component. These tags get compiled into a direct reference to the named variable, so if you use the JSX `<Foo />` expression, `Foo` must be in scope.
+
+### React Must Be in Scope
+
+Since JSX compiles into calls to `React.createElement`, the `React` library must also always be in scope from your JSX code.
+
+For example, both of the imports are necessary in this code, even though `React` and `CustomButton` are not directly referenced from JavaScript:
+
+```js{1,2,5}
+import React from 'react';
+import CustomButton from './CustomButton';
+
+function WarningButton() {
+  // return React.createElement(CustomButton, {color: 'red'}, null);
+  return <CustomButton color="red" />;
+}
+```
+
+If you don't use a JavaScript bundler and loaded React from a `<script>` tag, it is already in scope as the `React` global.
+
+### Using Dot Notation for JSX Type
+
+You can also refer to a React component using dot-notation from within JSX. This is convenient if you have a single module that exports many React components. For example, if `MyComponents.DatePicker` is a component, you can use it directly from JSX with:
+
+```js{10}
+import React from 'react';
+
+const MyComponents = {
+  DatePicker: function DatePicker(props) {
+    return <div>Imagine a {props.color} datepicker here.</div>;
+  }
+}
+
+function BlueDatePicker() {
+  return <MyComponents.DatePicker color="blue" />;
+}
+```
+
+### User-Defined Components Must Be Capitalized
+
+When an element type starts with a lowercase letter, it refers to a built-in component like `<div>` or `<span>` and results in a string `'div'` or `'span'` passed to `React.createElement`. Types that start with a capital letter like `<Foo />` compile to `React.createElement(Foo)` and correspond to a component defined or imported in your JavaScript file.
+
+We recommend naming components with a capital letter. If you do have a component that starts with a lowercase letter, assign it to a capitalized variable before using it in JSX.
+
+For example, this code will not run as expected:
+
+```js{3,4,10,11}
+import React from 'react';
+
+// Wrong! This is a component and should have been capitalized:
+function hello(props) {
+  // Correct! This use of <div> is legitimate because div is a valid HTML tag:
+  return <div>Hello {props.toWhat}</div>;
+}
+
+function HelloWorld() {
+  // Wrong! React thinks <hello /> is an HTML tag because it's not capitalized:
+  return <hello toWhat="World" />;
+}
+```
+
+To fix this, we will rename `hello` to `Hello` and use `<Hello />` when referring to it:
+
+```js{3,4,10,11}
+import React from 'react';
+
+// Correct! This is a component and should be capitalized:
+function Hello(props) {
+  // Correct! This use of <div> is legitimate because div is a valid HTML tag:
+  return <div>Hello {props.toWhat}</div>;
+}
+
+function HelloWorld() {
+  // Correct! React knows <Hello /> is a component because it's capitalized.
+  return <Hello toWhat="World" />;
+}
+```
+
+### Choosing the Type at Runtime
+
+You cannot use a general expression as the React element type. If you do want to use a general expression to indicate the type of the element, just assign it to a capitalized variable first. This often comes up when you want to render a different component based on a prop:
+
+```js{10,11}
+import React from 'react';
+import { PhotoStory, VideoStory } from './stories';
+
+const components = {
+  photo: PhotoStory,
+  video: VideoStory
+};
+
+function Story(props) {
+  // Wrong! JSX type can't be an expression.
+  return <components[props.storyType] story={props.story} />;
+}
+```
+
+To fix this, we will assign the type to a capitalized variable first:
+
+```js{10-12}
+import React from 'react';
+import { PhotoStory, VideoStory } from './stories';
+
+const components = {
+  photo: PhotoStory,
+  video: VideoStory
+};
+
+function Story(props) {
+  // Correct! JSX type can be a capitalized variable.
+  const SpecificStory = components[props.storyType];
+  return <SpecificStory story={props.story} />;
+}
+```
+
+## Props in JSX
+
+There are several different ways to specify props in JSX.
+
+### JavaScript Expressions as Props
+
+You can pass any JavaScript expression as a prop, by surrounding it with `{}`. For example, in this JSX:
+
+```js
+<MyComponent foo={1 + 2 + 3 + 4} />
+```
+
+For `MyComponent`, the value of `props.foo` will be `10` because the expression `1 + 2 + 3 + 4` gets evaluated.
+
+`if` statements and `for` loops are not expressions in JavaScript, so they can't be used in JSX directly. Instead, you can put these in the surrounding code. For example:
+
+```js{3-7}
+function NumberDescriber(props) {
+  let description;
+  if (props.number % 2 == 0) {
+    description = <strong>even</strong>;
+  } else {
+    description = <i>odd</i>;
+  }
+  return <div>{props.number} is an {description} number</div>;
+}
+```
+
+You can learn more about [conditional rendering](/react/docs/conditional-rendering.html) and [loops](/react/docs/lists-and-keys.html) in the corresponding sections.
+
+### String Literals
+
+You can pass a string literal as a prop. These two JSX expressions are equivalent:
+
+```js
+<MyComponent message="hello world" />
+
+<MyComponent message={'hello world'} />
+```
+
+When you pass a string literal, its value is HTML-unescaped. So these two JSX expressions are equivalent:
+
+```js
+<MyComponent message="&lt;3" />
+
+<MyComponent message={'<3'} />
+```
+
+This behavior is usually not relevant. It's only mentioned here for completeness.
+
+### Props Default to "True"
+
+If you pass no value for a prop, it defaults to `true`. These two JSX expressions are equivalent:
+
+```js
+<MyTextBox autocomplete />
+
+<MyTextBox autocomplete={true} />
+```
+
+In general, we don't recommend using this because it can be confused with the [ES6 object shorthand](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Object_initializer#New_notations_in_ECMAScript_2015) `{foo}` which is short for `{foo: foo}` rather than `{foo: true}`. This behavior is just there so that it matches the behavior of HTML.
+
+### Spread Attributes
+
+If you already have `props` as an object, and you want to pass it in JSX, you can use `...` as a "spread" operator to pass the whole props object. These two components are equivalent:
+
+```js{7}
+function App1() {
+  return <Greeting firstName="Ben" lastName="Hector" />;
+}
+
+function App2() {
+  const props = {firstName: 'Ben', lastName: 'Hector'};
+  return <Greeting {...props} />;
+}
+```
+
+Spread attributes can be useful when you are building generic containers. However, they can also make your code messy by making it easy to pass a lot of irrelevant props to components that don't care about them. We recommend that you use this syntax sparingly.
+
+## Children in JSX
+
+In JSX expressions that contain both an opening tag and a closing tag, the content between those tags is passed as a special prop: `props.children`. There are several different ways to pass children:
+
+### String Literals
+
+You can put a string between the opening and closing tags and `props.children` will just be that string. This is useful for many of the built-in HTML elements. For example:
+
+```js
+<MyComponent>Hello world!</MyComponent>
+```
+
+This is valid JSX, and `props.children` in `MyComponent` will simply be the string `"Hello world!"`. HTML is unescaped, so you can generally write JSX just like you would write HTML in this way:
+
+```html
+<div>This is valid HTML &amp; JSX at the same time.</div>
+```
+
+JSX removes whitespace at the beginning and ending of a line. It also removes blank lines. New lines adjacent to tags are removed; new lines that occur in the middle of string literals are condensed into a single space. So these all render to the same thing:
+
+```js
+<div>Hello World</div>
+
+<div>
+  Hello World
+</div>
+
+<div>
+  Hello
+  World
+</div>
+
+<div>
+
+  Hello World
+</div>
+```
+
+### JSX Children
+
+You can provide more JSX elements as the children. This is useful for displaying nested components:
+
+```js
+<MyContainer>
+  <MyFirstComponent />
+  <MySecondComponent />
+</MyContainer>
+```
+
+You can mix together different types of children, so you can use string literals together with JSX children. This is another way in which JSX is like HTML, so that this is both valid JSX and valid HTML:
+
+```html
+<div>
+  Here is a list:
+  <ul>
+    <li>Item 1</li>
+    <li>Item 2</li>
+  </ul>
+</div>
+```
+
+A React component can't return multiple React elements, but a single JSX expression can have multiple children, so if you want a component to render multiple things you can wrap it in a `div` like this.
+
+### JavaScript Expressions as Children
+
+You can pass any JavaScript expression as children, by enclosing it within `{}`. For example, these expressions are equivalent:
+
+```js
+<MyComponent>foo</MyComponent>
+
+<MyComponent>{'foo'}</MyComponent>
+```
+
+This is often useful for rendering a list of JSX expressions of arbitrary length. For example, this renders an HTML list:
+
+```js{2,9}
+function Item(props) {
+  return <li>{props.message}</li>;
+}
+
+function TodoList() {
+  const todos = ['finish doc', 'submit pr', 'nag dan to review'];
+  return (
+    <ul>
+      {todos.map((message) => <Item key={message} message={message} />)}
+    </ul>
+  );
+}
+```
+
+JavaScript expressions can be mixed with other types of children. This is often useful in lieu of string templates:
+
+```js{2}
+function Hello(props) {
+  return <div>Hello {props.addressee}!</div>;
+}
+```
+
+### Functions as Children
+
+Normally, JavaScript expressions inserted in JSX will evaluate to a string, a React element, or a list of those things. However, `props.children` works just like any other prop in that it can pass any sort of data, not just the sorts that React knows how to render. For example, if you have a custom component, you could have it take a callback as `props.children`:
+
+```js{4,13}
+// Calls the children callback numTimes to produce a repeated component
+function Repeat(props) {
+  let items = [];
+  for (let i = 0; i < props.numTimes; i++) {
+    items.push(props.children(i));
+  }
+  return <div>{items}</div>;
+}
+
+function ListOfTenThings() {
+  return (
+    <Repeat numTimes={10}>
+      {(index) => <div key={index}>This is item {index} in the list</div>}
+    </Repeat>
+  );
+}
+```
+
+Children passed to a custom component can be anything, as long as that component transforms them into something React can understand before rendering. This usage is not common, but it works if you want to stretch what JSX is capable of.
+
+### Booleans, Null, and Undefined Are Ignored
+
+`false`, `null`, `undefined`, and `true` are valid children. They simply don't render. These JSX expressions will all render to the same thing:
+
+```js
+<div />
+
+<div></div>
+
+<div>{false}</div>
+
+<div>{null}</div>
+
+<div>{undefined}</div>
+
+<div>{true}</div>
+```
+
+This can be useful to conditionally render React elements. This JSX only renders a `<Header />` if `showHeader` is `true`:
+
+```js{2}
+<div>
+  {showHeader && <Header />}
+  <Content />
+</div>
+```
+
+One caveat is that some ["falsy" values](https://developer.mozilla.org/en-US/docs/Glossary/Falsy), such as the `0` number, are still rendered by React. For example, this code will not behave as you might expect because `0` will be printed when `props.messages` is an empty array:
+
+```js{2}
+<div>
+  {props.messages.length &&
+    <MessageList messages={props.messages} />
+  }
+</div>
+```
+
+To fix this, make sure that the expression before `&&` is always boolean:
+
+```js{2}
+<div>
+  {props.messages.length > 0 &&
+    <MessageList messages={props.messages} />
+  }
+</div>
+```
+
+Conversely, if you want a value like `false`, `true`, `null`, or `undefined` to appear in the output, you have to [convert it to a string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#String_conversion) first:
+
+```js{2}
+<div>
+  My JavaScript variable is {String(myVariable)}.
+</div>
+```
diff --git a/docs/docs/lifting-state-up.md b/docs/docs/lifting-state-up.md
new file mode 100644
index 000000000000..56ab0feb20ec
--- /dev/null
+++ b/docs/docs/lifting-state-up.md
@@ -0,0 +1,325 @@
+---
+id: lifting-state-up
+title: Lifting State Up
+permalink: docs/lifting-state-up.html
+prev: forms.html
+next: composition-vs-inheritance.html
+redirect_from:
+  - "docs/flux-overview.html"
+  - "docs/flux-todo-list.html"
+---
+
+Often, several components need to reflect the same changing data. We recommend lifting the shared state up to their closest common ancestor. Let's see how this works in action.
+
+In this section, we will create a temperature calculator that calculates whether the water would boil at a given temperature.
+
+We will start with a component called `BoilingVerdict`. It accepts the `celsius` temperature as a prop, and prints whether it is enough to boil the water:
+
+```js{3,5}
+function BoilingVerdict(props) {
+  if (props.celsius >= 100) {
+    return <p>The water would boil.</p>;
+  }
+  return <p>The water would not boil.</p>;
+}
+```
+
+Next, we will create a component called `Calculator`. It renders an `<input>` that lets you enter the temperature, and keeps its value in `this.state.temperature`.
+
+Additionally, it renders the `BoilingVerdict` for the current input value.
+
+```js{5,9,13,17-21}
+class Calculator extends React.Component {
+  constructor(props) {
+    super(props);
+    this.handleChange = this.handleChange.bind(this);
+    this.state = {temperature: ''};
+  }
+
+  handleChange(e) {
+    this.setState({temperature: e.target.value});
+  }
+
+  render() {
+    const temperature = this.state.temperature;
+    return (
+      <fieldset>
+        <legend>Enter temperature in Celsius:</legend>
+        <input
+          value={temperature}
+          onChange={this.handleChange} />
+        <BoilingVerdict
+          celsius={parseFloat(temperature)} />
+      </fieldset>
+    );
+  }
+}
+```
+
+[Try it on CodePen.](http://codepen.io/valscion/pen/VpZJRZ?editors=0010)
+
+## Adding a Second Input
+
+Our new requirement is that, in addition to a Celsius input, we provide a Fahrenheit input, and they are kept in sync.
+
+We can start by extracting a `TemperatureInput` component from `Calculator`. We will add a new `scale` prop to it that can either be `"c"` or `"f"`:
+
+```js{1-4,19,22}
+const scaleNames = {
+  c: 'Celsius',
+  f: 'Fahrenheit'
+};
+
+class TemperatureInput extends React.Component {
+  constructor(props) {
+    super(props);
+    this.handleChange = this.handleChange.bind(this);
+    this.state = {temperature: ''};
+  }
+
+  handleChange(e) {
+    this.setState({temperature: e.target.value});
+  }
+
+  render() {
+    const temperature = this.state.temperature;
+    const scale = this.props.scale;
+    return (
+      <fieldset>
+        <legend>Enter temperature in {scaleNames[scale]}:</legend>
+        <input value={temperature}
+               onChange={this.handleChange} />
+      </fieldset>
+    );
+  }
+}
+```
+
+We can now change the `Calculator` to render two separate temperature inputs:
+
+```js{5,6}
+class Calculator extends React.Component {
+  render() {
+    return (
+      <div>
+        <TemperatureInput scale="c" />
+        <TemperatureInput scale="f" />
+      </div>
+    );
+  }
+}
+```
+
+[Try it on CodePen.](http://codepen.io/valscion/pen/GWKbao?editors=0010)
+
+We have two inputs now, but when you enter the temperature in one of them, the other doesn't update. This contradicts our requirement: we want to keep them in sync.
+
+We also can't display the `BoilingVerdict` from `Calculator`. The `Calculator` doesn't know the current temperature because it is hidden inside the `TemperatureInput`.
+
+## Writing Conversion Functions
+
+First, we will write two functions to convert from Celsius to Fahrenheit and back:
+
+```js
+function toCelsius(fahrenheit) {
+  return (fahrenheit - 32) * 5 / 9;
+}
+
+function toFahrenheit(celsius) {
+  return (celsius * 9 / 5) + 32;
+}
+```
+
+These two functions convert numbers. We will write another function that takes a string `temperature` and a converter function as arguments and returns a string. We will use it to calculate the value of one input based on the other input.
+
+It returns an empty string on an invalid `temperature`, and it keeps the output rounded to the third decimal place:
+
+```js
+function tryConvert(temperature, convert) {
+  const input = parseFloat(temperature);
+  if (Number.isNaN(input)) {
+    return '';
+  }
+  const output = convert(input);
+  const rounded = Math.round(output * 1000) / 1000;
+  return rounded.toString();
+}
+```
+
+For example, `tryConvert('abc', toCelsius)` returns an empty string, and `tryConvert('10.22', toFahrenheit)` returns `'50.396'`.
+
+## Lifting State Up
+
+Currently, both `TemperatureInput` components independently keep their values in the local state:
+
+```js{5,9,13}
+class TemperatureInput extends React.Component {
+  constructor(props) {
+    super(props);
+    this.handleChange = this.handleChange.bind(this);
+    this.state = {temperature: ''};
+  }
+
+  handleChange(e) {
+    this.setState({temperature: e.target.value});
+  }
+
+  render() {
+    const temperature = this.state.temperature;
+```
+
+However, we want these two inputs to be in sync with each other. When we update the Celsius input, the Fahrenheit input should reflect the converted temperature, and vice versa.
+
+In React, sharing state is accomplished by moving it up to the closest common ancestor of the components that need it. This is called "lifting state up". We will remove the local state from the `TemperatureInput` and move it into the `Calculator` instead.
+
+If the `Calculator` owns the shared state, it becomes the "source of truth" for the current temperature in both inputs. It can instruct them both to have values that are consistent with each other. Since the props of both `TemperatureInput` components are coming from the same parent `Calculator` component, the two inputs will always be in sync.
+
+Let's see how this works step by step.
+
+First, we will replace `this.state.temperature` with `this.props.temperature` in the `TemperatureInput` component. For now, let's pretend `this.props.temperature` already exists, although we will need to pass it from the `Calculator` in the future:
+
+```js{3}
+  render() {
+    // Before: const temperature = this.state.temperature;
+    const temperature = this.props.temperature;
+```
+
+We know that [props are read-only](/react/docs/components-and-props.html#props-are-read-only). When the `temperature` was in the local state, the `TemperatureInput` could just call `this.setState()` to change it. However, now that the `temperature` is coming from the parent as a prop, the `TemperatureInput` has no control over it.
+
+In React, this is usually solved by making a component "controlled". Just like the DOM `<input>` accepts both a `value` and an `onChange` prop, so can the custom `TemperatureInput` accept both `temperature` and `onTemperatureChange` props from its parent `Calculator`.
+
+Now, when the `TemperatureInput` wants to update its temperature, it calls `this.props.onTemperatureChange`:
+
+```js{3}
+  handleChange(e) {
+    // Before: this.setState({temperature: e.target.value});
+    this.props.onTemperatureChange(e.target.value);
+```
+
+>Note:
+>
+>There is no special meaning to either `temperature` or `onTemperatureChange` prop names in custom components. We could have called them anything else, like name them `value` and `onChange` which is a common convention.
+
+The `onTemperatureChange` prop will be provided together with the `temperature` prop by the parent `Calculator` component. It will handle the change by modifying its own local state, thus re-rendering both inputs with the new values. We will look at the new `Calculator` implementation very soon.
+
+Before diving into the changes in the `Calculator`, let's recap our changes to the `TemperatureInput` component. We have removed the local state from it, and instead of reading `this.state.temperature`, we now read `this.props.temperature`. Instead of calling `this.setState()` when we want to make a change, we now call `this.props.onTemperatureChange()`, which will be provided by the `Calculator`:
+
+```js{8,12}
+class TemperatureInput extends React.Component {
+  constructor(props) {
+    super(props);
+    this.handleChange = this.handleChange.bind(this);
+  }
+
+  handleChange(e) {
+    this.props.onTemperatureChange(e.target.value);
+  }
+
+  render() {
+    const temperature = this.props.temperature;
+    const scale = this.props.scale;
+    return (
+      <fieldset>
+        <legend>Enter temperature in {scaleNames[scale]}:</legend>
+        <input value={temperature}
+               onChange={this.handleChange} />
+      </fieldset>
+    );
+  }
+}
+```
+
+Now let's turn to the `Calculator` component.
+
+We will store the current input's `temperature` and `scale` in its local state. This is the state we "lifted up" from the inputs, and it will serve as the "source of truth" for both of them. It is the minimal representation of all the data we need to know in order to render both inputs.
+
+For example, if we enter 37 into the Celsius input, the state of the `Calculator` component will be:
+
+```js
+{
+  temperature: '37',
+  scale: 'c'
+}
+```
+
+If we later edit the Fahrenheit field to be 212, the state of the `Calculator` will be:
+
+```js
+{
+  temperature: '212',
+  scale: 'f'
+}
+```
+
+We could have stored the value of both inputs but it turns out to be unnecessary. It is enough to store the value of the most recently changed input, and the scale that it represents. We can then infer the value of the other input based on the current `temperature` and `scale` alone.
+
+The inputs stay in sync because their values are computed from the same state:
+
+```js{6,10,14,18-21,27-28,31-32,34}
+class Calculator extends React.Component {
+  constructor(props) {
+    super(props);
+    this.handleCelsiusChange = this.handleCelsiusChange.bind(this);
+    this.handleFahrenheitChange = this.handleFahrenheitChange.bind(this);
+    this.state = {temperature: '', scale: 'c'};
+  }
+
+  handleCelsiusChange(temperature) {
+    this.setState({scale: 'c', temperature});
+  }
+
+  handleFahrenheitChange(temperature) {
+    this.setState({scale: 'f', temperature});
+  }
+
+  render() {
+    const scale = this.state.scale;
+    const temperature = this.state.temperature;
+    const celsius = scale === 'f' ? tryConvert(temperature, toCelsius) : temperature;
+    const fahrenheit = scale === 'c' ? tryConvert(temperature, toFahrenheit) : temperature;
+
+    return (
+      <div>
+        <TemperatureInput
+          scale="c"
+          temperature={celsius}
+          onTemperatureChange={this.handleCelsiusChange} />
+        <TemperatureInput
+          scale="f"
+          temperature={fahrenheit}
+          onTemperatureChange={this.handleFahrenheitChange} />
+        <BoilingVerdict
+          celsius={parseFloat(celsius)} />
+      </div>
+    );
+  }
+}
+```
+
+[Try it on CodePen.](http://codepen.io/valscion/pen/jBNjja?editors=0010)
+
+Now, no matter which input you edit, `this.state.temperature` and `this.state.scale` in the `Calculator` get updated. One of the inputs gets the value as is, so any user input is preserved, and the other input value is always recalculated based on it.
+
+Let's recap what happens when you edit an input:
+
+* React calls the function specified as `onChange` on the DOM `<input>`. In our case, this is the `handleChange` method in `TemperatureInput` component.
+* The `handleChange` method in the `TemperatureInput` component calls `this.props.onTemperatureChange()` with the new desired value. Its props, including `onTemperatureChange`, were provided by its parent component, the `Calculator`.
+* When it previously rendered, the `Calculator` has specified that `onTemperatureChange` of the Celsius `TemperatureInput` is the `Calculator`'s `handleCelsiusChange` method, and `onTemperatureChange` of the Fahrenheit `TemperatureInput` is the `Calculator`'s `handleFahrenheitChange` method. So either of these two `Calculator` methods gets called depending on which input we edited.
+* Inside these methods, the `Calculator` component asks React to re-render itself by calling `this.setState()` with the new input value and the current scale of the input we just edited.
+* React calls the `Calculator` component's `render` method to learn what the UI should look like. The values of both inputs are recomputed based on the current temperature and the active scale. The temperature conversion is performed here.
+* React calls the `render` methods of the individual `TemperatureInput` components with their new props specified by the `Calculator`. It learns what their UI should look like.
+* React DOM updates the DOM to match the desired input values. The input we just edited receives its current value, and the other input is updated to the temperature after conversion.
+
+Every update goes through the same steps so the inputs stay in sync.
+
+## Lessons Learned
+
+There should be a single "source of truth" for any data that changes in a React application. Usually, the state is first added to the component that needs it for rendering. Then, if other components also need it, you can lift it up to their closest common ancestor. Instead of trying to sync the state between different components, you should rely on the [top-down data flow](/react/docs/state-and-lifecycle.html#the-data-flows-down).
+
+Lifting state involves writing more "boilerplate" code than two-way binding approaches, but as a benefit, it takes less work to find and isolate bugs. Since any state "lives" in some component and that component alone can change it, the surface area for bugs is greatly reduced. Additionally, you can implement any custom logic to reject or transform user input.
+
+If something can be derived from either props or state, it probably shouldn't be in the state. For example, instead of storing both `celsiusValue` and `fahrenheitValue`, we store just the last edited `temperature` and its `scale`. The value of the other input can always be calculated from them in the `render()` method. This lets us clear or apply rounding to the other field without losing any precision in the user input.
+
+When you see something wrong in the UI, you can use [React Developer Tools](https://github.com/facebook/react-devtools) to inspect the props and move up the tree until you find the component responsible for updating the state. This lets you trace the bugs to their source:
+
+<img src="/react/img/docs/react-devtools-state.gif" alt="Monitoring State in React DevTools" width="100%">
diff --git a/docs/docs/lists-and-keys.md b/docs/docs/lists-and-keys.md
new file mode 100644
index 000000000000..9283fbe4ae70
--- /dev/null
+++ b/docs/docs/lists-and-keys.md
@@ -0,0 +1,299 @@
+---
+id: lists-and-keys
+title: Lists and Keys
+permalink: docs/lists-and-keys.html
+prev: conditional-rendering.html
+next: forms.html
+---
+
+First, let's review how you transform lists in JavaScript.
+
+Given the code below, we use the [`map()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) function to take an array of `numbers` and double their values. We assign the new array returned by `map()` to the variable `doubled` and log it:
+
+```javascript{2}
+const numbers = [1, 2, 3, 4, 5];
+const doubled = numbers.map((number) => number * 2);
+console.log(doubled);
+```
+
+This code logs `[2, 4, 6, 8, 10]` to the console.
+
+In React, transforming arrays into lists of [elements](/react/docs/rendering-elements.html) is nearly identical.
+
+### Rendering Multiple Components
+
+You can build collections of elements and [include them in JSX](/react/docs/introducing-jsx.html#embedding-expressions-in-jsx) using curly braces `{}`.
+
+Below, we loop through the `numbers` array using the JavaScript [`map()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) function. We return an `<li>` element for each item. Finally, we assign the resulting array of elements to `listItems`:
+
+```javascript{2-4}
+const numbers = [1, 2, 3, 4, 5];
+const listItems = numbers.map((number) =>
+  <li>{number}</li>
+);
+```
+
+We include the entire `listItems` array inside a `<ul>` element, and [render it to the DOM](/react/docs/rendering-elements.html#rendering-an-element-into-the-dom):
+
+```javascript{2}
+ReactDOM.render(
+  <ul>{listItems}</ul>,
+  document.getElementById('root')
+);
+```
+
+[Try it on CodePen.](https://codepen.io/gaearon/pen/GjPyQr?editors=0011)
+
+This code displays a bullet list of numbers between 1 and 5.
+
+### Basic List Component
+
+Usually you would render lists inside a [component](/react/docs/components-and-props.html).
+
+We can refactor the previous example into a component that accepts an array of `numbers` and outputs an unordered list of elements.
+
+```javascript{3-5,7,13}
+function NumberList(props) {
+  const numbers = props.numbers;
+  const listItems = numbers.map((number) =>
+    <li>{number}</li>
+  );
+  return (
+    <ul>{listItems}</ul>
+  );
+}
+
+const numbers = [1, 2, 3, 4, 5];
+ReactDOM.render(
+  <NumberList numbers={numbers} />,
+  document.getElementById('root')
+);
+```
+
+When you run this code, you'll be given a warning that a key should be provided for list items. A "key" is a special string attribute you need to include when creating lists of elements. We'll discuss why it's important in the next section.
+
+Let's assign a `key` to our list items inside `numbers.map()` and fix the missing key issue.
+
+```javascript{4}
+function NumberList(props) {
+  const numbers = props.numbers;
+  const listItems = numbers.map((number) =>
+    <li key={number.toString()}>
+      {number}
+    </li>
+  );
+  return (
+    <ul>{listItems}</ul>
+  );
+}
+
+const numbers = [1, 2, 3, 4, 5];
+ReactDOM.render(
+  <NumberList numbers={numbers} />,
+  document.getElementById('root')
+);
+```
+
+[Try it on CodePen.](https://codepen.io/gaearon/pen/jrXYRR?editors=0011)
+
+## Keys
+
+Keys help React identify which items have changed, are added, or are removed. Keys should be given to the elements inside the array to give the elements a stable identity:
+
+```js{3}
+const numbers = [1, 2, 3, 4, 5];
+const listItems = numbers.map((number) =>
+  <li key={number.toString()}>
+    {number}
+  </li>
+);
+```
+
+The best way to pick a key is to use a string that uniquely identifies a list item among its siblings. Most often you would use IDs from your data as keys:
+
+```js{2}
+const todoItems = todos.map((todo) =>
+  <li key={todo.id}>
+    {todo.text}
+  </li>
+);
+```
+
+When you don't have stable IDs for rendered items, you may use the item index as a key as a last resort:
+
+```js{2,3}
+const todoItems = todos.map((todo, index) =>
+  // Only do this if items have no stable IDs
+  <li key={index}>
+    {todo.text}
+  </li>
+);
+```
+
+We don't recommend using indexes for keys if the items can reorder, as that would be slow. You may read an [in-depth explanation about why keys are necessary](/react/docs/reconciliation.html#recursing-on-children) if you're interested.
+
+### Extracting Components with Keys
+
+Keys only make sense in the context of the surrounding array.
+
+For example, if you [extract](/react/docs/components-and-props.html#extracting-components) a `ListItem` component, you should keep the key on the `<ListItem />` elements in the array rather than on the root `<li>` element in the `ListItem` itself.
+
+**Example: Incorrect Key Usage**
+
+```javascript{4,5,14,15}
+function ListItem(props) {
+  const value = props.value;
+  return (
+    // Wrong! There is no need to specify the key here:
+    <li key={value.toString()}>
+      {value}
+    </li>
+  );
+}
+
+function NumberList(props) {
+  const numbers = props.numbers;
+  const listItems = numbers.map((number) =>
+    // Wrong! The key should have been specified here:
+    <ListItem value={number} />
+  );
+  return (
+    <ul>
+      {listItems}
+    </ul>
+  );
+}
+
+const numbers = [1, 2, 3, 4, 5];
+ReactDOM.render(
+  <NumberList numbers={numbers} />,
+  document.getElementById('root')
+);
+```
+
+**Example: Correct Key Usage**
+
+```javascript{2,3,9,10}
+function ListItem(props) {
+  // Correct! There is no need to specify the key here:
+  return <li>{props.value}</li>;
+}
+
+function NumberList(props) {
+  const numbers = props.numbers;
+  const listItems = numbers.map((number) =>
+    // Correct! Key should be specified inside the array.
+    <ListItem key={number.toString()}
+              value={number} />
+  );
+  return (
+    <ul>
+      {listItems}
+    </ul>
+  );
+}
+
+const numbers = [1, 2, 3, 4, 5];
+ReactDOM.render(
+  <NumberList numbers={numbers} />,
+  document.getElementById('root')
+);
+```
+
+[Try it on CodePen.](https://codepen.io/rthor/pen/QKzJKG?editors=0010)
+
+A good rule of thumb is that elements inside the `map()` call need keys.
+
+### Keys Must Only Be Unique Among Siblings
+
+Keys used within arrays should be unique among their siblings. However they don't need to be globally unique. We can use the same keys when we produce two different arrays:
+
+```js{2,5,11,12,19,21}
+function Blog(props) {
+  const sidebar = (
+    <ul>
+      {props.posts.map((post) =>
+        <li key={post.id}>
+          {post.title}
+        </li>
+      )}
+    </ul>
+  );
+  const content = props.posts.map((post) =>
+    <div key={post.id}>
+      <h3>{post.title}</h3>
+      <p>{post.content}</p>
+    </div>
+  );
+  return (
+    <div>
+      {sidebar}
+      <hr />
+      {content}
+    </div>
+  );
+}
+
+const posts = [
+  {id: 1, title: 'Hello World', content: 'Welcome to learning React!'},
+  {id: 2, title: 'Installation', content: 'You can install React from npm.'}
+];
+ReactDOM.render(
+  <Blog posts={posts} />,
+  document.getElementById('root')
+);
+```
+
+[Try it on CodePen.](https://codepen.io/gaearon/pen/NRZYGN?editors=0010)
+
+Keys serve as a hint to React but they don't get passed to your components. If you need the same value in your component, pass it explicitly as a prop with a different name:
+
+```js{3,4}
+const content = posts.map((post) =>
+  <Post
+    key={post.id}
+    id={post.id}
+    title={post.title} />
+);
+```
+
+With the example above, the `Post` component can read `props.id`, but not `props.key`.
+
+### Embedding map() in JSX
+
+In the examples above we declared a separate `listItems` variable and included it in JSX:
+
+```js{3-6}
+function NumberList(props) {
+  const numbers = props.numbers;
+  const listItems = numbers.map((number) =>
+    <ListItem key={number.toString()}
+              value={number} />
+  );
+  return (
+    <ul>
+      {listItems}
+    </ul>
+  );
+}
+```
+
+JSX allows [embedding any expressions](/react/docs/introducing-jsx.html#embedding-expressions-in-jsx) in curly braces so we could inline the `map()` result:
+
+```js{5-8}
+function NumberList(props) {
+  const numbers = props.numbers;
+  return (
+    <ul>
+      {numbers.map((number) =>
+        <ListItem key={number.toString()}
+                  value={number} />
+      )}
+    </ul>
+  );
+}
+```
+
+[Try it on CodePen.](https://codepen.io/gaearon/pen/BLvYrB?editors=0010)
+
+Sometimes this results in clearer code, but this style can also be abused. Like in JavaScript, it is up to you to decide whether it is worth extracting a variable for readability. Keep in mind that if the `map()` body is too nested, it might be a good time to [extract a component](/react/docs/components-and-props.html#extracting-components).
diff --git a/docs/docs/optimizing-performance.md b/docs/docs/optimizing-performance.md
new file mode 100644
index 000000000000..4b13d41ea4e9
--- /dev/null
+++ b/docs/docs/optimizing-performance.md
@@ -0,0 +1,390 @@
+---
+id: optimizing-performance
+title: Optimizing Performance
+permalink: docs/optimizing-performance.html
+redirect_from: "docs/advanced-performance.html"
+---
+
+Internally, React uses several clever techniques to minimize the number of costly DOM operations required to update the UI. For many applications, using React will lead to a fast user interface without doing much work to specifically optimize for performance. Nevertheless, there are several ways you can speed up your React application.
+
+## Use the Production Build
+
+If you're benchmarking or experiencing performance problems in your React apps, make sure you're testing with the minified production build.
+
+By default, React includes many helpful warnings. These warnings are very useful in development. However, they make React larger and slower so you should make sure to use the production version when you deploy the app.
+
+If you aren't sure whether your build process is set up correctly, you can check it by installing [React Developer Tools for Chrome](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi). If you visit a site with React in production mode, the icon will have a dark background:
+
+<img src="/react/img/docs/devtools-prod.png" style="max-width:100%" alt="React DevTools on a website with production version of React">
+
+If you visit a site with React in development mode, the icon will have a red background:
+
+<img src="/react/img/docs/devtools-dev.png" style="max-width:100%" alt="React DevTools on a website with development version of React">
+
+It is expected that you use the development mode when working on your app, and the production mode when deploying your app to the users.
+
+You can find instructions for building your app for production below.
+
+### Create React App
+
+If your project is built with [Create React App](https://github.com/facebookincubator/create-react-app), run:
+
+```
+npm run build
+```
+
+This will create a production build of your app in the `build/` folder of your project.
+
+Remember that this is only necessary before deploying to production. For normal development, use `npm start`.
+
+### Single-File Builds
+
+We offer production-ready versions of React and React DOM as single files:
+
+```html
+<script src="https://unpkg.com/react@15/dist/react.min.js"></script>
+<script src="https://unpkg.com/react-dom@15/dist/react-dom.min.js"></script>
+```
+
+Remember that only React files ending with `.min.js` are suitable for production.
+
+### Brunch
+
+For the most efficient Brunch production build, install the [`uglify-js-brunch`](https://github.com/brunch/uglify-js-brunch) plugin:
+
+```
+# If you use npm
+npm install --save-dev uglify-js-brunch
+
+# If you use Yarn
+yarn add --dev uglify-js-brunch
+```
+
+Then, to create a production build, add the `-p` flag to the `build` command:
+
+```
+brunch build -p
+```
+
+Remember that you only need to do this for production builds. You shouldn't pass `-p` flag or apply this plugin in development because it will hide useful React warnings, and make the builds much slower.
+
+### Browserify
+
+For the most efficient Browserify production build, install a few plugins:
+
+```
+# If you use npm
+npm install --save-dev bundle-collapser envify uglify-js uglifyify 
+
+# If you use Yarn
+yarn add --dev bundle-collapser envify uglify-js uglifyify 
+```
+
+To create a production build, make sure that you add these transforms **(the order matters)**:
+
+* The [`envify`](https://github.com/hughsk/envify) transform ensures the right build environment is set. Make it global (`-g`).
+* The [`uglifyify`](https://github.com/hughsk/uglifyify) transform removes development imports. Make it global too (`-g`).
+* The [`bundle-collapser`](https://github.com/substack/bundle-collapser) plugin replaces long module IDs with numbers.
+* Finally, the resulting bundle is piped to [`uglify-js`](https://github.com/mishoo/UglifyJS2) for mangling ([read why](https://github.com/hughsk/uglifyify#motivationusage)).
+
+For example:
+
+```
+browserify ./index.js \
+  -g [ envify --NODE_ENV production ] \
+  -g uglifyify \
+  -p bundle-collapser/plugin \
+  | uglifyjs --compress --mangle > ./bundle.js
+```
+
+>**Note:**
+>
+>The package name is `uglify-js`, but the binary it provides is called `uglifyjs`.<br>
+>This is not a typo.
+
+Remember that you only need to do this for production builds. You shouldn't apply these plugins in development because they will hide useful React warnings, and make the builds much slower.
+
+### Rollup
+
+For the most efficient Rollup production build, install a few plugins:
+
+```
+# If you use npm
+npm install --save-dev rollup-plugin-commonjs rollup-plugin-replace rollup-plugin-uglify 
+
+# If you use Yarn
+yarn add --dev rollup-plugin-commonjs rollup-plugin-replace rollup-plugin-uglify 
+```
+
+To create a production build, make sure that you add these plugins **(the order matters)**:
+
+* The [`replace`](https://github.com/rollup/rollup-plugin-replace) plugin ensures the right build environment is set.
+* The [`commonjs`](https://github.com/rollup/rollup-plugin-commonjs) plugin provides support for CommonJS in Rollup.
+* The [`uglify`](https://github.com/TrySound/rollup-plugin-uglify) plugin compresses and mangles the final bundle.
+
+```js
+plugins: [
+  // ...
+  require('rollup-plugin-replace')({
+    'process.env.NODE_ENV': JSON.stringify('production')
+  }),
+  require('rollup-plugin-commonjs')(),
+  require('rollup-plugin-uglify')(),
+  // ...
+]
+```
+
+For a complete setup example [see this gist](https://gist.github.com/Rich-Harris/cb14f4bc0670c47d00d191565be36bf0).
+
+Remember that you only need to do this for production builds. You shouldn't apply the `uglify` plugin or the `replace` plugin with `'production'` value in development because they will hide useful React warnings, and make the builds much slower.
+
+### webpack
+
+>**Note:**
+>
+>If you're using Create React App, please follow [the instructions above](#create-react-app).<br>
+>This section is only relevant if you configure webpack directly.
+
+For the most efficient webpack production build, make sure to include these plugins in your production configuration:
+
+```js
+new webpack.DefinePlugin({
+  'process.env': {
+    NODE_ENV: JSON.stringify('production')
+  }
+}),
+new webpack.optimize.UglifyJsPlugin()
+```
+
+You can learn more about this in [webpack documentation](https://webpack.js.org/guides/production-build/).
+
+Remember that you only need to do this for production builds. You shouldn't apply `UglifyJsPlugin` or `DefinePlugin` with `'production'` value in development because they will hide useful React warnings, and make the builds much slower.
+
+## Profiling Components with the Chrome Performance Tab
+
+In the **development** mode, you can visualize how components mount, update, and unmount, using the performance tools in supported browsers. For example:
+
+<center><img src="/react/img/blog/react-perf-chrome-timeline.png" style="max-width:100%" alt="React components in Chrome timeline" /></center>
+
+To do this in Chrome:
+
+1. Load your app with `?react_perf` in the query string (for example, `http://localhost:3000/?react_perf`).
+
+2. Open the Chrome DevTools **[Performance](https://developers.google.com/web/tools/chrome-devtools/evaluate-performance/timeline-tool)** tab and press **Record**.
+
+3. Perform the actions you want to profile. Don't record more than 20 seconds or Chrome might hang.
+
+4. Stop recording.
+
+5. React events will be grouped under the **User Timing** label.
+
+Note that **the numbers are relative so components will render faster in production**. Still, this should help you realize when unrelated UI gets updated by mistake, and how deep and how often your UI updates occur.
+
+Currently Chrome, Edge, and IE are the only browsers supporting this feature, but we use the standard [User Timing API](https://developer.mozilla.org/en-US/docs/Web/API/User_Timing_API) so we expect more browsers to add support for it.
+
+
+## Avoid Reconciliation
+
+React builds and maintains an internal representation of the rendered UI. It includes the React elements you return from your components. This representation lets React avoid creating DOM nodes and accessing existing ones beyond necessity, as that can be slower than operations on JavaScript objects. Sometimes it is referred to as a "virtual DOM", but it works the same way on React Native.
+
+When a component's props or state change, React decides whether an actual DOM update is necessary by comparing the newly returned element with the previously rendered one. When they are not equal, React will update the DOM.
+
+In some cases, your component can speed all of this up by overriding the lifecycle function `shouldComponentUpdate`, which is triggered before the re-rendering process starts. The default implementation of this function returns `true`, leaving React to perform the update:
+
+```javascript
+shouldComponentUpdate(nextProps, nextState) {
+  return true;
+}
+```
+
+If you know that in some situations your component doesn't need to update, you can return `false` from `shouldComponentUpdate` instead, to skip the whole rendering process, including calling `render()` on this component and below.
+
+## shouldComponentUpdate In Action
+
+Here's a subtree of components. For each one, `SCU` indicates what `shouldComponentUpdate` returned, and `vDOMEq` indicates whether the rendered React elements were equivalent. Finally, the circle's color indicates whether the component had to be reconciled or not.
+
+<figure><img src="/react/img/docs/should-component-update.png" style="max-width:100%" /></figure>
+
+Since `shouldComponentUpdate` returned `false` for the subtree rooted at C2, React did not attempt to render C2, and thus didn't even have to invoke `shouldComponentUpdate` on C4 and C5.
+
+For C1 and C3, `shouldComponentUpdate` returned `true`, so React had to go down to the leaves and check them. For C6 `shouldComponentUpdate` returned `true`, and since the rendered elements weren't equivalent React had to update the DOM.
+
+The last interesting case is C8. React had to render this component, but since the React elements it returned were equal to the previously rendered ones, it didn't have to update the DOM.
+
+Note that React only had to do DOM mutations for C6, which was inevitable. For C8, it bailed out by comparing the rendered React elements, and for C2's subtree and C7, it didn't even have to compare the elements as we bailed out on `shouldComponentUpdate`, and `render` was not called.
+
+## Examples
+
+If the only way your component ever changes is when the `props.color` or the `state.count` variable changes, you could have `shouldComponentUpdate` check that:
+
+```javascript
+class CounterButton extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {count: 1};
+  }
+
+  shouldComponentUpdate(nextProps, nextState) {
+    if (this.props.color !== nextProps.color) {
+      return true;
+    }
+    if (this.state.count !== nextState.count) {
+      return true;
+    }
+    return false;
+  }
+
+  render() {
+    return (
+      <button
+        color={this.props.color}
+        onClick={() => this.setState(state => ({count: state.count + 1}))}>
+        Count: {this.state.count}
+      </button>
+    );
+  }
+}
+```
+
+In this code, `shouldComponentUpdate` is just checking if there is any change in `props.color` or `state.count`. If those values don't change, the component doesn't update. If your component got more complex, you could use a similar pattern of doing a "shallow comparison" between all the fields of `props` and `state` to determine if the component should update. This pattern is common enough that React provides a helper to use this logic - just inherit from `React.PureComponent`. So this code is a simpler way to achieve the same thing:
+
+```js
+class CounterButton extends React.PureComponent {
+  constructor(props) {
+    super(props);
+    this.state = {count: 1};
+  }
+
+  render() {
+    return (
+      <button
+        color={this.props.color}
+        onClick={() => this.setState(state => ({count: state.count + 1}))}>
+        Count: {this.state.count}
+      </button>
+    );
+  }
+}
+```
+
+Most of the time, you can use `React.PureComponent` instead of writing your own `shouldComponentUpdate`. It only does a shallow comparison, so you can't use it if the props or state may have been mutated in a way that a shallow comparison would miss.
+
+This can be a problem with more complex data structures. For example, let's say you want a `ListOfWords` component to render a comma-separated list of words, with a parent `WordAdder` component that lets you click a button to add a word to the list. This code does *not* work correctly:
+
+```javascript
+class ListOfWords extends React.PureComponent {
+  render() {
+    return <div>{this.props.words.join(',')}</div>;
+  }
+}
+
+class WordAdder extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      words: ['marklar']
+    };
+    this.handleClick = this.handleClick.bind(this);
+  }
+
+  handleClick() {
+    // This section is bad style and causes a bug
+    const words = this.state.words;
+    words.push('marklar');
+    this.setState({words: words});
+  }
+
+  render() {
+    return (
+      <div>
+        <button onClick={this.handleClick} />
+        <ListOfWords words={this.state.words} />
+      </div>
+    );
+  }
+}
+```
+
+The problem is that `PureComponent` will do a simple comparison between the old and new values of `this.props.words`. Since this code mutates the `words` array in the `handleClick` method of `WordAdder`, the old and new values of `this.props.words` will compare as equal, even though the actual words in the array have changed. The `ListOfWords` will thus not update even though it has new words that should be rendered.
+
+## The Power Of Not Mutating Data
+
+The simplest way to avoid this problem is to avoid mutating values that you are using as props or state. For example, the `handleClick` method above could be rewritten using `concat` as:
+
+```javascript
+handleClick() {
+  this.setState(prevState => ({
+    words: prevState.words.concat(['marklar'])
+  }));
+}
+```
+
+ES6 supports a [spread syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator) for arrays which can make this easier. If you're using Create React App, this syntax is available by default.
+
+```js
+handleClick() {
+  this.setState(prevState => ({
+    words: [...prevState.words, 'marklar'],
+  }));
+};
+```
+
+You can also rewrite code that mutates objects to avoid mutation, in a similar way. For example, let's say we have an object named `colormap` and we want to write a function that changes `colormap.right` to be `'blue'`. We could write:
+
+```js
+function updateColorMap(colormap) {
+  colormap.right = 'blue';
+}
+```
+
+To write this without mutating the original object, we can use [Object.assign](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) method:
+
+```js
+function updateColorMap(colormap) {
+  return Object.assign({}, colormap, {right: 'blue'});
+}
+```
+
+`updateColorMap` now returns a new object, rather than mutating the old one. `Object.assign` is in ES6 and requires a polyfill.
+
+There is a JavaScript proposal to add [object spread properties](https://github.com/sebmarkbage/ecmascript-rest-spread) to make it easier to update objects without mutation as well:
+
+```js
+function updateColorMap(colormap) {
+  return {...colormap, right: 'blue'};
+}
+```
+
+If you're using Create React App, both `Object.assign` and the object spread syntax are available by default.
+
+## Using Immutable Data Structures
+
+[Immutable.js](https://github.com/facebook/immutable-js) is another way to solve this problem. It provides immutable, persistent collections that work via structural sharing:
+
+* *Immutable*: once created, a collection cannot be altered at another point in time.
+* *Persistent*: new collections can be created from a previous collection and a mutation such as set. The original collection is still valid after the new collection is created.
+* *Structural Sharing*: new collections are created using as much of the same structure as the original collection as possible, reducing copying to a minimum to improve performance.
+
+Immutability makes tracking changes cheap. A change will always result in a new object so we only need to check if the reference to the object has changed. For example, in this regular JavaScript code:
+
+```javascript
+const x = { foo: 'bar' };
+const y = x;
+y.foo = 'baz';
+x === y; // true
+```
+
+Although `y` was edited, since it's a reference to the same object as `x`, this comparison returns `true`. You can write similar code with immutable.js:
+
+```javascript
+const SomeRecord = Immutable.Record({ foo: null });
+const x = new SomeRecord({ foo: 'bar' });
+const y = x.set('foo', 'baz');
+x === y; // false
+```
+
+In this case, since a new reference is returned when mutating `x`, we can safely assume that `x` has changed.
+
+Two other libraries that can help use immutable data are [seamless-immutable](https://github.com/rtfeldman/seamless-immutable) and [immutability-helper](https://github.com/kolodny/immutability-helper).
+
+Immutable data structures provide you with a cheap way to track changes on objects, which is all we need to implement `shouldComponentUpdate`. This can often provide you with a nice performance boost.
diff --git a/docs/docs/react-without-es6.md b/docs/docs/react-without-es6.md
new file mode 100644
index 000000000000..e49a5e075708
--- /dev/null
+++ b/docs/docs/react-without-es6.md
@@ -0,0 +1,225 @@
+---
+id: react-without-es6
+title: React Without ES6
+permalink: docs/react-without-es6.html
+---
+
+Normally you would define a React component as a plain JavaScript class:
+
+```javascript
+class Greeting extends React.Component {
+  render() {
+    return <h1>Hello, {this.props.name}</h1>;
+  }
+}
+```
+
+If you don't use ES6 yet, you may use the `create-react-class` module instead:
+
+
+```javascript
+var createReactClass = require('create-react-class');
+var Greeting = createReactClass({
+  render: function() {
+    return <h1>Hello, {this.props.name}</h1>;
+  }
+});
+```
+
+The API of ES6 classes is similar to `createReactClass()` with a few exceptions.
+
+## Declaring Default Props
+
+With functions and ES6 classes `defaultProps` is defined as a property on the component itself:
+
+```javascript
+class Greeting extends React.Component {
+  // ...
+}
+
+Greeting.defaultProps = {
+  name: 'Mary'
+};
+```
+
+With `createReactClass()`, you need to define `getDefaultProps()` as a function on the passed object:
+
+```javascript
+var Greeting = createReactClass({
+  getDefaultProps: function() {
+    return {
+      name: 'Mary'
+    };
+  },
+
+  // ...
+
+});
+```
+
+## Setting the Initial State
+
+In ES6 classes, you can define the initial state by assigning `this.state` in the constructor:
+
+```javascript
+class Counter extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {count: props.initialCount};
+  }
+  // ...
+}
+```
+
+With `createReactClass()`, you have to provide a separate `getInitialState` method that returns the initial state:
+
+```javascript
+var Counter = createReactClass({
+  getInitialState: function() {
+    return {count: this.props.initialCount};
+  },
+  // ...
+});
+```
+
+## Autobinding
+
+In React components declared as ES6 classes, methods follow the same semantics as regular ES6 classes. This means that they don't automatically bind `this` to the instance. You'll have to explicitly use `.bind(this)` in the constructor:
+
+```javascript
+class SayHello extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {message: 'Hello!'};
+    // This line is important!
+    this.handleClick = this.handleClick.bind(this);
+  }
+
+  handleClick() {
+    alert(this.state.message);
+  }
+
+  render() {
+    // Because `this.handleClick` is bound, we can use it as an event handler.
+    return (
+      <button onClick={this.handleClick}>
+        Say hello
+      </button>
+    );
+  }
+}
+```
+
+With `createReactClass()`, this is not necessary because it binds all methods:
+
+```javascript
+var SayHello = createReactClass({
+  getInitialState: function() {
+    return {message: 'Hello!'};
+  },
+
+  handleClick: function() {
+    alert(this.state.message);
+  },
+
+  render: function() {
+    return (
+      <button onClick={this.handleClick}>
+        Say hello
+      </button>
+    );
+  }
+});
+```
+
+This means writing ES6 classes comes with a little more boilerplate code for event handlers, but the upside is slightly better performance in large applications.
+
+If the boilerplate code is too unattractive to you, you may enable the **experimental** [Class Properties](https://babeljs.io/docs/plugins/transform-class-properties/) syntax proposal with Babel:
+
+
+```javascript
+class SayHello extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {message: 'Hello!'};
+  }
+  // WARNING: this syntax is experimental!
+  // Using an arrow here binds the method:
+  handleClick = () => {
+    alert(this.state.message);
+  }
+
+  render() {
+    return (
+      <button onClick={this.handleClick}>
+        Say hello
+      </button>
+    );
+  }
+}
+```
+
+Please note that the syntax above is **experimental** and the syntax may change, or the proposal might not make it into the language.
+
+If you'd rather play it safe, you have a few options:
+
+* Bind methods in the constructor.
+* Use arrow functions, e.g. `onClick={(e) => this.handleClick(e)}`.
+* Keep using `createReactClass`.
+
+## Mixins
+
+>**Note:**
+>
+>ES6 launched without any mixin support. Therefore, there is no support for mixins when you use React with ES6 classes.
+>
+>**We also found numerous issues in codebases using mixins, [and don't recommend using them in the new code](/react/blog/2016/07/13/mixins-considered-harmful.html).**
+>
+>This section exists only for the reference.
+
+Sometimes very different components may share some common functionality. These are sometimes called [cross-cutting concerns](https://en.wikipedia.org/wiki/Cross-cutting_concern). [`createReactClass`](/react/docs/top-level-api.html#react.createclass) lets you use a legacy `mixins` system for that.
+
+One common use case is a component wanting to update itself on a time interval. It's easy to use `setInterval()`, but it's important to cancel your interval when you don't need it anymore to save memory. React provides [lifecycle methods](/react/docs/working-with-the-browser.html#component-lifecycle) that let you know when a component is about to be created or destroyed. Let's create a simple mixin that uses these methods to provide an easy `setInterval()` function that will automatically get cleaned up when your component is destroyed.
+
+```javascript
+var SetIntervalMixin = {
+  componentWillMount: function() {
+    this.intervals = [];
+  },
+  setInterval: function() {
+    this.intervals.push(setInterval.apply(null, arguments));
+  },
+  componentWillUnmount: function() {
+    this.intervals.forEach(clearInterval);
+  }
+};
+
+var createReactClass = require('create-react-class');
+
+var TickTock = createReactClass({
+  mixins: [SetIntervalMixin], // Use the mixin
+  getInitialState: function() {
+    return {seconds: 0};
+  },
+  componentDidMount: function() {
+    this.setInterval(this.tick, 1000); // Call a method on the mixin
+  },
+  tick: function() {
+    this.setState({seconds: this.state.seconds + 1});
+  },
+  render: function() {
+    return (
+      <p>
+        React has been running for {this.state.seconds} seconds.
+      </p>
+    );
+  }
+});
+
+ReactDOM.render(
+  <TickTock />,
+  document.getElementById('example')
+);
+```
+
+If a component is using multiple mixins and several mixins define the same lifecycle method (i.e. several mixins want to do some cleanup when the component is destroyed), all of the lifecycle methods are guaranteed to be called. Methods defined on mixins run in the order mixins were listed, followed by a method call on the component.
diff --git a/docs/docs/react-without-jsx.md b/docs/docs/react-without-jsx.md
new file mode 100644
index 000000000000..e1439009504d
--- /dev/null
+++ b/docs/docs/react-without-jsx.md
@@ -0,0 +1,59 @@
+---
+id: react-without-jsx
+title: React Without JSX
+permalink: docs/react-without-jsx.html
+---
+
+JSX is not a requirement for using React. Using React without JSX is especially convenient when you don't want to set up compilation in your build environment.
+
+Each JSX element is just syntactic sugar for calling `React.createElement(component, props, ...children)`. So, anything you can do with JSX can also be done with just plain JavaScript.
+
+For example, this code written with JSX:
+
+```js
+class Hello extends React.Component {
+  render() {
+    return <div>Hello {this.props.toWhat}</div>;
+  }
+}
+
+ReactDOM.render(
+  <Hello toWhat="World" />,
+  document.getElementById('root')
+);
+```
+
+can be compiled to this code that does not use JSX:
+
+```js
+class Hello extends React.Component {
+  render() {
+    return React.createElement('div', null, `Hello ${this.props.toWhat}`);
+  }
+}
+
+ReactDOM.render(
+  React.createElement(Hello, {toWhat: 'World'}, null),
+  document.getElementById('root')
+);
+```
+
+If you're curious to see more examples of how JSX is converted to JavaScript, you can try out [the online Babel compiler](https://babeljs.io/repl/#?babili=false&evaluate=true&lineWrap=false&presets=es2015%2Creact%2Cstage-0&code=function%20hello()%20%7B%0A%20%20return%20%3Cdiv%3EHello%20world!%3C%2Fdiv%3E%3B%0A%7D).
+
+The component can either be provided as a string, or as a subclass of `React.Component`, or a plain function for stateless components.
+
+If you get tired of typing `React.createElement` so much, one common pattern is to assign a shorthand:
+
+```js
+const e = React.createElement;
+
+ReactDOM.render(
+  e('div', null, 'Hello World'),
+  document.getElementById('root')
+);
+```
+
+If you use this shorthand form for `React.createElement`, it can be almost as convenient to use React without JSX.
+
+Alternatively, you can refer to community projects such as [`react-hyperscript`](https://github.com/mlmorg/react-hyperscript) and [`hyperscript-helpers`](https://github.com/ohanhi/hyperscript-helpers) which offer a terser syntax.
+
diff --git a/docs/docs/reconciliation.md b/docs/docs/reconciliation.md
new file mode 100644
index 000000000000..19178069b53d
--- /dev/null
+++ b/docs/docs/reconciliation.md
@@ -0,0 +1,153 @@
+---
+id: reconciliation
+title: Reconciliation
+permalink: docs/reconciliation.html
+---
+
+React provides a declarative API so that you don't have to worry about exactly what changes on every update. This makes writing applications a lot easier, but it might not be obvious how this is implemented within React. This article explains the choices we made in React's "diffing" algorithm so that component updates are predictable while being fast enough for high-performance apps.
+
+## Motivation
+
+When you use React, at a single point in time you can think of the `render()` function as creating a tree of React elements. On the next state or props update, that `render()` function will return a different tree of React elements. React then needs to figure out how to efficiently update the UI to match the most recent tree.
+
+There are some generic solutions to this algorithmic problem of generating the minimum number of operations to transform one tree into another. However, the [state of the art algorithms](http://grfia.dlsi.ua.es/ml/algorithms/references/editsurvey_bille.pdf) have a complexity in the order of O(n<sup>3</sup>) where n is the number of elements in the tree.
+
+If we used this in React, displaying 1000 elements would require in the order of one billion comparisons. This is far too expensive. Instead, React implements a heuristic O(n) algorithm based on two assumptions:
+
+1. Two elements of different types will produce different trees.
+2. The developer can hint at which child elements may be stable across different renders with a `key` prop.
+
+In practice, these assumptions are valid for almost all practical use cases.
+
+## The Diffing Algorithm
+
+When diffing two trees, React first compares the two root elements. The behavior is different depending on the types of the root elements.
+
+### Elements Of Different Types
+
+Whenever the root elements have different types, React will tear down the old tree and build the new tree from scratch. Going from `<a>` to `<img>`, or from `<Article>` to `<Comment>`, or from `<Button>` to `<div>` - any of those will lead to a full rebuild.
+
+When tearing down a tree, old DOM nodes are destroyed. Component instances receive `componentWillUnmount()`. When building up a new tree, new DOM nodes are inserted into the DOM. Component instances receive `componentWillMount()` and then `componentDidMount()`. Any state associated with the old tree is lost.
+
+Any components below the root will also get unmounted and have their state destroyed. For example, when diffing:
+
+```xml
+<div>
+  <Counter />
+</div>
+
+<span>
+  <Counter />
+</span>
+```
+
+This will destroy the old `Counter` and remount a new one.
+
+### DOM Elements Of The Same Type
+
+When comparing two React DOM elements of the same type, React looks at the attributes of both, keeps the same underlying DOM node, and only updates the changed attributes. For example:
+
+```xml
+<div className="before" title="stuff" />
+
+<div className="after" title="stuff" />
+```
+
+By comparing these two elements, React knows to only modify the `className` on the underlying DOM node.
+
+When updating `style`, React also knows to update only the properties that changed. For example:
+
+```xml
+<div style={{'{{'}}color: 'red', fontWeight: 'bold'}} />
+
+<div style={{'{{'}}color: 'green', fontWeight: 'bold'}} />
+```
+
+When converting between these two elements, React knows to only modify the `color` style, not the `fontWeight`.
+
+After handling the DOM node, React then recurses on the children.
+
+### Component Elements Of The Same Type
+
+When a component updates, the instance stays the same, so that state is maintained across renders. React updates the props of the underlying component instance to match the new element, and calls `componentWillReceiveProps()` and `componentWillUpdate()` on the underlying instance.
+
+Next, the `render()` method is called and the diff algorithm recurses on the previous result and the new result.
+
+### Recursing On Children
+
+By default, when recursing on the children of a DOM node, React just iterates over both lists of children at the same time and generates a mutation whenever there's a difference.
+
+For example, when adding an element at the end of the children, converting between these two trees works well:
+
+```xml
+<ul>
+  <li>first</li>
+  <li>second</li>
+</ul>
+
+<ul>
+  <li>first</li>
+  <li>second</li>
+  <li>third</li>
+</ul>
+```
+
+React will match the two `<li>first</li>` trees, match the two `<li>second</li>` trees, and then insert the `<li>third</li>` tree.
+
+If you implement it naively, inserting an element at the beginning has worse performance. For example, converting between these two trees works poorly:
+
+```xml
+<ul>
+  <li>Duke</li>
+  <li>Villanova</li>
+</ul>
+
+<ul>
+  <li>Connecticut</li>
+  <li>Duke</li>
+  <li>Villanova</li>
+</ul>
+```
+
+React will mutate every child instead of realizing it can keep the `<li>Duke</li>` and `<li>Villanova</li>` subtrees intact. This inefficiency can be a problem.
+
+### Keys
+
+In order to solve this issue, React supports a `key` attribute. When children have keys, React uses the key to match children in the original tree with children in the subsequent tree. For example, adding a `key` to our inefficient example above can make the tree conversion efficient:
+
+```xml
+<ul>
+  <li key="2015">Duke</li>
+  <li key="2016">Villanova</li>
+</ul>
+
+<ul>
+  <li key="2014">Connecticut</li>
+  <li key="2015">Duke</li>
+  <li key="2016">Villanova</li>
+</ul>
+```
+
+Now React knows that the element with key `'2014'` is the new one, and the elements with the keys `'2015'` and `'2016'` have just moved.
+
+In practice, finding a key is usually not hard. The element you are going to display may already have a unique ID, so the key can just come from your data:
+
+```js
+<li key={item.id}>{item.name}</li>
+```
+
+When that's not the case, you can add a new ID property to your model or hash some parts of the content to generate a key. The key only has to be unique among its siblings, not globally unique.
+
+As a last resort, you can pass item's index in the array as a key. This can work well if the items are never reordered, but reorders will be slow.
+
+## Tradeoffs
+
+It is important to remember that the reconciliation algorithm is an implementation detail. React could rerender the whole app on every action; the end result would be the same. We are regularly refining the heuristics in order to make common use cases faster.
+
+In the current implementation, you can express the fact that a subtree has been moved amongst its siblings, but you cannot tell that it has moved somewhere else. The algorithm will rerender that full subtree.
+
+Because React relies on heuristics, if the assumptions behind them are not met, performance will suffer.
+
+1. The algorithm will not try to match subtrees of different component types. If you see yourself alternating between two component types with very similar output, you may want to make it the same type. In practice, we haven't found this to be an issue.
+
+2. Keys should be stable, predictable, and unique. Unstable keys (like those produced by `Math.random()`) will cause many component instances and DOM nodes to be unnecessarily recreated, which can cause performance degradation and lost state in child components.
diff --git a/docs/docs/ref-01-top-level-api.it-IT.md b/docs/docs/ref-01-top-level-api.it-IT.md
deleted file mode 100644
index 11953510d4e0..000000000000
--- a/docs/docs/ref-01-top-level-api.it-IT.md
+++ /dev/null
@@ -1,195 +0,0 @@
----
-id: top-level-api-it-IT
-title: API di Livello Elevato
-permalink: top-level-api-it-IT.html
-next: component-api-it-IT.html
-redirect_from: "/docs/reference.html"
----
-
-## React
-
-`React` è il punto di ingresso alla libreria React. Se stai usando uno dei pacchetti precompilati, è disponibile come variabile globale; se stai usando i moduli CommonJS puoi richiederlo con `require()`.
-
-
-### React.Component
-
-```javascript
-class Component
-```
-
-Questa è la classe base per i componenti React quando sono definiti usando le classi ES6. Vedi [Componenti Riutilizzabili](/react/docs/reusable-components.html#es6-classes) per usare le classi ES6 con React. Per i metodi forniti dalla classe base, vedi la [API dei Componenti](/react/docs/component-api.html).
-
-
-### React.createClass
-
-```javascript
-ReactClass createClass(object specification)
-```
-
-Crea la classe di un componente, data una specifica. Un componente implementa un metodo `render` che restituisce **un singolo** figlio. Tale figlio può avere una struttura di fogli arbitrariamente profonda. Una cosa che rende i componenti diversi dalle classi prototipiche standard è che non hai bisogno di chiamare `new` su di esse. Sono delle convenienti astrazioni che costruiscono (attraverso `new`) istanze dietro le quinte per te.
-
-Per maggiori informazioni sull'oggetto specifica, vedi [Specifiche dei Componenti e Ciclo di Vita](/react/docs/component-specs.html).
-
-
-### React.createElement
-
-```javascript
-ReactElement createElement(
-  string/ReactClass type,
-  [object props],
-  [children ...]
-)
-```
-
-Crea e restituisce un nuovo `ReactElement` del tipo desiderato. L'argomento `type` può essere una stringa contenente il nome di un tag HTML (ad es. 'div', 'span', etc), oppure una `ReactClass` (creata attraverso `React.createClass`).
-
-
-### React.cloneElement
-
-```
-ReactElement cloneElement(
-  ReactElement element,
-  [object props],
-  [children ...]
-)
-```
-
-Clona e restituisce un nuovo `ReactElement` usando `element` come punto di partenza. L'elemento risultante avrà le proprietà dell'elemento originale, con le nuove proprietà unite in maniera superficiale. I figli esistenti sono sostituiti dai figli passati come `children`. Diversamente da `React.addons.cloneWithProps`, `key` e `ref` dell'elemento originale saranno preservati. Non esiste alcun comportamento speciale per riunire le proprietà (diversamente da `cloneWithProps`). Vedi l'[articolo del blog sulla v0.13 RC2](/react/blog/2015/03/03/react-v0.13-rc2.html) per maggiori dettagli.
-
-
-### React.createFactory
-
-```javascript
-factoryFunction createFactory(
-  string/ReactClass type
-)
-```
-
-Restituisce una funzione che produce ReactElements di un tipo desiderato. Come `React.createElement`,
-l'argomento `type` può essere sia la stringa contenente il nome di un tag HTML (ad es. 'div', 'span', etc), oppure una
-`ReactClass`.
-
-
-### ReactDOM.render
-
-```javascript
-ReactComponent render(
-  ReactElement element,
-  DOMElement container,
-  [function callback]
-)
-```
-
-Effettua il rendering di un ReactElement nel DOM all'interno dell'elemento `container` fornito e restituisce un [riferimento](/react/docs/more-about-refs-it-IT.html) al componente (oppure restituisce `null` per i [componenti privi di stato](/react/docs/reusable-components-it-IT.html#stateless-functions)).
-
-Se il rendering del ReactElement è stato precedentemente effettuato all'interno di `container`, questa operazione effettuerà un aggiornamento su di esso e modificherà il DOM in modo necessario a riflettere il più recente componente React.
-
-Se la callback opzionale è fornita, sarà eseguita dopo che il rendering o l'aggiornamento del componente sono stati effettuati.
-
-> Nota:
->
-> `ReactDOM.render()` controlla i contenuti del nodo contenitore che viene passato come argomento `container`. Gli elementi DOM
-> esistenti al suo interno sono sostituiti quando viene chiamata la prima volta. Le chiamate successive usano l'algoritmo di
-> differenza di React per aggiornamenti efficienti.
->
-> `ReactDOM.render()` non modifica il nodo contenitore (modifica soltanto i figli del contenitore). In
-> futuro potrebbe essere possibile inserire un componente in un nodo DOM esistente senza sovrascrivere i figli esistenti.
-
-
-### ReactDOM.unmountComponentAtNode
-
-```javascript
-boolean unmountComponentAtNode(DOMElement container)
-```
-
-Rimuove un componente React montato nel DOM e ripulisce i suoi gestori di evento e lo stato. Se nessun componente è stato montato nel contenitore `container`, chiamare questa funzione non ha alcun effetto. Restituisce `true` se il componente è stato smontato e `false` se non è stato trovato un componente da smontare.
-
-
-### ReactDOM.renderToString
-
-```javascript
-string renderToString(ReactElement element)
-```
-
-Effettua il rendering di un ReactElement come il suo HTML iniziale. Questo dovrebe essere utilizzato soltanto lato server. React restituirà una stringa di HTML. Puoi usare questo metodo per generare HTML sul server e inviare il markup come risposta alla richiesta iniziale per un più rapido caricamento della pagina, e permettere ai motori di ricerca di effettuare il crawling della tua pagina per ottimizzazione SEO.
-
-Se chiami `ReactDOM.render()` su un nodo che possiede già questo markup generato lato server, React lo preserverà e vi attaccherà soltanto i gestori di eventi, permettendoti di avere una esperienza di primo caricamento altamente efficiente.
-
-
-### ReactDOM.renderToStaticMarkup
-
-```javascript
-string renderToStaticMarkup(ReactElement element)
-```
-
-Simile a `renderToString`, eccetto che non crea attributi DOM aggiuntivi come `data-react-id`, che React utilizza internamente. Questo è utile se vuoi usare React come un semplice generatore di pagine statiche, in quanto eliminare gli attributi aggiuntivi può risparmiare parecchi byte.
-
-
-### ReactDOM.isValidElement
-
-```javascript
-boolean isValidElement(* object)
-```
-
-Verifica che `object` sia un ReactElement.
-
-
-### ReactDOM.findDOMNode
-
-```javascript
-DOMElement findDOMNode(ReactComponent component)
-```
-Se questo componente è stato montato nel DOM, restituisce il corrispondente elemento DOM nativo del browser. Questo metodo è utile per leggere i valori dal DOM, come i valori dei campi dei moduli ed effettuare misure sul DOM. Quando `render` restituisce `null` o `false`, `findDOMNode` restituisce `null`.
-
-> Nota:
->
-> `findDOMNode()` è una via di fuga usata per accedere al nodo DOM sottostante. Nella maggior parte dei casi, l'uso di questa via di fuga è scoraggiato perché viola l'astrazione del componente. Tuttavia, esistono delle situazioni in cui questo è necessario (ad esempio, potresti aver bisogno di trovare un nodo DOM per posizionarlo in maniera assoluta oppure determinarne la larghezza visualizzata misurata in pixel).
-
->
-> `findDOMNode()` funziona soltanto su componenti montati (cioè, componenti che sono stati posizionati nel DOM). Se provi a chiamarlo su un componente che non è stato ancora montato (come chiamare `findDOMNode()` in `render()` su un componente che deve ancora essere creato) lancerà un'eccezione.
-
-### React.DOM
-
-`React.DOM` fornisce convenienti utilità che espongono `React.createElement` per componenti del DOM. Questi dovrebbero essere usate soltanto quando non si utilizza JSX. Ad esempio, `React.DOM.div(null, 'Ciao Mondo!')`
-
-
-### React.PropTypes
-
-`React.PropTypes` include tipi che possono essere usati con l'oggetto `propTypes` di un componente per validare le proprietà passate ai tuoi componenti. Per maggiori informazioni su `propTypes`, vedi [Componenti Riutilizzabili](/react/docs/reusable-components.html).
-
-
-### React.Children
-
-`React.Children` fornisce utilitià per gestire la struttura dati opaca `this.props.children`.
-
-#### React.Children.map
-
-```javascript
-object React.Children.map(object children, function fn [, object thisArg])
-```
-
-Invoca `fn` su ciascuno dei diretti discendenti contenuti in `children`, con `this` impostato a `thisArg`. Se `children` è un oggetto annidato o un array, esso verrà attraversato: ad `fn` non saranno mai passati gli oggetti contenitori. Se `children` è `null` o `undefined` restituisce `null` o `undefined` anziché un oggetto vuoto.
-
-#### React.Children.forEach
-
-```javascript
-React.Children.forEach(object children, function fn [, object thisArg])
-```
-
-Come `React.Children.map()` con la differenza che non restituisce un oggetto.
-
-#### React.Children.count
-
-```javascript
-number React.Children.count(object children)
-```
-
-Restituisce il numero totale di componenti in `children`, uguale al numero di volte che una callback passata a `map` o `forEach` verrebbe invocata.
-
-#### React.Children.only
-
-```javascript
-object React.Children.only(object children)
-```
-
-Restituisce il figlio unico contenuto in `children`, altrimenti lancia un'eccezione.
diff --git a/docs/docs/ref-01-top-level-api.ja-JP.md b/docs/docs/ref-01-top-level-api.ja-JP.md
deleted file mode 100644
index 2896650c8980..000000000000
--- a/docs/docs/ref-01-top-level-api.ja-JP.md
+++ /dev/null
@@ -1,172 +0,0 @@
----
-id: top-level-api-ja-JP
-title: Top-Level API
-permalink: top-level-api-ja-JP.html
-next: component-api-ja-JP.html
-redirect_from: "/docs/reference-ja-JP.html"
----
-
-## React
-
-`React` はReactのライブラリに対するエントリーポイントです。事前にビルドされたパッケージを使用する場合は、グローバルで使用可能です。CommonJSのモジュールを使用する場合は、 `require()` できます。
-
-
-### React.Component
-
-```javascript
-class Component
-```
-
-これは、ES6のクラスを使用して定義されている場合の、Reactコンポーネントに対する基底クラスです。ReactでES6のクラスを使用する方法については、[再利用可能なコンポーネント](/react/docs/reusable-components-ja-JP.html#es6-classes)をご覧ください。基底クラスからどのメソッドが実際に提供されるかについては、[コンポーネントAPI](/react/docs/component-api-ja-JP.html)をご覧ください。
-
-### React.createClass
-
-```javascript
-ReactClass createClass(object specification)
-```
-
-与えられた仕様に基づいてコンポーネントクラスを作成します。コンポーネントは **ある単一の** 子要素を返す `render` メソッドを実行します。その子要素は勝手に深い子要素の構造を保持しています。コンポーネントが標準的なプロトタイプのクラスと異なっている部分は、newを呼ぶ必要がないということです。それらは内部で（newを行う）インスタンスを構築する便利なラッパーです。
-
-specificationオブジェクトについての情報は、[コンポーネントのスペックとライフサイクル](/react/docs/component-specs-ja-JP.html)をご覧ください。
-
-### React.createElement
-
-```javascript
-ReactElement createElement(
-  string/ReactClass type,
-  [object props],
-  [children ...]
-)
-```
-
-与えられた型の `ReactElement` を作成し、返します。type引数はhtmlタグ名（例えば、'div'、'span'など）の文字列にも`ReactClass`（`React.createClass` によって作成される）にもなり得ます。
-
-### React.cloneElement
-
-```
-ReactElement cloneElement(
-  ReactElement element,
-  [object props],
-  [children ...]
-)
-```
-
-`element` をスターティングポイントとして使用する新しい `ReactElement` をクローンして返します。
-結果として生まれる要素はオリジナルの要素のpropsと新しいpropsを暗にマージしたものを保持しています。新しい子要素は現存する子要素を置き換えます。 `React.addons.cloneWithProps` と異なり、オリジナルの要素から得られた `key` と `ref` は保存されます。（`cloneWithProps` とは異なり）propsをマージする際に特別な動きは行いません。詳細については、[v0.13 RC2 blog記事](/react/blog/2015/03/03/react-v0.13-rc2.html)をご覧ください。
-
-### React.createFactory
-
-```javascript
-factoryFunction createFactory(
-  string/ReactClass type
-)
-```
-
-与えられた型のReactElementsを生成する関数を返します。 `React.createElement` と同様に、type引数はhtmlタグ名（例えば、'div'、'span'など）の文字列にも`ReactClass` にもなり得ます。
-
-### React.render
-
-```javascript
-ReactComponent render(
-  ReactElement element,
-  DOMElement container,
-  [function callback]
-)
-```
-
-与えられた `container` によってReactElementをDOMにレンダリングし、コンポーネントへの参照を返します。
-
-もしReactElementが事前に `container` にレンダリングされていた場合は、更新を行い、DOMが最新のReactのコンポーネントを表すように変化させます。
-
-オプションのコールバックが与えられた場合は、コンポーネントがレンダリングされたり、更新された後に実行されます。
-
-> 注意:
-> `React.render()` は渡されたコンテナーノードの内容を制御します。内部に存在するDOM要素は最初に呼ばれた際に置き換えられます。その後に呼ばれた場合は、ReactのDOMの差分アルゴリズムを使用して、効率的に更新されます。
->
-> `React.render()` はコンテナーノードの変更は行いません（コンテナの子要素のみ変更を行います）。今後、存在する子要素を上書きすることなく、存在するDOMノードにコンポーネントを挿入することが可能になるでしょう。
-
-### React.unmountComponentAtNode
-
-```javascript
-boolean unmountComponentAtNode(DOMElement container)
-```
-
-マウントされたReactのコンポーネントをDOMから削除し、そのイベントハンドラとstateをクリーンアップします。コンテナにコンポーネントがマウントされていない場合は、この関数を呼んでも何も行われません。コンポーネントがアンマウントされた場合は `true` を返し、アンマウントするコンポーネントが存在しない場合は `false` を返します。
-
-### React.renderToString
-
-```javascript
-string renderToString(ReactElement element)
-```
-
-ReactElementを最初にHTMLにレンダリングします。これはサーバでのみ使用されるべきです。ReactはHTML文字列を返します。このメソッドを、サーバでHTMLを生成し、最初のリクエストに対してマークアップを送るのに使用することができます。そうすることで、ページロードが速くなり、サーチエンジンはSEOの目的でページをクロールします。
-
-既にサーバでレンダリングされたマークアップを保持しているノードで `React.render()` を呼んだ場合は、Reactはそれを保護し、イベントハンドラを加えます。そうすることで、最初のローディングのパフォーマンスがとても良くなります。
-
-### React.renderToStaticMarkup
-
-```javascript
-string renderToStaticMarkup(ReactElement element)
-```
-
-`renderToString` に似ていますが、Reactが内部で使用する `data-react-id` のような外部のDOM属性を作成しません。Reactを、単純な静的なページを生成するために使用したい場合は有用です。外部の属性を取り除くことでメモリを節約することができます。
-
-### React.isValidElement
-
-```javascript
-boolean isValidElement(* object)
-```
-
-オブジェクトがReactElementであるかどうか調査します。
-
-### React.findDOMNode
-
-```javascript
-DOMElement findDOMNode(ReactComponent component)
-```
-
-このコンポーネントがDOMにマウントされた場合は、対応するネイティブブラウザのDOM要素を返します。このメソッドはDOMの外の値を読み込む場合に有用です。例えば、formフィールドの値やDOMの測定を行う場合があります。 `render` が `null` や `false` を返した場合は、 `findDOMNode` は `null` を返します。
-
-### React.DOM
-
-`React.DOM` はDOMコンポーネントのための `React.createElement` の周りの便利なラッパーを提供します。JSXを使用しない場合にのみ使用すべきです。例えば、 `React.DOM.div(null, 'Hello World!')` のように。
-
-### React.PropTypes
-
-`React.PropTypes` はコンポーネントに与えられたpropsをバリデーションするためにコンポーネントの `propTypes` と使用できる型を含んでいます。 `propTypes` についての更なる情報は、[再利用可能なコンポーネント](/react/docs/reusable-components-ja-JP.html)をご覧ください。
-
-### React.Children
-
-`React.Children` は `this.props.children` の不透明なデータ構造を扱うユーティリティを提供します。
-
-#### React.Children.map
-
-```javascript
-object React.Children.map(object children, function fn [, object thisArg])
-```
-
-全ての `children` を含む子要素に対して、 `fn` を実行します。 `this` は `thisArg` にセットされます。 `children` がネストしたオブジェクトや配列だった場合は、実行されません。 `fn` はコンテナのオブジェクトから渡されません。子要素が `null` か `undefined` だった場合は、空のオブジェクトではなく `null` か `undefined` を返します。
-
-#### React.Children.forEach
-
-```javascript
-React.Children.forEach(object children, function fn [, object thisArg])
-```
-
-`React.Children.map()` に似ていますが、オブジェクトを返しはしません。
-
-#### React.Children.count
-
-```javascript
-number React.Children.count(object children)
-```
-
-`children` の中のコンポーネントの合計数を返します。 `map` や `forEach` に渡されるコールバックが実行される数と等しくなります。
-
-#### React.Children.only
-
-```javascript
-object React.Children.only(object children)
-```
-
-`children` の単一の子要素を返します。それ以外の場合は例外をスローします。
diff --git a/docs/docs/ref-01-top-level-api.ko-KR.md b/docs/docs/ref-01-top-level-api.ko-KR.md
deleted file mode 100644
index bb61970295c7..000000000000
--- a/docs/docs/ref-01-top-level-api.ko-KR.md
+++ /dev/null
@@ -1,206 +0,0 @@
----
-id: top-level-api-ko-KR
-title: 최상위 API
-permalink: top-level-api-ko-KR.html
-next: component-api-ko-KR.html
-redirect_from: "/docs/reference-ko-KR.html"
----
-
-## React
-
-`React`는 React 라이브러리의 진입점입니다. 미리 빌드된 패키지를 사용하는 경우 전역 변수로 접근할 수 있습니다. CommonJS 모듈을 사용하는 경우에는 `require()`로 불러올 수 있습니다.
-
-
-### React.Component
-
-```javascript
-class Component
-```
-
-ES6 클래스 구문을 사용해 React 컴포넌트를 정의했을 때 기본 클래스가 되는 부분입니다. 어떻게 ES6 클래스 구문을 사용해 React를 다루는지는 [재사용가능한 컴포넌트](/react/docs/reusable-components-ko-KR.html#es6-classes)를 확인하세요. 기본 클래스에서 실제 제공되는 메소드들에는 어떤것이 있는지 알아보려면 [컴포넌트 API](/react/docs/component-api-ko-KR.html)를 확인하세요.
-
-
-### React.createClass
-
-```javascript
-ReactClass createClass(object specification)
-```
-
-주어진 명세에 따라 컴포넌트 클래스를 만듭니다. 컴포넌트는 단 하나의 자식만을 리턴하는 `render` 메소드를 구현합니다. 그 자식은 임의 깊이의 자식 구조를 가질 수 있습니다. 컴포넌트가 일반적인 프로토타입 기반의 클래스와 다른 점은 생성할 때 `new` 연산자를 사용하지 않아도 된다는 것입니다. 컴포넌트는 (`new` 연산자를 통해) 내부 인스턴스를 만들어 주는 편의 래퍼(wrapper)입니다.
-
-명세 객체에 대한 자세한 정보는 [컴포넌트 명세와 생명주기](/react/docs/component-specs-ko-KR.html)를 참고하세요.
-
-
-### React.createElement
-
-```javascript
-ReactElement createElement(
-  string/ReactClass type,
-  [object props],
-  [children ...]
-)
-```
-
-주어진 타입의 새 `ReactElement`를 만들고 리턴합니다. `type` 인자는 HTML 태그명 문자열 (예: 'div', 'span' 등) 또는 (`React.createClass`로 만든) `ReactClass`입니다.
-
-
-### React.cloneElement
-
-```
-ReactElement cloneElement(
-  ReactElement element,
-  [object props],
-  [children ...]
-)
-```
-
-`element`를 시작점으로 새로운 `ReactElement`를 클론해 반환합니다. 반환된 엘리먼트에는 원본의 props와 새로운 props가 얕게 병합됩니다. 새 자식은 존재하는 자식을 교체할 것입니다. `React.addons.cloneWithProps`와는 다르게, 원본 엘리먼트의 `key`와 `ref`는 보존될 것입니다. `cloneWithProps`와는 달리 props이 병합되는데는 어떠한 특별한 동작도 없습니다. [v0.13 RC2 블로그 포스트](/react/blog/2015/03/03/react-v0.13-rc2.html)에서 추가적인 내용을 확인하세요.
-
-
-### React.createFactory
-
-```javascript
-factoryFunction createFactory(
-  string/ReactClass type
-)
-```
-
-주어진 타입의 ReactElement를 만들어주는 함수를 리턴합니다. `React.createElement`와 마찬가지로 `type` 인자는 HTML 태그명 문자열 (예: 'div', 'span' 등) 또는 `ReactClass`입니다.
-
-
-### React.isValidElement
-
-```javascript
-boolean isValidElement(* object)
-```
-
-주어진 객체가 ReactElement인지 확인합니다.
-
-
-### React.DOM
-
-`React.DOM`은 DOM 컴포넌트에 대해 `React.createElement`의 편의 래퍼(wrapper)를 제공합니다. JSX를 사용하지 않는 경우에만 사용하십시오. 예를 들어, `React.DOM.div(null, 'Hello World!')`와 같이 사용할 수 있습니다.
-
-
-### React.PropTypes
-
-`React.PropTypes`는 컴포넌트에 넘어오는 props가 올바른지 검사할 수 있는 컴포넌트의 `propTypes` 객체에 들어가는 타입을 가집니다. `propTypes`에 대한 자세한 정보는 [재사용 가능한 컴포넌트](/react/docs/reusable-components-ko-KR.html)를 참고하세요.
-
-
-### React.Children
-
-`React.Children`은 불투명한 자료 구조인 `this.props.children`를 다룰 수 있는 유틸리티를 제공합니다.
-
-#### React.Children.map
-
-```javascript
-array React.Children.map(object children, function fn [, object thisArg])
-```
-
-`children`의 바로 밑에 있는 모든 자식에 `fn`을 호출합니다. 이 때 `this`는 `thisArg`로 설정됩니다. `children`이 중첩된 객체나 배열일 경우 그 안의 값을 순회합니다. 따라서 `fn`에 컨테이너 객체가 넘어가는 일은 일어나지 않습니다. `children`이 `null`이거나 `undefined`면 배열 대신 `null` 또는 `undefined`를 리턴합니다.
-
-#### React.Children.forEach
-
-```javascript
-React.Children.forEach(object children, function fn [, object thisArg])
-```
-
-`React.Children.map()`과 비슷하지만 배열을 리턴하지 않습니다.
-
-#### React.Children.count
-
-```javascript
-number React.Children.count(object children)
-```
-
-`children`에 들어있는 컴포넌트의 총 갯수를 리턴합니다. 이 갯수는 `map`이나 `forEach`에 넘긴 콜백이 호출되는 횟수와 동일합니다.
-
-#### React.Children.only
-
-```javascript
-object React.Children.only(object children)
-```
-
-`children`에 단 하나의 자식이 있을 때 그 자식을 리턴합니다. 그 밖의 경우에는 예외를 발생시킵니다.
-
-#### React.Children.toArray
-
-```javascript
-array React.Children.toArray(object children)
-```
-
-불투명한 자료구조인 `children`를 개별 자식마다 키를 할당해 평면 배열로 리턴합니다. 이는 render 메소드 내에서 자식의 컬렉션을 조작할 때, 특히 `this.props.children`을 넘기기 전에 재정렬하거나 재단할 때 유용합니다.   
-
-## ReactDOM
-
-`react-dom` 패키지는 앱의 최상위 레벨에서 사용될 DOM 고유의 메소드를 제공하며, 원한다면 리액트 외부모델을 위한 출구로 사용될 수 있습니다. 대부분의 컴포넌트는 이 모듈을 사용할 필요가 없습니다. 
-
-### ReactDOM.render
-
-```javascript
-ReactComponent render(
-  ReactElement element,
-  DOMElement container,
-  [function callback]
-)
-```
-
-주어진 ReactElement를 `container` 인자에 넘어온 DOM 안에 렌더링하고 컴포넌트의 [레퍼런스](/react/docs/more-about-refs-ko-KR.html)를 컴포넌트에 리턴합니다. [상태가 없는 컴포넌트](/react/docs/reusable-components-ko-KR.html#stateless-functions)에서는 `null`을 리턴합니다. 
-
-어떤 ReactElement가 이미 `container`에 렌더링 된 적이 있다면, 그것을 업데이트한 뒤 React 컴포넌트의 최신 상태를 반영하기 위해 꼭 필요한 만큼만 DOM을 변경합니다.
-
-콜백 인자를 넘기면 컴포넌트가 렌더링되거나 업데이트 된 다음 호출됩니다.
-
-> 주의:
->
-> `ReactDOM.render()`는 넘어온 컨테이너 노드의 내용을 교체합니다. 안에 있는 DOM 엘리먼트는 첫 호출을 할 때 교체됩니다. 그 후의 호출에는 효율석으로 업데이트하기 위해 React의 DOM diff 알고리즘을 사용합니다.
->
-> `ReactDOM.render()`는 컨테이너 노드를 수정하지 않습니다. (컨테이너의 자식만 수정함) 추후에 기존 자식들을 덮어쓰지 않고 이미 있는 DOM 노드에 컴포넌트를 삽입하는 것도 지원할 가능성이 있습니다.
-
-
-### ReactDOM.unmountComponentAtNode
-
-```javascript
-boolean unmountComponentAtNode(DOMElement container)
-```
-
-DOM에 마운트된 React 컴포넌트를 제거하고 이벤트 핸들러 및 state를 정리합니다. 컨테이너에 마운트된 컴포넌트가 없는 경우에는 호출해도 아무 동작을 하지 않습니다. 컴포넌트가 마운트 해제된 경우 `true`를, 마운트 해제할 컴포넌트가 없으면 `false`를 리턴합니다.
-
-
-### ReactDOM.findDOMNode
-
-```javascript
-DOMElement findDOMNode(ReactComponent component)
-```
-이 컴포넌트가 DOM에 마운트된 경우 해당하는 네이티브 브라우저 DOM 엘리먼트를 리턴합니다. 이 메소드는 폼 필드의 값이나 DOM의 크기/위치 등 DOM에서 정보를 읽을 때 유용합니다. **대부분의 경우, DOM 노드에 ref를 쓸 수 있으며 `findDOMNode`를 사욯할 필요는 없습니다.** `render`가 `null`이나 `false`를 리턴할 때 `findDOMNode()`는 `null`을 리턴합니다.
-
-> 주의:
->
-> `findDOMNode()`는 기본 DOM 노드에 접근하기 위한 출구입니다. 컴포넌트 추상화를 파괴하기 때문에 대부분의 경우 이것의 사용은 권장되지 않습니다.
->
-> `findDOMNode()`는 마운트된 컴포넌트에서만 작동합니다. 이는 컴포넌트가 DOM에 위치해야 함을 뜻합니다. 만약 아직 생성되기전의 컴포넌트에서 `render()`에서 `findDOMNode()`를 호출하는 등 컴포넌트가 마운트 되기 이전에 이를 호출한다면, 예외가 던져질 것입니다.  
->
-> `findDOMNode()`는 상태가없는 컴포넌트에서 쓸 수 없습니다.
-
-## ReactDOMServer
-
-`react-dom/server` 패키지는 서버단에서 컴포넌트를 렌더할 수 있도록 해 줍니다.
-
-### ReactDOMServer.renderToString
-
-```javascript
-string renderToString(ReactElement element)
-```
-
-주어진 ReactElement의 최초 HTML을 렌더링합니다. 이 함수는 서버에서만 사용해야 합니다. React가 HTML 문자열을 리턴합니다. HTML을 서버에서 생성하고 마크업을 최초 요청에 내려보내서, 페이지 로딩을 빠르게 하거나 검색 엔진이 크롤링할 수 있도록 하는 SEO 목적으로 이 메소드를 사용할 수 있습니다.
-
-또한 이 메소드로 서버에서 렌더링한 마크업을 포함한 노드에 `ReactDOM.render()`를 호출하면, React는 마크업을 보존하고 이벤트 핸들러만 붙이므로 최초 로딩을 매우 빠르게 느껴지게 할 수 있습니다.
-
-
-### ReactDOMServer.renderToStaticMarkup
-
-```javascript
-string renderToStaticMarkup(ReactElement element)
-```
-
-`renderToString`와 비슷하지만 `data-react-id`처럼 React에서 내부적으로 사용하는 추가적인 DOM 어트리뷰트를 만들지 않습니다. 추가적인 어트리뷰트를 제거하면 생성되는 마크업의 용량을 줄일 수 있기 때문에 React를 단순한 정적 페이지 생성기로 사용할 때 유용합니다.
diff --git a/docs/docs/ref-01-top-level-api.md b/docs/docs/ref-01-top-level-api.md
deleted file mode 100644
index 7aeb7158dc14..000000000000
--- a/docs/docs/ref-01-top-level-api.md
+++ /dev/null
@@ -1,211 +0,0 @@
----
-id: top-level-api
-title: Top-Level API
-permalink: top-level-api.html
-next: component-api.html
-redirect_from: "/docs/reference.html"
----
-
-## React
-
-`React` is the entry point to the React library. If you're using one of the prebuilt packages it's available as a global; if you're using CommonJS modules you can `require()` it.
-
-
-### React.Component
-
-```javascript
-class Component
-```
-
-This is the base class for React Components when they're defined using ES6 classes. See [Reusable Components](/react/docs/reusable-components.html#es6-classes) for how to use ES6 classes with React. For what methods are actually provided by the base class, see the [Component API](/react/docs/component-api.html).
-
-
-### React.createClass
-
-```javascript
-ReactClass createClass(object specification)
-```
-
-Create a component class, given a specification. A component implements a `render` method which returns **one single** child. That child may have an arbitrarily deep child structure. One thing that makes components different than standard prototypal classes is that you don't need to call new on them. They are convenience wrappers that construct backing instances (via new) for you.
-
-For more information about the specification object, see [Component Specs and Lifecycle](/react/docs/component-specs.html).
-
-
-### React.createElement
-
-```javascript
-ReactElement createElement(
-  string/ReactClass type,
-  [object props],
-  [children ...]
-)
-```
-
-Create and return a new `ReactElement` of the given type. The type argument can be either an
-html tag name string (eg. 'div', 'span', etc), or a `ReactClass` (created via `React.createClass`).
-
-
-### React.cloneElement
-
-```
-ReactElement cloneElement(
-  ReactElement element,
-  [object props],
-  [children ...]
-)
-```
-
-Clone and return a new `ReactElement` using `element` as the starting point. The resulting element will have the original element's props with the new props merged in shallowly. New children will replace existing children. Unlike `React.addons.cloneWithProps`, `key` and `ref` from the original element will be preserved. There is no special behavior for merging any props (unlike `cloneWithProps`). See the [v0.13 RC2 blog post](/react/blog/2015/03/03/react-v0.13-rc2.html) for additional details.
-
-
-### React.createFactory
-
-```javascript
-factoryFunction createFactory(
-  string/ReactClass type
-)
-```
-
-Return a function that produces ReactElements of a given type. Like `React.createElement`, the type argument can be either an html tag name string (eg. 'div', 'span', etc), or a `ReactClass`.
-
-
-### React.isValidElement
-
-```javascript
-boolean isValidElement(* object)
-```
-
-Verifies the object is a ReactElement.
-
-
-### React.DOM
-
-`React.DOM` provides convenience wrappers around `React.createElement` for DOM components. These should only be used when not using JSX. For example, `React.DOM.div(null, 'Hello World!')`
-
-
-### React.PropTypes
-
-`React.PropTypes` includes types that can be used with a component's `propTypes` object to validate props being passed to your components. For more information about `propTypes`, see [Reusable Components](/react/docs/reusable-components.html).
-
-
-### React.Children
-
-`React.Children` provides utilities for dealing with the `this.props.children` opaque data structure.
-
-#### React.Children.map
-
-```javascript
-array React.Children.map(object children, function fn [, object thisArg])
-```
-
-Invoke `fn` on every immediate child contained within `children` with `this` set to `thisArg`. If `children` is a nested object or array it will be traversed: `fn` will never be passed the container objects. If children is `null` or `undefined` returns `null` or `undefined` rather than an array.
-
-#### React.Children.forEach
-
-```javascript
-React.Children.forEach(object children, function fn [, object thisArg])
-```
-
-Like `React.Children.map()` but does not return an array.
-
-#### React.Children.count
-
-```javascript
-number React.Children.count(object children)
-```
-
-Return the total number of components in `children`, equal to the number of times that a callback passed to `map` or `forEach` would be invoked.
-
-#### React.Children.only
-
-```javascript
-object React.Children.only(object children)
-```
-
-Return the only child in `children`. Throws otherwise.
-
-#### React.Children.toArray
-
-```javascript
-array React.Children.toArray(object children)
-```
-
-Return the `children` opaque data structure as a flat array with keys assigned to each child. Useful if you want to manipulate collections of children in your render methods, especially if you want to reorder or slice `this.props.children` before passing it down.
-
-## ReactDOM
-
-The `react-dom` package provides DOM-specific methods that can be used at the top level of your app and as an escape hatch to get outside of the React model if you need to. Most of your components should not need to use this module.
-
-### ReactDOM.render
-
-```javascript
-ReactComponent render(
-  ReactElement element,
-  DOMElement container,
-  [function callback]
-)
-```
-
-Render a ReactElement into the DOM in the supplied `container` and return a [reference](/react/docs/more-about-refs.html) to the component (or returns `null` for [stateless components](/react/docs/reusable-components.html#stateless-functions)).
-
-If the ReactElement 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.
-
-If the optional callback is provided, it will be executed after the component is rendered or updated.
-
-> Note:
->
-> `ReactDOM.render()` controls the contents of the container node you pass in. Any existing DOM elements
-> inside are replaced when first called. Later calls use React’s DOM diffing algorithm for efficient
-> updates.
->
-> `ReactDOM.render()` does not modify the container node (only modifies the children of the container). In
-> the future, it may be possible to insert a component to an existing DOM node without overwriting
-> the existing children.
-
-
-### ReactDOM.unmountComponentAtNode
-
-```javascript
-boolean unmountComponentAtNode(DOMElement container)
-```
-
-Remove a mounted React component from the DOM and clean up its event handlers and state. If no component was mounted in the container, calling this function does nothing. Returns `true` if a component was unmounted and `false` if there was no component to unmount.
-
-
-### ReactDOM.findDOMNode
-
-```javascript
-DOMElement findDOMNode(ReactComponent component)
-```
-If this component has been mounted into the DOM, this returns the corresponding native browser DOM element. This method is useful for reading values out of the DOM, such as form field values and performing DOM measurements. **In most cases, you can attach a ref to the DOM node and avoid using `findDOMNode` at all.** When `render` returns `null` or `false`, `findDOMNode` returns `null`.
-
-> Note:
->
-> `findDOMNode()` is an escape hatch used to access the underlying DOM node. In most cases, use of this escape hatch is discouraged because it pierces the component abstraction.
->
-> `findDOMNode()` only works on mounted components (that is, components that have been placed in the DOM). If you try to call this on a component that has not been mounted yet (like calling `findDOMNode()` in `render()` on a component that has yet to be created) an exception will be thrown.
->
-> `findDOMNode()` cannot be used on stateless components.
-
-## ReactDOMServer
-
-The `react-dom/server` package allows you to render your components on the server.
-
-### ReactDOMServer.renderToString
-
-```javascript
-string renderToString(ReactElement element)
-```
-
-Render a ReactElement to its initial HTML. This should only be used on the server. React will return an HTML string. You can use this method to generate HTML on the server and send the markup down on the initial request for faster page loads and to allow search engines to crawl your pages for SEO purposes.
-
-If you call `ReactDOM.render()` on a node that already has this server-rendered markup, React will preserve it and only attach event handlers, allowing you to have a very performant first-load experience.
-
-
-### ReactDOMServer.renderToStaticMarkup
-
-```javascript
-string renderToStaticMarkup(ReactElement element)
-```
-
-Similar to `renderToString`, except this doesn't create extra DOM attributes such as `data-react-id`, that React uses internally. This is useful if you want to use React as a simple static page generator, as stripping away the extra attributes can save lots of bytes.
diff --git a/docs/docs/ref-01-top-level-api.zh-CN.md b/docs/docs/ref-01-top-level-api.zh-CN.md
deleted file mode 100644
index cc1e8ef64336..000000000000
--- a/docs/docs/ref-01-top-level-api.zh-CN.md
+++ /dev/null
@@ -1,211 +0,0 @@
----
-id: top-level-api-zh-CN
-title: Top-Level API
-permalink: top-level-api-zh-CN.html
-next: component-api-zh-CN.html
-redirect_from: "/docs/reference-zh-CN.html"
----
-
-## React
-
-`React` 是 React 库的入口点。如果你使用预编译包中的一个，则 `React` 为全局变量；如果你使用 CommonJS 模块，你可以 `require()` 它。
-
-
-### React.Component
-
-```javascript
-class Component
-```
-
-当使用ES6 类定义时，React.Component是 React 组件的基类。如何在React中使用 ES6 class 请参见 [可重用组件](/react/docs/reusable-components-zh-CN.html#es6-classes)。基类实际提供了哪些方法 请参见 [组件 API](/react/docs/component-api-zh-CN.html).
-
-
-### React.createClass
-
-```javascript
-ReactClass createClass(object specification)
-```
-
-给定一份规格（specification），创建一个组件类。组件通常要实现一个 `render()` 方法，它返回 **单个的** 子级。该子级可能包含任意深度的子级结构。组件与标准原型类的不同之处在于，你不需要对它们调用 new。  它们是为你在后台构造实例（通过 new）的便利的包装器。
-
-更多关于规格对象（specification object）的信息，请见 [组件规格和生命周期](/react/docs/component-specs-zh-CN.html) 。
-
-
-### React.createElement
-
-```javascript
-ReactElement createElement(
-  string/ReactClass type,
-  [object props],
-  [children ...]
-)
-```
-
-创建并返回一个新的给定类型的 `ReactElement`。type 参数既可以是一个 html 标签名字符串（例如. “div”，“span”，等等），也可以是一个 `ReactClass` （用 `React.createClass` 创建的）。
-
-
-
-### React.cloneElement
-
-```
-ReactElement cloneElement(
-  ReactElement element,
-  [object props],
-  [children ...]
-)
-```
-
-使用 `element` 作为起点，克隆并返回一个新的 `ReactElement` 。生成的 element 将会拥有原始 element 的 props 与新的 props 的浅合并。新的子级将会替换现存的子级。 不同于 `React.addons.cloneWithProps`，来自原始 element 的 `key` 和 `ref` 将会保留。对于合并任何 props 没有特别的行为（不同于 `cloneWithProps`）。更多细节详见[v0.13 RC2 blog post](/react/blog/2015/03/03/react-v0.13-rc2.html) 。
-
-
-### React.createFactory
-
-```javascript
-factoryFunction createFactory(
-  string/ReactClass type
-)
-```
-
-返回一个生成给定类型的 ReactElements 的函数。如同 `React.createElement`，type 参数既可以是一个 html 标签名字符串（例如. “div”，“span”，等等），也可以是一个 `ReactClass` 。
-
-
-### React.isValidElement
-
-```javascript
-boolean isValidElement(* object)
-```
-
-验证对象是否是一个 ReactElement。
-
-
-### React.DOM
-
-`React.DOM` 用 `React.createElement` 为 DOM 组件提供了便利的包装器。该方式应该只在不使用 JSX 的时使用。例如，`React.DOM.div(null, 'Hello World!')`。
-
-
-### React.PropTypes
-
-`React.PropTypes` 包含了能与 组件的`propTypes` 对象一起使用的类型，用以验证传入你的组件的 props。更多有关 `propTypes` 的信息，请见 [可重用组件](/react/docs/reusable-components-zh-CN.html)。
-
-
-### React.Children
-
-`React.Children` 为处理 `this.props.children` 这个不透明的数据结构提供了工具。
-
-#### React.Children.map
-
-```javascript
-array React.Children.map(object children, function fn [, object thisArg])
-```
-
-在每一个包含在 `children` 中的直接子级上调用 `fn` ，`fn`中的 `this` 设置为 `thisArg`。如果 `children` 是一个嵌套的对象或者数组，它将被遍历：不会传入容器对象到 `fn` 中。如果 children 是 `null` 或者 `undefined`，则返回 `null` 或者 `undefined` 而不是一个空数组。
-
-#### React.Children.forEach
-
-```javascript
-React.Children.forEach(object children, function fn [, object thisArg])
-```
-
-类似 `React.Children.map()`，但是不返回数组。
-
-#### React.Children.count
-
-```javascript
-number React.Children.count(object children)
-```
-
-返回 `children` 中的组件总数，相等于传递给 `map` 或者 `forEach` 的回调函数应被调用次数。
-
-#### React.Children.only
-
-```javascript
-object React.Children.only(object children)
-```
-
-返回 `children` 中仅有的子级。否则抛出异常。
-
-#### React.Children.toArray
-
-```javascript
-array React.Children.toArray(object children)
-```
-
-以赋key给每个child的平坦的数组形式,返回不透明的 `children` 数据结构.如果你想操纵你的渲染方法的子级的合集这很有用,尤其如果你想在 `this.props.children` 传下之前渲染或者切割.
-
-## ReactDOM
-
-`react-dom` 包提供了 具体的DOM方法,这些方法可以在你的app的顶层作为一个你需要时脱离React模式的安全舱口 被使用.你的大多数组件不需要使用这个模块.
-
-### ReactDOM.render
-
-```javascript
-ReactComponent render(
-  ReactElement element,
-  DOMElement container,
-  [function callback]
-)
-```
-
-渲染一个 ReactElement 到 DOM 里提供的 `容器（container）`中，并返回一个对 组件(或者返回 `null` 对于 [无状态组件](/react/docs/reusable-components.html#stateless-functions)) 的[引用](/react/docs/more-about-refs.html) 
-
-如果 ReactElement 之前被渲染到了 `container` 中，这将对它执行一次更新，并仅变动需要变动的 DOM 来反映最新的 React 组件。
-
-如果提供了可选的回调函数，则该函数将会在组件渲染或者更新之后被执行。
-
-> 注意:
->
-> `ReactDOM.render()` 控制你传入的 container 节点的内容。
->  当初次调用时，任何现存于内的 DOM 元素将被替换。
->  其后的调用使用 React的 diffing 算法来有效率的更新。
->
-> `ReactDOM.render()` 不会修改 container 节点（只修改 container 的子级）。
->  将来，也许能够直接插入一个组件到已经存在的 DOM 节点而不覆盖
->  现有的子级。
-
-
-### ReactDOM.unmountComponentAtNode
-
-```javascript
-boolean unmountComponentAtNode(DOMElement container)
-```
-
-从 DOM 中移除已经挂载的 React 组件，并清除它的事件处理器和 state。如果在 container 中没有组件被挂载，调用此函数将什么都不做。如果组件被卸载返回 `true`，如果没有组件被卸载返回 `false`。
-
-
-### ReactDOM.findDOMNode
-
-```javascript
-DOMElement findDOMNode(ReactComponent component)
-```
-如果这个组件已经被挂载到了 DOM，它返回相应的浏览器原生的 DOM 元素。这个方法对于读取 DOM 的值很有用，比如表单域的值和执行 DOM 的测量。**在大多数情况下,你可以连接一个ref到DOM节点上,并避免使用 `findDOMNode`** 如果 `render` 返回 `null` 或者 `false`， `findDOMNode` 返回 `null`.
-
-> 注意:
->
-> `findDOMNode()` 是一个用来访问底层DOM节点的安全舱口.大多数情况下,使用这个安全舱口是不被鼓励的,因为它穿破了组件的抽象.
->
-> `findDOMNode()` 只在已挂载的组件上工作(即是,已经被放置到DOM里的组件).如果你尝试在没有被挂载的组件上调用这个方法(比如在 一个没有被创建的组件的`render()`里 调用 `findDOMNode()` )会抛出一个异常. 
->
-> `findDOMNode()` 不能用在无状态组件.
-
-## ReactDOMServer
-
-`react-dom/server` 允许你在服务器上渲染你的组件.
-
-### ReactDOMServer.renderToString
-
-```javascript
-string renderToString(ReactElement element)
-```
-
-把 ReactElement 渲染为它原始的 HTML 。这应该仅在服务器端使用。React 将会返回一个 HTML 字符串。你可以用这种方法在服务器端生成 HTML，然后在初始请求下传这些标记，以获得更快的页面加载速度及允许搜索引擎抓取页面（便于 SEO）。
-
-如果在一个在已经有了这种服务器预渲染标记的节点上面调用 `ReactDOM.render()`，React 将会维护该节点，仅绑定事件处理器，让你有一个非常高效的初次加载体验。
-
-
-### ReactDOMServer.renderToStaticMarkup
-
-```javascript
-string renderToStaticMarkup(ReactElement element)
-```
-
-类似于 `renderToString` ，除了不创建额外的 DOM 属性，比如 `data-react-id`，这仅在 React 内部使用的属性。如果你想用 React 做一个简单的静态页面生成器，这是很有用的，因为去除额外的属性能够节省很多字节。
diff --git a/docs/docs/ref-02-component-api.it-IT.md b/docs/docs/ref-02-component-api.it-IT.md
deleted file mode 100644
index 9cdabab396d9..000000000000
--- a/docs/docs/ref-02-component-api.it-IT.md
+++ /dev/null
@@ -1,146 +0,0 @@
----
-id: component-api-it-IT
-title: API dei Componenti
-permalink: component-api-it-IT.html
-prev: top-level-api-it-IT.html
-next: component-specs-it-IT.html
----
-
-## React.Component
-
-Istanze di un React Component sono create internamente a React durante il rendering. Queste istanze sono riutilizzate in rendering successivi, e possono essere accedute dai metodi del tuo componente come `this`. L'unica maniera di ottenere un riferimento a una istanza di un React Component fuori da React è conservare il valore restituito da `ReactDOM.render`. All'interno di altri Component, puoi utilizzare [i ref](/react/docs/more-about-refs.html) per ottenere il medesimo risultato.
-
-
-### setState
-
-```javascript
-void setState(
-  function|object nextState,
-  [function callback]
-)
-```
-Effettua una combinazione di `nextState` nello stato attuale. Questo è il metodo principale che va usato per scatenare aggiornamenti della UI da gestori di eventi e callback di richieste al server.
-
-Il primo argomento può essere un oggetto (contenente zero o più chiavi da aggiornare) o una funzione (con argomenti `state` e `props`) che restituisce un oggetto contenente chiavi da aggiornare.
-
-Ecco come utilizzarla passando un oggetto:
-
-```javascript
-setState({mykey: 'my new value'});
-```
-
-È anche possibile passare una funzione con la firma `function(state, props)`. Questo può essere utile in certi casi quando desideri accodare un aggiornamento atomico che consulta i valori precedenti di state+props prima di impostare i nuovi valori. Ad esempio, supponi che vogliamo incrementare un valore nello stato:
-
-```javascript
-setState(function(previousState, currentProps) {
-  return {myInteger: previousState.myInteger + 1};
-});
-```
-
-Il secondo parametro (opzionale) è una funzione callback che verrà eseguita quando `setState` ha terminato e il rendering del componente è stato effettuato.
-
-> Note:
->
-> *MAI* modificare `this.state` direttamente, in quanto chiamare `setState()` successivamente potrebbe sovrascrivere la modifica fatta. Tratta `this.state` come se fosse immutabile.
->
-> `setState()` non cambia immediatamente `this.state`, ma crea una transizione di stato in corso. Accedere `this.state` subito dopo aver chiamato questo metodo potrebbe potenzialmente restituire il valore precedente.
->
-> Non viene garantita alcuna sincronicità per le chiamate di `setState`, e le chiamate stesse potrebbero essere raggruppate per migliorare le prestazioni.
->
-> `setState()` scatena sempre un ri-rendering a meno che la logica di rendering condizionale venga implementata in `shouldComponentUpdate()`. Se oggetti mutabili sono usati e la logica non può essere implementata in `shouldComponentUpdate()`, chiamare `setState()` solo quando il nuovo stato differisce dal precedente eviterà ri-rendering superflui.
-
-
-### replaceState
-
-```javascript
-void replaceState(
-  object nextState,
-  [function callback]
-)
-```
-
-Come `setState()`, ma elimina ogni chiave preesistente che non si trova in `nextState`.
-
-> Nota:
->
-> Questo metodo non è disponibile il componenti `class` ES6 che estendono `React.Component`. Potrebbe essere eliminato del tutto in una versione futura di React.
-
-
-### forceUpdate
-
-```javascript
-void forceUpdate(
-  [function callback]
-)
-```
-
-In modo predefinito, quando lo stato o le proprietà del tuo componente cambiano, ne verrà effettuato il ri-rendering. Tuttavia, se questi cambiano implicitamente (ad es.: dati profondi all'interno di un oggetto cambiano senza che l'oggetto stesso cambi) o se il tuo metodo `render()` dipende da altri dati, puoi istruire React perché riesegua `render()` chiamando `forceUpdate()`.
-
-Chiamare `forceUpdate()` causerà la chiamata di `render()` sul componente, saltando l'esecuzione di `shouldComponentUpdate()`. Questo scatenerà i normali metodi del ciclo di vita per i componenti figli, incluso il metodo `shouldComponentUpdate()` di ciascun figlio. React tuttavia aggiornerà il DOM soltanto se il markup effettivamente cambia.
-
-Normalmente dovresti cercare di evitare l'uso di `forceUpdate()` e leggere soltanto `this.props` e `this.state` all'interno di `render()`. Ciò rende il tuo componente "puro" e la tua applicazione molto più semplice ed efficiente.
-
-
-### getDOMNode
-
-```javascript
-DOMElement getDOMNode()
-```
-
-Se questo componente è stato montato nel DOM, restituisce il corrispondente elemento DOM nativo del browser. Questo metodo è utile per leggere valori dal DOM, come valori dei campi dei moduli ed effettuare misure sul DOM. Quando `render` restituisce `null` o `false`, `this.getDOMNode()` restituisce `null`.
-
-> Nota:
->
-> getDOMNode è deprecato ed è stato sostituito da [ReactDOM.findDOMNode()](/react/docs/top-level-api.html#reactdom.finddomnode).
->
-> Questo metodo non è disponibile il componenti `class` ES6 che estendono `React.Component`. Potrebbe essere eliminato del tutto in una versione futura di React.
-
-
-### isMounted
-
-```javascript
-boolean isMounted()
-```
-
-`isMounted()` restituisce `true` se il rendering del componente è stato effettuato nel DOM, `false` altrimenti. Puoi usare questo metodo come guardia per chiamate asincrone a `setState()` o `forceUpdate()`.
-
-> Nota:
->
-> Questo metodo non è disponibile il componenti `class` ES6 che estendono `React.Component`. Potrebbe essere eliminato del tutto in una versione futura di React.
-
-
-### setProps
-
-```javascript
-void setProps(
-  object nextProps,
-  [function callback]
-)
-```
-
-Quando stai integrando con un'applicazione JavaScript esterna puoi voler segnalare un cambiamento a un componente React il cui rendering è stato effettuato con `ReactDOM.render()`.
-
-Chiamare `setProps()` su un componente al livello radice cambierà le sue proprietà e scatenerà un ri-rendering. Inoltre, puoi fornire una funzione callback opzionale che verrà eseguita quando `setProps` ha terminato e il rendering del componente è terminato.
-
-> Nota:
->
-> Quando possibile, l'approccio dichiarativo di invocare nuovamente `ReactDOM.render()` sullo stesso nodo è preferibile. Quest'ultimo tende a rendere gli aggiornamenti più comprensibili. (Non vi è una differenza significativa di prestazioni tra i due approcci.)
->
-> Questo metodo può essere chiamato soltanto su un componente al livello radice. Ovvero, è disponibile soltanto sul componente passato direttamente a `ReactDOM.render()` e nessuno dei suoi figli. Se il tuo intento è usare `setProps()` su un componente figlio, approfitta degli aggiornamenti reattivi e passa la nuova proprietà al componente figlio quando viene creato in `render()`.
->
-> Questo metodo non è disponibile il componenti `class` ES6 che estendono `React.Component`. Potrebbe essere eliminato del tutto in una versione futura di React.
-
-### replaceProps
-
-```javascript
-void replaceProps(
-  object nextProps,
-  [function callback]
-)
-```
-
-Come `setProps()` ma elimina ogni proprietà preesistente anziché riunire i due oggetti.
-
-> Nota:
->
-> Questo metodo non è disponibile il componenti `class` ES6 che estendono `React.Component`. Potrebbe essere eliminato del tutto in una versione futura di React.
diff --git a/docs/docs/ref-02-component-api.ko-KR.md b/docs/docs/ref-02-component-api.ko-KR.md
deleted file mode 100644
index 0576e7dd13df..000000000000
--- a/docs/docs/ref-02-component-api.ko-KR.md
+++ /dev/null
@@ -1,148 +0,0 @@
----
-id: component-api-ko-KR
-title: 컴포넌트 API
-permalink: component-api-ko-KR.html
-prev: top-level-api-ko-KR.html
-next: component-specs-ko-KR.html
----
-
-## React.Component
-
-React 컴포넌트의 인스턴스는 React가 렌더링 시에 내부적으로 만듭니다. 이때 만들어진 인스턴스는 이후의 렌더링에서 다시 사용되고 컴포넌트의 메소드들에서 `this` 변수로 접근할 수 있습니다. React 외부에서 React 컴포넌트의 핸들을 얻는 방법은 `ReactDOM.render`의 리턴값을 저장하는 것이 유일합니다. 다른 컴포넌트 안에서 비슷한 결과를 얻으려면 [refs](/react/docs/more-about-refs-ko-KR.html)를 사용해야 합니다.
-
-
-### setState
-
-```javascript
-void setState(
-  function|object nextState, 
-  [function callback]
-)
-```
-
-nextState를 현재 state에 얕게(shallow) 병합합니다. 이벤트 핸들러와 서버 요청 콜백에서 UI 업데이트를 발생시키기 위해 이 메소드를 주로 사용합니다.
-
-첫번째 인자는 업데이트를 위한 키를 0개 이상 가진 객체이거나 업데이트를 위한 키들을 포함한 객체를 반환하는 함수(의 state나 props)일 수 있습니다.
-
-객체를 사용하는 간단한 예제입니다:
-
-```javascript
-setState({mykey: '새로운 값'});
-```
-
-`function(state, props)`처럼 인자를 포함한 함수를 넘겨주는 것도 가능합니다. 어떤 값이든 state와 props의 이전 값을 참고해서 원자적인 업데이트를 큐에 추가(enqueue)하려는 경우 이는 유용합니다. 예를 들어 state의 값을 증가 시키려는 경우 같이 처리 가능합니다:
-
-```javascript
-setState(function(previousState, currentProps) {
-  return {myInteger: previousState.myInteger + 1};
-});
-```
-
-두번째 인자는 선택적이며, `setState`가 한번 완료되고 컴포넌트가 다시 렌더 되었을때 실행되는 콜백 함수입니다.
-
-> 주의:
->
-> *절대로* `this.state`를 직접 변경하지 마세요. 그 뒤에 `setState()`를 호출하면 그동안 변경했던 것이 교체될 수 있습니다. `this.state`는 변경 불가능한 것으로 생각하시는 것이 좋습니다.
->
-> `setState()`를 호출해도 `this.state`가 곧바로 변경되지 않고 대기 중인 state transition이 만들어집니다. 이 메소드를 호출한 직후 `this.state`에 접근하면 바뀌기 전의 값을 리턴할 가능성이 있습니다.
->
-> `setState`에 대한 호출이 동기적으로 처리된다는 보장이 없으며, 성능 향상을 위해 배치 처리될 수 있습니다.
->
-> `setState()`는 `shouldComponentUpdate()`에 조건부 렌더링 로직이 구현되어 있지 않다면 항상 재렌더링을 발생시킵니다. 변경 가능한 객체를 사용하고 있고 조건부 렌더링 로직을 `shouldComponentUpdate()`에 구현할 수 없는 경우라면 새로운 state가 이전 state와 달라지는 경우에만 `setState()`를 호출하여 불필요한 재렌더링을 피할 수 있습니다.
-
-
-### replaceState
-
-```javascript
-void replaceState(
-  object nextState, 
-  [function callback]
-)
-```
-
-`setState()`와 비슷하지만 기존에 존재하는 state 중 nextState에 없는 키는 모두 삭제됩니다.
-
-> 주의:
->
-> 이 메소드는 `React.Component`를 확장한 ES6 `class` 컴포넌트에서는 사용할 수 없습니다. React의 미래 버전에서 이는 완전히 사라지게 될 것입니다.
-
-
-### forceUpdate
-
-```javascript
-void forceUpdate(
-  [function callback]
- )
-```
-
-기본적으로, 컴포넌트의 state나 props가 변경되면, 컴포넌트는 다시 렌더됩니다. 하지만 이런 변경이 묵시적이거나(예를들어 객체의 변경 없이 깊이 있는 데이터만 변경된 경우) `render()` 함수가 다른 값에 의존하는 경우, `forceUpdate()`를 호출해 React에게 `render()`를 다시 실행할 필요가 있다고 알릴 수 있습니다.
-
-`forceUpdate()`를 호출하면 `shouldComponentUpdate()`를 생략하고 해당 컴포넌트 `render()` 함수가 호출됩니다. 각 자식 컴포넌트에 대해서는 `shouldComponentUpdate()`를 포함해 보통 라이프 사이클 메서드를 호출합니다. React는 마크업이 변경된 경우에만 DOM을 업데이트합니다.
-
-특별한 경우가 아니면 `forceUpdate()`는 되도록 피하시고 `render()`에서는 `this.props`와 `this.state`에서만 읽어오세요. 그렇게 하는 것이 컴포넌트를 "순수"하게 하고 애플리케이션을 훨씬 단순하고 효율적으로 만들어줍니다.
-
-
-### getDOMNode
-
-```javascript
-DOMElement getDOMNode()
-```
-
-이 컴포넌트가 DOM에 마운트된 경우 해당하는 네이티브 브라우저 DOM 엘리먼트를 리턴합니다. 이 메소드는 폼 필드의 값이나 DOM의 크기/위치 등 DOM에서 정보를 읽을 때 유용합니다. `render`가 `null`이나 `false`를 리턴하였다면 `this.getDOMNode()`는 `null`을 리턴합니다.
-
-> 주의:
->
-> getDOMNode는 [ReactDOM.findDOMNode()](/react/docs/top-level-api.html#reactdom.finddomnode)로 교체되었습니다.
->
-> 이 메소드는 `React.Component`를 확장한 ES6 `class` 컴포넌트에서는 사용할 수 없습니다. React의 미래 버전에서 이는 완전히 사라지게 될 것입니다.
-
-
-### isMounted
-
-```javascript
-boolean isMounted()
-```
-
-`isMounted()`는 컴포넌트가 DOM에 렌더링되었으면 `true`를, 아니면 `false`를 리턴합니다. 비동기적으로 `setState()`나 `forceUpdate()`를 호출할 때 이 메소드를 사용하여 오류를 방지할 수 있습니다.
-
-> 주의:
->
-> 이 메소드는 `React.Component`를 확장한 ES6 `class` 컴포넌트에서는 사용할 수 없습니다. React의 미래 버전에서 이는 완전히 사라지게 될 것입니다.
-
-
-### setProps
-
-```javascript
-void setProps(
-  object nextProps, 
-  [function callback]
-)
-```
-
-외부 JavaScript 애플리케이션과 연동하는 경우 `ReactDOM.render()`로 렌더링된 React 컴포넌트에 변경을 알리고 싶을 때가 있습니다.
-
-최상위 컴포넌트에서 `setProps()`를 호출하면 프로퍼티를 변경하고 렌더를 다시 발생합니다. 거기에 콜백 함수를 넘기면 `setProps`가 완료되고 컴포넌트가 다시 렌더링된 다음에 한번 호출됩니다.
-
-> 주의:
->
-> 가능하다면 이것 대신 `ReactDOM.render()`를 같은 노드에서 다시 호출하는 선언적인 방법이 더 바람직합니다. 그렇게 하는 편이 업데이트에 대해 생각하는 것을 쉽게 만듭니다. (두가지 방식에 눈에 띄는 성능 차이는 없습니다.)
->
-> 이 메소드는 최상위 컴포넌트에만 호출 가능합니다. 다시 말해, `ReactDOM.render()`에 바로 넘긴 컴포넌트에서만 사용할 수 있고 자식에서는 불가능합니다. 자식 컴포넌트에 `setProps()`를 사용하고 싶다면, 그 대신 반응적인 업데이트의 장점을 활용하여 `render()` 안에서 자식 컴포넌트를 만들 때 새로운 prop을 넘기세요.
->
-> 이 메소드는 `React.Component`를 확장한 ES6 `class` 컴포넌트에서는 사용할 수 없습니다. React의 미래 버전에서 이는 완전히 사라지게 될 것입니다.
-
-
-### replaceProps
-
-```javascript
-void replaceProps(
-  object nextProps, 
-  function callback]
-)
-```
-
-`setProps()`와 비슷하지만 두 객체를 합치는 대신 이전에 존재하던 props를 삭제합니다.
-
-> 주의:
->
-> 이 메소드는 `React.Component`를 확장한 ES6 `class` 컴포넌트에서는 사용할 수 없습니다. React의 미래 버전에서 이는 완전히 사라지게 될 것입니다.
diff --git a/docs/docs/ref-02-component-api.md b/docs/docs/ref-02-component-api.md
deleted file mode 100644
index 216dd2cd492a..000000000000
--- a/docs/docs/ref-02-component-api.md
+++ /dev/null
@@ -1,146 +0,0 @@
----
-id: component-api
-title: Component API
-permalink: component-api.html
-prev: top-level-api.html
-next: component-specs.html
----
-
-## React.Component
-
-Instances of a React Component are created internally in React when rendering. These instances are reused in subsequent renders, and can be accessed in your component methods as `this`. The only way to get a handle to a React Component instance outside of React is by storing the return value of `ReactDOM.render`. Inside other Components, you may use [refs](/react/docs/more-about-refs.html) to achieve the same result.
-
-
-### setState
-
-```javascript
-void setState(
-  function|object nextState,
-  [function callback]
-)
-```
-Performs a shallow merge of nextState into current state. This is the primary method you use to trigger UI updates from event handlers and server request callbacks.
-
-The first argument can be an object (containing zero or more keys to update) or a function (of state and props) that returns an object containing keys to update.
-
-Here is the simple object usage:
-
-```javascript
-setState({mykey: 'my new value'});
-```
-
-It's also possible to pass a function with the signature `function(state, props)`. This can be useful in some cases when you want to enqueue an atomic update that consults the previous value of state+props before setting any values.  For instance, suppose we wanted to increment a value in state:
-
-```javascript
-setState(function(previousState, currentProps) {
-  return {myInteger: previousState.myInteger + 1};
-});
-```
-
-The second (optional) parameter is a callback function that will be executed once `setState` is completed and the component is re-rendered.
-
-> Notes:
->
-> *NEVER* mutate `this.state` directly, as calling `setState()` afterwards may replace the mutation you made. Treat `this.state` as if it were immutable.
->
-> `setState()` does not immediately mutate `this.state` but creates a pending state transition. Accessing `this.state` after calling this method can potentially return the existing value.
->
-> There is no guarantee of synchronous operation of calls to `setState` and calls may be batched for performance gains.
->
-> `setState()` will always trigger a re-render unless conditional rendering logic is implemented in `shouldComponentUpdate()`. If mutable objects are being used and the logic cannot be implemented in `shouldComponentUpdate()`, calling `setState()` only when the new state differs from the previous state will avoid unnecessary re-renders.
-
-
-### replaceState
-
-```javascript
-void replaceState(
-  object nextState,
-  [function callback]
-)
-```
-
-Like `setState()` but deletes any pre-existing state keys that are not in nextState.
-
-> Note:
->
-> This method is not available on ES6 `class` components that extend `React.Component`. It may be removed entirely in a future version of React.
-
-
-### forceUpdate
-
-```javascript
-void forceUpdate(
-  [function callback]
-)
-```
-
-By default, when your component's state or props change, your component will re-render. However, if these change implicitly (eg: data deep within an object changes without changing the object itself) or if your `render()` method depends on some other data, you can tell React that it needs to re-run `render()` by calling `forceUpdate()`.
-
-Calling `forceUpdate()` will cause `render()` to be called on the component, skipping `shouldComponentUpdate()`. This will trigger the normal lifecycle methods for child components, including the `shouldComponentUpdate()` method of each child. React will still only update the DOM if the markup changes.
-
-Normally you should try to avoid all uses of `forceUpdate()` and only read from `this.props` and `this.state` in `render()`. This makes your component "pure" and your application much simpler and more efficient.
-
-
-### getDOMNode
-
-```javascript
-DOMElement getDOMNode()
-```
-
-If this component has been mounted into the DOM, this returns the corresponding native browser DOM element. This method is useful for reading values out of the DOM, such as form field values and performing DOM measurements. When `render` returns `null` or `false`, `this.getDOMNode()` returns `null`.
-
-> Note:
->
-> getDOMNode is deprecated and has been replaced with [ReactDOM.findDOMNode()](/react/docs/top-level-api.html#reactdom.finddomnode).
->
-> This method is not available on ES6 `class` components that extend `React.Component`. It may be removed entirely in a future version of React.
-
-
-### isMounted
-
-```javascript
-boolean isMounted()
-```
-
-`isMounted()` returns `true` if the component is rendered into the DOM, `false` otherwise. You can use this method to guard asynchronous calls to `setState()` or `forceUpdate()`.
-
-> Note:
->
-> This method is not available on ES6 `class` components that extend `React.Component`. It will likely be removed entirely in a future version of React, so you might as well [start migrating away from isMounted() now](/react/blog/2015/12/16/ismounted-antipattern.html).
-
-
-### setProps
-
-```javascript
-void setProps(
-  object nextProps,
-  [function callback]
-)
-```
-
-When you're integrating with an external JavaScript application you may want to signal a change to a React component rendered with `ReactDOM.render()`.
-
-Calling `setProps()` on a root-level component will change its properties and trigger a re-render. In addition, you can supply an optional callback function that is executed once `setProps` is completed and the component is re-rendered.
-
-> Note:
->
-> This method is deprecated and will be removed soon. This method is not available on ES6 `class` components that extend `React.Component`. Instead of calling `setProps`, try invoking ReactDOM.render() again with the new props. For additional notes, see our [blog post about using the Top Level API](/react/blog/2015/10/01/react-render-and-top-level-api.html)
->
-> When possible, the declarative approach of calling `ReactDOM.render()` again on the same node is preferred instead. It tends to make updates easier to reason about. (There's no significant performance difference between the two approaches.)
->
-> This method can only be called on a root-level component. That is, it's only available on the component passed directly to `ReactDOM.render()` and none of its children. If you're inclined to use `setProps()` on a child component, instead take advantage of reactive updates and pass the new prop to the child component when it's created in `render()`.
-
-### replaceProps
-
-```javascript
-void replaceProps(
-  object nextProps,
-  [function callback]
-)
-```
-
-Like `setProps()` but deletes any pre-existing props instead of merging the two objects.
-
-> Note:
->
-> This method is deprecated and will be removed soon. This method is not available on ES6 `class` components that extend `React.Component`. Instead of calling `replaceProps`, try invoking ReactDOM.render() again with the new props. For additional notes, see our [blog post about using the Top Level API](/react/blog/2015/10/01/react-render-and-top-level-api.html)
diff --git a/docs/docs/ref-02-component-api.zh-CN.md b/docs/docs/ref-02-component-api.zh-CN.md
deleted file mode 100644
index 3186f22e93d4..000000000000
--- a/docs/docs/ref-02-component-api.zh-CN.md
+++ /dev/null
@@ -1,146 +0,0 @@
----
-id: component-api-zh-CN
-title: 组件 API
-permalink: component-api-zh-CN.html
-prev: top-level-api-zh-CN.html
-next: component-specs-zh-CN.html
----
-
-## React.Component
-
-当渲染时，React 组件的实例在 React 内部被创建。这些实例在随后的渲染中被重复使用，并可以在组件方法中通过 `this` 访问。唯一的在 React 之外获取 React 组件实例句柄的方法是保存 `ReactDOM.render` 的返回值。在其它组件内，你可以使用 [refs](/react/docs/more-about-refs-zh-CN.html) 得到相同的结果。
-
-
-### setState
-
-```javascript
-void setState(
-  function|object nextState,
-  [function callback]
-)
-```
-执行一个 nextState 到当前 state 的浅合并。这是你从事件处理器和服务器请求回调用来触发 UI 更新的主要手段。
-
-第一个参数可以是一个对象（包含0或者多个keys来更新）或者一个（state 和 props的）函数，它返回一个包含要更新的keys的对象。
-
-这里是一个简单的运用:
-
-```javascript
-setState({mykey: 'my new value'});
-```
-
-也可以以 `function(state, props)` 传递一个函数。当你想要把一个在设置任何值之前参考前一次 state+props 的值的原子更新放在队列中 这会有很用。例如，假如我们想在 state 增加一个值:
-
-```javascript
-setState(function(previousState, currentProps) {
-  return {myInteger: previousState.myInteger + 1};
-});
-```
-
-第二个（可选）的参数是一个将会在 `setState` 完成和组件被重绘后执行的回调函数。
-
-> 注意:
->
-> *绝对不要* 直接改变 `this.state`，因为之后调用 `setState()` 可能会替换掉你做的改变。把 `this.state` 当做是不可变的。
->
-> `setState()` 不会立刻改变 `this.state`，而是创建一个即将处理的 state 转变。在调用该方法之后访问 `this.state` 可能会返回现有的值。
->
-> 对 `setState` 的调用没有任何同步性的保证，并且调用可能会为了性能收益批量执行。
->
-> `setState()` 将总是触发一次重绘，除非在 `shouldComponentUpdate()` 中实现了条件渲染逻辑。如果可变对象被使用了，但又不能在 `shouldComponentUpdate()` 中实现这种逻辑，仅在新 state 和之前的 state 存在差异的时候调用 `setState()` 可以避免不必要的重新渲染。
-
-
-### replaceState
-
-```javascript
-void replaceState(
-  object nextState,
-  [function callback]
-)
-```
-
-类似于 `setState()`，但是删除任何 先前存在但不在 nextState 里的 state 键。
-
-> 注意:
->
-> 这个方法在从 `React.Component` 扩展的 ES6 `class` 组件里不可用。它也许会在未来的 React 版本中被完全移除。
-
-
-### forceUpdate
-
-```javascript
-void forceUpdate(
-  [function callback]
-)
-```
-
-默认情况下，当你的组件的 state 或者 props 改变，你的组件将会重绘。然而，如果它们隐式的改变（例如：在对象深处的数据改变了但没有改变对象本身）或者如果你的 `render()` 方法依赖于其他的数据，你可以用调用  `forceUpdate()` 来告诉 React 它需要重新运行 `render()`。
-
-调用 `forceUpdate()` 将会导致 `render()` 跳过 `shouldComponentUpdate()` 在组件上被调用，这会为子级触发正常的生命周期方法。包括每个子级的 `shouldComponentUpdate()` 方法。如果标记改变了，React 仍仅只更新 DOM。
-
-通常你应该试着避免所有对 `forceUpdate()` 的使用并且在 `render()` 里只从 `this.props` 和 `this.state` 读取。这会使你的组件 "纯粹" 并且你的组件会更简单和高效。
-
-
-### getDOMNode
-
-```javascript
-DOMElement getDOMNode()
-```
-
-如果这个组件已经被挂载到了 DOM，它返回相应的浏览器原生的 DOM 元素。这个方法对于读取 DOM 的值很有用，比如表单域的值和执行 DOM 的测量。如果 `render` 返回 `null` 或者 `false` 的时候，`this.getDOMNode()` 返回 `null`。
-
-> Note:
->
-> getDOMNode 被废弃了，已经被 [ReactDOM.findDOMNode()] 替换(/react/docs/top-level-api-zh-CN.html#reactdom.finddomnode).
->
-> 这个方法在从 `React.Component` 扩展的 ES6 `class` 组件里不可用。它也许会在未来的 React 版本中被完全移除。
-
-
-### isMounted
-
-```javascript
-boolean isMounted()
-```
-
-如果组件渲染到了 DOM 中，`isMounted()` 返回 true，否则返回 `false`。可以使用该方法来控制对 `setState()` 和 `forceUpdate()` 的异步调用。
-
-> 注意:
->
-> 这个方法在从 `React.Component` 扩展的 ES6 `class` 组件里不可用。它也许会在未来的 React 版本中被完全移除,所以你也要移除它 [start migrating away from isMounted() now](/react/blog/2015/12/16/ismounted-antipattern.html)
-
-
-### setProps
-
-```javascript
-void setProps(
-  object nextProps,
-  [function callback]
-)
-```
-
-当和一个外部的 JavaScript 应用整合的时候，你也许会想用 `ReactDOM.render()` 给 React 组件标示一个改变。
-
-在根组件上调用 `setProps()` 会改变他的属性并触发一次重绘。另外，你可以提供一个可选的回调函数，一旦 `setProps` 完成并且组件被重绘它就执行。
-
-> 注意:
->
-> 这个方法被弃用了并会很快移除.这个方法在从 `React.Component` 扩展的 ES6 `class` 组件里不可用. 取代调用 `setProps`,试着以新的 props 再次调用 `ReactDOM.render()`. 更多的注意事项,见我们的[blog post about using the Top Level API](/react/blog/2015/10/01/react-render-and-top-level-api.html)
->
-> 如果可能，上述的在同一个节点上再次调用 `ReactDOM.render()` 的方法是优先替代的。它往往使更新更容易理解。（两种方法并没有显著的性能区别。）
->
-> 这个方法仅能在根组件上被调用。也就是说，它仅在直接传给 `ReactDOM.render()` 的组件上可用，在它的子级上不可用。如果你倾向于在子组件上使用 `setProps()`，不要利用响应式更新，而是当子组件在 `render()` 中创建的时候传入新的 prop 到子组件中。
-
-### replaceProps
-
-```javascript
-void replaceProps(
-  object nextProps,
-  [function callback]
-)
-```
-
-类似于 `setProps()`，但是删除任何先前存在的 props，而不是合并这两个对象。
-
-> 注意:
->
-> 这个方法被弃用了并会很快移除.这个方法在从 `React.Component` 扩展的 ES6 `class` 组件里不可用.  取代调用 `replaceProps`,试着以新的 props 再次调用 `ReactDOM.render()`. 更多的注意事项,见我们的[blog post about using the Top Level API](/react/blog/2015/10/01/react-render-and-top-level-api.html)
diff --git a/docs/docs/ref-03-component-specs.it-IT.md b/docs/docs/ref-03-component-specs.it-IT.md
deleted file mode 100644
index 42a0e9d72a01..000000000000
--- a/docs/docs/ref-03-component-specs.it-IT.md
+++ /dev/null
@@ -1,217 +0,0 @@
----
-id: component-specs-it-IT
-title: Specifica dei Componenti e Ciclo di Vita
-permalink: component-specs-it-IT.html
-prev: component-api-it-IT.html
-next: tags-and-attributes-it-IT.html
----
-
-## Specifica dei Componenti
-
-Quando crei una classe di componente invocando `React.createClass()`, devi fornire un oggetto specifica che contiene un metodo `render` che può contenere opzionalmete altri metodi del ciclo di vita descritti di seguito.
-
-> Nota:
->
-> È anche possibile usare pure classi JavaScript come classi di componente. Queste classi possono implementare la maggior parte degli stessi metodi, sebbene vi siano delle differenze. Per maggiori informazioni su queste differenze, leggi la nostra documentazione sulle [classi ES6](/react/docs/reusable-components.html#es6-classes).
-
-### render
-
-```javascript
-ReactElement render()
-```
-
-Il metodo `render()` è richiesto.
-
-Quando viene chiamato, dovrebbe esaminare `this.props` e `this.state` e restituire un singolo elemento figlio. Questo elemento figlio può essere sia una rappresentazione virtuale di un componente DOM nativo (come `<div />` o `React.DOM.div()`) o un altro componente composito che hai definito tu stesso.
-
-Puoi anche restituire `null` o `false` per indicare che desideri che non venga visualizzato nulla. Dietro le quinte, React visualizza un tag `<noscript>` per lavorare con il nostro attuale algoritmo di differenza. Quando si restituisce `null` o `false`, `ReactDOM.findDOMNode(this)` restituirà `null`.
-
-La funzione `render()` dovrebbe essere *pura*, nel senso che non modifica lo stato del componente, restituisce lo stesso risultato ogni volta che viene invocato, e non legge o scrive il DOM o interagisce in altro modo con il browser (ad es. usando `setTimeout`). Se devi interagire con il browser, effettua le tue operazioni in `componentDidMount()` o negli altri metodi del ciclo di vita. Mantenere `render()` puro rende il rendering lato server più praticabile e rende i componenti più facili da comprendere.
-
-
-### getInitialState
-
-```javascript
-object getInitialState()
-```
-
-Invocato una volta prima che il componente venga montato. Il valore di ritorno sarà usato come il valore iniziale di `this.state`.
-
-
-### getDefaultProps
-
-```javascript
-object getDefaultProps()
-```
-
-Invocato una volta e conservato quando la classe è creata. I valori nella mappa saranno impostati in `this.props` se tale proprietà non è specificata dal componente genitore (ad es. usando un controllo `in`).
-
-Questo metodo è invocato prima che un'istanza sia creata e quindi non può dipendere da `this.props`. Inoltre, tieni presente che ogni oggetto complesso restituito da `getDefaultProps()` sarà condiviso tra le diverse istanze, non copiato.
-
-
-### propTypes
-
-```javascript
-object propTypes
-```
-
-L'oggetto `propTypes` ti permette di validare le proprietà passate ai tuoi componenti. Per maggiori informazioni su `propTypes`, leggi [Componenti Riutilizzabili](/react/docs/reusable-components-it-IT.html).
-
-
-### mixins
-
-```javascript
-array mixins
-```
-
-L'array `mixins` ti permette di usare i mixin per condividere il comportamento tra componenti multipli. Per maggiori informazioni sui mixin, leggi [Componenti Riutilizzabili](/react/docs/reusable-components-it-IT.html).
-
-
-### statics
-
-```javascript
-object statics
-```
-
-L'oggetto `statics` ti permette di definire metodi statici che possono essere chiamati sulla classe del componente. Ad esempio:
-
-```javascript
-var MyComponent = React.createClass({
-  statics: {
-    customMethod: function(foo) {
-      return foo === 'bar';
-    }
-  },
-  render: function() {
-  }
-});
-
-MyComponent.customMethod('bar');  // true
-```
-
-I metodi definiti in questo blocco sono _statici_, ovvero puoi eseguirli prima che un'istanza del componente venga creata, e i metodi non hanno accesso alle proprietà e lo stato dei tuoi componenti. Se desideri confrontare i valori delle proprietà in un metodo statico, devi farle passare dal chiamante al metodo statico tramite un argomento.
-
-
-### displayName
-
-```javascript
-string displayName
-```
-
-La stringa `displayName` viene usata nei messaggi di debug. JSX imposta questo valore automaticamente; vedi [JSX in Profondità](/react/docs/jsx-in-depth-it-IT.html#the-transform).
-
-
-## Metodi del Ciclo di Vita
-
-Vari metodi vengono eseguiti durante precisi momenti del ciclo di vita di un componente.
-
-
-### Montaggio: componentWillMount
-
-```javascript
-void componentWillMount()
-```
-
-Invocato una volta, sia sul client che sul server, immediatamente prima che il rendering iniziale abbia luogo. Se chiami `setState` all'interno di questo metodo, `render()` vedrà lo stato aggiornato e sarà eseguito solo una volta nonostante il cambiamento di stato.
-
-
-### Montaggio: componentDidMount
-
-```javascript
-void componentDidMount()
-```
-
-Invocato una volta, solo sul client (e non sul server), immediatamente dopo che il rendering iniziale ha avuto luogo. A questo punto del ciclo di vita, il componente ha una rappresentazione DOM che puoi accedere attraverso `ReactDOM.findDOMNode(this)`. Il metodo `componentDidMount()` dei componenti figli è invocato prima di quello dei componenti genitori.
-
-Se desideri integrare con altri framework JavaScript, impostare dei timer usando `setTimeout` o `setInterval`, oppure inviare richieste AJAX, effettua tali operazioni in questo metodo.
-
-
-### Aggiornamento: componentWillReceiveProps
-
-```javascript
-void componentWillReceiveProps(
-  object nextProps
-)
-```
-
-Invocato quando un componente sta ricevendo nuove proprietà. Questo metodo non viene chiamato durante il rendering iniziale.
-
-Usa questo metodo come opportunità per reagire a una transizione di proprietà prima che `render()` venga chiamato, aggiornando lo stato usando `this.setState()`. I vecchi valori delle proprietà possono essere letti tramite `this.props`. Chiamare `this.setState()` all'interno di questa funzione non scatenerà un rendering addizionale.
-
-```javascript
-componentWillReceiveProps: function(nextProps) {
-  this.setState({
-    likesIncreasing: nextProps.likeCount > this.props.likeCount
-  });
-}
-```
-
-> Nota:
->
-> Non esiste un metodo analogo `componentWillReceiveState`. Una imminente transizione delle proprietà potrebbe causare un cambiamento di stato, ma il contrario non è vero. Se devi effettuare delle operazioni in risposta a un cambiamento di stato, usa `componentWillUpdate`.
-
-
-### Aggiornamento: shouldComponentUpdate
-
-```javascript
-boolean shouldComponentUpdate(
-  object nextProps, object nextState
-)
-```
-
-Invocato prima del rendering quando vengono ricevuti nuove proprietà o un nuovo stato. Questo metodo non viene chiamato per il rendering iniziale o quando viene usato `forceUpdate`.
-
-Usa questo metodo come opportunità per restituire `false` quando si è certi che la transizione alle nuove proprietà e al nuovo stato non richieda un aggiornamento del componente.
-
-```javascript
-shouldComponentUpdate: function(nextProps, nextState) {
-  return nextProps.id !== this.props.id;
-}
-```
-
-Se `shouldComponentUpdate` restituisce false, allora `render()` sarà saltato completamente fino al prossimo cambiamento di stato. Inoltre, `componentWillUpdate` e `componentDidUpdate` non verranno chiamati.
-
-In modo predefinito, `shouldComponentUpdate` restituisce sempre `true` per evitare bachi subdoli quando `state` viene modificato direttamente, ma se hai l'accortezza di trattare sempre `state` come immutabile e accedere a `props` e `state` in sola lettura in `render()`, allora puoi tranquillamente ridefinire `shouldComponentUpdate` con un'implementazione che confronta i vecchi valori di props e state con quelli nuovi.
-
-Se le prestazioni diventano un collo di bottiglia, specialmente in presenza di  decine o centinaia di componenti, usa `shouldComponentUpdate` per accelerare la tua applicazione.
-
-
-### Aggiornamento: componentWillUpdate
-
-```javascript
-void componentWillUpdate(
-  object nextProps, object nextState
-)
-```
-
-Invocato immediatamente prima del rendering quando nuove proprietà o un nuovo stato vengono ricevuti. Questo metodo non viene chiamato per il rendering iniziale.
-
-Usa questo metodo come opportunità per effettuare la preparazione prima che si verifichi un aggiornamento.
-
-> Nota:
->
-> *Non puoi* usare `this.setState()` in questo metodo. Se devi aggiornare lo stato in risposta al cambiamento di una proprietà, usa `componentWillReceiveProps`.
-
-
-### Aggiornamento: componentDidUpdate
-
-```javascript
-void componentDidUpdate(
-  object prevProps, object prevState
-)
-```
-
-Invocato immediatamente dopo che gli aggiornamenti del componente sono stati trasmessi al DOM. Questo metodo non viene chiamato per il rendering iniziale.
-
-Usa questo metodo come opportunità per operare sul DOM quando il componente è stato  the component has been updated.
-
-
-### Smontaggio: componentWillUnmount
-
-```javascript
-void componentWillUnmount()
-```
-
-Invocato immediatamente prima che un componente venga smontato dal DOM.
-
-Effettua la necessaria pulizia in questo metodo, come invalidare i timer o ripulire ciascun elemento DOM creato all'interno di `componentDidMount`.
diff --git a/docs/docs/ref-03-component-specs.ko-KR.md b/docs/docs/ref-03-component-specs.ko-KR.md
deleted file mode 100644
index 266ffc2181d4..000000000000
--- a/docs/docs/ref-03-component-specs.ko-KR.md
+++ /dev/null
@@ -1,220 +0,0 @@
----
-id: component-specs-ko-KR
-title:  컴포넌트 명세와 생명주기
-permalink: component-specs-ko-KR.html
-prev: component-api-ko-KR.html
-next: tags-and-attributes-ko-KR.html
----
-
-## 컴포넌트 명세
-
-`React.createClass()`를 호출하여 컴포넌트 클래스를 생성할 때, `render` 메소드를 포함한 명세 객체를 제공해야 합니다. 또한 필요한 경우 여기에서 설명하는 다른 생명주기 메소드를 명세 객체에 추가로 제공할 수 있습니다.
-
-> 주의:
->
-> 그냥 JavaScript 클래스를 컴포넌트 클래스로 사용할 수도 있습니다. 이 클래스는 구현할 수 있는 메소드가 거의 같지만 약간의 차이가 있습니다. 차이에 관한 더 자세한 정보는 [ES6 클래스](/react/docs/reusable-components-ko-KR.html#es6-classes)를 읽어보세요.
-
-### render
-
-```javascript
-ReactElement render()
-```
-
-`render()` 메소드는 필수 항목입니다.
-
-호출되면 `this.props`와 `this.state`를 토대로 하나의 자식 엘리먼트를 리턴합니다. 이 자식 엘리먼트는 네이티브 DOM 컴포넌트의 가상 표현 (`<div />`나 `React.DOM.div()` 등) 또는 직접 정의한 조합(composite) 컴포넌트가 될 수 있습니다.
-
-아무 것도 렌더링되지 않도록 하려면 `null`이나 `false`를 리턴합니다. React는 지금의 차이 비교 알고리즘이 작동할 수 있도록 내부적으로는 `<noscript>` 태그를 렌더링합니다. `null`이나 `false`를 리턴한 경우, `ReactDOM.findDOMNode(this)`는 `null`을 리턴합니다.
-
-`render()` 함수는 순수 함수여야 합니다. 즉, 컴포넌트의 상태를 변경하지 않고, 여러번 호출해도 같은 결과를 리턴하며, DOM을 읽고 쓰거나 브라우저와 상호작용(예를 들어 `setTimeout`를 사용)하지 않아야 합니다. 브라우저와 상호작용해야 한다면 `componentDidMount()`나 다른 생명주기 메소드에서 수행해야 합니다. `render()` 함수를 순수 함수로 유지하면 서버 렌더링이 훨씬 쓸만해지고 컴포넌트에 대해 생각하기 쉬워집니다.
-
-
-### getInitialState
-
-```javascript
-object getInitialState()
-```
-
-컴포넌트가 마운트되기 전에 한번 호출됩니다. 리턴값은 `this.state`의 초기값으로 사용됩니다.
-
-
-### getDefaultProps
-
-```javascript
-object getDefaultProps()
-```
-
-클래스가 생성될 때 한번 호출되고 캐시됩니다. 부모 컴포넌트에서 prop이 넘어오지 않은 경우 (`in` 연산자로 확인) 매핑의 값이 `this.props`에 설정됩니다.
-
-이 메소드는 인스턴스가 만들어지기 전에 호출되므로 `this.props`에 의존할 수 없습니다. 그리고 `getDefaultProps()`의 리턴값에 포함된 복잡한 객체는 복사되지 않고 인스턴스 간에 공유됩니다.
-
-
-### propTypes
-
-```javascript
-object propTypes
-```
-
-`propTypes` 객체는 컴포넌트에 넘어오는 props가 올바른지 검사할 수 있게 해줍니다. `propTypes`에 대한 자세한 정보는 [재사용 가능한 컴포넌트](/react/docs/reusable-components-ko-KR.html)를 참고하세요.
-
-
-### mixins
-
-```javascript
-array mixins
-```
-
-`mixins` 배열은 여러 컴포넌트 사이에 동작을 공유하는 믹스인을 사용할 수 있게 해줍니다. 믹스인에 대한 자세한 정보는 [재사용 가능한 컴포넌트](/react/docs/reusable-components-ko-KR.html)를 참고하세요.
-
-
-### statics
-
-```javascript
-object statics
-```
-
-`statics` 객체는 컴포넌트 클래스의 스태틱 메소드를 정의할 수 있게 해줍니다. 에를 들어:
-
-```javascript
-var MyComponent = React.createClass({
-  statics: {
-    customMethod: function(foo) {
-      return foo === 'bar';
-    }
-  },
-  render: function() {
-  }
-});
-
-MyComponent.customMethod('bar');  // true
-```
-
-이 블럭 안에서 정의된 메소드는 인스턴스를 하나도 만들지 않은 시점에도 호출할 수 있고, 컴포넌트의 props나 state에 접근할 수 없습니다. 스태틱 메소드에서 props의 값을 확인하려면 호출자가 스태틱 메소드에 props를 인자로 넘기도록 해야합니다.
-
-
-### displayName
-
-```javascript
-string displayName
-```
-
-`displayName` 문자열은 디버그 메시지에 사용됩니다. JSX는 이 값을 자동으로 설정합니다. [JSX 깊이 알기](/react/docs/jsx-in-depth-ko-KR.html#the-transform)를 참고하세요.
-
-
-<a name="lifecycle-methods"></a>
-## 생명주기 메소드
-
-컴포넌트의 생명주기에서 특정 시점마다 실행되는 메소드들입니다.
-
-
-### 마운트 시: componentWillMount
-
-```javascript
-void componentWillMount()
-```
-
-최초 렌더링이 일어나기 직전에 클라이언트 및 서버에서 한번 호출됩니다. 이 메소드 안에서 `setState`를 호출하면, `render()`에서 업데이트된 state를 확인할 수 있고 state가 변함에도 불구하고 `render()`가 한번만 실행됩니다.
-
-
-### 마운트 시: componentDidMount
-
-```javascript
-void componentDidMount()
-```
-
-최초 렌더링이 일어난 다음 클라이언트에서만 한번 호출됩니다. (서버에서는 호출되지 않습니다.) 이 시점에 자식의 refs들에 접근 할 수 있습니다. (기본 DOM 표현에 접근하는 등). 자식 컴포넌트의 `componentDidMount()` 메소드는 부모 컴포넌트보다 먼저 호출됩니다.
-
-다른 JavaScript 프레임워크를 연동하거나, `setTimeout`/`setInterval`로 타이머를 설정하고 AJAX 요청을 보내는 등의 작업을 이 메소드에서 합니다.
-
-
-### 업데이트 시: componentWillReceiveProps
-
-```javascript
-void componentWillReceiveProps(
-  object nextProps
-)
-```
-
-컴포넌트가 새로운 props를 받을 때 호출됩니다. 이 메소드는 최초 렌더링 시에는 호출되지 않습니다.
-
-`render()`가 호출되기 전에 prop의 변화를 감지하여 `this.setState()`를 호출해서 state를 업데이트할 수 있습니다. 이전 props는 `this.props`로 접근할 수 있습니다. 이 함수 안에서 `this.setState()`를 호출해도 추가 렌더링이 발생하지 않습니다.
-
-```javascript
-componentWillReceiveProps: function(nextProps) {
-  this.setState({
-    likesIncreasing: nextProps.likeCount > this.props.likeCount
-  });
-}
-```
-
-> 주의:
->
-> `componentWillReceiveState`에 해당하는 메소드는 없습니다. prop이 변할 때 state가 바뀔 수는 있지만, 그 역은 불가능합니다. state의 변화에 따라 작업을 실행해야 하면 `componentWillUpdate`를 사용하세요.
-
-
-<a name="updating-shouldcomponentupdate"></a>
-### 업데이트 시: shouldComponentUpdate
-
-```javascript
-boolean shouldComponentUpdate(
-  object nextProps, object nextState
-)
-```
-
-새로운 props 또는 state를 받아 렌더링을 하기 전에 호출됩니다. 최초 렌더링 시나 `forceUpdate`를 사용하는 경우에는 호출되지 않습니다.
-
-새로운 props와 state가 컴포넌트 업데이트를 필요로 하지 않는 것이 확실하다면
-`false`를 리턴하세요.
-
-```javascript
-shouldComponentUpdate: function(nextProps, nextState) {
-  return nextProps.id !== this.props.id;
-}
-```
-
-`shouldComponentUpdate`가 false를 리턴하면, 다음에 state가 바뀌기 전까지 `render()`가 완전히 호출되지 않고 넘어갑니다. `componentWillUpdate`와 `componentDidUpdate` 또한 호출되지 않습니다.
-
-기본적으로 `shouldComponentUpdate`는 항상 `true`를 리턴합니다. `state`가 제자리에서(in place) 바뀐 경우에 발생하는 파악하기 힘든 버그를 막기 위함입니다. 하지만 `state`가 항상 변경 불가능하도록 주의하고 `render()`에서 `props`와 `state`를 읽기만 하면 이전 props 및 state와 바뀌는 값을 비교하는 `shouldComponentUpdate`를 직접 구현할 수 있습니다.
-
-성능에 병목이 있다면, 특히 컴포넌트가 매우 많은 경우 `shouldComponentUpdate`를 사용하여 앱을 빠르게 만들 수 있습니다.
-
-
-### 업데이트 시: componentWillUpdate
-
-```javascript
-void componentWillUpdate(
-  object nextProps, object nextState
-)
-```
-
-새로운 props나 state를 받았을 때 렌더링 직전에 호출됩니다. 최초 렌더링 시에는 호출되지 않습니다.
-
-업데이트가 일어나기 전에 준비하기 위해 사용할 수 있습니다.
-
-> 주의:
->
-> 이 메소드에서는 `this.setState()`를 호출할 수 없습니다. prop 변화에 반응하여 state를 업데이트해야 할 경우, `componentWillReceiveProps`를 대신 사용하세요.
-
-
-### 업데이트 시: componentDidUpdate
-
-```javascript
-void componentDidUpdate(
-  object prevProps, object prevState
-)
-```
-
-컴포넌트의 업데이트가 DOM에 반영된 직후에 호출됩니다. 최초 렌더링 시에는 호출되지 않습니다.
-
-컴포넌트가 업데이트된 뒤 DOM을 조작해야 하는 경우 사용할 수 있습니다.
-
-
-### 마운트 해제 시: componentWillUnmount
-
-```javascript
-void componentWillUnmount()
-```
-
-컴포넌트가 DOM에서 마운트 해제 되기 직전에 호출됩니다.
-
-이 메소드에서 타이머를 무효화하거나 `componentDidMount`에서 만들어진 DOM 엘리먼트를 정리하는 등 필요한 정리 작업을 수행할 수 있습니다.
diff --git a/docs/docs/ref-03-component-specs.md b/docs/docs/ref-03-component-specs.md
deleted file mode 100644
index 9e5a956209a2..000000000000
--- a/docs/docs/ref-03-component-specs.md
+++ /dev/null
@@ -1,219 +0,0 @@
----
-id: component-specs
-title: Component Specs and Lifecycle
-permalink: component-specs.html
-prev: component-api.html
-next: tags-and-attributes.html
----
-
-## Component Specifications
-
-When creating a component class by invoking `React.createClass()`, you should provide a specification object that contains a `render` method and can optionally contain other lifecycle methods described here.
-
-> Note:
->
-> It is also possible to use plain JavaScript classes as component classes. These classes can implement most of the same methods, though there are some differences. For more information about these differences, please read our documentation about [ES6 classes](/react/docs/reusable-components.html#es6-classes).
-
-### render
-
-```javascript
-ReactElement render()
-```
-
-The `render()` method is required.
-
-When called, it should examine `this.props` and `this.state` and return a single child element. This child element can be either a virtual representation of a native DOM component (such as `<div />` or `React.DOM.div()`) or another composite component that you've defined yourself.
-
-You can also return `null` or `false` to indicate that you don't want anything rendered. Behind the scenes, React renders a `<noscript>` tag to work with our current diffing algorithm. When returning `null` or `false`, `ReactDOM.findDOMNode(this)` will return `null`.
-
-The `render()` function should be *pure*, meaning that it does not modify component state, it returns the same result each time it's invoked, and it does not read from or write to the DOM or otherwise interact with the browser (e.g., by using `setTimeout`). If you need to interact with the browser, perform your work in `componentDidMount()` or the other lifecycle methods instead. Keeping `render()` pure makes server rendering more practical and makes components easier to think about.
-
-
-### getInitialState
-
-```javascript
-object getInitialState()
-```
-
-Invoked once before the component is mounted. The return value will be used as the initial value of `this.state`.
-
-
-### getDefaultProps
-
-```javascript
-object getDefaultProps()
-```
-
-Invoked once and cached when the class is created. Values in the mapping will be set on `this.props` if that prop is not specified by the parent component (i.e. using an `in` check).
-
-This method is invoked before any instances are created and thus cannot rely on `this.props`. In addition, be aware that any complex objects returned by `getDefaultProps()` will be shared across instances, not copied.
-
-
-### propTypes
-
-```javascript
-object propTypes
-```
-
-The `propTypes` object allows you to validate props being passed to your components. For more information about `propTypes`, see [Reusable Components](/react/docs/reusable-components.html).
-
-
-### mixins
-
-```javascript
-array mixins
-```
-
-The `mixins` array allows you to use mixins to share behavior among multiple components. For more information about mixins, see [Reusable Components](/react/docs/reusable-components.html).
-
-
-### statics
-
-```javascript
-object statics
-```
-
-The `statics` object allows you to define static methods that can be called on the component class. For example:
-
-```javascript
-var MyComponent = React.createClass({
-  statics: {
-    customMethod: function(foo) {
-      return foo === 'bar';
-    }
-  },
-  render: function() {
-  }
-});
-
-MyComponent.customMethod('bar');  // true
-```
-
-Methods defined within this block are _static_, meaning that you can run them before any component instances are created, and the methods do not have access to the props or state of your components. If you want to check the value of props in a static method, have the caller pass in the props as an argument to the static method.
-
-
-### displayName
-
-```javascript
-string displayName
-```
-
-The `displayName` string is used in debugging messages. JSX sets this value automatically; see [JSX in Depth](/react/docs/jsx-in-depth.html#the-transform).
-
-
-## Lifecycle Methods
-
-Various methods are executed at specific points in a component's lifecycle.
-
-
-### Mounting: componentWillMount
-
-```javascript
-void componentWillMount()
-```
-
-Invoked once, both on the client and server, immediately before the initial rendering occurs. If you call `setState` within this method, `render()` will see the updated state and will be executed only once despite the state change.
-
-
-### Mounting: componentDidMount
-
-```javascript
-void componentDidMount()
-```
-
-Invoked once, only on the client (not on the server), immediately after the initial rendering occurs. At this point in the lifecycle, you can access any refs to your children (e.g., to access the underlying DOM representation). The `componentDidMount()` method of child components is invoked before that of parent components.
-
-If you want to integrate with other JavaScript frameworks, set timers using `setTimeout` or `setInterval`, or send AJAX requests, perform those operations in this method.
-
-
-### Updating: componentWillReceiveProps
-
-```javascript
-void componentWillReceiveProps(
-  object nextProps
-)
-```
-
-Invoked when a component is receiving new props. This method is not called for the initial render.
-
-Use this as an opportunity to react to a prop transition before `render()` is called by updating the state using `this.setState()`. The old props can be accessed via `this.props`. Calling `this.setState()` within this function will not trigger an additional render.
-
-```javascript
-componentWillReceiveProps: function(nextProps) {
-  this.setState({
-    likesIncreasing: nextProps.likeCount > this.props.likeCount
-  });
-}
-```
-
-> Note:
->
-> One common mistake is for code executed during this lifecycle method to assume that props have changed.  To understand why this is invalid, read [A implies B does not imply B implies A](/react/blog/2016/01/08/A-implies-B-does-not-imply-B-implies-A.html)
->
-> There is no analogous method `componentWillReceiveState`. An incoming prop transition may cause a state change, but the opposite is not true. If you need to perform operations in response to a state change, use `componentWillUpdate`.
-
-
-### Updating: shouldComponentUpdate
-
-```javascript
-boolean shouldComponentUpdate(
-  object nextProps, object nextState
-)
-```
-
-Invoked before rendering when new props or state are being received. This method is not called for the initial render or when `forceUpdate` is used.
-
-Use this as an opportunity to `return false` when you're certain that the transition to the new props and state will not require a component update.
-
-```javascript
-shouldComponentUpdate: function(nextProps, nextState) {
-  return nextProps.id !== this.props.id;
-}
-```
-
-If `shouldComponentUpdate` returns false, then `render()` will be completely skipped until the next state change. In addition, `componentWillUpdate` and `componentDidUpdate` will not be called.
-
-By default, `shouldComponentUpdate` always returns `true` to prevent subtle bugs when `state` is mutated in place, but if you are careful to always treat `state` as immutable and to read only from `props` and `state` in `render()` then you can override `shouldComponentUpdate` with an implementation that compares the old props and state to their replacements.
-
-If performance is a bottleneck, especially with dozens or hundreds of components, use `shouldComponentUpdate` to speed up your app.
-
-
-### Updating: componentWillUpdate
-
-```javascript
-void componentWillUpdate(
-  object nextProps, object nextState
-)
-```
-
-Invoked immediately before rendering when new props or state are being received. This method is not called for the initial render.
-
-Use this as an opportunity to perform preparation before an update occurs.
-
-> Note:
->
-> You *cannot* use `this.setState()` in this method. If you need to update state in response to a prop change, use `componentWillReceiveProps` instead.
-
-
-### Updating: componentDidUpdate
-
-```javascript
-void componentDidUpdate(
-  object prevProps, object prevState
-)
-```
-
-Invoked immediately after the component's updates are flushed to the DOM. This method is not called for the initial render.
-
-Use this as an opportunity to operate on the DOM when the component has been updated.
-
-
-### Unmounting: componentWillUnmount
-
-```javascript
-void componentWillUnmount()
-```
-
-Invoked immediately before a component is unmounted from the DOM.
-
-Perform any necessary cleanup in this method, such as invalidating timers or cleaning up any DOM elements that were created in `componentDidMount`.
diff --git a/docs/docs/ref-03-component-specs.zh-CN.md b/docs/docs/ref-03-component-specs.zh-CN.md
deleted file mode 100644
index 95d6cb19a673..000000000000
--- a/docs/docs/ref-03-component-specs.zh-CN.md
+++ /dev/null
@@ -1,217 +0,0 @@
----
-id: component-specs-zh-CN
-title: 组件的规范和生命周期
-permalink: component-specs-zh-CN.html
-prev: component-api-zh-CN.html
-next: tags-and-attributes-zh-CN.html
----
-
-## 组件规范(Specifications)
-
-当调用 `React.createClass()` 创建一个组件类时,你应该提供一个包含有 `render` 方法以及可选的其他生命周期方法的 规范(Specifications)对象.
-
-> 注意:
-> 
-> 同样可以使用单纯的 JavaScript 类作为组件类. 这些类可以实现大多数相同的方法,虽然有一些不同.更多关于不同的信息,请阅读我们关于[ES6 classes](/react/docs/reusable-components.html#es6-classes)的文档.
-
-### render
-
-```javascript
-ReactElement render()
-```
-
- `render()` 是必须的
- 
- 当被调用时,它应该检查 `this.props` 和 `this.state` 并返回单个子元素.这个子元素即可以是一个 对原生DOM的虚拟表达(比如 `<div />` 或 `React.DOM.div()`)也可以是其他你自定义的复合组件.
- 
- 你也可以返回 `null` 或 `false` 来指示你不想要任何东西被渲染.幕后,React 渲染一个 `<noscript>` tag 来与我们当前的diffing算法协同工作.当返回 `null` 或 `false` ,`ReactDOM.findDOMNode(this)` 会返回 `null`.
- 
- `render()` 函数应该是纯净的,意味着它不改变组件的状态,它在每次调用时返回相同的结果,并且它不读和写 DOM 或者其他方式与浏览器互动(例如,使用 `setTimeout`).如果你需要与浏览器互动,在 `componentDidMount()` 里执行你的工作,或者其他生命周期方法里.保持 `render()` 纯净使服务器渲染更实用并且让组件更容易被思考.
- 
- 
- ### getInitialState
- 
- ```javascript
-object getInitialState()
-```
-
-当组件被挂载时调用一次.返回值会被用作为 `this.state` 的初始值.
-
-
-### getDefaultProps
-
-```javascript
-object getDefaultProps()
-```
-
-在类被创建时调用一次并被缓存.在这个mapping里的值会被设置给 `this.props` 如果父组件没有指定对应的 prop (例如 使用一个 `in` 检查).
-
-这个方法在任何实例被创建之前调用,因此不能依赖于 `this.props`.另外,小心,任何被 `getDefaultProps()`返回的复杂对象会被跨实例共享,而不是被拷贝.
-
-
-### propTypes
-
-```javascript
-object propTypes
-```
-
- `propTypes` 对象允许你验证传递到你的组建的 props.更多关于 `propTypes` 的信息,见 [Reusable Components](/react/docs/reusable-components.html).
-
-
-### mixins
-
-```javascript
-array mixins
-```
-
- `mixins` 数组允许你用 mixins 来在多个组件间共享行为.更多关于 mixins 的信息,见 [Reusable Components](/react/docs/reusable-components.html).
-
-
-### statics
-
-```javascript
-object statics
-```
-
-`statics` 对象允许你定义可以在组件类上调用的静态方法.例如:
-
-```javascript
-var MyComponent = React.createClass({
-  statics: {
-    customMethod: function(foo) {
-      return foo === 'bar';
-    }
-  },
-  render: function() {
-  }
-});
-
-MyComponent.customMethod('bar');  // true
-```
-
-在这个块里定义的方法是 _static_,意味着你可以在任何组件实例被创建前运行他们,并且这些方法没有对你组件的  props 或 state 的访问权.如果你在静态方法里检查props的值,把调用者作为参数传入props给静态函数.
-
-
-### displayName
-
-```javascript
-string displayName
-```
-
-`displayName` 字符串被用在调试信息.JSX 自动设置这个值；见 [JSX in Depth](/react/docs/jsx-in-depth.html#the-transform).
-
-
-## Lifecycle Methods
-
-多种方法在组件生命周期的特定点上被执行.
-
-
-### Mounting: componentWillMount
-
-```javascript
-void componentWillMount()
-```
-
-被调用一次,即在客户端也在服务端,在最初的渲染发生之前 立即被调用.如果你在这个方法里调用 `setState` , `render()` 将会看到更新的 state 并不论state的变化只执行一次.
-
-
-### Mounting: componentDidMount
-
-```javascript
-void componentDidMount()
-```
-
-被调用一次,只在客户端(不在服务端),在最初的渲染发生之后 立即被调用.在生命周期的这个点上,你可以访问任何对你的子级的refs (比如 访问底层的DOM表达).子组件的 `componentDidMount()` 方法在父组件之前被调用.
-
-如果你想与其他 JavaScript 框架整合,用 `setTimeout` 或 `setInterval` 设置timers,或者发送 AJAX 请求,执行这些操作在此方法中.
-
-
-### Updating: componentWillReceiveProps
-
-```javascript
-void componentWillReceiveProps(
-  object nextProps
-)
-```
-
-当一个组件收到新的props时被调用.这个方法不会为最初的渲染调用.
-
-使用它作为响应 prop 转换的时机(在`render()` 被用 `this.setState()` 更新state调用 之前) .旧的 props 可以通过 `this.props` 访问. 在这个函数里调用 `this.setState()` 不会触发任何额外的渲染.
-
-```javascript
-componentWillReceiveProps: function(nextProps) {
-  this.setState({
-    likesIncreasing: nextProps.likeCount > this.props.likeCount
-  });
-}
-```
-
-> 注意:
->
-> 并没有类似的 `componentWillReceiveState` 方法. 一个即将到来的 prop 转变可能会导致一个 state 变化,但是反之不是. 如果你需要实现一个对 state 变化相应的操作,使用 `componentWillUpdate`.
-
-
-### Updating: shouldComponentUpdate
-
-```javascript
-boolean shouldComponentUpdate(
-  object nextProps, object nextState
-)
-```
-
-当新的props或者state被收到,在渲染前被调用.这个方法不会在最初的渲染或者 `forceUpdate` 时被调用.
-
-使用此方法作为一个 `return false` 的时机,当你确定新的 props 和 state 的转换不需要组件更新时.
-
-```javascript
-shouldComponentUpdate: function(nextProps, nextState) {
-  return nextProps.id !== this.props.id;
-}
-```
-
-如果 `shouldComponentUpdate` 返回false, `render()` 会在下次state变化前被完全跳过. 另外,`componentWillUpdate` 和 `componentDidUpdate` 将不会被调用.
-
-默认情况下, `shouldComponentUpdate` 总是返回 `true` 来阻止当 `state` 突变时的细微bug,但是如果你仔细的把 `state` 作为不变量对待并只从 `render()`里的 `props` 和 `state`读,你就可以用一个比较旧的props和state与他们的替换者的实现来重写 `shouldComponentUpdate`.
-
-如果性能是瓶颈,尤其是随着成百上千的组件,使用 `shouldComponentUpdate` 来加速你的app.
-
-
-### Updating: componentWillUpdate
-
-```javascript
-void componentWillUpdate(
-  object nextProps, object nextState
-)
-```
-
-当新的props或者state被接受时,在渲染前被立即调用.这个方法不会被初始渲染调用.
-
-使用这个方法作为 在更新发生前执行一些准备 的时机.
-
-> Note:
->
-> 你 *不能* 在这个方法里使用 `this.setState()` .如果你需要响应一个prop变化来更新state,使用 `componentWillReceiveProps` 来替代.
-
-
-### Updating: componentDidUpdate
-
-```javascript
-void componentDidUpdate(
-  object prevProps, object prevState
-)
-```
-
-在组件的更新被刷新到DOM后立即被调用.这个方法不会被初始渲染调用.
-
-使用这个方法作为 当组件被更新后在DOM上操作 的时机.
-
-
-### Unmounting: componentWillUnmount
-
-```javascript
-void componentWillUnmount()
-```
-
-在组件被从DOM卸载 前 被立即调用.
-
-在这个方法里执行一些必要的清理操作,比如无效化 timers 或者清理任何被 `componentDidMount` 创建的DOM元素.
diff --git a/docs/docs/ref-04-tags-and-attributes.it-IT.md b/docs/docs/ref-04-tags-and-attributes.it-IT.md
deleted file mode 100644
index a8dc279f80dc..000000000000
--- a/docs/docs/ref-04-tags-and-attributes.it-IT.md
+++ /dev/null
@@ -1,117 +0,0 @@
----
-id: tags-and-attributes-it-IT
-title: Tag e Attributi
-permalink: tags-and-attributes-it-IT.html
-prev: component-specs-it-IT.html
-next: events-it-IT.html
----
-
-## Tag Supportati
-
-React tenta di supportare tutti gli elementi comuni. Se hai bisogno di un elemento che non è elencato di seguito, per favore [apri una issue](https://github.com/facebook/react/issues/new).
-
-### Elementi HTML
-
-I seguenti elementi HTML sono supportati:
-
-```
-a abbr address area article aside audio b base bdi bdo big blockquote body br
-button canvas caption cite code col colgroup data datalist dd del details dfn
-dialog div dl dt em embed fieldset figcaption figure footer form h1 h2 h3 h4 h5
-h6 head header hr html i iframe img input ins kbd keygen label legend li link
-main map mark menu menuitem meta meter nav noscript object ol optgroup option
-output p param picture pre progress q rp rt ruby s samp script section select
-small source span strong style sub summary sup table tbody td textarea tfoot th
-thead time title tr track u ul var video wbr
-```
-
-### Elementi SVG
-
-I seguenti elementi SVG sono supportati:
-
-```
-circle clipPath defs ellipse g line linearGradient mask path pattern polygon polyline
-radialGradient rect stop svg text tspan
-```
-
-Potresti trovare utile [react-art](https://github.com/facebook/react-art), una libreria di disegno per React che può disegnare su Canvas, SVG oppure VML (per IE8).
-
-
-## Attributi Supportati
-
-React supporta tutti gli attributi `data-*` e `aria-*`, oltre a ciascun attributo nelle liste seguenti.
-
-> Nota:
->
-> Tutti gli attributi sono camel-cased, e gli attributi `class` e `for` sono resi come `className` e `htmlFor` rispettivamente, per adeguarsi alla specifica delle API del DOM.
-
-Per una lista di eventi, consulta gli [Eventi Supportati](/react/docs/events.html).
-
-### Attributi HTML
-
-Questi attributi standard sono supportati:
-
-```
-accept acceptCharset accessKey action allowFullScreen allowTransparency alt
-async autoComplete autoFocus autoPlay capture cellPadding cellSpacing challenge
-charSet checked cite classID className colSpan cols content contentEditable
-contextMenu controls coords crossOrigin data dateTime default defer dir
-disabled download draggable encType form formAction formEncType formMethod
-formNoValidate formTarget frameBorder headers height hidden high href hrefLang
-htmlFor httpEquiv icon id inputMode integrity is keyParams keyType kind label
-lang list loop low manifest marginHeight marginWidth max maxLength media
-mediaGroup method min minLength multiple muted name noValidate nonce open
-optimum pattern placeholder poster preload profile radioGroup readOnly rel
-required reversed role rowSpan rows sandbox scope scoped scrolling seamless
-selected shape size sizes span spellCheck src srcDoc srcLang srcSet start step
-style summary tabIndex target title type useMap value width wmode wrap
-```
-
-In aggiunta, i seguenti attributi non-standard sono supportati:
-
-- `autoCapitalize autoCorrect` per Mobile Safari.
-- `property` per i meta tag [Open Graph](http://ogp.me/).
-- `itemProp itemScope itemType itemRef itemID` per i [microdata HTML5](http://schema.org/docs/gs.html).
-- `unselectable` per Internet Explorer.
-- `results autoSave` per campi di input del tipo `search` in WebKit/Blink.
-
-Esiste anche l'attributo specifico di React `dangerouslySetInnerHTML` ([maggiori informazioni](/react/docs/special-non-dom-attributes.html)), usato per inserire direttamente stringhe di HTML in un componente.
-
-### Attributi SVG
-
-```
-accentHeight accumulate additive alignmentBaseline allowReorder alphabetic
-amplitude arabicForm ascent attributeName attributeType autoReverse azimuth
-baseFrequency baseProfile baselineShift bbox begin bias by calcMode capHeight
-clip clipPath clipPathUnits clipRule colorInterpolation
-colorInterpolationFilters colorProfile colorRendering contentScriptType
-contentStyleType cursor cx cy d decelerate descent diffuseConstant direction
-display divisor dominantBaseline dur dx dy edgeMode elevation enableBackground
-end exponent externalResourcesRequired fill fillOpacity fillRule filter
-filterRes filterUnits floodColor floodOpacity focusable fontFamily fontSize
-fontSizeAdjust fontStretch fontStyle fontVariant fontWeight format from fx fy
-g1 g2 glyphName glyphOrientationHorizontal glyphOrientationVertical glyphRef
-gradientTransform gradientUnits hanging horizAdvX horizOriginX ideographic
-imageRendering in in2 intercept k k1 k2 k3 k4 kernelMatrix kernelUnitLength
-kerning keyPoints keySplines keyTimes lengthAdjust letterSpacing lightingColor
-limitingConeAngle local markerEnd markerHeight markerMid markerStart
-markerUnits markerWidth mask maskContentUnits maskUnits mathematical mode
-numOctaves offset opacity operator order orient orientation origin overflow
-overlinePosition overlineThickness paintOrder panose1 pathLength
-patternContentUnits patternTransform patternUnits pointerEvents points
-pointsAtX pointsAtY pointsAtZ preserveAlpha preserveAspectRatio primitiveUnits
-r radius refX refY renderingIntent repeatCount repeatDur requiredExtensions
-requiredFeatures restart result rotate rx ry scale seed shapeRendering slope
-spacing specularConstant specularExponent speed spreadMethod startOffset
-stdDeviation stemh stemv stitchTiles stopColor stopOpacity
-strikethroughPosition strikethroughThickness string stroke strokeDasharray
-strokeDashoffset strokeLinecap strokeLinejoin strokeMiterlimit strokeOpacity
-strokeWidth surfaceScale systemLanguage tableValues targetX targetY textAnchor
-textDecoration textLength textRendering to transform u1 u2 underlinePosition
-underlineThickness unicode unicodeBidi unicodeRange unitsPerEm vAlphabetic
-vHanging vIdeographic vMathematical values vectorEffect version vertAdvY
-vertOriginX vertOriginY viewBox viewTarget visibility widths wordSpacing
-writingMode x x1 x2 xChannelSelector xHeight xlinkActuate xlinkArcrole
-xlinkHref xlinkRole xlinkShow xlinkTitle xlinkType xmlBase xmlLang xmlSpace
-y y1 y2 yChannelSelector z zoomAndPan
-```
diff --git a/docs/docs/ref-04-tags-and-attributes.ko-KR.md b/docs/docs/ref-04-tags-and-attributes.ko-KR.md
deleted file mode 100644
index 4128af23a597..000000000000
--- a/docs/docs/ref-04-tags-and-attributes.ko-KR.md
+++ /dev/null
@@ -1,117 +0,0 @@
----
-id: tags-and-attributes-ko-KR
-title: 태그와 어트리뷰트
-permalink: tags-and-attributes-ko-KR.html
-prev: component-specs-ko-KR.html
-next: events-ko-KR.html
----
-
-## 지원되는 태그
-
-React는 모든 공통 엘리먼트를 지원하려 합니다. 필요한 엘리먼트가 목록에 없다면, [이슈로 등록](https://github.com/facebook/react/issues/new)해 주세요.
-
-### HTML 엘리먼트
-
-다음의 HTML 엘리먼트가 지원됩니다.
-
-```
-a abbr address area article aside audio b base bdi bdo big blockquote body br
-button canvas caption cite code col colgroup data datalist dd del details dfn
-dialog div dl dt em embed fieldset figcaption figure footer form h1 h2 h3 h4 h5
-h6 head header hr html i iframe img input ins kbd keygen label legend li link
-main map mark menu menuitem meta meter nav noscript object ol optgroup option
-output p param picture pre progress q rp rt ruby s samp script section select
-small source span strong style sub summary sup table tbody td textarea tfoot th
-thead time title tr track u ul var video wbr
-```
-
-### SVG 엘리먼트
-
-다음의 SVG 엘리먼트가 지원됩니다.
-
-```
-circle clipPath defs ellipse g line linearGradient mask path pattern polygon polyline
-radialGradient rect stop svg text tspan
-```
-
-아마 Canvas, SVG, VML(IE8 전용)에 렌더할 때 쓰는 React의 드로잉 라이브러리인 [react-art](https://github.com/facebook/react-art)도 흥미 있으실 수 있습니다.
-
-
-## 지원되는 어트리뷰트
-
-React는 모든 `data-*`, `aria-*` 어트리뷰트와 밑에 있는 모든 어트리뷰트를 지원합니다.
-
-> 주의:
->
-> 모든 어트리뷰트는 카멜케이스이고, `class` `for` 어트리뷰트는 각각  DOM API의 사양에 맞춰서 `className` `htmlFor` 가 됩니다.
-
-이벤트의 목록을 보시려면 [지원되는 이벤트](/react/docs/events-ko-KR.html)를 확인하세요.
-
-### HTML 어트리뷰트
-
-이런 표준 어트리뷰트가 지원됩니다.
-
-```
-accept acceptCharset accessKey action allowFullScreen allowTransparency alt
-async autoComplete autoFocus autoPlay capture cellPadding cellSpacing challenge
-charSet checked cite classID className colSpan cols content contentEditable
-contextMenu controls coords crossOrigin data dateTime default defer dir
-disabled download draggable encType form formAction formEncType formMethod
-formNoValidate formTarget frameBorder headers height hidden high href hrefLang
-htmlFor httpEquiv icon id inputMode integrity is keyParams keyType kind label
-lang list loop low manifest marginHeight marginWidth max maxLength media
-mediaGroup method min minLength multiple muted name noValidate nonce open
-optimum pattern placeholder poster preload profile radioGroup readOnly rel
-required reversed role rowSpan rows sandbox scope scoped scrolling seamless
-selected shape size sizes span spellCheck src srcDoc srcLang srcSet start step
-style summary tabIndex target title type useMap value width wmode wrap
-```
-
-덧붙여, 이런 비표준 어트리뷰트도 지원됩니다.
-
-- 모바일 사파리를 위한 `autoCapitalize autoCorrect`.
-- [오픈 그래프](http://ogp.me/) 메타 태그를 위한 `property`.
-- [HTML5 마이크로데이터](http://schema.org/docs/gs.html)를 위한 `itemProp itemScope itemType itemRef itemID`.
-- 인터넷 익스플로어를 위한 `unselectable`.
-- WebKit/Blink의 `search` 타입 input 필드를 위한 `results autoSave` 
-
-컴포넌트에 직접 HTML 문자열을 넣을 때 사용하는, React 전용 어트리뷰트 `dangerouslySetInnerHTML`([자세한 정보는 여기](/react/docs/special-non-dom-attributes-ko-KR.html))도 있습니다.
-
-### SVG 어트리뷰트
-
-```
-accentHeight accumulate additive alignmentBaseline allowReorder alphabetic
-amplitude arabicForm ascent attributeName attributeType autoReverse azimuth
-baseFrequency baseProfile baselineShift bbox begin bias by calcMode capHeight
-clip clipPath clipPathUnits clipRule colorInterpolation
-colorInterpolationFilters colorProfile colorRendering contentScriptType
-contentStyleType cursor cx cy d decelerate descent diffuseConstant direction
-display divisor dominantBaseline dur dx dy edgeMode elevation enableBackground
-end exponent externalResourcesRequired fill fillOpacity fillRule filter
-filterRes filterUnits floodColor floodOpacity focusable fontFamily fontSize
-fontSizeAdjust fontStretch fontStyle fontVariant fontWeight format from fx fy
-g1 g2 glyphName glyphOrientationHorizontal glyphOrientationVertical glyphRef
-gradientTransform gradientUnits hanging horizAdvX horizOriginX ideographic
-imageRendering in in2 intercept k k1 k2 k3 k4 kernelMatrix kernelUnitLength
-kerning keyPoints keySplines keyTimes lengthAdjust letterSpacing lightingColor
-limitingConeAngle local markerEnd markerHeight markerMid markerStart
-markerUnits markerWidth mask maskContentUnits maskUnits mathematical mode
-numOctaves offset opacity operator order orient orientation origin overflow
-overlinePosition overlineThickness paintOrder panose1 pathLength
-patternContentUnits patternTransform patternUnits pointerEvents points
-pointsAtX pointsAtY pointsAtZ preserveAlpha preserveAspectRatio primitiveUnits
-r radius refX refY renderingIntent repeatCount repeatDur requiredExtensions
-requiredFeatures restart result rotate rx ry scale seed shapeRendering slope
-spacing specularConstant specularExponent speed spreadMethod startOffset
-stdDeviation stemh stemv stitchTiles stopColor stopOpacity
-strikethroughPosition strikethroughThickness string stroke strokeDasharray
-strokeDashoffset strokeLinecap strokeLinejoin strokeMiterlimit strokeOpacity
-strokeWidth surfaceScale systemLanguage tableValues targetX targetY textAnchor
-textDecoration textLength textRendering to transform u1 u2 underlinePosition
-underlineThickness unicode unicodeBidi unicodeRange unitsPerEm vAlphabetic
-vHanging vIdeographic vMathematical values vectorEffect version vertAdvY
-vertOriginX vertOriginY viewBox viewTarget visibility widths wordSpacing
-writingMode x x1 x2 xChannelSelector xHeight xlinkActuate xlinkArcrole
-xlinkHref xlinkRole xlinkShow xlinkTitle xlinkType xmlBase xmlLang xmlSpace
-y y1 y2 yChannelSelector z zoomAndPan
-```
diff --git a/docs/docs/ref-04-tags-and-attributes.md b/docs/docs/ref-04-tags-and-attributes.md
deleted file mode 100644
index 8157582ea6a3..000000000000
--- a/docs/docs/ref-04-tags-and-attributes.md
+++ /dev/null
@@ -1,131 +0,0 @@
----
-id: tags-and-attributes
-title: Tags and Attributes
-permalink: tags-and-attributes.html
-prev: component-specs.html
-next: events.html
----
-
-## Supported Elements
-
-React attempts to support all common elements in both HTML and SVG. Any lower case tag in JSX will be rendered to an element with that tag. SVG elements must be contained within an `<svg>` element to work properly.
-
-### Using `React.DOM` Factory methods
-
-If you aren't using JSX and are using the `React.DOM.*` API to create elements, then you are slightly more limited and there is list of supported elements that will be available on that API.
-
-#### HTML Elements
-
-The following HTML elements are supported in `React.DOM.*`:
-
-```
-a abbr address area article aside audio b base bdi bdo big blockquote body br
-button canvas caption cite code col colgroup data datalist dd del details dfn
-dialog div dl dt em embed fieldset figcaption figure footer form h1 h2 h3 h4 h5
-h6 head header hgroup hr html i iframe img input ins kbd keygen label legend li
-link main map mark menu menuitem meta meter nav noscript object ol optgroup
-option output p param picture pre progress q rp rt ruby s samp script section
-select small source span strong style sub summary sup table tbody td textarea
-tfoot th thead time title tr track u ul var video wbr
-```
-
-#### SVG elements
-
-The following SVG elements are supported in `React.DOM.*`:
-
-```
-circle clipPath defs ellipse g image line linearGradient mask path pattern
-polygon polyline radialGradient rect stop svg text tspan
-```
-
-You may also be interested in [react-art](https://github.com/facebook/react-art), a cross-browser drawing library for React.
-
-
-## Supported Attributes
-
-React supports all `data-*` and `aria-*` attributes as well as every attribute in the following lists.
-
-> Note:
->
-> All attributes are camel-cased and the attributes `class` and `for` are `className` and `htmlFor`, respectively, to match the DOM API specification.
-
-For a list of events, see [Supported Events](/react/docs/events.html).
-
-### HTML Attributes
-
-These standard attributes are supported:
-
-```
-accept acceptCharset accessKey action allowFullScreen allowTransparency alt
-async autoComplete autoFocus autoPlay capture cellPadding cellSpacing challenge
-charSet checked cite classID className colSpan cols content contentEditable
-contextMenu controls coords crossOrigin data dateTime default defer dir
-disabled download draggable encType form formAction formEncType formMethod
-formNoValidate formTarget frameBorder headers height hidden high href hrefLang
-htmlFor httpEquiv icon id inputMode integrity is keyParams keyType kind label
-lang list loop low manifest marginHeight marginWidth max maxLength media
-mediaGroup method min minLength multiple muted name noValidate nonce open
-optimum pattern placeholder poster preload profile radioGroup readOnly rel
-required reversed role rowSpan rows sandbox scope scoped scrolling seamless
-selected shape size sizes span spellCheck src srcDoc srcLang srcSet start step
-style summary tabIndex target title type useMap value width wmode wrap
-```
-
-These RDFa attributes are supported (several RDFa attributes overlap with standard HTML attributes and thus are excluded from this list):
-
-```
-about datatype inlist prefix property resource typeof vocab
-```
-
-In addition, the following non-standard attributes are supported:
-
-- `autoCapitalize autoCorrect` for Mobile Safari.
-- `color` for `<link rel="mask-icon" />` in Safari.
-- `itemProp itemScope itemType itemRef itemID` for [HTML5 microdata](http://schema.org/docs/gs.html).
-- `security` for older versions of Internet Explorer.
-- `unselectable` for Internet Explorer.
-- `results autoSave` for WebKit/Blink input fields of type `search`.
-
-There is also 2 React-specific attributes:
-- `dangerouslySetInnerHTML` ([more here](/react/docs/special-non-dom-attributes.html)), used for directly inserting HTML strings into a component.
-- `suppressContentEditableWarning`, used to suppress the warning when using `contentEditable` and `children`.
-
-### SVG Attributes
-
-```
-accentHeight accumulate additive alignmentBaseline allowReorder alphabetic
-amplitude arabicForm ascent attributeName attributeType autoReverse azimuth
-baseFrequency baseProfile baselineShift bbox begin bias by calcMode capHeight
-clip clipPath clipPathUnits clipRule colorInterpolation
-colorInterpolationFilters colorProfile colorRendering contentScriptType
-contentStyleType cursor cx cy d decelerate descent diffuseConstant direction
-display divisor dominantBaseline dur dx dy edgeMode elevation enableBackground
-end exponent externalResourcesRequired fill fillOpacity fillRule filter
-filterRes filterUnits floodColor floodOpacity focusable fontFamily fontSize
-fontSizeAdjust fontStretch fontStyle fontVariant fontWeight format from fx fy
-g1 g2 glyphName glyphOrientationHorizontal glyphOrientationVertical glyphRef
-gradientTransform gradientUnits hanging horizAdvX horizOriginX ideographic
-imageRendering in in2 intercept k k1 k2 k3 k4 kernelMatrix kernelUnitLength
-kerning keyPoints keySplines keyTimes lengthAdjust letterSpacing lightingColor
-limitingConeAngle local markerEnd markerHeight markerMid markerStart
-markerUnits markerWidth mask maskContentUnits maskUnits mathematical mode
-numOctaves offset opacity operator order orient orientation origin overflow
-overlinePosition overlineThickness paintOrder panose1 pathLength
-patternContentUnits patternTransform patternUnits pointerEvents points
-pointsAtX pointsAtY pointsAtZ preserveAlpha preserveAspectRatio primitiveUnits
-r radius refX refY renderingIntent repeatCount repeatDur requiredExtensions
-requiredFeatures restart result rotate rx ry scale seed shapeRendering slope
-spacing specularConstant specularExponent speed spreadMethod startOffset
-stdDeviation stemh stemv stitchTiles stopColor stopOpacity
-strikethroughPosition strikethroughThickness string stroke strokeDasharray
-strokeDashoffset strokeLinecap strokeLinejoin strokeMiterlimit strokeOpacity
-strokeWidth surfaceScale systemLanguage tableValues targetX targetY textAnchor
-textDecoration textLength textRendering to transform u1 u2 underlinePosition
-underlineThickness unicode unicodeBidi unicodeRange unitsPerEm vAlphabetic
-vHanging vIdeographic vMathematical values vectorEffect version vertAdvY
-vertOriginX vertOriginY viewBox viewTarget visibility widths wordSpacing
-writingMode x x1 x2 xChannelSelector xHeight xlinkActuate xlinkArcrole
-xlinkHref xlinkRole xlinkShow xlinkTitle xlinkType xmlBase xmlLang xmlSpace
-y y1 y2 yChannelSelector z zoomAndPan
-
-```
diff --git a/docs/docs/ref-04-tags-and-attributes.zh-CN.md b/docs/docs/ref-04-tags-and-attributes.zh-CN.md
deleted file mode 100644
index cccd97b7f306..000000000000
--- a/docs/docs/ref-04-tags-and-attributes.zh-CN.md
+++ /dev/null
@@ -1,124 +0,0 @@
----
-id: tags-and-attributes-zh-CN
-title: Tags和属性
-permalink: tags-and-attributes-zh-CN.html
-prev: component-specs-zh-CN.html
-next: events-zh-CN.html
----
-
-## 支持的Tags
-
-React试着支持所有常见的元素.如果你需要一个没有列在这里的元素,请 [file an issue](https://github.com/facebook/react/issues/new).
-
-### HTML 元素
-
-下面的HTML是被支持的:
-
-```
-a abbr address area article aside audio b base bdi bdo big blockquote body br
-button canvas caption cite code col colgroup data datalist dd del details dfn
-dialog div dl dt em embed fieldset figcaption figure footer form h1 h2 h3 h4 h5
-h6 head header hgroup hr html i iframe img input ins kbd keygen label legend li
-link main map mark menu menuitem meta meter nav noscript object ol optgroup
-option output p param picture pre progress q rp rt ruby s samp script section
-select small source span strong style sub summary sup table tbody td textarea
-tfoot th thead time title tr track u ul var video wbr
-```
-
-### SVG 元素
-
-下面的 SVG 元素是被支持的:
-
-```
-circle clipPath defs ellipse g image line linearGradient mask path pattern
-polygon polyline radialGradient rect stop svg text tspan
-```
-
-你也许对 [react-art](https://github.com/facebook/react-art)有兴趣,一个让React绘制Canvas, SVG, 或者 VML (for IE8) 的绘制库.
-
-
-## 支持的属性
-
-React支持所有的 `data-*` 和 `aria-*` 以及下列的属性.
-
-> 注意:
->
-> 所有的属性都是 camel-cased ,`class` 和 `for` 分别是 `className` 和 `htmlFor`,来符合DOM API 规范.
-
-关于事件的列表,见 [Supported Events](/react/docs/events.html).
-
-### HTML 属性
-
-下面的标准属性是被支持的:
-
-```
-accept acceptCharset accessKey action allowFullScreen allowTransparency alt
-async autoComplete autoFocus autoPlay capture cellPadding cellSpacing challenge
-charSet checked cite classID className colSpan cols content contentEditable
-contextMenu controls coords crossOrigin data dateTime default defer dir
-disabled download draggable encType form formAction formEncType formMethod
-formNoValidate formTarget frameBorder headers height hidden high href hrefLang
-htmlFor httpEquiv icon id inputMode integrity is keyParams keyType kind label
-lang list loop low manifest marginHeight marginWidth max maxLength media
-mediaGroup method min minLength multiple muted name noValidate nonce open
-optimum pattern placeholder poster preload profile radioGroup readOnly rel
-required reversed role rowSpan rows sandbox scope scoped scrolling seamless
-selected shape size sizes span spellCheck src srcDoc srcLang srcSet start step
-style summary tabIndex target title type useMap value width wmode wrap
-```
-
-这些RDFa属性是被支持的 （许多RDFa属性和标准的HTML属性重叠，因此被从这个列表里去除）：
-
-```
-about datatype inlist prefix property resource typeof vocab
-```
-
-另外,支持下面的非标准属性:
-
-- `autoCapitalize autoCorrect` for Mobile Safari.
-- `color` for `<link rel="mask-icon" />` in Safari.
-- `itemProp itemScope itemType itemRef itemID` for [HTML5 microdata](http://schema.org/docs/gs.html).
-- `security` 老的IE浏览器.
-- `unselectable` IE浏览器.
-- `results autoSave` for WebKit/Blink input fields of type `search`.
-
-同样有React规范的属性 `dangerouslySetInnerHTML` ([more here](/react/docs/special-non-dom-attributes.html)),用于直接插入HTML字符串到组件里.
-
-### SVG 属性
-
-```
-accentHeight accumulate additive alignmentBaseline allowReorder alphabetic
-amplitude arabicForm ascent attributeName attributeType autoReverse azimuth
-baseFrequency baseProfile baselineShift bbox begin bias by calcMode capHeight
-clip clipPath clipPathUnits clipRule colorInterpolation
-colorInterpolationFilters colorProfile colorRendering contentScriptType
-contentStyleType cursor cx cy d decelerate descent diffuseConstant direction
-display divisor dominantBaseline dur dx dy edgeMode elevation enableBackground
-end exponent externalResourcesRequired fill fillOpacity fillRule filter
-filterRes filterUnits floodColor floodOpacity focusable fontFamily fontSize
-fontSizeAdjust fontStretch fontStyle fontVariant fontWeight format from fx fy
-g1 g2 glyphName glyphOrientationHorizontal glyphOrientationVertical glyphRef
-gradientTransform gradientUnits hanging horizAdvX horizOriginX ideographic
-imageRendering in in2 intercept k k1 k2 k3 k4 kernelMatrix kernelUnitLength
-kerning keyPoints keySplines keyTimes lengthAdjust letterSpacing lightingColor
-limitingConeAngle local markerEnd markerHeight markerMid markerStart
-markerUnits markerWidth mask maskContentUnits maskUnits mathematical mode
-numOctaves offset opacity operator order orient orientation origin overflow
-overlinePosition overlineThickness paintOrder panose1 pathLength
-patternContentUnits patternTransform patternUnits pointerEvents points
-pointsAtX pointsAtY pointsAtZ preserveAlpha preserveAspectRatio primitiveUnits
-r radius refX refY renderingIntent repeatCount repeatDur requiredExtensions
-requiredFeatures restart result rotate rx ry scale seed shapeRendering slope
-spacing specularConstant specularExponent speed spreadMethod startOffset
-stdDeviation stemh stemv stitchTiles stopColor stopOpacity
-strikethroughPosition strikethroughThickness string stroke strokeDasharray
-strokeDashoffset strokeLinecap strokeLinejoin strokeMiterlimit strokeOpacity
-strokeWidth surfaceScale systemLanguage tableValues targetX targetY textAnchor
-textDecoration textLength textRendering to transform u1 u2 underlinePosition
-underlineThickness unicode unicodeBidi unicodeRange unitsPerEm vAlphabetic
-vHanging vIdeographic vMathematical values vectorEffect version vertAdvY
-vertOriginX vertOriginY viewBox viewTarget visibility widths wordSpacing
-writingMode x x1 x2 xChannelSelector xHeight xlinkActuate xlinkArcrole
-xlinkHref xlinkRole xlinkShow xlinkTitle xlinkType xmlBase xmlLang xmlSpace
-y y1 y2 yChannelSelector z zoomAndPan
-```
diff --git a/docs/docs/ref-05-events.it-IT.md b/docs/docs/ref-05-events.it-IT.md
deleted file mode 100644
index 563714733d32..000000000000
--- a/docs/docs/ref-05-events.it-IT.md
+++ /dev/null
@@ -1,262 +0,0 @@
----
-id: events-it-IT
-title: Sistema di Eventi
-permalink: events-it-IT.html
-prev: tags-and-attributes-it-IT.html
-next: dom-differences-it-IT.html
----
-
-## SyntheticEvent
-
-Ai tuoi gestori di eventi saranno passate istanze di `SyntheticEvent`, un involucro cross-browser attorno all'evento nativo del browser. Possiede la stessa interfaccia dell'evento nativo del browser, incluso `stopPropagation()` e `preventDefault()`, con l'eccezione che gli eventi funzionano in modo identico su tutti i browser.
-
-Se ti trovi nella situazione di avere bisogno dell'evento sottostante del browser per qualunque ragione, usa semplicemente l'attributo `nativeEvent` per ottenerlo. Ogni oggetto `SyntheticEvent` ha i seguenti attributi:
-
-```javascript
-boolean bubbles
-boolean cancelable
-DOMEventTarget currentTarget
-boolean defaultPrevented
-number eventPhase
-boolean isTrusted
-DOMEvent nativeEvent
-void preventDefault()
-boolean isDefaultPrevented()
-void stopPropagation()
-boolean isPropagationStopped()
-DOMEventTarget target
-number timeStamp
-string type
-```
-
-> Nota:
->
-> A partire dalla v0.14, restituire `false` da un gestore di eventi non fermerà più la propagazione dell'evento. Invece, `e.stopPropagation()` o `e.preventDefault()` devono essere invocati manualmente, in maniera appropriata.
-
-## Riutilizzo degli eventi
-
-Gli oggetti `SyntheticEvent` sono gestiti come un pool. Ciò significa che ciascun oggetto `SyntheticEvent` sarà riutilizzato e tutte le sue proprietà annullate dopo che la callback dell'evento è stata invocata.
-Ciò avviene per ragioni di performance.
-Per questo motivo non potrai accedere all'evento in maniera asincrona.
-
-```javascript
-function onClick(event) {
-  console.log(event); // => oggetto annullato.
-  console.log(event.type); // => "click"
-  var eventType = event.type; // => "click"
-
-  setTimeout(function() {
-    console.log(event.type); // => null
-    console.log(eventType); // => "click"
-  }, 0);
-
-  this.setState({clickEvent: event}); // Non funzionerà. this.state.clickEvent conterrà soltanto valori null.
-  this.setState({eventType: event.type}); // Puoi sempre esportare le singole proprietà dell'evento.
-}
-```
-
-> Nota:
->
-> Se vuoi accedere alle proprietà dell'evento in maniera asincrona, devi invocare `event.persist()` sull'evento, che rimuoverà l'evento sintetico dal pool e permetterà ai riferimenti all'evento di essere mantenuti nel codice dell'utente.
-
-## Eventi Supportati
-
-React normalizza gli eventi in modo che abbiano proprietà consistenti su browser differenti.
-
-I gestori di eventi seguenti sono scatenati da un evento nella fase di propagazione. Per registrare un gestore di eventi per la fase di cattura, aggiungi il suffisso `Capture` al nome dell'evento; ad esempio, anziché usare `onClick`, useresti `onClickCapture` per gestire l'evento click nella fase di cattura.
-
-
-### Eventi della Clipboard
-
-Nomi degli eventi:
-
-```
-onCopy onCut onPaste
-```
-
-Proprietà:
-
-```javascript
-DOMDataTransfer clipboardData
-```
-
-
-### Eventi di Composizione
-
-Nomi degli eventi:
-
-```
-onCompositionEnd onCompositionStart onCompositionUpdate
-```
-
-Proprietà:
-
-```javascript
-string data
-
-```
-
-
-### Eventi di Tastiera
-
-Nomi degli eventi:
-
-```
-onKeyDown onKeyPress onKeyUp
-```
-
-Proprietà:
-
-```javascript
-boolean altKey
-number charCode
-boolean ctrlKey
-boolean getModifierState(key)
-string key
-number keyCode
-string locale
-number location
-boolean metaKey
-boolean repeat
-boolean shiftKey
-number which
-```
-
-
-### Eventi del Focus
-
-Nomi degli eventi:
-
-```
-onFocus onBlur
-```
-
-Proprietà:
-
-```javascript
-DOMEventTarget relatedTarget
-```
-
-
-### Eventi dei Moduli
-
-Nomi degli eventi:
-
-```
-onChange onInput onSubmit
-```
-
-Per maggiori informazioni sull'evento onChange, leggi [Moduli](/react/docs/forms.html).
-
-
-### Eventi del Mouse
-
-Nomi degli eventi:
-
-```
-onClick onContextMenu onDoubleClick onDrag onDragEnd onDragEnter onDragExit
-onDragLeave onDragOver onDragStart onDrop onMouseDown onMouseEnter onMouseLeave
-onMouseMove onMouseOut onMouseOver onMouseUp
-```
-
-Gli eventi `onMouseEnter` e `onMouseLeave` vengono propagati dal componente che viene abbandonato a quello in cui viene effettuato l'ingresso anziché seguire la propagazione ordinaria, e non posseggono una fase di cattura.
-
-Proprietà:
-
-```javascript
-boolean altKey
-number button
-number buttons
-number clientX
-number clientY
-boolean ctrlKey
-boolean getModifierState(key)
-boolean metaKey
-number pageX
-number pageY
-DOMEventTarget relatedTarget
-number screenX
-number screenY
-boolean shiftKey
-```
-
-
-### Eventi di Selezione
-
-Nomi degli eventi:
-
-```
-onSelect
-```
-
-
-### Eventi del Tocco
-
-Nomi degli eventi:
-
-```
-onTouchCancel onTouchEnd onTouchMove onTouchStart
-```
-
-Proprietà:
-
-```javascript
-boolean altKey
-DOMTouchList changedTouches
-boolean ctrlKey
-boolean getModifierState(key)
-boolean metaKey
-boolean shiftKey
-DOMTouchList targetTouches
-DOMTouchList touches
-```
-
-
-### Eventi UI
-
-Nomi degli eventi:
-
-```
-onScroll
-```
-
-Proprietà:
-
-```javascript
-number detail
-DOMAbstractView view
-```
-
-
-### Eventi della Rotellina
-
-Nomi degli eventi:
-
-```
-onWheel
-```
-
-Proprietà:
-
-```javascript
-number deltaMode
-number deltaX
-number deltaY
-number deltaZ
-```
-
-### Eventi dei Media
-
-Nomi degli eventi:
-
-```
-onAbort onCanPlay onCanPlayThrough onDurationChange onEmptied onEncrypted onEnded onError onLoadedData onLoadedMetadata onLoadStart onPause onPlay onPlaying onProgress onRateChange onSeeked onSeeking onStalled onSuspend onTimeUpdate onVolumeChange onWaiting
-```
-
-### Eventi delle Immagini
-
-Nomi degli eventi:
-
-```
-onLoad onError
-```
diff --git a/docs/docs/ref-05-events.ko-KR.md b/docs/docs/ref-05-events.ko-KR.md
deleted file mode 100644
index b727bb90c533..000000000000
--- a/docs/docs/ref-05-events.ko-KR.md
+++ /dev/null
@@ -1,264 +0,0 @@
----
-id: events-ko-KR
-title: 이벤트 시스템
-permalink: events-ko-KR.html
-prev: tags-and-attributes-ko-KR.html
-next: dom-differences-ko-KR.html
----
-
-## 통합적인(Synthetic) 이벤트
-
-이벤트 핸들러는 브라우저의 네이티브 이벤트의 크로스 브라우저 래퍼(wrapper)인`SyntheticEvent`의 인스턴스에 전달됩니다. 모든 브라우저에서 동작한다는 점을 제외하면, `SyntheticEvent`는 `stopPropagation()`나 `preventDefault()`를 포함해, 브라우저의 네이티브 이벤트와 같은 인터페이스를 가지고 있습니다.
-
-어떤 이유로 기본 브라우저 이벤트가 필요하다면, 그냥 `nativeEvent`를 사용해 할 수 있습니다. 모든 `SyntheticEvent` 객체는 이런 어트리뷰트를 가집니다.
-
-```javascript
-boolean bubbles
-boolean cancelable
-DOMEventTarget currentTarget
-boolean defaultPrevented
-number eventPhase
-boolean isTrusted
-DOMEvent nativeEvent
-void preventDefault()
-boolean isDefaultPrevented()
-void stopPropagation()
-boolean isPropagationStopped()
-DOMEventTarget target
-number timeStamp
-string type
-```
-
-> 주의:
->
-> v0.14 시점에서, 이벤트 핸들러에서 `false` 를 리턴하는 것은 더 이상 이벤트의 전달(propagation)을 멈추지 않습니다. 대신, `e.stopPropagation()`나 `e.preventDefault()`로 적절히 수동으로 트리거해야 합니다.
-
-## 이벤트 풀링
-
-`SyntheticEvent`는 풀링됩니다. 이는 `SyntheticEvent` 객체가 재사용될 것이며 이벤트 콜백이 호출된 후 모든 프로퍼티가 null 값을 갖게 된다는 것을 뜻합니다.
-이는 성능을 위한 동작입니다.
-이 때문에, 비동기 방식으로는 이벤트에 접근할 수 없습니다.
-
-```javascript
-function onClick(event) {
-  console.log(event); // => null이 된 객체.
-  console.log(event.type); // => "click"
-  var eventType = event.type; // => "click"
-
-  setTimeout(function() {
-    console.log(event.type); // => null
-    console.log(eventType); // => "click"
-  }, 0);
-
-  this.setState({clickEvent: event}); // 작동하지 않습니다. this.state.clickEvent 는 null값들만을 갖고 있습니다.
-  this.setState({eventType: event.type}); // 여전히 이벤트 프로퍼티를 내보낼 수 있습니다.
-}
-```
-
-> 주의:
->
-> 만약 비동기 방식으로 이벤트 프로퍼티에 접근하길 원한다면, 이벤트의 `event.persist()`를 호출해야 합니다, 이는 풀로부터 통합적인 이벤트를 제거하고 이벤트에 대한 참조는 사용자의 코드에 의해 유지 될 수 있도록 합니다.
-
-## 지원되는 이벤트
-
-React는 다른 브라우저에서 일관된 특성을 가지도록 이벤트를 일반화합니다.
-
-밑에 있는 이벤트 핸들러들은 일으키는(bubbling) 단계에서 이벤트를 트리거합니다. 이벤트 핸들러를 캡처 단계로 등록하려면, 이벤트 이름에 `Capture`를 붙이면 됩니다.  예를 들어, 캡처 단계의 클릭 이벤트를 다루려면 `onClick`를 사용하는 대신에 `onClickCapture`를 사용해야 합니다.
-
-
-### 클립보드 이벤트
-
-이벤트 이름:
-
-```
-onCopy onCut onPaste
-```
-
-프로퍼티:
-
-```javascript
-DOMDataTransfer clipboardData
-```
-
-
-### Composition Events
-
-이벤트 이름:
-
-```
-onCompositionEnd onCompositionStart onCompositionUpdate
-```
-
-프로퍼티:
-
-```javascript
-string data
-
-```
-
-
-### 키보드 이벤트
-
-이벤트 이름:
-
-```
-onKeyDown onKeyPress onKeyUp
-```
-
-프로퍼티:
-
-```javascript
-boolean altKey
-number charCode
-boolean ctrlKey
-boolean getModifierState(key)
-string key
-number keyCode
-string locale
-number location
-boolean metaKey
-boolean repeat
-boolean shiftKey
-number which
-```
-
-
-### 포커스 이벤트
-
-이벤트 이름:
-
-```
-onFocus onBlur
-```
-
-프로퍼티:
-
-```javascript
-DOMEventTarget relatedTarget
-```
-
-이 포커스 이벤트는 폼 엘리먼트뿐만 아니라 모든 React DOM 엘리먼트에서 작동합니다.
-
-<a name="form-events"></a>
-### 폼 이벤트
-
-이벤트 이름:
-
-```
-onChange onInput onSubmit
-```
-
-onChange 이벤트에 대한 더 자세한 정보는 [폼](/react/docs/forms-ko-KR.html)에서 확인하세요.
-
-
-### 마우스 이벤트
-
-이벤트 이름:
-
-```
-onClick onContextMenu onDoubleClick onDrag onDragEnd onDragEnter onDragExit
-onDragLeave onDragOver onDragStart onDrop onMouseDown onMouseEnter onMouseLeave
-onMouseMove onMouseOut onMouseOver onMouseUp
-```
-
-`onMouseEnter`와 `onMouseLeave` 이벤트는 평범하게 일어나는(bubbling) 대신 입력된 엘리먼트에 남겨지도록 엘리먼트에서 전달되고 캡쳐 단계가 없습니다.
-
-프로퍼티:
-
-```javascript
-boolean altKey
-number button
-number buttons
-number clientX
-number clientY
-boolean ctrlKey
-boolean getModifierState(key)
-boolean metaKey
-number pageX
-number pageY
-DOMEventTarget relatedTarget
-number screenX
-number screenY
-boolean shiftKey
-```
-
-
-### 셀렉션 이벤트
-
-이벤트 이름:
-
-```
-onSelect
-```
-
-
-### 터치 이벤트
-
-이벤트 이름:
-
-```
-onTouchCancel onTouchEnd onTouchMove onTouchStart
-```
-
-프로퍼티:
-
-```javascript
-boolean altKey
-DOMTouchList changedTouches
-boolean ctrlKey
-boolean getModifierState(key)
-boolean metaKey
-boolean shiftKey
-DOMTouchList targetTouches
-DOMTouchList touches
-```
-
-
-### UI 이벤트
-
-이벤트 이름:
-
-```
-onScroll
-```
-
-프로퍼티:
-
-```javascript
-number detail
-DOMAbstractView view
-```
-
-
-### 휠 이벤트
-
-이벤트 이름:
-
-```
-onWheel
-```
-
-프로퍼티:
-
-```javascript
-number deltaMode
-number deltaX
-number deltaY
-number deltaZ
-```
-
-### 미디어 이벤트
-
-이벤트 이름:
-
-```
-onAbort onCanPlay onCanPlayThrough onDurationChange onEmptied onEncrypted onEnded onError onLoadedData onLoadedMetadata onLoadStart onPause onPlay onPlaying onProgress onRateChange onSeeked onSeeking onStalled onSuspend onTimeUpdate onVolumeChange onWaiting
-```
-
-### 이미지 이벤트
-
-이벤트 이름:
-
-```
-onLoad onError
-```
diff --git a/docs/docs/ref-05-events.md b/docs/docs/ref-05-events.md
deleted file mode 100644
index 93ad7fe009a4..000000000000
--- a/docs/docs/ref-05-events.md
+++ /dev/null
@@ -1,300 +0,0 @@
----
-id: events
-title: Event System
-permalink: events.html
-prev: tags-and-attributes.html
-next: dom-differences.html
----
-
-## SyntheticEvent
-
-Your event handlers will be passed instances of `SyntheticEvent`, a cross-browser wrapper around the browser's native event. It has the same interface as the browser's native event, including `stopPropagation()` and `preventDefault()`, except the events work identically across all browsers.
-
-If you find that you need the underlying browser event for some reason, simply use the `nativeEvent` attribute to get it. Every `SyntheticEvent` object has the following attributes:
-
-```javascript
-boolean bubbles
-boolean cancelable
-DOMEventTarget currentTarget
-boolean defaultPrevented
-number eventPhase
-boolean isTrusted
-DOMEvent nativeEvent
-void preventDefault()
-boolean isDefaultPrevented()
-void stopPropagation()
-boolean isPropagationStopped()
-DOMEventTarget target
-number timeStamp
-string type
-```
-
-> Note:
->
-> As of v0.14, returning `false` from an event handler will no longer stop event propagation. Instead, `e.stopPropagation()` or `e.preventDefault()` should be triggered manually, as appropriate.
-
-## Event pooling
-
-The `SyntheticEvent` is pooled. This means that the `SyntheticEvent` object will be reused and all properties will be nullified after the event callback has been invoked.
-This is for performance reasons.
-As such, you cannot access the event in an asynchronous way.
-
-```javascript
-function onClick(event) {
-  console.log(event); // => nullified object.
-  console.log(event.type); // => "click"
-  var eventType = event.type; // => "click"
-
-  setTimeout(function() {
-    console.log(event.type); // => null
-    console.log(eventType); // => "click"
-  }, 0);
-
-  this.setState({clickEvent: event}); // Won't work. this.state.clickEvent will only contain null values.
-  this.setState({eventType: event.type}); // You can still export event properties.
-}
-```
-
-> Note:
->
-> If you want to access the event properties in an asynchronous way, you should call `event.persist()` on the event, which will remove the synthetic event from the pool and allow references to the event to be retained by user code.
-
-## Supported Events
-
-React normalizes events so that they have consistent properties across different browsers.
-
-The event handlers below are triggered by an event in the bubbling phase. To register an event handler for the capture phase, append `Capture` to the event name; for example, instead of using `onClick`, you would use `onClickCapture` to handle the click event in the capture phase.
-
-
-### Clipboard Events
-
-Event names:
-
-```
-onCopy onCut onPaste
-```
-
-Properties:
-
-```javascript
-DOMDataTransfer clipboardData
-```
-
-
-### Composition Events
-
-Event names:
-
-```
-onCompositionEnd onCompositionStart onCompositionUpdate
-```
-
-Properties:
-
-```javascript
-string data
-
-```
-
-
-### Keyboard Events
-
-Event names:
-
-```
-onKeyDown onKeyPress onKeyUp
-```
-
-Properties:
-
-```javascript
-boolean altKey
-number charCode
-boolean ctrlKey
-boolean getModifierState(key)
-string key
-number keyCode
-string locale
-number location
-boolean metaKey
-boolean repeat
-boolean shiftKey
-number which
-```
-
-
-### Focus Events
-
-Event names:
-
-```
-onFocus onBlur
-```
-
-Properties:
-
-```javascript
-DOMEventTarget relatedTarget
-```
-
-These focus events work on all elements in the React DOM, not just form elements.
-
-
-### Form Events
-
-Event names:
-
-```
-onChange onInput onSubmit
-```
-
-For more information about the onChange event, see [Forms](/react/docs/forms.html).
-
-
-### Mouse Events
-
-Event names:
-
-```
-onClick onContextMenu onDoubleClick onDrag onDragEnd onDragEnter onDragExit
-onDragLeave onDragOver onDragStart onDrop onMouseDown onMouseEnter onMouseLeave
-onMouseMove onMouseOut onMouseOver onMouseUp
-```
-
-The `onMouseEnter` and `onMouseLeave` events propagate from the element being left to the one being entered instead of ordinary bubbling and do not have a capture phase.
-
-Properties:
-
-```javascript
-boolean altKey
-number button
-number buttons
-number clientX
-number clientY
-boolean ctrlKey
-boolean getModifierState(key)
-boolean metaKey
-number pageX
-number pageY
-DOMEventTarget relatedTarget
-number screenX
-number screenY
-boolean shiftKey
-```
-
-
-### Selection Events
-
-Event names:
-
-```
-onSelect
-```
-
-
-### Touch Events
-
-Event names:
-
-```
-onTouchCancel onTouchEnd onTouchMove onTouchStart
-```
-
-Properties:
-
-```javascript
-boolean altKey
-DOMTouchList changedTouches
-boolean ctrlKey
-boolean getModifierState(key)
-boolean metaKey
-boolean shiftKey
-DOMTouchList targetTouches
-DOMTouchList touches
-```
-
-
-### UI Events
-
-Event names:
-
-```
-onScroll
-```
-
-Properties:
-
-```javascript
-number detail
-DOMAbstractView view
-```
-
-
-### Wheel Events
-
-Event names:
-
-```
-onWheel
-```
-
-Properties:
-
-```javascript
-number deltaMode
-number deltaX
-number deltaY
-number deltaZ
-```
-
-
-### Media Events
-
-Event names:
-
-```
-onAbort onCanPlay onCanPlayThrough onDurationChange onEmptied onEncrypted onEnded onError onLoadedData onLoadedMetadata onLoadStart onPause onPlay onPlaying onProgress onRateChange onSeeked onSeeking onStalled onSuspend onTimeUpdate onVolumeChange onWaiting
-```
-
-
-### Image Events
-
-Event names:
-
-```
-onLoad onError
-```
-
-
-### Animation Events
-
-Event names:
-
-```
-onAnimationStart onAnimationEnd onAnimationIteration
-```
-
-Properties:
-
-```javascript
-string animationName
-string pseudoElement
-float elapsedTime
-```
-
-
-### Transition Events
-
-Event names:
-
-```
-onTransitionEnd
-```
-
-Properties:
-
-```javascript
-string propertyName
-string pseudoElement
-float elapsedTime
-```
diff --git a/docs/docs/ref-05-events.zh-CN.md b/docs/docs/ref-05-events.zh-CN.md
deleted file mode 100644
index 8305081beecc..000000000000
--- a/docs/docs/ref-05-events.zh-CN.md
+++ /dev/null
@@ -1,300 +0,0 @@
----
-id: events-zh-CN
-title: 事件系统
-permalink: events-zh-CN.html
-prev: tags-and-attributes-zh-CN.html
-next: dom-differences-zh-CN.html
----
-
-## 合成事件
-
-事件处理程序通过 `合成事件`（`SyntheticEvent`）的实例传递，`SyntheticEvent` 是浏览器原生事件跨浏览器的封装。`SyntheticEvent` 和浏览器原生事件一样有 `stopPropagation()`、`preventDefault()` 接口，而且这些接口夸浏览器兼容。
-
-如果出于某些原因想使用浏览器原生事件，可以使用 `nativeEvent` 属性获取。每个和成事件（`SyntheticEvent`）对象都有以下属性：
-
-```javascript
-boolean bubbles
-boolean cancelable
-DOMEventTarget currentTarget
-boolean defaultPrevented
-number eventPhase
-boolean isTrusted
-DOMEvent nativeEvent
-void preventDefault()
-boolean isDefaultPrevented()
-void stopPropagation()
-boolean isPropagationStopped()
-DOMEventTarget target
-number timeStamp
-string type
-```
-
-> 注意：
->
-> React v0.14 中，事件处理程序返回 `false` 不再停止事件传播，取而代之，应该根据需要手动触发 `e.stopPropagation()` 或 `e.preventDefault()`。
-
-## 事件池
-
-`SyntheticEvent` 是池化的. 这意味着 `SyntheticEvent` 对象将会被重用并且所有的属性都会在事件回调被调用后被 nullified.
-这是因为性能的原因.
-因此,你不能异步的访问事件.
-
-```javascript
-function onClick(event) {
-  console.log(event); // => nullified object.
-  console.log(event.type); // => "click"
-  var eventType = event.type; // => "click"
-
-  setTimeout(function() {
-    console.log(event.type); // => null
-    console.log(eventType); // => "click"
-  }, 0);
-
-  this.setState({clickEvent: event}); // Won't work. this.state.clickEvent will only contain null values.
-  this.setState({eventType: event.type}); // You can still export event properties.
-}
-```
-
-> 注意:
->
-> 如果你想异步访问事件属性,你应该在事件上调用 `event.persist()` ,这会从池中移除合成事件并允许对事件的引用被用会保留.
-
-## 支持的事件
-
-React 将事件统一化，使事件在不同浏览器上有一致的属性.
-
-下面的事件处理程序在事件冒泡阶段被触发。如果要注册事件捕获处理程序，应该使用 `Capture` 事件，例如使用 `onClickCapture` 处理点击事件的捕获阶段，而不是 `onClick`。
-
-
-### 剪贴板事件
-
-事件名称：
-
-```
-onCopy onCut onPaste
-```
-
-属性：
-
-```javascript
-DOMDataTransfer clipboardData
-```
-
-
-### Composition 事件
-
-事件名称:
-
-```
-onCompositionEnd onCompositionStart onCompositionUpdate
-```
-
-属性:
-
-```javascript
-string data
-
-```
-
-
-### 键盘事件
-
-事件名称：
-
-```
-onKeyDown onKeyPress onKeyUp
-```
-
-属性:
-
-```javascript
-boolean altKey
-number charCode
-boolean ctrlKey
-boolean getModifierState(key)
-string key
-number keyCode
-string locale
-number location
-boolean metaKey
-boolean repeat
-boolean shiftKey
-number which
-```
-
-
-### 焦点事件
-
-事件名称
-
-```
-onFocus onBlur
-```
-
-属性：
-
-```javascript
-DOMEventTarget relatedTarget
-```
-
-焦点事件在所有的React DOM上工作,不仅仅是表单元素.
-
-
-### 表单事件
-
-事件名称：
-
-```
-onChange onInput onSubmit
-```
-
-关于 `onChange` 事件的更多信息，参见 [表单组件](/react/docs/forms-zh-CN.html)。
-
-
-### 鼠标事件
-
-事件名称：
-
-```
-onClick onContextMenu onDoubleClick onDrag onDragEnd onDragEnter onDragExit
-onDragLeave onDragOver onDragStart onDrop onMouseDown onMouseEnter onMouseLeave
-onMouseMove onMouseOut onMouseOver onMouseUp
-```
-
-`onMouseEnter` 和 `onMouseLeave` 事件从离开的元素传播到进入的元素,代替冒泡排序并且没有捕获阶段. 
-
-属性：
-
-```javascript
-boolean altKey
-number button
-number buttons
-number clientX
-number clientY
-boolean ctrlKey
-boolean getModifierState(key)
-boolean metaKey
-number pageX
-number pageY
-DOMEventTarget relatedTarget
-number screenX
-number screenY
-boolean shiftKey
-```
-
-
-### Selection Events
-
-事件名称:
-
-```
-onSelect
-```
-
-
-### 触控事件
-
-事件名称：
-
-```
-onTouchCancel onTouchEnd onTouchMove onTouchStart
-```
-
-属性：
-
-```javascript
-boolean altKey
-DOMTouchList changedTouches
-boolean ctrlKey
-boolean getModifierState(key)
-boolean metaKey
-boolean shiftKey
-DOMTouchList targetTouches
-DOMTouchList touches
-```
-
-
-### 用户界面事件
-
-事件名称：
-
-```
-onScroll
-```
-
-属性：
-
-```javascript
-number detail
-DOMAbstractView view
-```
-
-
-### 滚轮事件
-
-事件名称：
-
-```
-onWheel
-```
-
-属性：
-
-```javascript
-number deltaMode
-number deltaX
-number deltaY
-number deltaZ
-```
-
-
-### 媒体事件
-
-事件名称:
-
-```
-onAbort onCanPlay onCanPlayThrough onDurationChange onEmptied onEncrypted onEnded onError onLoadedData onLoadedMetadata onLoadStart onPause onPlay onPlaying onProgress onRateChange onSeeked onSeeking onStalled onSuspend onTimeUpdate onVolumeChange onWaiting
-```
-
-
-### 图片事件
-
-事件名称:
-
-```
-onLoad onError
-```
-
-
-### 动画事件
-
-事件名称:
-
-```
-onAnimationStart onAnimationEnd onAnimationIteration
-```
-
-属性：
-
-```javascript
-string animationName
-string pseudoElement
-float elapsedTime
-```
-
-
-### Transition Events
-
-事件名称:
-
-```
-onTransitionEnd
-```
-
-属性：
-
-```javascript
-string propertyName
-string pseudoElement
-float elapsedTime
-```
diff --git a/docs/docs/ref-06-dom-differences.it-IT.md b/docs/docs/ref-06-dom-differences.it-IT.md
deleted file mode 100644
index 8fae0c6e320d..000000000000
--- a/docs/docs/ref-06-dom-differences.it-IT.md
+++ /dev/null
@@ -1,15 +0,0 @@
----
-id: dom-differences-it-IT
-title: Differenze del DOM
-permalink: dom-differences-it-IT.html
-prev: events-it-IT.html
-next: special-non-dom-attributes-it-IT.html
----
-
-React ha implementato eventi indipendenti dal browser e un sistema DOM per ragioni di prestazioni e compatibilità cross-browser. Abbiamo colto l'occasione di dare una ripulita ad alcuni aspetti trascurati nelle implementazioni del DOM nei browser.
-
-* Tutte le proprietà e attributi del DOM (incluso i gestori di eventi) dovrebbero essere camelCased per essere consistenti con lo stile standard JavaScript. Abbiamo intenzionalmente deviato dalla specifica perché la specifica stessa è inconsistente. **Tuttavia**, gli attributi `data-*` e `aria-*` [sono conformi alle specifiche](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes#data-*) e dovrebbero essere soltanto in minuscolo.
-* L'attributo `style` accetta un oggetto JavaScript con proprietà camelCased anziché una stringa CSS. Questo è consistente con la proprietà DOM `style` di JavaScript, è più efficiente, e previene falle nella sicurezza XSS.
-* Tutti gli oggetti evento sono conformi con la specifica W3C, e tutti gli eventi (incluso il submit) si propagano correttamente secondo la specifica W3C. Consulta il [Sistema degli Eventi](/react/docs/events.html) per maggiori dettagli.
-* L'evento `onChange` si comporta come ti aspetteresti: questo evento è emesso ogni qualvolta il valore di un campo di un modulo cambia anziché, in maniera inconsistente, quando il campo perde il focus. Abbiamo intenzionalmente deviato dal comportamento corrente dei browser perché `onChange` è un nome incorretto per questo comportamento e React dipende dall'emissione di questo evento in tempo reale in risposta all'input dell'utente. Leggi [Moduli](/react/docs/forms.html) per maggiori dettagli.
-* Attributi dei campi di modulo come `value` e `checked`, oppure `textarea`. [Maggiori dettagli](/react/docs/forms.html).
diff --git a/docs/docs/ref-06-dom-differences.ko-KR.md b/docs/docs/ref-06-dom-differences.ko-KR.md
deleted file mode 100644
index 36d75eca032c..000000000000
--- a/docs/docs/ref-06-dom-differences.ko-KR.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-id: dom-differences-ko-KR
-title: DOM과의 차이점
-permalink: dom-differences-ko-KR.html
-prev: events-ko-KR.html
-next: special-non-dom-attributes-ko-KR.html
----
-
-React는 성능과 크로스 브라우저 호환성을 이유로 브라우저에 독립적인 이벤트와 DOM 시스템으로 구현되었습니다. 브라우저 DOM 구현의 일관성없는 부분들을 정리할 기회를 가졌습니다.
-
-* 모든 DOM 프로퍼티와 어트리뷰트는 (이벤트 핸들러를 포함해) 표준 JavaScript 스타일과 일치하도록 카멜케이스를 사용해야 합니다. **하지만**, `data-*` 와 `aria-*` 어트리뷰트는 [사양을 준수해](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes#data-*) 소문자만 사용해야 합니다.
-* `style` 어트리뷰트는 CSS 문자열 대신에 카멜케이스로 된 프로퍼티를 가지는 JavaScript 객체를 받습니다. 이는 DOM `style` JavaScript 프로퍼티와 일치하면서도 좀 더 효율적이며, XSS 보안 취약점을 예방할 수 있습니다.
-* 모든 이벤트 객체는 W3C 사양을 준수하고, 모든 이벤트(submit을 포함해)는 W3C 사양에 따라 일으킵(bubble)니다. 좀 더 자세한 정보는 [이벤트 시스템](/react/docs/events-ko-KR.html)을 보세요.
-* `onChange` 이벤트는 기대대로 동작합니다. 이 이벤트는 일관성없이 blur시점에서 발생하지 않고 폼 필드가 변경될 때만 발생합니다.[^1] 우리는 의도적으로 기존 브라우저 동작을 차단했습니다. `onChange`는 이름과 실제 동작이 다르고, React는 실시간으로 사용자 입력에 반응할 때 이 이벤트에 의존하기 때문입니다. 더 자세한 정보는 [폼](/react/docs/forms-ko-KR.html)을 보세요.
-* `value`와 `checked` 폼 input 어트리뷰트, `textarea`. [자세히 보기](/react/docs/forms-ko-KR.html).
-
-[^1]: **역주**: 일관성 없다는 표현에 대해 부연 설명하자면, 네이티브의 onChange는 변경뿐만 아니라 blur에서도 반응합니다.
diff --git a/docs/docs/ref-06-dom-differences.md b/docs/docs/ref-06-dom-differences.md
deleted file mode 100644
index 3d510618767d..000000000000
--- a/docs/docs/ref-06-dom-differences.md
+++ /dev/null
@@ -1,16 +0,0 @@
----
-id: dom-differences
-title: DOM Differences
-permalink: dom-differences.html
-prev: events.html
-next: special-non-dom-attributes.html
----
-
-React has implemented a browser-independent events and DOM system for performance and cross-browser compatibility reasons. We took the opportunity to clean up a few rough edges in browser DOM implementations.
-
-* All DOM properties and attributes (including event handlers) should be camelCased to be consistent with standard JavaScript style. We intentionally break with the spec here since the spec is inconsistent. **However**, `data-*` and `aria-*` attributes [conform to the specs](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes#data-*) and should be lower-cased only.
-* The `style` attribute accepts a JavaScript object with camelCased properties rather than a CSS string. This is consistent with the DOM `style` JavaScript property, is more efficient, and prevents XSS security holes.
-* Since `class` and `for` are reserved words in JavaScript, the JSX elements for built-in [DOM nodes](http://javascript.info/tutorial/dom-nodes) should use the attribute names `className` and `htmlFor` respectively, (eg. `<div className="foo" />` ). Custom elements should use `class` and `for` directly (eg. `<my-tag class="foo" />` ).
-* All event objects conform to the W3C spec, and all events (including submit) bubble correctly per the W3C spec. See [Event System](/react/docs/events.html) for more details.
-* The `onChange` event behaves as you would expect it to: whenever a form field is changed this event is fired rather than inconsistently on blur. We intentionally break from existing browser behavior because `onChange` is a misnomer for its behavior and React relies on this event to react to user input in real time. See [Forms](/react/docs/forms.html) for more details.
-* Form input attributes such as `value` and `checked`, as well as `textarea`. [More here](/react/docs/forms.html).
diff --git a/docs/docs/ref-06-dom-differences.zh-CN.md b/docs/docs/ref-06-dom-differences.zh-CN.md
deleted file mode 100644
index 2b869db2b2a0..000000000000
--- a/docs/docs/ref-06-dom-differences.zh-CN.md
+++ /dev/null
@@ -1,16 +0,0 @@
----
-id: dom-differences-zh-CN
-title: DOM 的不同之处
-permalink: dom-differences-zh-CN.html
-prev: events-zh-CN.html
-next: special-non-dom-attributes-zh-CN.html
----
-
-React 实现了一个浏览器无关的 事件和DOM 系统,原因是为了性能和跨浏览器的兼容性.我们利用这个机会来清理了一些浏览器DOM实现的一些粗糙边缘.
-
-* 所有的 DOM properties 和 attributes (包括事件处理器) 都应该 camelCased 来保持和标准的 JavaScript 风格一致.我们在这里故意打破了这个规范是因为规范是不一致的. **然而**,`data-*` 和 `aria-*` attributes [conform to the specs](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes#data-*) 应该只 lower-cased.
-* `style` attribute 接受 camelCased properties 的JavaScript对象 而不是一个CSS字符串. 这保持了和 DOM `style` JavaScript property 的一致,更有效率,而且阻止了XSS安全漏洞.
-* 因为 `class` 和 `for` 是 JavaScript的保留字,内建[DOM nodes](http://javascript.info/tutorial/dom-nodes)的JSX元素  应该分别使用 attribute名`className` 和 `htmlFor` ,(比如 `<div className="foo" />`).自定义元素应该直接使用 `class` 和 `for` (例如. `<my-tag class="foo" />` ).
-* 所有事件对象遵循 W3C 规范,所有事件(包括提交)正确按W3C规范冒泡.详见[Event System](/react/docs/events.html).
-* `onChange` 事件表现的像你期望的那样:不论何时一个表单域改变了这个事件就会激发,而不是模糊的不一致.我们故意打破了已有浏览器的行为,因为 `onChange` 对于他的行为来说用词不当,并且React依赖于这个事件来实时响应用户的输入.详见[Forms](/react/docs/forms.html).
-* 表单 输入attributes 类似 `value` 和 `checked`,就像`textarea`一样[More here](/react/docs/forms.html).
diff --git a/docs/docs/ref-07-special-non-dom-attributes.it-IT.md b/docs/docs/ref-07-special-non-dom-attributes.it-IT.md
deleted file mode 100644
index 457fd27eaa93..000000000000
--- a/docs/docs/ref-07-special-non-dom-attributes.it-IT.md
+++ /dev/null
@@ -1,13 +0,0 @@
----
-id: special-non-dom-attributes-it-IT
-title: Attributi Speciali Non-DOM
-permalink: special-non-dom-attributes-it-IT.html
-prev: dom-differences-it-IT.html
-next: reconciliation-it-IT.html
----
-
-Oltre alle [Differenze del DOM](/react/docs/dom-differences.html), React offre alcuni attributi che semplicemente non esistono nel DOM.
-
-- `key`: un identificatore univoco opzionale. Quando il tuo componente viene riordinato durante i passaggi di `render`, potrebbe essere distrutto e ricreato in base all'algoritmo di calcolo delle differenze. Assegnargli una chiave che persiste assicura che il componente venga preservato. Scopri maggiori dettagli [qui](/react/docs/multiple-components.html#dynamic-children).
-- `ref`: leggi [qui](/react/docs/more-about-refs.html).
-- `dangerouslySetInnerHTML`: Offre l'abilità di inserire HTML grezzo, principalmente per cooperare con librerie di manipolazione di stringhe DOM. Scopri maggiori dettagli [qui](/react/tips/dangerously-set-inner-html.html).
diff --git a/docs/docs/ref-07-special-non-dom-attributes.ko-KR.md b/docs/docs/ref-07-special-non-dom-attributes.ko-KR.md
deleted file mode 100644
index 54a8c4520931..000000000000
--- a/docs/docs/ref-07-special-non-dom-attributes.ko-KR.md
+++ /dev/null
@@ -1,13 +0,0 @@
----
-id: special-non-dom-attributes-ko-KR
-title: DOM이 아닌 특별한 어트리뷰트
-permalink: special-non-dom-attributes-ko-KR.html
-prev: dom-differences-ko-KR.html
-next: reconciliation-ko-KR.html
----
-
-[DOM 차이점](/react/docs/dom-differences-ko-KR.html)처럼, React는 DOM에는 존재하지 않는 몇몇 어트리뷰트도 제공합니다.
-
-- `key`: 선택적인 고유 식별자. 컴포넌트가 `render` 과정에서 섞일 때, diff 알고리즘에 의해 파괴되고, 다시 생성될 수 있습니다. 컴포넌트에 영속적인(persists) 키를 할당하면 컴포넌트가 확실히 유지되게 할 수 있습니다. 더 자세한 것은 [여기](/react/docs/multiple-components-ko-KR.html#dynamic-children)에서 보세요.
-- `ref`: [여기](/react/docs/more-about-refs-ko-KR.html)를 보세요.
-- `dangerouslySetInnerHTML`: 생(raw) HTML을 넣을 수 있게 합니다. 주로 DOM 문자열 관리 라이브러리와의 협력하기 위해 사용합니다. 더 자세한 것은 [여기](/react/tips/dangerously-set-inner-html.html)를 보세요.
diff --git a/docs/docs/ref-07-special-non-dom-attributes.md b/docs/docs/ref-07-special-non-dom-attributes.md
deleted file mode 100644
index f3fd90c16a9f..000000000000
--- a/docs/docs/ref-07-special-non-dom-attributes.md
+++ /dev/null
@@ -1,13 +0,0 @@
----
-id: special-non-dom-attributes
-title: Special Non-DOM Attributes
-permalink: special-non-dom-attributes.html
-prev: dom-differences.html
-next: reconciliation.html
----
-
-Beside [DOM differences](/react/docs/dom-differences.html), React offers some attributes that simply don't exist in DOM.
-
-- `key`: an optional, unique identifier. When your component shuffles around during `render` passes, it might be destroyed and recreated due to the diff algorithm. Assigning it a key that persists makes sure the component stays. See more [here](/react/docs/multiple-components.html#dynamic-children).
-- `ref`: see [here](/react/docs/more-about-refs.html).
-- `dangerouslySetInnerHTML`: Provides the ability to insert raw HTML, mainly for cooperating with DOM string manipulation libraries. See more [here](/react/tips/dangerously-set-inner-html.html).
diff --git a/docs/docs/ref-07-special-non-dom-attributes.zh-CN.md b/docs/docs/ref-07-special-non-dom-attributes.zh-CN.md
deleted file mode 100644
index 3b29fe38204f..000000000000
--- a/docs/docs/ref-07-special-non-dom-attributes.zh-CN.md
+++ /dev/null
@@ -1,13 +0,0 @@
----
-id: special-non-dom-attributes-zh-CN
-title: 特殊的 Non-DOM Attributes
-permalink: special-non-dom-attributes-zh-CN.html
-prev: dom-differences-zh-CN.html
-next: reconciliation-zh-CN.html
----
-
-和 [DOM 的不同之处](/react/docs/dom-differences-zh-CN.html)相比, React 提供了一些不存在于DOM的 attributes .
-
-- `key`: 一个可选的.独特的标识.当你的组件穿梭于 `render` 的pass,它也许会因为diff算法被摧毁和重建.赋予它一个持久的key保证这个component可达.详见 [这里](/react/docs/multiple-components.html#dynamic-children).
-- `ref`: 见 [这里](/react/docs/more-about-refs.html).
-- `dangerouslySetInnerHTML`: 提供了直接插入raw HTML的能力,主要是为了与操纵DOM字符串的库协作.详见 [这里](/react/tips/dangerously-set-inner-html.html).
diff --git a/docs/docs/ref-08-reconciliation.it-IT.md b/docs/docs/ref-08-reconciliation.it-IT.md
deleted file mode 100644
index b68e63503625..000000000000
--- a/docs/docs/ref-08-reconciliation.it-IT.md
+++ /dev/null
@@ -1,132 +0,0 @@
----
-id: reconciliation-it-IT
-title: Riconciliazione
-permalink: reconciliation-it-IT.html
-prev: special-non-dom-attributes-it-IT.html
-next: webcomponents.html
----
-
-La decisione chiave del design di React è fare in modo che l'API sembri ripetere il rendering dell'intera applicazione per ciascun aggiornamento. Ciò rende la scrittura delle applicazione molto più semplice, ma è anche una sfida incredibile per renderlo trattabile. Questo articolo spiega come siamo riusciti a trasformare, tramite potenti euristiche, un problema O(n<sup>3</sup>) in uno O(n).
-
-
-## Motivazione
-
-Generare il minimo numero di operazioni necessarie a trasformare un albero in un altro è un problema complesso e ben noto. Gli [algoritmi dello stato dell'arte](http://grfia.dlsi.ua.es/ml/algorithms/references/editsurvey_bille.pdf) hanno una complessità dell'ordine di O(n<sup>3</sup>) dove n è il numero di nodi dell'albero.
-
-Ciò significa che visualizzare 1000 nodi richiederebbe un numero di confronti dell'ordine del miliardo. Ciò è decisamente troppo costoso per il nostro caso d'uso. Per mettere questo numero in prospettiva, le CPU oggi giorno eseguono approssimativamente 3 miliardi di istruzioni al secondo. Quindi anche con l'implementazione più efficiente, non saremmo in grado di calcolare la differenza in meno di un secondo.
-
-Dal momento che un algoritmo ottimo non è trattabile, implementiamo un algoritmo O(n) non ottimale usando euristiche basate su due assunzioni:
-
-1. Due componenti della stessa classe genereranno alberi simili e due componenti di classi diverse genereranno alberi diversi.
-2. È possibile fornire una chiave unica per gli elementi che sia stabile durante rendering differenti.
-
-In pratica, queste assunzioni sono eccezionalmente veloci per quasi tutti i casi d'uso pratici.
-
-
-## Differenza a coppie
-
-Per effettuare la differenza di due alberi, dobbiamo prima essere capaci di effettuare la differenza tra due nodi. Esistono tre diversi casi da considerare.
-
-
-### Tipi di Nodo Differenti
-
-Se il tipo di nodo è differente, React li tratterà come due sottoalberi diversi, getterà via il primo e costruirà e inserirà il secondo.
-
-```xml
-renderA: <div />
-renderB: <span />
-=> [removeNode <div />], [insertNode <span />]
-```
-
-La stessa logica è usata per i componenti personalizzati. Se non sono dello stesso tipo, React non proverà neppure a confrontare ciò che visualizzano. Rimuoverà soltanto il primo dal DOM e inserirà il secondo.
-
-```xml
-renderA: <Header />
-renderB: <Content />
-=> [removeNode <Header />], [insertNode <Content />]
-```
-
-Possedere questa conoscenza di alto livello è un aspetto molto importante del perché l'algoritmo di differenza di React è sia veloce che preciso. Ciò fornisce una buona euristica per potare rapidamente gran parte dell'albero e concentrarsi su parti che hanno una buona probabilità di essere simili.
-
-È molto improbabile che un elemento `<Header>` generi un DOM che somigli a quello generato da un elemento `<Content>`. Anziché perdere tempo provando a confrontare queste due strutture, React semplicemente ricostruisce l'albero da zero.
-
-Come corollario, se c'è un elemento `<Header>` nella stessa posizione in due rendering consecutivi, ti puoi aspettare di trovare una struttura molto simile che vale la pena di esplorare.
-
-
-### Nodi DOM
-
-Quando vengono confrontati nodi DOM, guardiamo gli attributi di entrambi e decidiamo quali di essi sono cambiati in un tempo lineare.
-
-```xml
-renderA: <div id="before" />
-renderB: <div id="after" />
-=> [replaceAttribute id "after"]
-```
-
-Anziché trattare lo stile come una stringa opaca, viene rappresentato come un oggetto chiave-valore. Ciò ci permette di aggiornare solo le proprietà che sono cambiate.
-
-```xml
-renderA: <div style={{'{{'}}color: 'red'}} />
-renderB: <div style={{'{{'}}fontWeight: 'bold'}} />
-=> [removeStyle color], [addStyle font-weight 'bold']
-```
-
-Dopo che gli attributi sono stati aggiornati, effettuiamo un confronto ricorsivo su ciascuno dei nodi figli.
-
-
-### Componenti Personalizzati
-
-We decided that the two custom components are the same. Since components are stateful, we cannot just use the new component and call it a day. React takes all the attributes from the new component and calls `component[Will/Did]ReceiveProps()` on the previous one.
-
-The previous component is now operational. Its `render()` method is called and the diff algorithm restarts with the new result and the previous result.
-
-
-## List-wise diff
-
-### Problematic Case
-
-In order to do children reconciliation, React adopts a very naive approach. It goes over both lists of children at the same time and generates a mutation whenever there's a difference.
-
-For example if you add an element at the end:
-
-```xml
-renderA: <div><span>first</span></div>
-renderB: <div><span>first</span><span>second</span></div>
-=> [insertNode <span>second</span>]
-```
-
-Inserting an element at the beginning is problematic. React is going to see that both nodes are spans and therefore run into a mutation mode.
-
-```xml
-renderA: <div><span>first</span></div>
-renderB: <div><span>second</span><span>first</span></div>
-=> [replaceAttribute textContent 'second'], [insertNode <span>first</span>]
-```
-
-There are many algorithms that attempt to find the minimum sets of operations to transform a list of elements. [Levenshtein distance](https://en.wikipedia.org/wiki/Levenshtein_distance) can find the minimum using single element insertion, deletion and substitution in O(n<sup>2</sup>). Even if we were to use Levenshtein, this doesn't find when a node has moved into another position and algorithms to do that have much worse complexity.
-
-### Keys
-
-In order to solve this seemingly intractable issue, an optional attribute has been introduced. You can provide for each child a key that is going to be used to do the matching. If you specify a key, React is now able to find insertion, deletion, substitution and moves in O(n) using a hash table.
-
-
-```xml
-renderA: <div><span key="first">first</span></div>
-renderB: <div><span key="second">second</span><span key="first">first</span></div>
-=> [insertNode <span>second</span>]
-```
-
-In practice, finding a key is not really hard. Most of the time, the element you are going to display already has a unique id. When that's not the case, you can add a new ID property to your model or hash some parts of the content to generate a key. Remember that the key only has to be unique among its siblings, not globally unique.
-
-
-## Trade-offs
-
-It is important to remember that the reconciliation algorithm is an implementation detail. React could re-render the whole app on every action; the end result would be the same. We are regularly refining the heuristics in order to make common use cases faster.
-
-In the current implementation, you can express the fact that a sub-tree has been moved amongst its siblings, but you cannot tell that it has moved somewhere else. The algorithm will re-render that full sub-tree.
-
-Because we rely on two heuristics, if the assumptions behind them are not met, performance will suffer.
-
-1. The algorithm will not try to match sub-trees of different components classes. If you see yourself alternating between two components classes with very similar output, you may want to make it the same class. In practice, we haven't found this to be an issue.
-
-2. If you don't provide stable keys (by using Math.random() for example), all the sub-trees are going to be re-rendered every single time. By giving the users the choice to choose the key, they have the ability to shoot themselves in the foot.
diff --git a/docs/docs/ref-08-reconciliation.ko-KR.md b/docs/docs/ref-08-reconciliation.ko-KR.md
deleted file mode 100644
index e8bce339ac20..000000000000
--- a/docs/docs/ref-08-reconciliation.ko-KR.md
+++ /dev/null
@@ -1,132 +0,0 @@
----
-id: reconciliation-ko-KR
-title: 비교조정(Reconciliation)
-permalink: reconciliation-ko-KR.html
-prev: special-non-dom-attributes-ko-KR.html
-next: webcomponents.html
----
-
-React의 주요 설계 철학은 업데이트할 때마다 전체 앱을 다시 렌더하는 것처럼 보이게 API를 만드는 것입니다. 이렇게 하면 애플리케이션 작성이 훨씬 쉬워지지만 한편으로는 어려운 도전 과제이기도 합니다. 이 글에서는 강력한 휴리스틱으로 어떻게 O(n<sup>3</sup>) 복잡도의 문제를 O(n)짜리로 바꿀 수 있었는지 설명합니다.
-
-
-## 동기
-
-최소한의 연산으로 어떤 트리를 다른 트리로 바꾸는 것은 복잡하고 많이 연구된 문제입니다. n을 트리에 있는 노드 수라고 할 때 [최신 알고리즘](http://grfia.dlsi.ua.es/ml/algorithms/references/editsurvey_bille.pdf)은 O(n<sup>3</sup>) 복잡도를 가집니다.
-
-다시 말해 1000개의 노드를 표시하려면 10억 번 수준의 비교를 해야 한다는 뜻입니다. 이는 우리가 필요한 용도로는 너무 비쌉니다. 이 수치를 좀 더 알기 쉽게 설명하면, 요즘 CPU는 1초에 대략 30억 번의 연산을 하므로 가장 빠른 구현으로도 1초 안에 이러한 비교는 계산해낼 수 없다는 것입니다.
-
-최적의 알고리즘을 사용할 수 없기 때문에, 완전하진 않지만 다음의 두 가지 가정에 기반한 휴리스틱을 사용한 O(n) 알고리즘으로 구현했습니다.
-
-1. 같은 클래스의 두 컴포넌트는 비슷한 트리를 생성하고, 서로 다른 클래스를 가진 두 컴포넌트는 서로 다른 트리를 생성할 것이다.
-2. 각 렌더 과정들 사이에 유지되는 엘리먼트에 고유한 키를 제공할 수 있다.
-
-실제로 이러한 가정은 거의 모든 실용적인 상황에서 굉장히 빠릅니다.
-
-
-## 일대일 비교
-
-트리 비교를 하기 위해서는 먼저 두 노드를 비교할 수 있어야 합니다. 세 가지 경우를 다룹니다.
-
-
-### 서로 다른 노드 타입
-
-두 노드의 타입이 서로 다르다면, React는 이를 두 개의 서로 다른 서브트리로 간주해 처음 것을 버리고 두번째 것을 만들어 삽입합니다.
-
-```xml
-renderA: <div />
-renderB: <span />
-=> [removeNode <div />], [insertNode <span />]
-```
-
-동일한 로직이 커스텀 컴포넌트에 대해서도 적용됩니다. 타입이 다르다면 React는 그 컴포넌트들이 무엇을 렌더하는지 조차도 비교하지 않습니다. 그저 처음 것을 DOM에서 제거하고 두번째 것을 삽입합니다.
-
-```xml
-renderA: <Header />
-renderB: <Content />
-=> [removeNode <Header />], [insertNode <Content />]
-```
-
-이러한 고수준의 사실을 알 수 있다는 것이 React의 비교 알고리즘이 빠르면서 정확할 수 있는 비결입니다. 트리의 커다란 부분을 일찌감치 탐색 대상에서 제외하고 비슷할 가능성이 높은 부분에 집중할 수 있는 좋은 휴리스틱을 제공합니다.
-
-`<Header>` 엘리먼트가 생성하는 DOM이 `<Content>`가 생성하는 것과 비슷하게 생길 확률은 매우 낮습니다. 이 두 구조를 비교하는데 시간을 낭비하지 않고 React는 그냥 트리를 처음부터 새로 만듭니다.
-
-한편 두 번의 연속적인 렌더에서 같은 위치에 `<Header>` 엘리먼트가 있다면 비슷한 구조일 것이므로 탐색할만 합니다.
-
-
-### DOM 노드
-
-두 DOM 노드를 비교할 때는 어트리뷰트를 보고 무엇이 바뀌었는지 선형 시간 안에 결정할 수 있습니다.
-
-```xml
-renderA: <div id="before" />
-renderB: <div id="after" />
-=> [replaceAttribute id "after"]
-```
-
-스타일을 불명확한 문자열로 다루지 않고 키-값 객체를 사용합니다. 이는 변경된 프로퍼티만 업데이트 하도록 해줍니다.
-
-```xml
-renderA: <div style={{'{{'}}color: 'red'}} />
-renderB: <div style={{'{{'}}fontWeight: 'bold'}} />
-=> [removeStyle color], [addStyle font-weight 'bold']
-```
-
-어트리뷰트가 업데이트된 다음에는, 모든 자식도 재귀적으로 업데이트합니다.
-
-
-### 커스텀 컴포넌트
-
-우리는 두 커스텀 컴포넌트를 같은 것으로 취급하기로 했습니다. 컴포넌트는 상태를 가지기 때문에 새 컴포넌트를 그냥 사용할 수는 없습니다. React는 새 컴포넌트의 모든 어트리뷰트를 취해 이전 컴포넌트의 `component[Will/Did]ReceiveProps()`를 호출해 줍니다.
-
-이제 이전 컴포넌트가 작동합니다. 거기 있는 `render()` 메소드가 호출되고 비교 알고리즘이 다시 새로운 결과와 이전 결과를 비교합니다.
-
-
-## 목록끼리 비교
-
-### 문제가 되는 경우
-
-React는 매우 단순한 방식으로 자식 비교조정(children reconciliation)을 합니다. 자식 목록을 동시에 서로 비교하다가 차이를 발견하면 변경 사항을 적용합니다.
-
-예를 들어 맨 끝에 엘리먼트를 추가한 경우에는:
-
-```xml
-renderA: <div><span>first</span></div>
-renderB: <div><span>first</span><span>second</span></div>
-=> [insertNode <span>second</span>]
-```
-
-맨 앞에 엘리먼트를 삽입하는 경우가 문제입니다. React는 두 노드가 모두 span인지 확인하고 변경 모드로 작동합니다.
-
-```xml
-renderA: <div><span>first</span></div>
-renderB: <div><span>second</span><span>first</span></div>
-=> [replaceAttribute textContent 'second'], [insertNode <span>first</span>]
-```
-
-원소의 목록을 변환하기 위한 최소 연산 집합을 찾는 알고리즘이 여럿 있습니다. [Levenshtein distance](https://en.wikipedia.org/wiki/Levenshtein_distance)를 사용하면 O(n<sup>2</sup>) 복잡도로 원소 한 개의 삽입, 삭제, 교체를 위해 필요한 최솟값을 찾을 수 있습니다. Levenshtein 알고리즘을 사용해도 노드가 다른 위치로 이동한 경우는 알아낼 수 없고, 그것을 알아내는 알고리즘은 더욱 높은 복잡도를 가집니다.
-
-### 키(keys)
-
-해결할 수 없어보이는 이 문제를 풀기 위해 선택적인 어트리뷰트를 도입했습니다. 각 자식에 키(key)를 할당해 이를 비교하는 데에 사용합니다. 키를 명시하면 React가 해시 테이블을 사용하여 삽입, 삭제, 교체 및 이동을 O(n) 복잡도로 찾아낼 수 있습니다.
-
-
-```xml
-renderA: <div><span key="first">first</span></div>
-renderB: <div><span key="second">second</span><span key="first">first</span></div>
-=> [insertNode <span>second</span>]
-```
-
-실제 상황에서 키를 찾는 것은 별로 어렵지 않습니다. 대부분의 경우, 표시하려는 엘리먼트는 이미 고유한 식별자를 가지고 있습니다. 그렇지 않은 경우에도 모델에 새로운 ID 프로퍼티를 추가하거나 내용의 일부분을 해시하여 키를 생성할 수 있습니다. 키는 형제 노드 사이에서만 고유하면 됩니다. 전역적으로 고유할 필요는 없습니다.
-
-
-## 트레이드오프
-
-비교조정 알고리즘이 구현 세부사항이라는 것을 기억하는 것은 중요합니다. React가 전체 앱을 모든 동작마다 새로 렌더해도 결과는 같을 것입니다. 일반적인 사용 패턴을 빠르게 만들 수 있도록 저희는 계속 휴리스틱을 다듬고 있습니다.
-
-현재 구현에서 서브트리가 형제 노드 사이에서 이동하는 경우는 표현할 수 있지만, 그 외의 곳으로 이동했는지는 알 수 없습니다. 알고리즘에 따라 전체 서브트리가 다시 렌더됩니다.
-
-두 가지 휴리스틱에 의존하기 때문에 그에 대한 가정이 만족되지 않으면 성능이 좋지 않을 것입니다.
-
-1. 서로 다른 컴포넌트 클래스의 서브트리는 비교하려고 시도하지 않습니다. 만약 매우 비슷한 출력 결과의 두 컴포넌트를 왔다갔다 하는 경우 같은 클래스로 만들 수 있습니다. 실제 상황에서는 큰 문제가 없습니다.
-
-2. 안정적인 키를 붙이지 않을 경우 (예를 들어 Math.random()을 사용한다거나) 모든 서브트리가 매번 다시 렌더될 것입니다. 사용자에게 키를 선택하도록 하는 대신 실수할 수 있는 여지가 있습니다.
diff --git a/docs/docs/ref-08-reconciliation.md b/docs/docs/ref-08-reconciliation.md
deleted file mode 100644
index aefd2edf5f23..000000000000
--- a/docs/docs/ref-08-reconciliation.md
+++ /dev/null
@@ -1,133 +0,0 @@
----
-id: reconciliation
-title: Reconciliation
-permalink: reconciliation.html
-prev: special-non-dom-attributes.html
-next: webcomponents.html
----
-
-React's key design decision is to make the API seem like it re-renders the whole app on every update. This makes writing applications a lot easier but is also an incredible challenge to make it tractable. This article explains how with powerful heuristics we managed to turn a O(n<sup>3</sup>) problem into a O(n) one.
-
-
-## Motivation
-
-Generating the minimum number of operations to transform one tree into another is a complex and well-studied problem. The [state of the art algorithms](http://grfia.dlsi.ua.es/ml/algorithms/references/editsurvey_bille.pdf) have a complexity in the order of O(n<sup>3</sup>) where n is the number of nodes in the tree.
-
-This means that displaying 1000 nodes would require in the order of one billion comparisons. This is far too expensive for our use case. To put this number in perspective, CPUs nowadays execute roughly 3 billion instructions per second. So even with the most performant implementation, we wouldn't be able to compute that diff in less than a second.
-
-Since an optimal algorithm is not tractable, we implement a non-optimal O(n) algorithm using heuristics based on two assumptions:
-
-1. Two components of the same class will generate similar trees and two components of different classes will generate different trees.
-2. It is possible to provide a unique key for elements that is stable across different renders.
-
-In practice, these assumptions are ridiculously fast for almost all practical use cases.
-
-
-## Pair-wise diff
-
-In order to do a tree diff, we first need to be able to diff two nodes. There are three different cases being handled.
-
-
-### Different Node Types
-
-If the node type is different, React is going to treat them as two different sub-trees, throw away the first one and build/insert the second one.
-
-```xml
-renderA: <div />
-renderB: <span />
-=> [removeNode <div />], [insertNode <span />]
-```
-
-The same logic is used for custom components. If they are not of the same type, React is not going to even try at matching what they render. It is just going to remove the first one from the DOM and insert the second one.
-
-```xml
-renderA: <Header />
-renderB: <Content />
-=> [removeNode <Header />], [insertNode <Content />]
-```
-
-Having this high level knowledge is a very important aspect of why React's diff algorithm is both fast and precise. It provides a good heuristic to quickly prune big parts of the tree and focus on parts likely to be similar.
-
-It is very unlikely that a `<Header>` element is going to generate a DOM that is going to look like what a `<Content>` would generate. Instead of spending time trying to match those two structures, React just re-builds the tree from scratch.
-
-As a corollary, if there is a `<Header>` element at the same position in two consecutive renders, you would expect to see a very similar structure and it is worth exploring it.
-
-
-### DOM Nodes
-
-When comparing two DOM nodes, we look at the attributes of both and can decide which of them changed in linear time.
-
-```xml
-renderA: <div id="before" />
-renderB: <div id="after" />
-=> [replaceAttribute id "after"]
-```
-
-Instead of treating style as an opaque string, a key-value object is used instead. This lets us update only the properties that changed.
-
-```xml
-renderA: <div style={{'{{'}}color: 'red'}} />
-renderB: <div style={{'{{'}}fontWeight: 'bold'}} />
-=> [removeStyle color], [addStyle font-weight 'bold']
-```
-
-After the attributes have been updated, we recurse on all the children.
-
-
-### Custom Components
-
-We decided that the two custom components are the same. Since components are stateful, we cannot just use the new component and call it a day. React takes all the attributes from the new component and calls `componentWillReceiveProps()` and `componentWillUpdate()` on the previous one.
-
-The previous component is now operational. Its `render()` method is called and the diff algorithm restarts with the new result and the previous result.
-
-
-## List-wise diff
-
-### Problematic Case
-
-In order to do children reconciliation, React adopts a very naive approach. It goes over both lists of children at the same time and generates a mutation whenever there's a difference.
-
-For example if you add an element at the end:
-
-```xml
-renderA: <div><span>first</span></div>
-renderB: <div><span>first</span><span>second</span></div>
-=> [insertNode <span>second</span>]
-```
-
-Inserting an element at the beginning is problematic. React is going to see that both nodes are spans and therefore run into a mutation mode.
-
-```xml
-renderA: <div><span>first</span></div>
-renderB: <div><span>second</span><span>first</span></div>
-=> [replaceAttribute textContent 'second'], [insertNode <span>first</span>]
-```
-
-There are many algorithms that attempt to find the minimum sets of operations to transform a list of elements. [Levenshtein distance](https://en.wikipedia.org/wiki/Levenshtein_distance) can find the minimum using single element insertion, deletion and substitution in O(n<sup>2</sup>). Even if we were to use Levenshtein, this doesn't find when a node has moved into another position and algorithms to do that have much worse complexity.
-
-### Keys
-
-In order to solve this seemingly intractable issue, an optional attribute has been introduced. You can provide for each child a key that is going to be used to do the matching. If you specify a key, React is now able to find insertion, deletion, substitution and moves in O(n) using a hash table.
-
-
-```xml
-renderA: <div><span key="first">first</span></div>
-renderB: <div><span key="second">second</span><span key="first">first</span></div>
-=> [insertNode <span>second</span>]
-```
-
-In practice, finding a key is not really hard. Most of the time, the element you are going to display already has a unique id. When that's not the case, you can add a new ID property to your model or hash some parts of the content to generate a key. Remember that the key only has to be unique among its siblings, not globally unique.
-
-
-## Trade-offs
-
-It is important to remember that the reconciliation algorithm is an implementation detail. React could re-render the whole app on every action; the end result would be the same. We are regularly refining the heuristics in order to make common use cases faster.
-
-In the current implementation, you can express the fact that a sub-tree has been moved amongst its siblings, but you cannot tell that it has moved somewhere else. The algorithm will re-render that full sub-tree.
-
-Because we rely on two heuristics, if the assumptions behind them are not met, performance will suffer.
-
-1. The algorithm will not try to match sub-trees of different components classes. If you see yourself alternating between two components classes with very similar output, you may want to make it the same class. In practice, we haven't found this to be an issue.
-
-2. Keys should be stable, predictable, and unique. Unstable keys (like those produced by Math.random()) will cause many nodes to be unnecessarily re-created, which can cause performance degradation and lost state in child components.
-
diff --git a/docs/docs/ref-09-webcomponents.md b/docs/docs/ref-09-webcomponents.md
deleted file mode 100644
index 3442bcfccd31..000000000000
--- a/docs/docs/ref-09-webcomponents.md
+++ /dev/null
@@ -1,56 +0,0 @@
----
-id: webcomponents
-title: Web Components
-permalink: webcomponents.html
-prev: reconciliation.html
-next: glossary.html
----
-
-Trying to compare and contrast React with WebComponents inevitably results in specious conclusions, because the two libraries are built to solve different problems.  WebComponents provide strong encapsulation for reusable components, while React provides a declarative library that keeps the DOM in sync with your data.  The two goals are complementary; engineers can mix-and-match the technologies.  As a developer, you are free to use React in your WebComponents, or to use WebComponents in React, or both.
-
-## Using Web Components in React
-
-```javascript
-class HelloMessage extends React.Component{
-  render() {
-    return <div>Hello <x-search>{this.props.name}</x-search>!</div>;
-  }
-}
-```
-
-> Note:
->
-> The programming models of the two component systems (web components vs. react components) differ in that
-> web components often expose an imperative API (for instance, a `video` web component might expose `play()`
-> and `pause()` functions).  To the extent that web components are declarative functions of their attributes,
-> they should work, but to access the imperative APIs of a web component, you will need to attach a ref to the
-> component and interact with the DOM node directly.  If you are using third-party web components, the
-> recommended solution is to write a React component that behaves as a wrapper for your web component.
-> 
-> At this time, events emitted by a web component may not properly propagate through a React render tree.
-> You will need to manually attach event handlers to handle these events within your React components.
-
-
-## Using React in your Web Components
-
-
-```javascript
-var proto = Object.create(HTMLElement.prototype, {
-  createdCallback: {
-    value: function() {
-      var mountPoint = document.createElement('span');
-      this.createShadowRoot().appendChild(mountPoint);
-
-      var name = this.getAttribute('name');
-      var url = 'https://www.google.com/search?q=' + encodeURIComponent(name);
-      ReactDOM.render(<a href={url}>{name}</a>, mountPoint);
-    }
-  }
-});
-document.registerElement('x-search', {prototype: proto});
-```
-
-## Complete Example
-
-Check out the `webcomponents` example in the [starter kit](/react/downloads.html) for a complete example.
-
diff --git a/docs/docs/ref-10-glossary.it-IT.md b/docs/docs/ref-10-glossary.it-IT.md
deleted file mode 100644
index 01af918ef6d0..000000000000
--- a/docs/docs/ref-10-glossary.it-IT.md
+++ /dev/null
@@ -1,192 +0,0 @@
----
-id: glossary-it-IT
-title: Terminologia del DOM (Virtuale)
-permalink: glossary-it-IT.html
-prev: webcomponents.html
----
-
-Nella terminologia di React, esistono cinque tipi base che è importante distinguere:
-
-- [ReactElement / ReactElement Factory](#react-elements)
-- [ReactNode](#react-nodes)
-- [ReactComponent / ReactComponent Class](#react-components)
-
-## Elementi React
-
-Il tipo primario in React è il `ReactElement`. Possiede quattro proprietà: `type`, `props`, `key` e `ref`. Non possiede alcun metodo e non espone nulla sul prototype.
-
-Puoi creare uno di questi oggetti attraverso `React.createElement`.
-
-```javascript
-var root = React.createElement('div');
-```
-
-Per effettuare il rendering di un nuovo albero nel DOM, crei dei `ReactElement` ande li passi a `ReactDOM.render` assieme a un `Element` DOM regolare (`HTMLElement` o `SVGElement`). I `ReactElement` non vanno confusi con gli `Element` del DOM. Un `ReactElement` è una rappresentazione leggera, priva di stato, immutabile e virtuale di un `Element` del DOM. È un DOM virtuale.
-
-```javascript
-ReactDOM.render(root, document.getElementById('example'));
-```
-
-Per aggiungere proprietà ad un elemento DOM, passa un oggetto di proprietà come secondo argomento, e i figli come terzo argomento.
-
-```javascript
-var child = React.createElement('li', null, 'Contenuto di Testo');
-var root = React.createElement('ul', { className: 'my-list' }, child);
-ReactDOM.render(root, document.getElementById('example'));
-```
-
-Se usi React JSX, allora questi `ReactElement` verranno creati per te. Questa espressione è equivalente:
-
-```javascript
-var root = <ul className="my-list">
-             <li>Contenuto di Testo</li>
-           </ul>;
-ReactDOM.render(root, document.getElementById('example'));
-```
-
-### Le Factory
-
-Una factory di `ReactElement` è semplicemente una funzione che genera un  `ReactElement` con una particolare proprietà `type`. React ha uno helper integrato per permetterti di creare factory. La sua implementazione è semplicemente:
-
-```javascript
-function createFactory(type) {
-  return React.createElement.bind(null, type);
-}
-```
-
-Ti permette di creare una conveniente scorciatoia anziché scrivere ogni volta `React.createElement('div')`.
-
-```javascript
-var div = React.createFactory('div');
-var root = div({ className: 'my-div' });
-ReactDOM.render(root, document.getElementById('example'));
-```
-
-React possiede già factory integrate per tag HTML comuni:
-
-```javascript
-var root = React.DOM.ul({ className: 'my-list' },
-             React.DOM.li(null, 'Contenuto di Testo')
-           );
-```
-
-Se stai usando JSX non hai bisogno di factory. JSX fornisce già una conveniente scorciatoia per creare `ReactElement`.
-
-
-## Nodi React
-
-Un `ReactNode` può essere uno tra:
-
-- `ReactElement`
-- `string` (ovvero `ReactText`)
-- `number` (ovvero `ReactText`)
-- Array di `ReactNode` (ovvero `ReactFragment`)
-
-Questi sono usati come proprietà di altri `ReactElement` per rappresentare i figli. Effettivamente creano un albero di `ReactElement`.
-
-
-## Componenti React
-
-Puoi usare React usando soltanto `ReactElement`, ma per avvantaggiarti seriamente di  React vorrai usare i `ReactComponent` per creare incapsulamento con uno stato incluso.
-
-Una classe `ReactComponent` è semplicemente una classe JavaScript (o una "funzione costruttore").
-
-```javascript
-var MyComponent = React.createClass({
-  render: function() {
-    ...
-  }
-});
-```
-
-Quando questo costruttore è invocato, ci si aspetta che restituisca un oggetto con almeno un metodo `render`. Questo oggetto è chiamato `ReactComponent`.
-
-```javascript
-var component = new MyComponent(props); // non farlo mai!
-```
-
-Per scopi diversi dai test, *non chiamerai mai* questo costruttore direttamente. React lo chiamerà per te.
-
-Invece, passa una classe `ReactComponent` a `createElement` per ottenere un `ReactElement`.
-
-```javascript
-var element = React.createElement(MyComponent);
-```
-
-OPPURE usando JSX:
-
-```javascript
-var element = <MyComponent />;
-```
-
-Quando `element` viene passato a `ReactDOM.render`, React chiamerà il costruttore al tuo posto e creerà un`ReactComponent`, che verrà restituito.
-
-```javascript
-var component = ReactDOM.render(element, document.getElementById('example'));
-```
-
-Se chiami ripetutamente `ReactDOM.render` con lo stesso tipo di `ReactElement` e lo stesso `Element` DOM come contenitore, ti restituirà sempre la stessa istanza. Questa istanza è dotata di stato.
-
-```javascript
-var componentA = ReactDOM.render(<MyComponent />, document.getElementById('example'));
-var componentB = ReactDOM.render(<MyComponent />, document.getElementById('example'));
-componentA === componentB; // true
-```
-
-Questo è il motivo per cui non dovresti mai costruire la tua istanza. Invece, `ReactElement` è un `ReactComponent` virtuale prima che venga costruito. Un vecchio `ReactElement` e uno nuovo possono essere confrontati per vedere se una nuova istanza di `ReactComponent` è stata creata o quella esistente è stata riutilizzata.
-
-Ci si aspetta che il metodo `render` di un `ReactComponent` restituisca un altro `ReactElement`. Ciò permette a questi componenti di essere composti. In ultima analisi, il rendering si risolve in un `ReactElement` con un tag `string` che viene istanziato come un `Element` DOM e viene inserito nel documento.
-
-
-## Definizioni Formali dei Tipi
-
-### Punto di Entrata
-
-```
-ReactDOM.render = (ReactElement, HTMLElement | SVGElement) => ReactComponent;
-```
-
-### Nodi ed Elementi
-
-```
-type ReactNode = ReactElement | ReactFragment | ReactText;
-
-type ReactElement = ReactComponentElement | ReactDOMElement;
-
-type ReactDOMElement = {
-  type : string,
-  props : {
-    children : ReactNodeList,
-    className : string,
-    etc.
-  },
-  key : string | boolean | number | null,
-  ref : string | null
-};
-
-type ReactComponentElement<TProps> = {
-  type : ReactClass<TProps>,
-  props : TProps,
-  key : string | boolean | number | null,
-  ref : string | null
-};
-
-type ReactFragment = Array<ReactNode | ReactEmpty>;
-
-type ReactNodeList = ReactNode | ReactEmpty;
-
-type ReactText = string | number;
-
-type ReactEmpty = null | undefined | boolean;
-```
-
-### Classi e Componenti
-
-```
-type ReactClass<TProps> = (TProps) => ReactComponent<TProps>;
-
-type ReactComponent<TProps> = {
-  props : TProps,
-  render : () => ReactElement
-};
-```
diff --git a/docs/docs/ref-10-glossary.ko-KR.md b/docs/docs/ref-10-glossary.ko-KR.md
deleted file mode 100644
index 01131040d95f..000000000000
--- a/docs/docs/ref-10-glossary.ko-KR.md
+++ /dev/null
@@ -1,193 +0,0 @@
----
-id: glossary-ko-KR
-title: React (가상) DOM 용어
-permalink: glossary-ko-KR.html
-prev: webcomponents-ko-KR.html
----
-
-다음은 React에서 사용되는 용어들로, 이 다섯 가지의 타입을 구별하는 것은 중요합니다.
-
-- [ReactElement / ReactElement 팩토리](#react-elements)
-- [ReactNode](#react-nodes)
-- [ReactComponent / ReactComponent 클래스](#react-components)
-
-## React 엘리먼트
-
-`ReactElement`는 React의 주요 타입입니다. `type`, `props`, `key`, `ref`의 네 가지 프로퍼티를 가집니다. 메소드는 가지지 않으며 프로토타입에는 아무 것도 들어있지 않습니다.
-
-이러한 객체는 `React.createElement`를 통해 만들 수 있습니다.
-
-```javascript
-var root = React.createElement('div');
-```
-
-DOM에 새로운 트리를 렌더링하기 위해서는 `ReactElement`를 만들고 일반적인 DOM `Element` (`HTMLElement` 또는 `SVGElement`)와 함께 `ReactDOM.render`에 넘깁니다. `ReactElement`를 DOM `Element`와 혼동해서는 안됩니다. `ReactElement`는 가볍고, 상태를 갖지 않으며, 변경 불가능한, DOM `Element`의 가상 표현입니다. 즉 가상 DOM입니다.
-
-```javascript
-ReactDOM.render(root, document.getElementById('example'));
-```
-
-DOM 엘리먼트에 프로퍼티를 추가하려면 두번째 인자로 프로퍼티 객체를, 세번째 인자로 자식을 넘깁니다.
-
-```javascript
-var child = React.createElement('li', null, 'Text Content');
-var root = React.createElement('ul', { className: 'my-list' }, child);
-ReactDOM.render(root, document.getElementById('example'));
-```
-
-React JSX를 사용하면 `ReactElement`가 알아서 만들어집니다. 따라서 다음 코드는 앞의 코드와 같습니다:
-
-```javascript
-var root = <ul className="my-list">
-             <li>Text Content</li>
-           </ul>;
-ReactDOM.render(root, document.getElementById('example'));
-```
-
-### 팩토리
-
-`ReactElement` 팩토리는 그저 특정한 `type` 프로퍼티를 가지는 `ReactElement`를 만들어주는 함수입니다. React에는 팩토리를 만드는 헬퍼가 내장되어 있습니다. 그 함수는 사실상 다음과 같습니다:
-
-```javascript
-function createFactory(type) {
-  return React.createElement.bind(null, type);
-}
-```
-
-이를 이용하면 편리한 단축 함수를 만들 수 있어 항상 `React.createElement('div')`를 입력하지 않아도 됩니다.
-
-```javascript
-var div = React.createFactory('div');
-var root = div({ className: 'my-div' });
-ReactDOM.render(root, document.getElementById('example'));
-```
-
-React에는 이미 보통의 HTML 태그를 위한 팩토리가 내장되어 있습니다:
-
-```javascript
-var root = React.DOM.ul({ className: 'my-list' },
-             React.DOM.li(null, 'Text Content')
-           );
-```
-
-JSX를 사용하면 팩토리가 필요하지 않습니다. 이미 JSX가 `ReactElement`를 만드는 편리한 단축 문법을 제공합니다.
-
-
-## React 노드
-
-`ReactNode`는 다음 중 하나가 될 수 있습니다:
-
-- `ReactElement`
-- `string` (`ReactText`로 부르기도 함)
-- `number` (`ReactText`로 부르기도 함)
-- `ReactNode`의 배열 (`ReactFragment`로 부르기도 함)
-
-이들은 자식을 표현하기 위해 다른 `ReactElement`의 프로퍼티에 사용됩니다. 사실상 이들이 `ReactElement`의 트리를 형성합니다.
-
-
-## React 컴포넌트
-
-`ReactElement`만 가지고도 React를 사용할 수는 있지만, React의 장점을 제대로 활용하려면 `ReactComponent`를 사용하여 상태를 가진 캡슐화된 객체를 만들기를 원할 것입니다.
-
-`ReactComponent` 클래스는 그냥 JavaScript 클래스 (또는 "생성자 함수")입니다.
-
-```javascript
-var MyComponent = React.createClass({
-  render: function() {
-    ...
-  }
-});
-```
-
-이 생성자가 호출될 때 최소한 `render` 메소드를 가진 객체를 리턴해야 합니다. 이 리턴된 객체를 `ReactComponent`라고 부릅니다.
-
-```javascript
-var component = new MyComponent(props); // 절대 하지 마세요.
-```
-
-테스트 목적이 아니라면 *절대* 이 생성자를 직접 호출하지 마십시오. React가 알아서 호출해줍니다.
-
-대신 `ReactComponent` 클래스를 `createElement`에 넘겨 `ReactElement`를 받을 수 있습니다.
-
-```javascript
-var element = React.createElement(MyComponent);
-```
-
-또는 JSX를 사용하면:
-
-```javascript
-var element = <MyComponent />;
-```
-
-이것이 `ReactDOM.render`에 넘겨지면 React가 알아서 생성자를 호출하여 `ReactComponent`를 만들고 리턴합니다.
-
-```javascript
-var component = ReactDOM.render(element, document.getElementById('example'));
-```
-
-같은 타입의 `ReactElement`와 같은 컨테이너 DOM `Element`를 가지고 `ReactDOM.render`를 계속 호출하면 항상 같은 인스턴스를 리턴합니다. 이 인스턴스는 상태를 가집니다.
-
-```javascript
-var componentA = ReactDOM.render(<MyComponent />, document.getElementById('example'));
-var componentB = ReactDOM.render(<MyComponent />, document.getElementById('example'));
-componentA === componentB; // true
-```
-
-그렇기 때문에 직접 인스턴스를 만들어서는 안됩니다. `ReactComponent`가 생성되기 전에 `ReactElement`가 대신 가상의 `ReactComponent` 역할을 합니다. 이전 `ReactElement`와 새 `ReactElement`를 비교하여 새로운 `ReactComponent`를 만들지, 아니면 기존 것을 재사용할지 결정합니다.
-
-`ReactComponent`의 `render` 메소드는 또다른 `ReactElement`를 리턴해야 합니다. 이렇게 해서 컴포넌트들이 조합됩니다. 결과적으로 렌더링 과정은 다음과 같습니다. `string` 타입의 태그를 가진 `ReactElement`를 통해 DOM `Element` 인스턴스가 생성되며 문서에 삽입됩니다.
-
-
-## 형식 타입 정의
-
-### 진입점
-
-```
-ReactDOM.render = (ReactElement, HTMLElement | SVGElement) => ReactComponent;
-```
-
-### 노드와 엘리먼트
-
-```
-type ReactNode = ReactElement | ReactFragment | ReactText;
-
-type ReactElement = ReactComponentElement | ReactDOMElement;
-
-type ReactDOMElement = {
-  type : string,
-  props : {
-    children : ReactNodeList,
-    className : string,
-    etc.
-  },
-  key : string | boolean | number | null,
-  ref : string | null
-};
-
-type ReactComponentElement<TProps> = {
-  type : ReactClass<TProps>,
-  props : TProps,
-  key : string | boolean | number | null,
-  ref : string | null
-};
-
-type ReactFragment = Array<ReactNode | ReactEmpty>;
-
-type ReactNodeList = ReactNode | ReactEmpty;
-
-type ReactText = string | number;
-
-type ReactEmpty = null | undefined | boolean;
-```
-
-### 클래스와 컴포넌트
-
-```
-type ReactClass<TProps> = (TProps) => ReactComponent<TProps>;
-
-type ReactComponent<TProps> = {
-  props : TProps,
-  render : () => ReactElement
-};
-```
-
diff --git a/docs/docs/ref-10-glossary.md b/docs/docs/ref-10-glossary.md
deleted file mode 100644
index f5e5533053e3..000000000000
--- a/docs/docs/ref-10-glossary.md
+++ /dev/null
@@ -1,193 +0,0 @@
----
-id: glossary
-title: React (Virtual) DOM Terminology
-permalink: glossary.html
-prev: webcomponents.html
----
-
-In React's terminology, there are five core types that are important to distinguish:
-
-- [ReactElement / ReactElement Factory](#react-elements)
-- [ReactNode](#react-nodes)
-- [ReactComponent / ReactComponent Class](#react-components)
-
-## React Elements
-
-The primary type in React is the `ReactElement`. It has four properties: `type`, `props`, `key` and `ref`. It has no methods and nothing on the prototype.
-
-You can create one of these objects through `React.createElement`.
-
-```javascript
-var root = React.createElement('div');
-```
-
-To render a new tree into the DOM, you create `ReactElement`s and pass them to `ReactDOM.render` along with a regular DOM `Element` (`HTMLElement` or `SVGElement`). `ReactElement`s are not to be confused with DOM `Element`s. A `ReactElement` is a light, stateless, immutable, virtual representation of a DOM `Element`. It is a virtual DOM.
-
-```javascript
-ReactDOM.render(root, document.getElementById('example'));
-```
-
-To add properties to a DOM element, pass a properties object as the second argument and children to the third argument.
-
-```javascript
-var child = React.createElement('li', null, 'Text Content');
-var root = React.createElement('ul', { className: 'my-list' }, child);
-ReactDOM.render(root, document.getElementById('example'));
-```
-
-If you use React JSX, then these `ReactElement`s are created for you. So this is equivalent:
-
-```javascript
-var root = <ul className="my-list">
-             <li>Text Content</li>
-           </ul>;
-ReactDOM.render(root, document.getElementById('example'));
-```
-
-### Factories
-
-A `ReactElement`-factory is simply a function that generates a `ReactElement` with a particular `type` property. React has a built-in helper for you to create factories. It's effectively just:
-
-```javascript
-function createFactory(type) {
-  return React.createElement.bind(null, type);
-}
-```
-
-It allows you to create a convenient short-hand instead of typing out `React.createElement('div')` all the time.
-
-```javascript
-var div = React.createFactory('div');
-var root = div({ className: 'my-div' });
-ReactDOM.render(root, document.getElementById('example'));
-```
-
-React already has built-in factories for common HTML tags:
-
-```javascript
-var root = React.DOM.ul({ className: 'my-list' },
-             React.DOM.li(null, 'Text Content')
-           );
-```
-
-If you are using JSX you have no need for factories. JSX already provides a convenient short-hand for creating `ReactElement`s.
-
-
-## React Nodes
-
-A `ReactNode` can be either:
-
-- `ReactElement`
-- `string` (aka `ReactText`)
-- `number` (aka `ReactText`)
-- Array of `ReactNode`s (aka `ReactFragment`)
-
-These are used as properties of other `ReactElement`s to represent children. Effectively they create a tree of `ReactElement`s.
-
-
-## React Components
-
-You can use React using only `ReactElement`s but to really take advantage of React, you'll want to use `ReactComponent`s to create encapsulations with embedded state.
-
-A `ReactComponent` Class is simply just a JavaScript class (or "constructor function").
-
-```javascript
-var MyComponent = React.createClass({
-  render: function() {
-    ...
-  }
-});
-```
-
-When this constructor is invoked it is expected to return an object with at least a `render` method on it. This object is referred to as a `ReactComponent`.
-
-```javascript
-var component = new MyComponent(props); // never do this
-```
-
-Other than for testing, you would normally *never* call this constructor yourself. React calls it for you.
-
-Instead, you pass the `ReactComponent` Class to `createElement` you get a `ReactElement`.
-
-```javascript
-var element = React.createElement(MyComponent);
-```
-
-OR using JSX:
-
-```javascript
-var element = <MyComponent />;
-```
-
-When this is passed to `ReactDOM.render`, React will call the constructor for you and create a `ReactComponent`, which is returned.
-
-```javascript
-var component = ReactDOM.render(element, document.getElementById('example'));
-```
-
-If you keep calling `ReactDOM.render` with the same type of `ReactElement` and the same container DOM `Element` it always returns the same instance. This instance is stateful.
-
-```javascript
-var componentA = ReactDOM.render(<MyComponent />, document.getElementById('example'));
-var componentB = ReactDOM.render(<MyComponent />, document.getElementById('example'));
-componentA === componentB; // true
-```
-
-This is why you shouldn't construct your own instance. Instead, `ReactElement` is a virtual `ReactComponent` before it gets constructed. An old and new `ReactElement` can be compared to see if a new `ReactComponent` instance should be created or if the existing one should be reused.
-
-The `render` method of a `ReactComponent` is expected to return another `ReactElement`. This allows these components to be composed. Ultimately the render resolves into `ReactElement` with a `string` tag which instantiates a DOM `Element` instance and inserts it into the document.
-
-
-## Formal Type Definitions
-
-### Entry Point
-
-```
-ReactDOM.render = (ReactElement, HTMLElement | SVGElement) => ReactComponent;
-```
-
-### Nodes and Elements
-
-```
-type ReactNode = ReactElement | ReactFragment | ReactText;
-
-type ReactElement = ReactComponentElement | ReactDOMElement;
-
-type ReactDOMElement = {
-  type : string,
-  props : {
-    children : ReactNodeList,
-    className : string,
-    etc.
-  },
-  key : string | boolean | number | null,
-  ref : string | null
-};
-
-type ReactComponentElement<TProps> = {
-  type : ReactClass<TProps>,
-  props : TProps,
-  key : string | boolean | number | null,
-  ref : string | null
-};
-
-type ReactFragment = Array<ReactNode | ReactEmpty>;
-
-type ReactNodeList = ReactNode | ReactEmpty;
-
-type ReactText = string | number;
-
-type ReactEmpty = null | undefined | boolean;
-```
-
-### Classes and Components
-
-```
-type ReactClass<TProps> = (TProps) => ReactComponent<TProps>;
-
-type ReactComponent<TProps> = {
-  props : TProps,
-  render : () => ReactElement
-};
-```
-
diff --git a/docs/docs/ref-10-glossary.zh-CN.md b/docs/docs/ref-10-glossary.zh-CN.md
deleted file mode 100644
index 40f61c62b502..000000000000
--- a/docs/docs/ref-10-glossary.zh-CN.md
+++ /dev/null
@@ -1,193 +0,0 @@
----
-id: glossary-zh-CN
-title: React (虚拟) DOM 术语
-permalink: glossary-zh-CN.html
-prev: webcomponents-zh-CN.html
----
-
-在 React 的术语中,有五个要重点区分的核心类型:
-
-- [ReactElement / ReactElement Factory](#react-elements)
-- [ReactNode](#react-nodes)
-- [ReactComponent / ReactComponent Class](#react-components)
-
-## React Elements(React 元素)
-
-React里的首要类型是 `ReactElement`.它有四个 properties:`type`, `props`, `key` 和 `ref`.它没有方法,在 prototype 上什么也没有.
-
-你可以通过 `React.createElement` 来创建这些对象.
-
-```javascript
-var root = React.createElement('div');
-```
-
-要渲染一个新的树到DOM上,你创建 `ReactElement`s 并传递他们到 `ReactDOM.render` 伴随着一个标准的 DOM `Element` (`HTMLElement` 或 `SVGElement`).`ReactElement`s 不要与 DOM `Element`s 混淆.`ReactElement` 是一个轻的,有状态的,不可变的,虚拟的DOM `Element` 的表达.它是一个虚拟 DOM.
-
-```javascript
-ReactDOM.render(root, document.getElementById('example'));
-```
-
-要给一个DOM元素添加 properties,传递一个properties 对象作为第二个参数,第三个参数传递子级.
-
-```javascript
-var child = React.createElement('li', null, 'Text Content');
-var root = React.createElement('ul', { className: 'my-list' }, child);
-ReactDOM.render(root, document.getElementById('example'));
-```
-
-如果你使用 React JSX,这些`ReactElement`s 已经为你创建了.所以 这是等价的:
-
-```javascript
-var root = <ul className="my-list">
-             <li>Text Content</li>
-           </ul>;
-ReactDOM.render(root, document.getElementById('example'));
-```
-
-### Factories(工厂)
-
-`ReactElement`-工厂 是一个产生特定 `type` property的 `ReactElement` 的函数.React有一个为你内建的辅助工具来创建工厂.它想这样起作用:
-
-```javascript
-function createFactory(type) {
-  return React.createElement.bind(null, type);
-}
-```
-
-它允许你创建一个方便的速记 来代替每次输入 `React.createElement('div')` .
-
-```javascript
-var div = React.createFactory('div');
-var root = div({ className: 'my-div' });
-ReactDOM.render(root, document.getElementById('example'));
-```
-
-React 已经具备用于常用 HTML tags的内建工厂
-
-```javascript
-var root = React.DOM.ul({ className: 'my-list' },
-             React.DOM.li(null, 'Text Content')
-           );
-```
-
-如果你使用JSX 你没有必要使用工厂.JSX已经为创建 `ReactElement`s 提供了一个 方便的速记.
-
-
-## React Nodes
-
-一个 `ReactNode` 可以是:
-
-- `ReactElement`
-- `string` (aka `ReactText`)
-- `number` (aka `ReactText`)
-- Array of `ReactNode`s (aka `ReactFragment`)
-
-他们被用作其他`ReactElement`s的properties来表示子级.事实上他们创建了一个 `ReactElement`s 的树.
-
-
-## React Components
-
-你可以使用 React只使用`ReactElement`s 但是要真正利用React,你将要使用 `ReactComponent`s 来创建内嵌 state 的封装.
-
-一个 `ReactComponent` 类就是一个 JavaScript 类 (或者 "constructor function").
-
-```javascript
-var MyComponent = React.createClass({
-  render: function() {
-    ...
-  }
-});
-```
-
-当这个构造函数被调用,期望返回一个至少有一个 `render` 方法的对象.这个对象被称为一个 `ReactComponent`.
-
-```javascript
-var component = new MyComponent(props); // never do this
-```
-
-与测试不同,你可能通常 *绝不会* 亲自调用这个构造函数.React 为你调用它.
-
-作为替代,你传递 `ReactComponent` 类到 `createElement`,你得到一个 `ReactElement`.
-
-```javascript
-var element = React.createElement(MyComponent);
-```
-
-或者用 JSX:
-
-```javascript
-var element = <MyComponent />;
-```
-
-当这个被传给 `ReactDOM.render`,React 会为你调用构造函数并创建一个 `ReactComponent`,返回给你.
-
-```javascript
-var component = ReactDOM.render(element, document.getElementById('example'));
-```
-
-如果你保持用相同类型的 `ReactElement` 和相同的DOM `Element`容器调用 `ReactDOM.render` ,它总是会返回相同的实例.这个实例是状态化的.
-
-```javascript
-var componentA = ReactDOM.render(<MyComponent />, document.getElementById('example'));
-var componentB = ReactDOM.render(<MyComponent />, document.getElementById('example'));
-componentA === componentB; // true
-```
-
-这就是为什么你不应该构造你自己的实例.作为替代,`ReactElement` 在它被构造以前 是一个虚拟的 `ReactComponent`.一个老的和新的`ReactElement` 可以被比较来判断 一个新的 `ReactComponent` 实例是否需要被创建或者已经存在的是否应该被重用.
-
- `ReactComponent` 的 `render` 方法被期望返回另一个 `ReactElement`.这允许这些组件被结构化.最后,渲染分解为 带着一个 `string` tag的`ReactElement`,它实例化一个 DOM `Element` 实例并把它插入document里.
-
-
-## Formal Type Definitions
-
-### Entry Point
-
-```
-ReactDOM.render = (ReactElement, HTMLElement | SVGElement) => ReactComponent;
-```
-
-### Nodes and Elements
-
-```
-type ReactNode = ReactElement | ReactFragment | ReactText;
-
-type ReactElement = ReactComponentElement | ReactDOMElement;
-
-type ReactDOMElement = {
-  type : string,
-  props : {
-    children : ReactNodeList,
-    className : string,
-    etc.
-  },
-  key : string | boolean | number | null,
-  ref : string | null
-};
-
-type ReactComponentElement<TProps> = {
-  type : ReactClass<TProps>,
-  props : TProps,
-  key : string | boolean | number | null,
-  ref : string | null
-};
-
-type ReactFragment = Array<ReactNode | ReactEmpty>;
-
-type ReactNodeList = ReactNode | ReactEmpty;
-
-type ReactText = string | number;
-
-type ReactEmpty = null | undefined | boolean;
-```
-
-### Classes and Components
-
-```
-type ReactClass<TProps> = (TProps) => ReactComponent<TProps>;
-
-type ReactComponent<TProps> = {
-  props : TProps,
-  render : () => ReactElement
-};
-```
-
diff --git a/docs/docs/reference-dom-elements.md b/docs/docs/reference-dom-elements.md
new file mode 100644
index 000000000000..1f32eb22bb63
--- /dev/null
+++ b/docs/docs/reference-dom-elements.md
@@ -0,0 +1,174 @@
+---
+id: dom-elements
+title: DOM Elements
+layout: docs
+category: Reference
+permalink: docs/dom-elements.html
+redirect_from:
+  - "docs/tags-and-attributes.html"
+  - "docs/dom-differences.html"
+  - "docs/special-non-dom-attributes.html"
+  - "docs/class-name-manipulation.html"
+  - "tips/inline-styles.html"
+  - "tips/style-props-value-px.html"
+  - "tips/dangerously-set-inner-html.html"
+---
+
+React implements a browser-independent DOM system for performance and cross-browser compatibility. We took the opportunity to clean up a few rough edges in browser DOM implementations.
+
+In React, all DOM properties and attributes (including event handlers) should be camelCased. For example, the HTML attribute `tabindex` corresponds to the attribute `tabIndex` in React. The exception is `aria-*` and `data-*` attributes, which should be lowercased. For example, you can keep `aria-label` as `aria-label`.
+
+## Differences In Attributes
+
+There are a number of attributes that work differently between React and HTML:
+
+### checked
+
+The `checked` attribute is supported by `<input>` components of type `checkbox` or `radio`. You can use it to set whether the component is checked. This is useful for building controlled components. `defaultChecked` is the uncontrolled equivalent, which sets whether the component is checked when it is first mounted.
+
+### className
+
+To specify a CSS class, use the `className` attribute. This applies to all regular DOM and SVG elements like `<div>`, `<a>`, and others.
+
+If you use React with Web Components (which is uncommon), use the `class` attribute instead.
+
+### dangerouslySetInnerHTML
+
+`dangerouslySetInnerHTML` is React's replacement for using `innerHTML` in the browser DOM. In general, setting HTML from code is risky because it's easy to inadvertently expose your users to a [cross-site scripting (XSS)](https://en.wikipedia.org/wiki/Cross-site_scripting) attack. So, you can set HTML directly from React, but you have to type out `dangerouslySetInnerHTML` and pass an object with a `__html` key, to remind yourself that it's dangerous. For example:
+
+```js
+function createMarkup() {
+  return {__html: 'First &middot; Second'};
+}
+
+function MyComponent() {
+  return <div dangerouslySetInnerHTML={createMarkup()} />;
+}
+```
+
+### htmlFor
+
+Since `for` is a reserved word in JavaScript, React elements use `htmlFor` instead.
+
+### onChange
+
+The `onChange` event behaves as you would expect it to: whenever a form field is changed, this event is fired. We intentionally do not use the existing browser behavior because `onChange` is a misnomer for its behavior and React relies on this event to handle user input in real time.
+
+### selected
+
+The `selected` attribute is supported by `<option>` components. You can use it to set whether the component is selected. This is useful for building controlled components.
+
+### style
+
+The `style` attribute accepts a JavaScript object with camelCased properties rather than a CSS string. This is consistent with the DOM `style` JavaScript property, is more efficient, and prevents XSS security holes. For example:
+
+```js
+const divStyle = {
+  color: 'blue',
+  backgroundImage: 'url(' + imgUrl + ')',
+};
+
+function HelloWorldComponent() {
+  return <div style={divStyle}>Hello World!</div>;
+}
+```
+
+Note that styles are not autoprefixed. To support older browsers, you need to supply corresponding style properties:
+
+```js
+const divStyle = {
+  WebkitTransition: 'all', // note the capital 'W' here
+  msTransition: 'all' // 'ms' is the only lowercase vendor prefix
+};
+
+function ComponentWithTransition() {
+  return <div style={divStyle}>This should work cross-browser</div>;
+}
+```
+
+Style keys are camelCased in order to be consistent with accessing the properties on DOM nodes from JS (e.g. `node.style.backgroundImage`). Vendor prefixes [other than `ms`](http://www.andismith.com/blog/2012/02/modernizr-prefixed/) should begin with a capital letter. This is why `WebkitTransition` has an uppercase "W".
+
+### suppressContentEditableWarning
+
+Normally, there is a warning when an element with children is also marked as `contentEditable`, because it won't work. This attribute suppresses that warning. Don't use this unless you are building a library like [Draft.js](https://facebook.github.io/draft-js/) that manages `contentEditable` manually.
+
+### value
+
+The `value` attribute is supported by `<input>` and `<textarea>` components. You can use it to set the value of the component. This is useful for building controlled components. `defaultValue` is the uncontrolled equivalent, which sets the value of the component when it is first mounted.
+
+## All Supported HTML Attributes
+
+React supports all `data-*` and `aria-*` attributes as well as these attributes:
+
+```
+accept acceptCharset accessKey action allowFullScreen allowTransparency alt
+async autoComplete autoFocus autoPlay capture cellPadding cellSpacing challenge
+charSet checked cite classID className colSpan cols content contentEditable
+contextMenu controls coords crossOrigin data dateTime default defer dir
+disabled download draggable encType form formAction formEncType formMethod
+formNoValidate formTarget frameBorder headers height hidden high href hrefLang
+htmlFor httpEquiv icon id inputMode integrity is keyParams keyType kind label
+lang list loop low manifest marginHeight marginWidth max maxLength media
+mediaGroup method min minLength multiple muted name noValidate nonce open
+optimum pattern placeholder poster preload profile radioGroup readOnly rel
+required reversed role rowSpan rows sandbox scope scoped scrolling seamless
+selected shape size sizes span spellCheck src srcDoc srcLang srcSet start step
+style summary tabIndex target title type useMap value width wmode wrap
+```
+
+These RDFa attributes are supported (several RDFa attributes overlap with standard HTML attributes and thus are excluded from this list):
+
+```
+about datatype inlist prefix property resource typeof vocab
+```
+
+In addition, the following non-standard attributes are supported:
+
+- `autoCapitalize autoCorrect` for Mobile Safari.
+- `color` for `<link rel="mask-icon" />` in Safari.
+- `itemProp itemScope itemType itemRef itemID` for [HTML5 microdata](http://schema.org/docs/gs.html).
+- `security` for older versions of Internet Explorer.
+- `unselectable` for Internet Explorer.
+- `results autoSave` for WebKit/Blink input fields of type `search`.
+
+## All Supported SVG Attributes
+
+React supports these SVG attributes:
+
+```
+accentHeight accumulate additive alignmentBaseline allowReorder alphabetic
+amplitude arabicForm ascent attributeName attributeType autoReverse azimuth
+baseFrequency baseProfile baselineShift bbox begin bias by calcMode capHeight
+clip clipPath clipPathUnits clipRule colorInterpolation
+colorInterpolationFilters colorProfile colorRendering contentScriptType
+contentStyleType cursor cx cy d decelerate descent diffuseConstant direction
+display divisor dominantBaseline dur dx dy edgeMode elevation enableBackground
+end exponent externalResourcesRequired fill fillOpacity fillRule filter
+filterRes filterUnits floodColor floodOpacity focusable fontFamily fontSize
+fontSizeAdjust fontStretch fontStyle fontVariant fontWeight format from fx fy
+g1 g2 glyphName glyphOrientationHorizontal glyphOrientationVertical glyphRef
+gradientTransform gradientUnits hanging horizAdvX horizOriginX ideographic
+imageRendering in in2 intercept k k1 k2 k3 k4 kernelMatrix kernelUnitLength
+kerning keyPoints keySplines keyTimes lengthAdjust letterSpacing lightingColor
+limitingConeAngle local markerEnd markerHeight markerMid markerStart
+markerUnits markerWidth mask maskContentUnits maskUnits mathematical mode
+numOctaves offset opacity operator order orient orientation origin overflow
+overlinePosition overlineThickness paintOrder panose1 pathLength
+patternContentUnits patternTransform patternUnits pointerEvents points
+pointsAtX pointsAtY pointsAtZ preserveAlpha preserveAspectRatio primitiveUnits
+r radius refX refY renderingIntent repeatCount repeatDur requiredExtensions
+requiredFeatures restart result rotate rx ry scale seed shapeRendering slope
+spacing specularConstant specularExponent speed spreadMethod startOffset
+stdDeviation stemh stemv stitchTiles stopColor stopOpacity
+strikethroughPosition strikethroughThickness string stroke strokeDasharray
+strokeDashoffset strokeLinecap strokeLinejoin strokeMiterlimit strokeOpacity
+strokeWidth surfaceScale systemLanguage tableValues targetX targetY textAnchor
+textDecoration textLength textRendering to transform u1 u2 underlinePosition
+underlineThickness unicode unicodeBidi unicodeRange unitsPerEm vAlphabetic
+vHanging vIdeographic vMathematical values vectorEffect version vertAdvY
+vertOriginX vertOriginY viewBox viewTarget visibility widths wordSpacing
+writingMode x x1 x2 xChannelSelector xHeight xlinkActuate xlinkArcrole
+xlinkHref xlinkRole xlinkShow xlinkTitle xlinkType xmlns xmlnsXlink xmlBase
+xmlLang xmlSpace y y1 y2 yChannelSelector z zoomAndPan
+
+```
diff --git a/docs/docs/reference-events.md b/docs/docs/reference-events.md
new file mode 100644
index 000000000000..6e275db9b583
--- /dev/null
+++ b/docs/docs/reference-events.md
@@ -0,0 +1,340 @@
+---
+id: events
+title: SyntheticEvent
+permalink: docs/events.html
+layout: docs
+category: Reference
+---
+
+This reference guide documents the `SyntheticEvent` wrapper that forms part of React's Event System. See the [Handling Events](/react/docs/handling-events.html) guide to learn more.
+
+## Overview
+
+Your event handlers will be passed instances of `SyntheticEvent`, a cross-browser wrapper around the browser's native event. It has the same interface as the browser's native event, including `stopPropagation()` and `preventDefault()`, except the events work identically across all browsers.
+
+If you find that you need the underlying browser event for some reason, simply use the `nativeEvent` attribute to get it. Every `SyntheticEvent` object has the following attributes:
+
+```javascript
+boolean bubbles
+boolean cancelable
+DOMEventTarget currentTarget
+boolean defaultPrevented
+number eventPhase
+boolean isTrusted
+DOMEvent nativeEvent
+void preventDefault()
+boolean isDefaultPrevented()
+void stopPropagation()
+boolean isPropagationStopped()
+DOMEventTarget target
+number timeStamp
+string type
+```
+
+> Note:
+>
+> As of v0.14, returning `false` from an event handler will no longer stop event propagation. Instead, `e.stopPropagation()` or `e.preventDefault()` should be triggered manually, as appropriate.
+
+### Event Pooling
+
+The `SyntheticEvent` is pooled. This means that the `SyntheticEvent` object will be reused and all properties will be nullified after the event callback has been invoked.
+This is for performance reasons.
+As such, you cannot access the event in an asynchronous way.
+
+```javascript
+function onClick(event) {
+  console.log(event); // => nullified object.
+  console.log(event.type); // => "click"
+  const eventType = event.type; // => "click"
+
+  setTimeout(function() {
+    console.log(event.type); // => null
+    console.log(eventType); // => "click"
+  }, 0);
+
+  // Won't work. this.state.clickEvent will only contain null values.
+  this.setState({clickEvent: event});
+
+  // You can still export event properties.
+  this.setState({eventType: event.type});
+}
+```
+
+> Note:
+>
+> If you want to access the event properties in an asynchronous way, you should call `event.persist()` on the event, which will remove the synthetic event from the pool and allow references to the event to be retained by user code.
+
+## Supported Events
+
+React normalizes events so that they have consistent properties across different browsers.
+
+The event handlers below are triggered by an event in the bubbling phase. To register an event handler for the capture phase, append `Capture` to the event name; for example, instead of using `onClick`, you would use `onClickCapture` to handle the click event in the capture phase.
+
+- [Clipboard Events](#clipboard-events)
+- [Composition Events](#composition-events)
+- [Keyboard Events](#keyboard-events)
+- [Focus Events](#focus-events)
+- [Form Events](#form-events)
+- [Mouse Events](#mouse-events)
+- [Selection Events](#selection-events)
+- [Touch Events](#touch-events)
+- [UI Events](#ui-events)
+- [Wheel Events](#wheel-events)
+- [Media Events](#media-events)
+- [Image Events](#image-events)
+- [Animation Events](#animation-events)
+- [Transition Events](#transition-events)
+
+* * *
+
+## Reference
+
+### Clipboard Events
+
+Event names:
+
+```
+onCopy onCut onPaste
+```
+
+Properties:
+
+```javascript
+DOMDataTransfer clipboardData
+```
+
+* * *
+
+### Composition Events
+
+Event names:
+
+```
+onCompositionEnd onCompositionStart onCompositionUpdate
+```
+
+Properties:
+
+```javascript
+string data
+
+```
+
+* * *
+
+### Keyboard Events
+
+Event names:
+
+```
+onKeyDown onKeyPress onKeyUp
+```
+
+Properties:
+
+```javascript
+boolean altKey
+number charCode
+boolean ctrlKey
+boolean getModifierState(key)
+string key
+number keyCode
+string locale
+number location
+boolean metaKey
+boolean repeat
+boolean shiftKey
+number which
+```
+
+* * *
+
+### Focus Events
+
+Event names:
+
+```
+onFocus onBlur
+```
+
+These focus events work on all elements in the React DOM, not just form elements.
+
+Properties:
+
+```javascript
+DOMEventTarget relatedTarget
+```
+
+* * *
+
+### Form Events
+
+Event names:
+
+```
+onChange onInput onSubmit
+```
+
+For more information about the onChange event, see [Forms](/react/docs/forms.html).
+
+* * *
+
+### Mouse Events
+
+Event names:
+
+```
+onClick onContextMenu onDoubleClick onDrag onDragEnd onDragEnter onDragExit
+onDragLeave onDragOver onDragStart onDrop onMouseDown onMouseEnter onMouseLeave
+onMouseMove onMouseOut onMouseOver onMouseUp
+```
+
+The `onMouseEnter` and `onMouseLeave` events propagate from the element being left to the one being entered instead of ordinary bubbling and do not have a capture phase.
+
+Properties:
+
+```javascript
+boolean altKey
+number button
+number buttons
+number clientX
+number clientY
+boolean ctrlKey
+boolean getModifierState(key)
+boolean metaKey
+number pageX
+number pageY
+DOMEventTarget relatedTarget
+number screenX
+number screenY
+boolean shiftKey
+```
+
+* * *
+
+### Selection Events
+
+Event names:
+
+```
+onSelect
+```
+
+* * *
+
+### Touch Events
+
+Event names:
+
+```
+onTouchCancel onTouchEnd onTouchMove onTouchStart
+```
+
+Properties:
+
+```javascript
+boolean altKey
+DOMTouchList changedTouches
+boolean ctrlKey
+boolean getModifierState(key)
+boolean metaKey
+boolean shiftKey
+DOMTouchList targetTouches
+DOMTouchList touches
+```
+
+* * *
+
+### UI Events
+
+Event names:
+
+```
+onScroll
+```
+
+Properties:
+
+```javascript
+number detail
+DOMAbstractView view
+```
+
+* * *
+
+### Wheel Events
+
+Event names:
+
+```
+onWheel
+```
+
+Properties:
+
+```javascript
+number deltaMode
+number deltaX
+number deltaY
+number deltaZ
+```
+
+* * *
+
+### Media Events
+
+Event names:
+
+```
+onAbort onCanPlay onCanPlayThrough onDurationChange onEmptied onEncrypted 
+onEnded onError onLoadedData onLoadedMetadata onLoadStart onPause onPlay 
+onPlaying onProgress onRateChange onSeeked onSeeking onStalled onSuspend 
+onTimeUpdate onVolumeChange onWaiting
+```
+
+* * *
+
+### Image Events
+
+Event names:
+
+```
+onLoad onError
+```
+
+* * *
+
+### Animation Events
+
+Event names:
+
+```
+onAnimationStart onAnimationEnd onAnimationIteration
+```
+
+Properties:
+
+```javascript
+string animationName
+string pseudoElement
+float elapsedTime
+```
+
+* * *
+
+### Transition Events
+
+Event names:
+
+```
+onTransitionEnd
+```
+
+Properties:
+
+```javascript
+string propertyName
+string pseudoElement
+float elapsedTime
+```
+
diff --git a/docs/docs/reference-pure-render-mixin.md b/docs/docs/reference-pure-render-mixin.md
new file mode 100644
index 000000000000..cee8bcaa948b
--- /dev/null
+++ b/docs/docs/reference-pure-render-mixin.md
@@ -0,0 +1,51 @@
+---
+id: pure-render-mixin
+title: PureRenderMixin
+layout: docs
+category: Reference
+permalink: docs/pure-render-mixin.html
+---
+
+> Note
+
+> The `PureRenderMixin` mixin predates `React.PureComponent`. This reference doc is provided for legacy purposes, and you should consider using [`React.PureComponent`](/react/docs/react-api.html#react.purecomponent) instead.
+
+If your React component's render function renders the same result given the same props and state, you can use this mixin for a performance boost in some cases.
+
+Example:
+
+```js
+var PureRenderMixin = require('react-addons-pure-render-mixin');
+var createReactClass = require('create-react-class');
+createReactClass({
+  mixins: [PureRenderMixin],
+
+  render: function() {
+    return <div className={this.props.className}>foo</div>;
+  }
+});
+```
+
+Example using ES6 class syntax:
+
+```js
+import PureRenderMixin from 'react-addons-pure-render-mixin';
+class FooComponent extends React.Component {
+  constructor(props) {
+    super(props);
+    this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);
+  }
+
+  render() {
+    return <div className={this.props.className}>foo</div>;
+  }
+}
+```
+
+Under the hood, the mixin implements [shouldComponentUpdate](/react/docs/component-specs.html#updating-shouldcomponentupdate), in which it compares the current props and state with the next ones and returns `false` if the equalities pass.
+
+> Note:
+>
+> This only shallowly compares the objects. If these contain complex data structures, it may produce false-negatives for deeper differences. Only mix into components which have simple props and state, or use `forceUpdate()` when you know deep data structures have changed. Or, consider using [immutable objects](https://facebook.github.io/immutable-js/) to facilitate fast comparisons of nested data.
+>
+> Furthermore, `shouldComponentUpdate` skips updates for the whole component subtree. Make sure all the children components are also "pure".
diff --git a/docs/docs/reference-react-component.md b/docs/docs/reference-react-component.md
new file mode 100644
index 000000000000..b71b92a47adf
--- /dev/null
+++ b/docs/docs/reference-react-component.md
@@ -0,0 +1,366 @@
+---
+id: react-component
+title: React.Component
+layout: docs
+category: Reference
+permalink: docs/react-component.html
+redirect_from:
+  - "docs/component-api.html"
+  - "docs/component-specs.html"
+  - "docs/component-specs-ko-KR.html"
+  - "docs/component-specs-zh-CN.html"
+  - "tips/componentWillReceiveProps-not-triggered-after-mounting.html"
+  - "tips/dom-event-listeners.html"
+  - "tips/initial-ajax.html"
+  - "tips/use-react-with-other-libraries.html"
+---
+
+[Components](/react/docs/components-and-props.html) let you split the UI into independent, reusable pieces, and think about each piece in isolation. `React.Component` is provided by [`React`](/react/docs/react-api.html).
+
+## Overview
+
+`React.Component` is an abstract base class, so it rarely makes sense to refer to `React.Component` directly. Instead, you will typically subclass it, and define at least a [`render()`](#render) method.
+
+Normally you would define a React component as a plain [JavaScript class](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes):
+
+```javascript
+class Greeting extends React.Component {
+  render() {
+    return <h1>Hello, {this.props.name}</h1>;
+  }
+}
+```
+
+If you don't use ES6 yet, you may use the [`create-react-class`](/react/docs/react-api.html#createclass) module instead. Take a look at [Using React without ES6](/react/docs/react-without-es6.html) to learn more.
+
+### The Component Lifecycle
+
+Each component has several "lifecycle methods" that you can override to run code at particular times in the process. Methods prefixed with **`will`** are called right before something happens, and methods prefixed with **`did`** are called right after something happens.
+
+#### Mounting
+
+These methods are called when an instance of a component is being created and inserted into the DOM:
+
+- [`constructor()`](#constructor)
+- [`componentWillMount()`](#componentwillmount)
+- [`render()`](#render)
+- [`componentDidMount()`](#componentdidmount)
+
+#### Updating
+
+An update can be caused by changes to props or state. These methods are called when a component is being re-rendered:
+
+- [`componentWillReceiveProps()`](#componentwillreceiveprops)
+- [`shouldComponentUpdate()`](#shouldcomponentupdate)
+- [`componentWillUpdate()`](#componentwillupdate)
+- [`render()`](#render)
+- [`componentDidUpdate()`](#componentdidupdate)
+
+#### Unmounting
+
+This method is called when a component is being removed from the DOM:
+
+- [`componentWillUnmount()`](#componentwillunmount)
+
+### Other APIs
+
+Each component also provides some other APIs:
+
+  - [`setState()`](#setstate)
+  - [`forceUpdate()`](#forceupdate)
+
+### Class Properties
+
+  - [`defaultProps`](#defaultprops)
+  - [`displayName`](#displayname)
+
+### Instance Properties
+
+  - [`props`](#props)
+  - [`state`](#state)
+
+* * *
+
+## Reference
+
+### `render()`
+
+```javascript
+render()
+```
+
+The `render()` method is required.
+
+When called, it should examine `this.props` and `this.state` and return a single React element. This element can be either a representation of a native DOM component, such as `<div />`, or another composite component that you've defined yourself.
+
+You can also return `null` or `false` to indicate that you don't want anything rendered. When returning `null` or `false`, `ReactDOM.findDOMNode(this)` will return `null`.
+
+The `render()` function should be pure, meaning that it does not modify component state, it returns the same result each time it's invoked, and it does not directly interact with the browser. If you need to interact with the browser, perform your work in `componentDidMount()` or the other lifecycle methods instead. Keeping `render()` pure makes components easier to think about.
+
+> Note
+>
+> `render()` will not be invoked if [`shouldComponentUpdate()`](#shouldcomponentupdate) returns false.
+
+* * *
+
+### `constructor()`
+
+```javascript
+constructor(props)
+```
+
+The constructor for a React component is called before it is mounted. When implementing the constructor for a `React.Component` subclass, you should call `super(props)` before any other statement. Otherwise, `this.props` will be undefined in the constructor, which can lead to bugs.
+
+The constructor is the right place to initialize state. If you don't initialize state and you don't bind methods, you don't need to implement a constructor for your React component.
+
+It's okay to initialize state based on props. This effectively "forks" the props and sets the state with the initial props. Here's an example of a valid `React.Component` subclass constructor:
+
+```js
+constructor(props) {
+  super(props);
+  this.state = {
+    color: props.initialColor
+  };
+}
+```
+
+Beware of this pattern, as state won't be up-to-date with any props update. Instead of syncing props to state, you often want to [lift the state up](/react/docs/lifting-state-up.html).
+
+If you "fork" props by using them for state, you might also want to implement [`componentWillReceiveProps(nextProps)`](#componentwillreceiveprops) to keep the state up-to-date with them. But lifting state up is often easier and less bug-prone.
+
+* * *
+
+### `componentWillMount()`
+
+```javascript
+componentWillMount()
+```
+
+`componentWillMount()` is invoked immediately before mounting occurs. It is called before `render()`, therefore setting state synchronously in this method will not trigger a re-rendering. Avoid introducing any side-effects or subscriptions in this method.
+
+This is the only lifecycle hook called on server rendering. Generally, we recommend using the `constructor()` instead.
+
+* * *
+
+### `componentDidMount()`
+
+```javascript
+componentDidMount()
+```
+
+`componentDidMount()` is invoked immediately after a component is mounted. Initialization that requires DOM nodes should go here. If you need to load data from a remote endpoint, this is a good place to instantiate the network request. Setting state in this method will trigger a re-rendering.
+
+* * *
+
+### `componentWillReceiveProps()`
+
+```javascript
+componentWillReceiveProps(nextProps)
+```
+
+`componentWillReceiveProps()` is invoked before a mounted component receives new props. If you need to update the state in response to prop changes (for example, to reset it), you may compare `this.props` and `nextProps` and perform state transitions using `this.setState()` in this method.
+
+Note that React may call this method even if the props have not changed, so make sure to compare the current and next values if you only want to handle changes. This may occur when the parent component causes your component to re-render.
+
+React doesn't call `componentWillReceiveProps` with initial props during [mounting](#mounting). It only calls this method if some of component's props may update. Calling `this.setState` generally doesn't trigger `componentWillReceiveProps`.
+
+* * *
+
+### `shouldComponentUpdate()`
+
+```javascript
+shouldComponentUpdate(nextProps, nextState)
+```
+
+Use `shouldComponentUpdate()` to let React know if a component's output is not affected by the current change in state or props. The default behavior is to re-render on every state change, and in the vast majority of cases you should rely on the default behavior.
+
+`shouldComponentUpdate()` is invoked before rendering when new props or state are being received. Defaults to `true`. This method is not called for the initial render or when `forceUpdate()` is used.
+
+Returning `false` does not prevent child components from re-rendering when *their* state changes.
+
+Currently, if `shouldComponentUpdate()` returns `false`, then [`componentWillUpdate()`](#componentwillupdate), [`render()`](#render), and [`componentDidUpdate()`](#componentdidupdate) will not be invoked. Note that in the future React may treat `shouldComponentUpdate()` as a hint rather than a strict directive, and returning `false` may still result in a re-rendering of the component.
+
+If you determine a specific component is slow after profiling, you may change it to inherit from [`React.PureComponent`](/react/docs/react-api.html#react.purecomponent) which implements `shouldComponentUpdate()` with a shallow prop and state comparison. If you are confident you want to write it by hand, you may compare `this.props` with `nextProps` and `this.state` with `nextState` and return `false` to tell React the update can be skipped.
+
+* * *
+
+### `componentWillUpdate()`
+
+```javascript
+componentWillUpdate(nextProps, nextState)
+```
+
+`componentWillUpdate()` is invoked immediately before rendering when new props or state are being received. Use this as an opportunity to perform preparation before an update occurs. This method is not called for the initial render.
+
+Note that you cannot call `this.setState()` here. If you need to update state in response to a prop change, use `componentWillReceiveProps()` instead.
+
+> Note
+>
+> `componentWillUpdate()` will not be invoked if [`shouldComponentUpdate()`](#shouldcomponentupdate) returns false.
+
+* * *
+
+### `componentDidUpdate()`
+
+```javascript
+componentDidUpdate(prevProps, prevState)
+```
+
+`componentDidUpdate()` is invoked immediately after updating occurs. This method is not called for the initial render.
+
+Use this as an opportunity to operate on the DOM when the component has been updated. This is also a good place to do network requests as long as you compare the current props to previous props (e.g. a network request may not be necessary if the props have not changed).
+
+> Note
+>
+> `componentDidUpdate()` will not be invoked if [`shouldComponentUpdate()`](#shouldcomponentupdate) returns false.
+
+* * *
+
+### `componentWillUnmount()`
+
+```javascript
+componentWillUnmount()
+```
+
+`componentWillUnmount()` is invoked immediately before a component is unmounted and destroyed. Perform any necessary cleanup in this method, such as invalidating timers, canceling network requests, or cleaning up any DOM elements that were created in `componentDidMount`
+
+* * *
+
+### `setState()`
+
+```javascript
+setState(updater, [callback])
+```
+
+`setState()` enqueues changes to the component state and tells React that this component and its children need to be re-rendered with the updated state. This is the primary method you use to update the user interface in response to event handlers and server responses.
+
+Think of `setState()` as a *request* rather than an immediate command to update the component. For better perceived performance, React may delay it, and then update several components in a single pass. React does not guarantee that the state changes are applied immediately.
+
+`setState()` does not always immediately update the component. It may batch or defer the update until later. This makes reading `this.state` right after calling `setState()` a potential pitfall. Instead, use `componentDidUpdate` or a `setState` callback (`setState(updater, callback)`), either of which are guaranteed to fire after the update has been applied. If you need to set the state based on the previous state, read about the `updater` argument below.
+
+`setState()` will always lead to a re-render unless `shouldComponentUpdate()` returns `false`. If mutable objects are being used and conditional rendering logic cannot be implemented in `shouldComponentUpdate()`, calling `setState()` only when the new state differs from the previous state will avoid unnecessary re-renders.
+
+The first argument is an `updater` function with the signature:
+
+```javascript
+(prevState, props) => stateChange
+```
+
+`prevState` is a reference to the previous state. It should not be directly mutated. Instead, changes should be represented by building a new object based on the input from `prevState` and `props`. For instance, suppose we wanted to increment a value in state by `props.step`:
+
+```javascript
+this.setState((prevState, props) => {
+  return {counter: prevState.counter + props.step};
+});
+```
+
+Both `prevState` and `props` received by the updater function are guaranteed to be up-to-date. The output of the updater is shallowly merged with `prevState`.
+
+The second parameter to `setState()` is an optional callback function that will be executed once `setState` is completed and the component is re-rendered. Generally we recommend using `componentDidUpdate()` for such logic instead.
+
+You may optionally pass an object as the first argument to `setState()` instead of a function:
+
+```javascript
+setState(stateChange, [callback])
+```
+
+This performs a shallow merge of `stateChange` into the new state, e.g., to adjust a shopping cart item quantity:
+
+```javascript
+this.setState({quantity: 2})
+```
+
+This form of `setState()` is also asynchronous, and multiple calls during the same cycle may be batched together. For example, if you attempt to increment an item quantity more than once in the same cycle, that will result in the equivalent of:
+
+```javaScript
+Object.assign(
+  previousState,
+  {quantity: state.quantity + 1},
+  {quantity: state.quantity + 1},
+  ...
+)
+```
+
+Subsequent calls will override values from previous calls in the same cycle, so the quantity will only be incremented once. If the next state depends on the previous state, we recommend using the updater function form, instead:
+
+```js
+this.setState((prevState) => {
+  return {counter: prevState.quantity + 1};
+});
+```
+
+For more detail, see the [State and Lifecycle guide](/react/docs/state-and-lifecycle.html).
+
+* * *
+
+### `forceUpdate()`
+
+```javascript
+component.forceUpdate(callback)
+```
+
+By default, when your component's state or props change, your component will re-render. If your `render()` method depends on some other data, you can tell React that the component needs re-rendering by calling `forceUpdate()`.
+
+Calling `forceUpdate()` will cause `render()` to be called on the component, skipping `shouldComponentUpdate()`. This will trigger the normal lifecycle methods for child components, including the `shouldComponentUpdate()` method of each child. React will still only update the DOM if the markup changes.
+
+Normally you should try to avoid all uses of `forceUpdate()` and only read from `this.props` and `this.state` in `render()`.
+
+* * *
+
+## Class Properties
+
+### `defaultProps`
+
+`defaultProps` can be defined as a property on the component class itself, to set the default props for the class. This is used for undefined props, but not for null props. For example:
+
+```js
+class CustomButton extends React.Component {
+  // ...
+}
+
+CustomButton.defaultProps = {
+  color: 'blue'
+};
+```
+
+If `props.color` is not provided, it will be set by default to `'blue'`:
+
+```js
+  render() {
+    return <CustomButton /> ; // props.color will be set to blue
+  }
+```
+
+If `props.color` is set to null, it will remain null:
+
+```js
+  render() {
+    return <CustomButton color={null} /> ; // props.color will remain null
+  }
+```
+
+* * *
+
+### `displayName`
+
+The `displayName` string is used in debugging messages. JSX sets this value automatically; see [JSX in Depth](/react/docs/jsx-in-depth.html).
+
+* * *
+
+## Instance Properties
+
+### `props`
+
+`this.props` contains the props that were defined by the caller of this component. See [Components and Props](/react/docs/components-and-props.html) for an introduction to props.
+
+In particular, `this.props.children` is a special prop, typically defined by the child tags in the JSX expression rather than in the tag itself.
+
+### `state`
+
+The state contains data specific to this component that may change over time. The state is user-defined, and it should be a plain JavaScript object.
+
+If you don't use it in `render()`, it shouldn't be in the state. For example, you can put timer IDs directly on the instance.
+
+See [State and Lifecycle](/react/docs/state-and-lifecycle.html) for more information about the state.
+
+Never mutate `this.state` directly, as calling `setState()` afterwards may replace the mutation you made. Treat `this.state` as if it were immutable.
diff --git a/docs/docs/reference-react-dom-server.md b/docs/docs/reference-react-dom-server.md
new file mode 100644
index 000000000000..00bc87ba370c
--- /dev/null
+++ b/docs/docs/reference-react-dom-server.md
@@ -0,0 +1,40 @@
+---
+id: react-dom-server
+title: ReactDOMServer
+layout: docs
+category: Reference
+permalink: docs/react-dom-server.html
+---
+
+If you load React from a `<script>` tag, these top-level APIs are available on the `ReactDOMServer` global. If you use ES6 with npm, you can write `import ReactDOMServer from 'react-dom/server'`. If you use ES5 with npm, you can write `var ReactDOMServer = require('react-dom/server')`.
+
+## Overview
+
+The `ReactDOMServer` class allows you to render your components on the server.
+
+ - [`renderToString()`](#rendertostring)
+ - [`renderToStaticMarkup()`](#rendertostaticmarkup)
+
+* * *
+
+## Reference
+
+### `renderToString()`
+
+```javascript
+ReactDOMServer.renderToString(element)
+```
+
+Render a React element to its initial HTML. This should only be used on the server. React will return an HTML string. You can use this method to generate HTML on the server and send the markup down on the initial request for faster page loads and to allow search engines to crawl your pages for SEO purposes.
+
+If you call [`ReactDOM.render()`](/react/docs/react-dom.html#render) on a node that already has this server-rendered markup, React will preserve it and only attach event handlers, allowing you to have a very performant first-load experience.
+
+* * *
+
+### `renderToStaticMarkup()`
+
+```javascript
+ReactDOMServer.renderToStaticMarkup(element)
+```
+
+Similar to [`renderToString`](#rendertostring), except this doesn't create extra DOM attributes such as `data-reactid`, that React uses internally. This is useful if you want to use React as a simple static page generator, as stripping away the extra attributes can save lots of bytes.
diff --git a/docs/docs/reference-react-dom.md b/docs/docs/reference-react-dom.md
new file mode 100644
index 000000000000..8534e2301c73
--- /dev/null
+++ b/docs/docs/reference-react-dom.md
@@ -0,0 +1,82 @@
+---
+id: react-dom
+title: ReactDOM
+layout: docs
+category: Reference
+permalink: docs/react-dom.html
+---
+
+If you load React from a `<script>` tag, these top-level APIs are available on the `ReactDOM` global. If you use ES6 with npm, you can write `import ReactDOM from 'react-dom'`. If you use ES5 with npm, you can write `var ReactDOM = require('react-dom')`.
+
+## Overview
+
+The `react-dom` package provides DOM-specific methods that can be used at the top level of your app and as an escape hatch to get outside of the React model if you need to. Most of your components should not need to use this module.
+
+- [`render()`](#render)
+- [`unmountComponentAtNode()`](#unmountcomponentatnode)
+- [`findDOMNode()`](#finddomnode)
+
+### Browser Support
+
+React supports all popular browsers, including Internet Explorer 9 and above.
+
+> Note
+>
+> We don't support older browsers that don't support ES5 methods, but you may find that your apps do work in older browsers if polyfills such as [es5-shim and es5-sham](https://github.com/es-shims/es5-shim) are included in the page. You're on your own if you choose to take this path.
+
+* * *
+
+## Reference
+
+### `render()`
+
+```javascript
+ReactDOM.render(
+  element,
+  container,
+  [callback]
+)
+```
+
+Render a React element into the DOM in the supplied `container` and return a [reference](/react/docs/more-about-refs.html) to the component (or returns `null` for [stateless components](/react/docs/components-and-props.html#functional-and-class-components)).
+
+If the React element was previously rendered into `container`, this will perform an update on it and only mutate the DOM as necessary to reflect the latest React element.
+
+If the optional callback is provided, it will be executed after the component is rendered or updated.
+
+> Note:
+>
+> `ReactDOM.render()` controls the contents of the container node you pass in. Any existing DOM elements inside are replaced when first called. Later calls use React’s DOM diffing algorithm for efficient updates.
+>
+> `ReactDOM.render()` does not modify the container node (only modifies the children of the container). It may be possible to insert a component to an existing DOM node without overwriting the existing children.
+>
+> `ReactDOM.render()` currently returns a reference to the root `ReactComponent` instance. However, using this return value is legacy
+> and should be avoided because future versions of React may render components asynchronously in some cases. If you need a reference to the root `ReactComponent` instance, the preferred solution is to attach a
+> [callback ref](/react/docs/more-about-refs.html#the-ref-callback-attribute) to the root element.
+
+* * *
+
+### `unmountComponentAtNode()`
+
+```javascript
+ReactDOM.unmountComponentAtNode(container)
+```
+
+Remove a mounted React component from the DOM and clean up its event handlers and state. If no component was mounted in the container, calling this function does nothing. Returns `true` if a component was unmounted and `false` if there was no component to unmount.
+
+* * *
+
+### `findDOMNode()`
+
+```javascript
+ReactDOM.findDOMNode(component)
+```
+If this component has been mounted into the DOM, this returns the corresponding native browser DOM element. This method is useful for reading values out of the DOM, such as form field values and performing DOM measurements. **In most cases, you can attach a ref to the DOM node and avoid using `findDOMNode` at all.** When `render` returns `null` or `false`, `findDOMNode` returns `null`.
+
+> Note:
+>
+> `findDOMNode` is an escape hatch used to access the underlying DOM node. In most cases, use of this escape hatch is discouraged because it pierces the component abstraction.
+>
+> `findDOMNode` only works on mounted components (that is, components that have been placed in the DOM). If you try to call this on a component that has not been mounted yet (like calling `findDOMNode()` in `render()` on a component that has yet to be created) an exception will be thrown.
+>
+> `findDOMNode` cannot be used on functional components.
diff --git a/docs/docs/reference-react.md b/docs/docs/reference-react.md
new file mode 100644
index 000000000000..96413c2f3a2c
--- /dev/null
+++ b/docs/docs/reference-react.md
@@ -0,0 +1,193 @@
+---
+id: react-api
+title: React Top-Level API
+layout: docs
+category: Reference
+permalink: docs/react-api.html
+redirect_from:
+  - "docs/reference.html"
+  - "docs/clone-with-props.html"
+  - "docs/top-level-api.html"
+  - "docs/top-level-api-ja-JP.html"
+  - "docs/top-level-api-ko-KR.html"
+  - "docs/top-level-api-zh-CN.html"
+  - "docs/glossary.html"
+---
+
+`React` is the entry point to the React library. If you load React from a `<script>` tag, these top-level APIs are available on the `React` global. If you use ES6 with npm, you can write `import React from 'react'`. If you use ES5 with npm, you can write `var React = require('react')`.
+
+## Overview
+
+### Components
+
+React components let you split the UI into independent, reusable pieces, and think about each piece in isolation. React components can be defined by subclassing `React.Component` or `React.PureComponent`.
+
+ - [`React.Component`](#react.component)
+ - [`React.PureComponent`](#react.purecomponent)
+
+If you don't use ES6 classes, you may use the `create-react-class` module instead. See [Using React without ES6](/react/docs/react-without-es6.html) for more information.
+
+### Creating React Elements
+
+We recommend [using JSX](/react/docs/introducing-jsx.html) to describe what your UI should look like. Each JSX element is just syntactic sugar for calling [`React.createElement()`](#createelement). You will not typically invoke the following methods directly if you are using JSX.
+
+- [`createElement()`](#createelement)
+- [`createFactory()`](#createfactory)
+
+See [Using React without JSX](/react/docs/react-without-jsx.html) for more information.
+
+### Transforming Elements
+
+`React` also provides some other APIs:
+
+- [`cloneElement()`](#cloneelement)
+- [`isValidElement()`](#isvalidelement)
+- [`React.Children`](#react.children)
+
+* * *
+
+## Reference
+
+### `React.Component`
+
+`React.Component` is the base class for React components when they are defined using [ES6 classes](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes).
+
+```javascript
+class Greeting extends React.Component {
+  render() {
+    return <h1>Hello, {this.props.name}</h1>;
+  }
+}
+```
+
+See the [React.Component API Reference](/react/docs/react-component.html) for a list of methods and properties related to the base `React.Component` class.
+
+* * *
+
+### `React.PureComponent`
+
+`React.PureComponent` is exactly like [`React.Component`](#react.component) but implements [`shouldComponentUpdate()`](/react/docs/react-component.html#shouldcomponentupdate) with a shallow prop and state comparison.
+
+If your React component's `render()` function renders the same result given the same props and state, you can use `React.PureComponent` for a performance boost in some cases.
+
+> Note
+
+> `React.PureComponent`'s `shouldComponentUpdate()` only shallowly compares the objects. If these contain complex data structures, it may produce false-negatives for deeper differences. Only extend `PureComponent` when you expect to have simple props and state, or use [`forceUpdate()`](/react/docs/react-component.html#forceupdate) when you know deep data structures have changed. Or, consider using [immutable objects](https://facebook.github.io/immutable-js/) to facilitate fast comparisons of nested data.
+>
+> Furthermore, `React.PureComponent`'s `shouldComponentUpdate()` skips prop updates for the whole component subtree. Make sure all the children components are also "pure".
+
+* * *
+
+### `createElement()`
+
+```javascript
+React.createElement(
+  type,
+  [props],
+  [...children]
+)
+```
+
+Create and return a new [React element](/react/docs/rendering-elements.html) of the given type. The type argument can be either a tag name string (such as `'div'` or `'span'`), or a [React component](/react/docs/components-and-props.html) type (a class or a function).
+
+Convenience wrappers around `React.createElement()` for DOM components are provided by `React.DOM`. For example, `React.DOM.a(...)` is a convenience wrapper for `React.createElement('a', ...)`. They are considered legacy, and we encourage you to either use JSX or use `React.createElement()` directly instead.
+
+Code written with [JSX](/react/docs/introducing-jsx.html) will be converted to use `React.createElement()`. You will not typically invoke `React.createElement()` directly if you are using JSX. See [React Without JSX](/react/docs/react-without-jsx.html) to learn more.
+
+* * *
+
+### `cloneElement()`
+
+```
+React.cloneElement(
+  element,
+  [props],
+  [...children]
+)
+```
+
+Clone and return a new React element using `element` as the starting point. The resulting element will have the original element's props with the new props merged in shallowly. New children will replace existing children. `key` and `ref` from the original element will be preserved.
+
+`React.cloneElement()` is almost equivalent to:
+
+```js
+<element.type {...element.props} {...props}>{children}</element.type>
+```
+
+However, it also preserves `ref`s. This means that if you get a child with a `ref` on it, you won't accidentally steal it from your ancestor. You will get the same `ref` attached to your new element.
+
+This API was introduced as a replacement of the deprecated `React.addons.cloneWithProps()`.
+
+* * *
+
+### `createFactory()`
+
+```javascript
+React.createFactory(type)
+```
+
+Return a function that produces React elements of a given type. Like [`React.createElement()`](#createElement), the type argument can be either a tag name string (such as `'div'` or `'span'`), or a [React component](/react/docs/components-and-props.html) type (a class or a function).
+
+This helper is considered legacy, and we encourage you to either use JSX or use `React.createElement()` directly instead.
+
+You will not typically invoke `React.createFactory()` directly if you are using JSX. See [React Without JSX](/react/docs/react-without-jsx.html) to learn more.
+
+* * *
+
+### `isValidElement()`
+
+```javascript
+React.isValidElement(object)
+```
+
+Verifies the object is a React element. Returns `true` or `false`.
+
+* * *
+
+### `React.Children`
+
+`React.Children` provides utilities for dealing with the `this.props.children` opaque data structure.
+
+#### `React.Children.map`
+
+```javascript
+React.Children.map(children, function[(thisArg)])
+```
+
+Invokes a function on every immediate child contained within `children` with `this` set to `thisArg`. If `children` is a keyed fragment or array it will be traversed: the function will never be passed the container objects. If children is `null` or `undefined`, returns `null` or `undefined` rather than an array.
+
+#### `React.Children.forEach`
+
+```javascript
+React.Children.forEach(children, function[(thisArg)])
+```
+
+Like [`React.Children.map()`](#react.children.map) but does not return an array.
+
+#### `React.Children.count`
+
+```javascript
+React.Children.count(children)
+```
+
+Returns the total number of components in `children`, equal to the number of times that a callback passed to `map` or `forEach` would be invoked.
+
+#### `React.Children.only`
+
+```javascript
+React.Children.only(children)
+```
+
+Returns the only child in `children`. Throws otherwise.
+
+#### `React.Children.toArray`
+
+```javascript
+React.Children.toArray(children)
+```
+
+Returns the `children` opaque data structure as a flat array with keys assigned to each child. Useful if you want to manipulate collections of children in your render methods, especially if you want to reorder or slice `this.props.children` before passing it down.
+
+> Note:
+>
+> `React.Children.toArray()` changes keys to preserve the semantics of nested arrays when flattening lists of children. That is, `toArray` prefixes each key in the returned array so that each element's key is scoped to the input array containing it.
diff --git a/docs/docs/refs-and-the-dom.md b/docs/docs/refs-and-the-dom.md
new file mode 100644
index 000000000000..b6c919964474
--- /dev/null
+++ b/docs/docs/refs-and-the-dom.md
@@ -0,0 +1,225 @@
+---
+id: refs-and-the-dom
+title: Refs and the DOM
+redirect_from:
+  - "docs/working-with-the-browser.html"
+  - "docs/more-about-refs.html"
+  - "docs/more-about-refs-ko-KR.html"
+  - "docs/more-about-refs-zh-CN.html"
+  - "tips/expose-component-functions.html"
+  - "tips/children-undefined.html"
+permalink: docs/refs-and-the-dom.html
+---
+
+In the typical React dataflow, [props](/react/docs/components-and-props.html) are the only way that parent components interact with their children. To modify a child, you re-render it with new props. However, there are a few cases where you need to imperatively modify a child outside of the typical dataflow. The child to be modified could be an instance of a React component, or it could be a DOM element. For both of these cases, React provides an escape hatch.
+
+### When to Use Refs
+
+There are a few good use cases for refs:
+
+* Managing focus, text selection, or media playback.
+* Triggering imperative animations.
+* Integrating with third-party DOM libraries.
+
+Avoid using refs for anything that can be done declaratively.
+
+For example, instead of exposing `open()` and `close()` methods on a `Dialog` component, pass an `isOpen` prop to it.
+
+### Don't Overuse Refs
+
+Your first inclination may be to use refs to "make things happen" in your app. If this is the case, take a moment and think more critically about where state should be owned in the component hierarchy. Often, it becomes clear that the proper place to "own" that state is at a higher level in the hierarchy. See the [Lifting State Up](/react/docs/lifting-state-up.html) guide for examples of this.
+
+### Adding a Ref to a DOM Element
+
+React supports a special attribute that you can attach to any component. The `ref` attribute takes a callback function, and the callback will be executed immediately after the component is mounted or unmounted.
+
+When the `ref` attribute is used on an HTML element, the `ref` callback receives the underlying DOM element as its argument. For example, this code uses the `ref` callback to store a reference to a DOM node:
+
+```javascript{8,9,19}
+class CustomTextInput extends React.Component {
+  constructor(props) {
+    super(props);
+    this.focus = this.focus.bind(this);
+  }
+
+  focus() {
+    // Explicitly focus the text input using the raw DOM API
+    this.textInput.focus();
+  }
+
+  render() {
+    // Use the `ref` callback to store a reference to the text input DOM
+    // element in an instance field (for example, this.textInput).
+    return (
+      <div>
+        <input
+          type="text"
+          ref={(input) => { this.textInput = input; }} />
+        <input
+          type="button"
+          value="Focus the text input"
+          onClick={this.focus}
+        />
+      </div>
+    );
+  }
+}
+```
+
+React will call the `ref` callback with the DOM element when the component mounts, and call it with `null` when it unmounts.
+
+Using the `ref` callback just to set a property on the class is a common pattern for accessing DOM elements. The preferred way is to set the property in the `ref` callback like in the above example. There is even a shorter way to write it: `ref={input => this.textInput = input}`. 
+
+### Adding a Ref to a Class Component
+
+When the `ref` attribute is used on a custom component declared as a class, the `ref` callback receives the mounted instance of the component as its argument. For example, if we wanted to wrap the `CustomTextInput` above to simulate it being clicked immediately after mounting:
+
+```javascript{3,9}
+class AutoFocusTextInput extends React.Component {
+  componentDidMount() {
+    this.textInput.focus();
+  }
+
+  render() {
+    return (
+      <CustomTextInput
+        ref={(input) => { this.textInput = input; }} />
+    );
+  }
+}
+```
+
+Note that this only works if `CustomTextInput` is declared as a class:
+
+```js{1}
+class CustomTextInput extends React.Component {
+  // ...
+}
+```
+
+### Refs and Functional Components
+
+**You may not use the `ref` attribute on functional components** because they don't have instances:
+
+```javascript{1,7}
+function MyFunctionalComponent() {
+  return <input />;
+}
+
+class Parent extends React.Component {
+  render() {
+    // This will *not* work!
+    return (
+      <MyFunctionalComponent
+        ref={(input) => { this.textInput = input; }} />
+    );
+  }
+}
+```
+
+You should convert the component to a class if you need a ref to it, just like you do when you need lifecycle methods or state.
+
+You can, however, **use the `ref` attribute inside a functional component** as long as you refer to a DOM element or a class component:
+
+```javascript{2,3,6,13}
+function CustomTextInput(props) {
+  // textInput must be declared here so the ref callback can refer to it
+  let textInput = null;
+
+  function handleClick() {
+    textInput.focus();
+  }
+
+  return (
+    <div>
+      <input
+        type="text"
+        ref={(input) => { textInput = input; }} />
+      <input
+        type="button"
+        value="Focus the text input"
+        onClick={handleClick}
+      />
+    </div>
+  );  
+}
+```
+
+### Exposing DOM Refs to Parent Components
+
+In rare cases, you might want to have access to a child's DOM node from a parent component. This is generally not recommended because it breaks component encapsulation, but it can occasionally be useful for triggering focus or measuring the size or position of a child DOM node.
+
+While you could [add a ref to the child component](#adding-a-ref-to-a-class-component), this is not an ideal solution, as you would only get a component instance rather than a DOM node. Additionally, this wouldn't work with functional components.
+
+Instead, in such cases we recommend exposing a special prop on the child. The child would take a function prop with an arbitrary name (e.g. `inputRef`) and attach it to the DOM node as a `ref` attribute. This lets the parent pass its ref callback to the child's DOM node through the component in the middle.
+
+This works both for classes and for functional components.
+
+```javascript{4,13}
+function CustomTextInput(props) {
+  return (
+    <div>
+      <input ref={props.inputRef} />
+    </div>
+  );
+}
+
+class Parent extends React.Component {
+  render() {
+    return (
+      <CustomTextInput
+        inputRef={el => this.inputElement = el}
+      />
+    );
+  }
+}
+```
+
+In the example above, `Parent` passes its ref callback as an `inputRef` prop to the `CustomTextInput`, and the `CustomTextInput` passes the same function as a special `ref` attribute to the `<input>`. As a result, `this.inputElement` in `Parent` will be set to the DOM node corresponding to the `<input>` element in the `CustomTextInput`.
+
+Note that the name of the `inputRef` prop in the above example has no special meaning, as it is a regular component prop. However, using the `ref` attribute on the `<input>` itself is important, as it tells React to attach a ref to its DOM node.
+
+This works even though `CustomTextInput` is a functional component. Unlike the special `ref` attribute which can [only be specified for DOM elements and for class components](#refs-and-functional-components), there are no restrictions on regular component props like `inputRef`.
+
+Another benefit of this pattern is that it works several components deep. For example, imagine `Parent` didn't need that DOM node, but a component that rendered `Parent` (let's call it `Grandparent`) needed access to it. Then we could let the `Grandparent` specify the `inputRef` prop to the `Parent`, and let `Parent` "forward" it to the `CustomTextInput`:
+
+```javascript{4,12,22}
+function CustomTextInput(props) {
+  return (
+    <div>
+      <input ref={props.inputRef} />
+    </div>
+  );
+}
+
+function Parent(props) {
+  return (
+    <div>
+      My input: <CustomTextInput inputRef={props.inputRef} />
+    </div>
+  );
+}
+
+
+class Grandparent extends React.Component {
+  render() {
+    return (
+      <Parent
+        inputRef={el => this.inputElement = el}
+      />
+    );
+  }
+}
+```
+
+Here, the ref callback is first specified by `Grandparent`. It is passed to the `Parent` as a regular prop called `inputRef`, and the `Parent` passes it to the `CustomTextInput` as a prop too. Finally, the `CustomTextInput` reads the `inputRef` prop and attaches the passed function as a `ref` attribute to the `<input>`. As a result, `this.inputElement` in `Grandparent` will be set to the DOM node corresponding to the `<input>` element in the `CustomTextInput`.
+
+All things considered, we advise against exposing DOM nodes whenever possible, but this can be a useful escape hatch. Note that this approach requires you to add some code to the child component. If you have absolutely no control over the child component implementation, your last option is to use [`findDOMNode()`](/react/docs/react-dom.html#finddomnode), but it is discouraged.
+
+### Legacy API: String Refs
+
+If you worked with React before, you might be familiar with an older API where the `ref` attribute is a string, like `"textInput"`, and the DOM node is accessed as `this.refs.textInput`. We advise against it because string refs have [some issues](https://github.com/facebook/react/pull/8333#issuecomment-271648615), are considered legacy, and **are likely to be removed in one of the future releases**. If you're currently using `this.refs.textInput` to access refs, we recommend the callback pattern instead.
+
+### Caveats
+
+If the `ref` callback is defined as an inline function, it will get called twice during updates, first with `null` and then again with the DOM element. This is because a new instance of the function is created with each render, so React needs to clear the old ref and set up the new one. You can avoid this by defining the `ref` callback as a bound method on the class, but note that it shouldn't matter in most cases.
diff --git a/docs/docs/rendering-elements.md b/docs/docs/rendering-elements.md
new file mode 100644
index 000000000000..512070c21b18
--- /dev/null
+++ b/docs/docs/rendering-elements.md
@@ -0,0 +1,95 @@
+---
+id: rendering-elements
+title: Rendering Elements
+permalink: docs/rendering-elements.html
+redirect_from: "docs/displaying-data.html"
+prev: introducing-jsx.html
+next: components-and-props.html
+---
+
+Elements are the smallest building blocks of React apps.
+
+An element describes what you want to see on the screen:
+
+```js
+const element = <h1>Hello, world</h1>;
+```
+
+Unlike browser DOM elements, React elements are plain objects, and are cheap to create. React DOM takes care of updating the DOM to match the React elements.
+
+>**Note:**
+>
+>One might confuse elements with a more widely known concept of "components". We will introduce components in the [next section](/react/docs/components-and-props.html). Elements are what components are "made of", and we encourage you to read this section before jumping ahead.
+
+## Rendering an Element into the DOM
+
+Let's say there is a `<div>` somewhere in your HTML file:
+
+```html
+<div id="root"></div>
+```
+
+We call this a "root" DOM node because everything inside it will be managed by React DOM.
+
+Applications built with just React usually have a single root DOM node. If you are integrating React into an existing app, you may have as many isolated root DOM nodes as you like.
+
+To render a React element into a root DOM node, pass both to `ReactDOM.render()`:
+
+```js
+const element = <h1>Hello, world</h1>;
+ReactDOM.render(
+  element,
+  document.getElementById('root')
+);
+```
+
+[Try it on CodePen.](http://codepen.io/gaearon/pen/rrpgNB?editors=1010)
+
+It displays "Hello World" on the page.
+
+## Updating the Rendered Element
+
+React elements are [immutable](https://en.wikipedia.org/wiki/Immutable_object). Once you create an element, you can't change its children or attributes. An element is like a single frame in a movie: it represents the UI at a certain point in time.
+
+With our knowledge so far, the only way to update the UI is to create a new element, and pass it to `ReactDOM.render()`.
+
+Consider this ticking clock example:
+
+```js{8-11}
+function tick() {
+  const element = (
+    <div>
+      <h1>Hello, world!</h1>
+      <h2>It is {new Date().toLocaleTimeString()}.</h2>
+    </div>
+  );
+  ReactDOM.render(
+    element,
+    document.getElementById('root')
+  );
+}
+
+setInterval(tick, 1000);
+```
+
+[Try it on CodePen.](http://codepen.io/gaearon/pen/gwoJZk?editors=0010)
+
+It calls `ReactDOM.render()` every second from a [`setInterval()`](https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval) callback.
+
+>**Note:**
+>
+>In practice, most React apps only call `ReactDOM.render()` once. In the next sections we will learn how such code gets encapsulated into [stateful components](/react/docs/state-and-lifecycle.html).
+>
+>We recommend that you don't skip topics because they build on each other.
+
+## React Only Updates What's Necessary
+
+React DOM compares the element and its children to the previous one, and only applies the DOM updates necessary to bring the DOM to the desired state.
+
+You can verify by inspecting the [last example](http://codepen.io/gaearon/pen/gwoJZk?editors=0010) with the browser tools:
+
+![DOM inspector showing granular updates](/react/img/docs/granular-dom-updates.gif)
+
+Even though we create an element describing the whole UI tree on every tick, only the text node whose contents has changed gets updated by React DOM.
+
+In our experience, thinking about how the UI should look at any given moment rather than how to change it over time eliminates a whole class of bugs.
diff --git a/docs/docs/state-and-lifecycle.md b/docs/docs/state-and-lifecycle.md
new file mode 100644
index 000000000000..5c23a9959402
--- /dev/null
+++ b/docs/docs/state-and-lifecycle.md
@@ -0,0 +1,472 @@
+---
+id: state-and-lifecycle
+title: State and Lifecycle
+permalink: docs/state-and-lifecycle.html
+redirect_from: "docs/interactivity-and-dynamic-uis.html"
+prev: components-and-props.html
+next: handling-events.html
+---
+
+Consider the ticking clock example from [one of the previous sections](/react/docs/rendering-elements.html#updating-the-rendered-element).
+
+So far we have only learned one way to update the UI.
+
+We call `ReactDOM.render()` to change the rendered output:
+
+```js{8-11}
+function tick() {
+  const element = (
+    <div>
+      <h1>Hello, world!</h1>
+      <h2>It is {new Date().toLocaleTimeString()}.</h2>
+    </div>
+  );
+  ReactDOM.render(
+    element,
+    document.getElementById('root')
+  );
+}
+
+setInterval(tick, 1000);
+```
+
+[Try it on CodePen.](http://codepen.io/gaearon/pen/gwoJZk?editors=0010)
+
+In this section, we will learn how to make the `Clock` component truly reusable and encapsulated. It will set up its own timer and update itself every second.
+
+We can start by encapsulating how the clock looks:
+
+```js{3-6,12}
+function Clock(props) {
+  return (
+    <div>
+      <h1>Hello, world!</h1>
+      <h2>It is {props.date.toLocaleTimeString()}.</h2>
+    </div>
+  );
+}
+
+function tick() {
+  ReactDOM.render(
+    <Clock date={new Date()} />,
+    document.getElementById('root')
+  );
+}
+
+setInterval(tick, 1000);
+```
+
+[Try it on CodePen.](http://codepen.io/gaearon/pen/dpdoYR?editors=0010)
+
+However, it misses a crucial requirement: the fact that the `Clock` sets up a timer and updates the UI every second should be an implementation detail of the `Clock`.
+
+Ideally we want to write this once and have the `Clock` update itself:
+
+```js{2}
+ReactDOM.render(
+  <Clock />,
+  document.getElementById('root')
+);
+```
+
+To implement this, we need to add "state" to the `Clock` component.
+
+State is similar to props, but it is private and fully controlled by the component.
+
+We [mentioned before](/react/docs/components-and-props.html#functional-and-class-components) that components defined as classes have some additional features. Local state is exactly that: a feature available only to classes.
+
+## Converting a Function to a Class
+
+You can convert a functional component like `Clock` to a class in five steps:
+
+1. Create an [ES6 class](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes) with the same name that extends `React.Component`.
+
+2. Add a single empty method to it called `render()`.
+
+3. Move the body of the function into the `render()` method.
+
+4. Replace `props` with `this.props` in the `render()` body.
+
+5. Delete the remaining empty function declaration.
+
+```js
+class Clock extends React.Component {
+  render() {
+    return (
+      <div>
+        <h1>Hello, world!</h1>
+        <h2>It is {this.props.date.toLocaleTimeString()}.</h2>
+      </div>
+    );
+  }
+}
+```
+
+[Try it on CodePen.](http://codepen.io/gaearon/pen/zKRGpo?editors=0010)
+
+`Clock` is now defined as a class rather than a function.
+
+This lets us use additional features such as local state and lifecycle hooks.
+
+## Adding Local State to a Class
+
+We will move the `date` from props to state in three steps:
+
+1) Replace `this.props.date` with `this.state.date` in the `render()` method:
+
+```js{6}
+class Clock extends React.Component {
+  render() {
+    return (
+      <div>
+        <h1>Hello, world!</h1>
+        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
+      </div>
+    );
+  }
+}
+```
+
+2) Add a [class constructor](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes#Constructor) that assigns the initial `this.state`:
+
+```js{4}
+class Clock extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {date: new Date()};
+  }
+
+  render() {
+    return (
+      <div>
+        <h1>Hello, world!</h1>
+        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
+      </div>
+    );
+  }
+}
+```
+
+Note how we pass `props` to the base constructor:
+
+```js{2}
+  constructor(props) {
+    super(props);
+    this.state = {date: new Date()};
+  }
+```
+
+Class components should always call the base constructor with `props`.
+
+3) Remove the `date` prop from the `<Clock />` element:
+
+```js{2}
+ReactDOM.render(
+  <Clock />,
+  document.getElementById('root')
+);
+```
+
+We will later add the timer code back to the component itself.
+
+The result looks like this:
+
+```js{2-5,11,18}
+class Clock extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {date: new Date()};
+  }
+
+  render() {
+    return (
+      <div>
+        <h1>Hello, world!</h1>
+        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
+      </div>
+    );
+  }
+}
+
+ReactDOM.render(
+  <Clock />,
+  document.getElementById('root')
+);
+```
+
+[Try it on CodePen.](http://codepen.io/gaearon/pen/KgQpJd?editors=0010)
+
+Next, we'll make the `Clock` set up its own timer and update itself every second.
+
+## Adding Lifecycle Methods to a Class
+
+In applications with many components, it's very important to free up resources taken by the components when they are destroyed.
+
+We want to [set up a timer](https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval) whenever the `Clock` is rendered to the DOM for the first time. This is called "mounting" in React.
+
+We also want to [clear that timer](https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearInterval) whenever the DOM produced by the `Clock` is removed. This is called "unmounting" in React.
+
+We can declare special methods on the component class to run some code when a component mounts and unmounts:
+
+```js{7-9,11-13}
+class Clock extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {date: new Date()};
+  }
+
+  componentDidMount() {
+
+  }
+
+  componentWillUnmount() {
+
+  }
+
+  render() {
+    return (
+      <div>
+        <h1>Hello, world!</h1>
+        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
+      </div>
+    );
+  }
+}
+```
+
+These methods are called "lifecycle hooks".
+
+The `componentDidMount()` hook runs after the component output has been rendered to the DOM. This is a good place to set up a timer:
+
+```js{2-5}
+  componentDidMount() {
+    this.timerID = setInterval(
+      () => this.tick(),
+      1000
+    );
+  }
+```
+
+Note how we save the timer ID right on `this`.
+
+While `this.props` is set up by React itself and `this.state` has a special meaning, you are free to add additional fields to the class manually if you need to store something that is not used for the visual output.
+
+If you don't use something in `render()`, it shouldn't be in the state.
+
+We will tear down the timer in the `componentWillUnmount()` lifecycle hook:
+
+```js{2}
+  componentWillUnmount() {
+    clearInterval(this.timerID);
+  }
+```
+
+Finally, we will implement the `tick()` method that runs every second.
+
+It will use `this.setState()` to schedule updates to the component local state:
+
+```js{18-22}
+class Clock extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {date: new Date()};
+  }
+
+  componentDidMount() {
+    this.timerID = setInterval(
+      () => this.tick(),
+      1000
+    );
+  }
+
+  componentWillUnmount() {
+    clearInterval(this.timerID);
+  }
+
+  tick() {
+    this.setState({
+      date: new Date()
+    });
+  }
+
+  render() {
+    return (
+      <div>
+        <h1>Hello, world!</h1>
+        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
+      </div>
+    );
+  }
+}
+
+ReactDOM.render(
+  <Clock />,
+  document.getElementById('root')
+);
+```
+
+[Try it on CodePen.](http://codepen.io/gaearon/pen/amqdNA?editors=0010)
+
+Now the clock ticks every second.
+
+Let's quickly recap what's going on and the order in which the methods are called:
+
+1) When `<Clock />` is passed to `ReactDOM.render()`, React calls the constructor of the `Clock` component. Since `Clock` needs to display the current time, it initializes `this.state` with an object including the current time. We will later update this state.
+
+2) React then calls the `Clock` component's `render()` method. This is how React learns what should be displayed on the screen. React then updates the DOM to match the `Clock`'s render output.
+
+3) When the `Clock` output is inserted in the DOM, React calls the `componentDidMount()` lifecycle hook. Inside it, the `Clock` component asks the browser to set up a timer to call `tick()` once a second.
+
+4) Every second the browser calls the `tick()` method. Inside it, the `Clock` component schedules a UI update by calling `setState()` with an object containing the current time. Thanks to the `setState()` call, React knows the state has changed, and calls `render()` method again to learn what should be on the screen. This time, `this.state.date` in the `render()` method will be different, and so the render output will include the updated time. React updates the DOM accordingly.
+
+5) If the `Clock` component is ever removed from the DOM, React calls the `componentWillUnmount()` lifecycle hook so the timer is stopped.
+
+## Using State Correctly
+
+There are three things you should know about `setState()`.
+
+### Do Not Modify State Directly
+
+For example, this will not re-render a component:
+
+```js
+// Wrong
+this.state.comment = 'Hello';
+```
+
+Instead, use `setState()`:
+
+```js
+// Correct
+this.setState({comment: 'Hello'});
+```
+
+The only place where you can assign `this.state` is the constructor.
+
+### State Updates May Be Asynchronous
+
+React may batch multiple `setState()` calls into a single update for performance.
+
+Because `this.props` and `this.state` may be updated asynchronously, you should not rely on their values for calculating the next state.
+
+For example, this code may fail to update the counter:
+
+```js
+// Wrong
+this.setState({
+  counter: this.state.counter + this.props.increment,
+});
+```
+
+To fix it, use a second form of `setState()` that accepts a function rather than an object. That function will receive the previous state as the first argument, and the props at the time the update is applied as the second argument:
+
+```js
+// Correct
+this.setState((prevState, props) => ({
+  counter: prevState.counter + props.increment
+}));
+```
+
+We used an [arrow function](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions) above, but it also works with regular functions:
+
+```js
+// Correct
+this.setState(function(prevState, props) {
+  return {
+    counter: prevState.counter + props.increment
+  };
+});
+```
+
+### State Updates are Merged
+
+When you call `setState()`, React merges the object you provide into the current state.
+
+For example, your state may contain several independent variables:
+
+```js{4,5}
+  constructor(props) {
+    super(props);
+    this.state = {
+      posts: [],
+      comments: []
+    };
+  }
+```
+
+Then you can update them independently with separate `setState()` calls:
+
+```js{4,10}
+  componentDidMount() {
+    fetchPosts().then(response => {
+      this.setState({
+        posts: response.posts
+      });
+    });
+
+    fetchComments().then(response => {
+      this.setState({
+        comments: response.comments
+      });
+    });
+  }
+```
+
+The merging is shallow, so `this.setState({comments})` leaves `this.state.posts` intact, but completely replaces `this.state.comments`.
+
+## The Data Flows Down
+
+Neither parent nor child components can know if a certain component is stateful or stateless, and they shouldn't care whether it is defined as a function or a class.
+
+This is why state is often called local or encapsulated. It is not accessible to any component other than the one that owns and sets it.
+
+A component may choose to pass its state down as props to its child components:
+
+```js
+<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
+```
+
+This also works for user-defined components:
+
+```js
+<FormattedDate date={this.state.date} />
+```
+
+The `FormattedDate` component would receive the `date` in its props and wouldn't know whether it came from the `Clock`'s state, from the `Clock`'s props, or was typed by hand:
+
+```js
+function FormattedDate(props) {
+  return <h2>It is {props.date.toLocaleTimeString()}.</h2>;
+}
+```
+
+[Try it on CodePen.](http://codepen.io/gaearon/pen/zKRqNB?editors=0010)
+
+This is commonly called a "top-down" or "unidirectional" data flow. Any state is always owned by some specific component, and any data or UI derived from that state can only affect components "below" them in the tree.
+
+If you imagine a component tree as a waterfall of props, each component's state is like an additional water source that joins it at an arbitrary point but also flows down.
+
+To show that all components are truly isolated, we can create an `App` component that renders three `<Clock>`s:
+
+```js{4-6}
+function App() {
+  return (
+    <div>
+      <Clock />
+      <Clock />
+      <Clock />
+    </div>
+  );
+}
+
+ReactDOM.render(
+  <App />,
+  document.getElementById('root')
+);
+```
+
+[Try it on CodePen.](http://codepen.io/gaearon/pen/vXdGmd?editors=0010)
+
+Each `Clock` sets up its own timer and updates independently.
+
+In React apps, whether a component is stateful or stateless is considered an implementation detail of the component that may change over time. You can use stateless components inside stateful components, and vice versa.
diff --git a/docs/docs/thinking-in-react.it-IT.md b/docs/docs/thinking-in-react.it-IT.md
deleted file mode 100644
index 7cc96b61efb3..000000000000
--- a/docs/docs/thinking-in-react.it-IT.md
+++ /dev/null
@@ -1,147 +0,0 @@
----
-id: thinking-in-react-it-IT
-title: Pensare in React
-prev: tutorial-it-IT.html
-next: conferences-it-IT.html
-redirect_from: 'blog/2013/11/05/thinking-in-react.html'
----
-
-di Pete Hunt
-
-React è, a mio parere, la maniera più adeguata di costruire veloci applicazioni Web di grandi dimensioni con JavaScript. Ha scalato molto bene per noi a Facebook e Instagram.
-
-Una delle molte parti migliori di React è come ti fa pensare alle applicazioni mentre le costruisci. In questo articolo vi guiderò attraverso il processo di pensiero per la costruzione di una tabella di dati di prodotti che possono essere cercati usando React.
-
-## Comincia con un mock
-
-Immagina di possedere già una API JSON e un mock prodotto dai nostri designer. I nostri designer apparentemente non sono molto capaci perché il mock ha questo aspetto:
-
-![Mockup](/react/img/blog/thinking-in-react-mock.png)
-
-La nostra API JSON restituisce dei dati che somigliano a quanto segue:
-
-```
-[
-  {category: "Sporting Goods", price: "$49.99", stocked: true, name: "Football"},
-  {category: "Sporting Goods", price: "$9.99", stocked: true, name: "Baseball"},
-  {category: "Sporting Goods", price: "$29.99", stocked: false, name: "Basketball"},
-  {category: "Electronics", price: "$99.99", stocked: true, name: "iPod Touch"},
-  {category: "Electronics", price: "$399.99", stocked: false, name: "iPhone 5"},
-  {category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7"}
-];
-```
-
-## Passo 1: suddividi la UI in una gerarchia di componenti
-
-La prima azione che vorrai compiere è disegnare dei rettangoli attorno a ciascun componente (e subcomponenti) nel mock e dare un nome a ciascuno di essi. Se stai lavorando con i designer, potrebbero averlo già fatto, quindi parla anzitutto con loro! I nomi dei loro layer di Photoshop potrebbero finire per diventare i nomi dei tuoi componenti React!
-
-Come fai tuttavia a sapere cosa dovrebbe essere un componente a sé? Usa una delle tecniche per decidere se devi creare un nuovo oggetto o una nuova funzione. Una di tali tecniche è il [principio della singola responsibilità](https://en.wikipedia.org/wiki/Single_responsibility_principle), ovvero, un componente dovrebbe idealmente servire a un solo scopo. Se finisce per crescere, dovrebbe essere decomposto in componenti più piccoli.
-
-Dal momento che stai spesso mostrando un modello di dati JSON all'utente, ti accorgerai che se il tuo modello è stato costruito correttamente, la tua UI (e quindi anche la struttura dei tuoi componenti) si adatterà facilmente. Ciò accade perché le UI e i modelli di dati tendono ad aderire alla medesima *architettura dell'informazione*, che significa che il compito di separare la tua UI in componenti è spesso banale. Suddividila semplicemente in componenti che rappresentano esattamente un frammento del tuo modello di dati.
-
-![Diagramma dei componenti](/react/img/blog/thinking-in-react-components.png)
-
-Vedrai che abbiamo in tutto cinque componenti nella nostra semplice applicazione. Ho scritto in corsivo i dati che ciascun componente rappresenta.
-
-  1. **`FilterableProductTable` (arancione):** contiene l'intero esempio
-  2. **`SearchBar` (blu):** riceve tutti gli *input dell'utente*
-  3. **`ProductTable` (verde):** mostra e filtra la *collezione dei dati* basandosi sull'*input dell'utente*
-  4. **`ProductCategoryRow` (turchese):** mostra un titolo per ciascuna *categoria*
-  5. **`ProductRow` (rosso):** mostra una riga per ciascun *prodotto*
-
-Se osservi la `ProductTable`, ti accorgerai che l'intestazione della tabella (che contiene le etichette "Name" e "Price") non è un componente a sé. Questa è una questione di gusti, e ci sono ragioni valide per ciascun approccio. Per questo esempio, l'ho lasciata parte di `ProductTable` perché fa parte della visualizzazione della *collezione dei dati* che è la responsabilità di `ProductTable`. Tuttavia, se questa intestazione cresce fino a diventare complessa (cioè se dovessimo aggiungere la possibilità di riordinare i dati), avrebbe certamente senso renderla un componente `ProductTableHeader` a sé.
-
-Adesso che abbiamo identificato i componenti nel nostro mock, organizziamoli in una gerarchia. Questo è un compito facile. I componenti che appaiono all'interno di un altro componente nel the mock devono apparire come figli nella gerarchia:
-
-  * `FilterableProductTable`
-    * `SearchBar`
-    * `ProductTable`
-      * `ProductCategoryRow`
-      * `ProductRow`
-
-## Passo 2: Costruisci una versione statica in React
-
-<iframe width="100%" height="600" src="https://jsfiddle.net/reactjs/yun1vgqb/embedded/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
-
-Adesso che hai la tua gerarchia di componenti, è venuto il momento di implementare la tua applicazione. La maniera più semplice è costruire una versione che prende il tuo modello di dati e visualizza la UI ma non è interattiva. È buona norma disaccoppiare questi processi perché costruire una versione statica richiede la scrittura di parecchio codice e poco pensare, mentre aggiungere l'interattività richiede un parecchio pensare ma non un granché di scrittura. Vedremo perché.
-
-Per costruire una versione statica della tua applicazione dhe visualizzi il tuo modello dei dati, vorrai costruire componenti che riutilizano altri componenti e passano loro dati usando le *props*. Le *props* sono una maniera di passare dati da genitore a figlio. Se hai dimestichezza con il concetto di *state*, **non usare lo stato** per costruire questa versione statica. Lo stato è riservato solo per l'interattività, cioè dati che cambiano nel tempo. Dal momento che questa è una versione statica dell'applicazione, non ne avrai bisogno.
-
-Puoi costruire dall'alto in basso, o dal basso in alto. Ovvero, puoi cominciare a costruire i componenti più in alto nella gerarchia (cioè cominciare con `FilterableProductTable`) oppure con quelli più in basso (`ProductRow`). In esempi più semplici, è solitamente più facile andare dall'alto in basso, mentre in progetti più grandi è più facile andare dal basso in alto e scrivere test mentre costruisci.
-
-Alla fine di questo passo avrai una libreria di componenti riutilizzabili che visualizzano il tuo modello dati. I componenti avranno soltanto metodi `render()` dal momento che questa è una versione statica della tua applicazione. Il componente al vertice della gerarchia (`FilterableProductTable`) prenderà il tuo modello dati come una proprietà. Se apporti un cambiamento al tuo modello dati sottostante e chiami nuovamente `ReactDOM.render()`, la UI sarà aggiornata. È facile vedere come la tua UI viene aggiornata e dove applicare cambiamenti dal momento che non c'è nulla di complicato. Il **flusso dati unidirezionale** di React (detto anche *binding unidirezionale*) mantiene tutto modulare e veloce.
-
-Fai riferimento alla [documentazione React](/react/docs/) se hai bisogno di aiuto nell'eseguire questo passo.
-
-### Un breve intermezzo: proprietà oppure stato
-
-Esistono due tipi di dati "modello" in React: proprietà e stato. È importante capire la distinzione tra i due; scorri [la documentazione ufficiale di React](/react/docs/interactivity-and-dynamic-uis.html) se non hai ben chiara la differenza.
-
-## Passo 3: Identifica la rappresentazione minima (ma completa) dello stato della UI
-
-Per rendere la tua UI interattiva, hai bisogno di poter scatenare cambiamenti al tuo modello dati sottostante. React lo rende facile tramite lo **stato**.
-
-Per costruire correttamente la tua applicaizone, devi prima pensare all'insieme minimo di stato mutevole di cui la tua applicazione ha bisogno. La chiave qui è il principio DRY: *Don't Repeat Yourself (Non ripeterti)*. Una volta compresa la rappresentazione minima in assoluto dello stato della tua applicazione e calcola tutto lil resto sul momento. Ad esempio, se stai costruendo una lista di cose da fare, mantieni un array delle cose da fare; non tenere una variabile di stato separata per il conteggio. Invece, quando vuoi visualizzare il conteggio degli elementi, prendi semplicemente la lunghezza dell'arraiy delle cose da fare.
-
-Pensa a tutti gli elementi di dati nella nostra applicazione di esempio. Abbiamo:
-
-  * La lista originaria dei prodotti
-  * Il testo di ricerca che l'utente ha introdotto
-  * Il valore del checkbox
-  * La lista filtrata dei prodotti
-
-Rivediamo ciascuno di essi e capiamo se si tratta di stato. Chiediti queste tre semplici domande su ciascun elemento di dati:
-
-  1. Viene passato da un genitore attraverso le proprietà? Se sì, probabilmente non è stato.
-  2. Cambia nel tempo? Se no, probabilmente non è stato.
-  3. Puoi calcolarlo basandoti su altro stato o proprietà del tuo componente? Se sì, non è stato.
-
-La lista originaria di prodotti viene passata come proprietà, quindi non si tratta di stato. Il testo di ricerca e la checkbox sembrano essere stato perché cambiano nel tempo e non possono essere ricavate da altri dati. Infine, la lista filtrata di prodotti non è stato, perché può essere calcolata combinando la lista originaria dei prodotti con il testo di ricerca e il valore della checkbox.
-
-Quindi, per concludere, il nostro stato è:
-
-  * Il testo di ricerca che l'utente ha introdotto
-  * Il valore del checkbox
-
-## Passo 4: Identifica dove debba risiedere il tuo stato
-
-<iframe width="100%" height="600" src="https://jsfiddle.net/reactjs/zafjbw1e/embedded/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
-
-OK, abbiamo dunque identificato quale sia l'insieme minimo dello stato dell'applicazione. Successivamente, dobbiamo identificare quale componente muta, o *possiede*, questo stato.
-
-Ricorda: React è basato esclusivamente su flusso dati unidirezionale verso il basso della gerarchia dei componenti. Potrebbe non essere immediatamente chiaro quale componente debba possedere quale stato. **Questa è spesso la parte più difficile da capire per i principianti,** quindi segui questi passi per capirlo:
-
-Per ogni elemento dello stato nella tua applicazione:
-
-  * Identifica ciascun componente che visualizza qualcosa basato su quello stato.
-  * Trova un componente proprietario comune (un singolo componente più in alto nella gerarchia di ciascun componente che ha bisogno dello stato).
-  * Il proprietario comune o un altro componente più in alto nella gerarchia deve possedere lo stato.
-  * Se non riesci a trovare un componente per cui abbia senso possedere lo stato, crea un nuovo componente con il solo scopo di contenere lo stato e aggiungilo da qualche parte nella gerarchia sopra il componente proprietario comune.
-
-Applichiamo questa strategia per la nostra applicazione:
-
-  * `ProductTable` deve filtrare la lista dei prodotti basandosi sullo stato e `SearchBar` deve visualizzare il testo di ricerca e lo stato della checkbox.
-  * Il componente proprietario comune è `FilterableProductTable`.
-  * Ha concettualmente senso che il testo di ricerca e lo stato della checkbox appartengano a `FilterableProductTable`
-
-Bene, abbiamo deciso che il nostro stato appartenga a `FilterableProductTable`. Anzitutto aggiungiamo un metodo `getInitialState()` a `FilterableProductTable` che restituisce `{filterText: '', inStockOnly: false}` per riflettere lo stato iniziale della tua applicazione. Dunque, passiamo `filterText` e `inStockOnly` a `ProductTable` e `SearchBar` come una proprietà. Infine, usiamo queste proprietà per filtrare le righe in `ProductTable` e impostare i valori dei campi del modulo in `SearchBar`.
-
-Puoi cominciare a vedere come si comporterà la tua applicazione: imposta `filterText` a `"ball"` e aggiorna la tua applicazione. Vedrai che la tabella dei dati è correttamente aggiornata.
-
-## Passo 5: Aggiungi il flusso dati inverso
-
-<iframe width="100%" height="600" src="https://jsfiddle.net/reactjs/n47gckhr/embedded/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
-
-Finora abbiamo costruito un'applicazione che visualizza correttamente come una funzione di proprietà e stato che fluiscono verso il basso della gerarchia. Adesso è il momento di supportare il flusso dei dati nella direzione opposta: i componenti del modulo in profondità nella gerarchia devono aggiornare lo stato in `FilterableProductTable`.
-
-React rende questo flusso dati esplicito per rendere più semplice la comprensione di come funziona la tua applicazione, ma richiede leggermente più codice di un tradizionale binding bidirezionale dei dati. React offre un add-on chiamato `ReactLink` per rendere questo pattern altrettanto conveniente del binding bidirezionale ma, per gli scopi di questo articolo, faremo tutto in modo esplicito.
-
-Se provi a scrivere o spunti la casella nella versione attuale dell'esempio, vedrai che React ignora il tuo input. Questo è un comportamento intenzionale, in quanto abbiamo impostato la proprietà `value` del campo `input` perché sia sempre uguale al valore di `state` passato da `FilterableProductTable`.
-
-Pensiamo a cosa vogliamo che accada. Vogliamo assicurarci che quando l'utente cambia il modulo noi aggiorniamo lo stato per riflettere l'input dell'utente. Dal momento che i componenti devono soltanto aggiornare il proprio stato, `FilterableProductTable` passerà una callback a `SearchBar` che sarà eseguita quando lo stato debba essere aggiornato. Possiamo utilizzare l'evento `onChange` sui campi di input per esserne notificati. E la callback passata da `FilterableProductTable` chiamerà `setState()`, e l'applicazione verrà aggiornata.
-
-Anche se sembra complesso, si tratta realmente di poche righe di codice. Inoltre, il flusso dati attraverso l'applicazione è davvero esplicito.
-
-## Tutto qui
-
-Speriamo che questo ti abbia dato un'idea di come pensare a costruire componenti e applicazioni con React. Mentre potrebbe richiedere leggermente più codice di quanto si sia abituati a scrivere, ricorda che il codice è letto più spesso di quanto sia scritto, ed è estremamente facile leggere codice così esplicito e modulare. Mentre ti avvii a costruire grandi librerie di componenti, apprezzerai questa chiarezza e modularità, e con il riutilizzo del codice le tue righe di codice cominceranno a ridursi. :)
diff --git a/docs/docs/thinking-in-react.ja-JP.md b/docs/docs/thinking-in-react.ja-JP.md
deleted file mode 100644
index ee1768a75956..000000000000
--- a/docs/docs/thinking-in-react.ja-JP.md
+++ /dev/null
@@ -1,148 +0,0 @@
----
-id: thinking-in-react-ja-JP
-title: Reactの考え方
-prev: tutorial-ja-JP.html
-next: conferences.html
-redirect_from: 'blog/2013/11/05/thinking-in-react.html'
----
-
-Pete Hunt著
-
-ReactはJavascriptで大きなアプリを早く作成するのに良い方法だと私は思います。FacebookとInstagram製で規模を大きすすることも容易いです。
-
-Reactのたくさんある中の偉大なパーツの1つのは、あなたに構築するアプリについて考えさせます。このページで、私はReactを使って検索可能な製品データテーブルを構築する思考プロセスをご案内します。
-
-## モックから始めましょう
-
-私たちはすでにデザイナーからJSON APIとモックをもらっていると想像してください。このモックを見ればわかるように私たちのデザイナーは明らかに良くないです。
-
-![Mockup](/react/img/blog/thinking-in-react-mock.png)
-
-JSON APIはこれらのようなデータを返します。
-
-```
-[
-  {category: "Sporting Goods", price: "$49.99", stocked: true, name: "Football"},
-  {category: "Sporting Goods", price: "$9.99", stocked: true, name: "Baseball"},
-  {category: "Sporting Goods", price: "$29.99", stocked: false, name: "Basketball"},
-  {category: "Electronics", price: "$99.99", stocked: true, name: "iPod Touch"},
-  {category: "Electronics", price: "$399.99", stocked: false, name: "iPhone 5"},
-  {category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7"}
-];
-```
-
-## ステップ1 : コンポーネント階層を用いてUIを改築します
-
-まずあなたが行いたいことは、モックに必要なすべてのコンポーネント(サブコンポーネントも)の箱を作り、名前をつけることでしょう。もしあなたがデザイナーと共に働いているなら、すでに行っているかもしれませんが、彼らと話に行きましょう！彼らのPhotoshopのレイヤーの名前をReactのコンポーネントの名前にして終わらせることもできます。
-
-独自コンポーネントがどのようにあるべきか知っていますか？ あなたが新しい関数やオブジェクトを作る必要があるかどうかを決定するために同じ技術を使用しています。そのうちの一つのテクニックが[単一責任の原則(single responsibility principle)](https://en.wikipedia.org/wiki/Single_responsibility_principle)です。これは一つのコンポーネントは一つの振る舞いをするべきというものです。もしこれが難しいのであれば、より小さなサブコンポーネントに分ける必要があります。
-
-あなたは多くの場合、ユーザーにJSONデータ・モデルを表示しているので、あなたのモデルが正しく構築された場合、あなたのUI (したがって、コンポーネントの構造)がうまくマッピングされることがわかります。なぜなら、UIとデータモデルは同じ*情報構造*を持つ傾向にあり、つまりコンポーネントにUIを分離する作業は些細なことです。あなたの一つのデータモデルを表すコンポーネントに分割することが重要です。
-
-
-![Component diagram](/react/img/blog/thinking-in-react-components.png)
-
-これは私たちのシンプルなアプリの5つのコンポーネントです。各コンポーネントが表すデータが斜体になっています。
-
-  1. **`FilterableProductTable` (orange):** 例のすべてを含んでいます。
-  2. **`SearchBar` (blue):** *ユーザー入力*のすべてを含んでいます。
-  3. **`ProductTable` (green):** displays and filters the *ユーザー入力*に基づいた*データコレクション*を表示、選別します
-  4. **`ProductCategoryRow` (turquoise):** *カテゴリー*ごとに表示します。
-  5. **`ProductRow` (red):** *製品*の行ごとに表示します。
-
-`ProductTable`を見ると、テーブルのヘッダー("Name"と"Price"ラベルを含んでいる)が独自コンポーネントではないとわかります。これは好みの問題で、どちらの方法が良いかの議論があります。この例では、`ProductTable`の責任の範囲である*データ収集*レンダリングの一部であるため、私は`ProductTable`の一部として残しました。しかし、もしこのヘッダーが複雑になりそうであれば、(ソートにアフォーダンスを追加した場合など)新しい `ProductTableHeader` という独自コンポーネントを作る意味が高まります。
-
-
-私たちは自分たちのモックのコンポーネントを特定し、階層に配置してみましょう。これらは簡単です。モックの中の他のコンポーネントと一緒に使用するコンポーネントはその子供の階層にいなくてはいけません。
-
-  * `FilterableProductTable`
-    * `SearchBar`
-    * `ProductTable`
-      * `ProductCategoryRow`
-      * `ProductRow`
-
-## ステップ2 : 静的なReactの構築
-
-<iframe width="100%" height="600" src="https://jsfiddle.net/reactjs/yun1vgqb/embedded/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
-
-あなたは今コンポーネントの階層を持っており、アプリを実装する時がきました。最も簡単な方法はあなたの持っているデータモデルを受け取りUIをレンダリングするが、双方向性を持っていないバージョンを構築することです。静的なバージョンを構築するには多くのコードを書く必要があるが考えることはなく、双方向性を加えるためには熟考する必要がありコード量は多くないです。そのためこれらのプロセスは分離するのが最善の手段です。理由をみていきましょう。
-
-データモデルをレンダリングさせる静的なバージョンを構築するために、あなたは他のコンポーネントを再利用したり、*props*を使用してコンポーネントを構築したいと思うでしょう。*props*とは親から子へデータを受け渡す方法のことです。もしあなたが*state*のことを知っているなら、この静的なバージョンを構築する際には**絶対にstateは使わないでください**。stateは双方向性のためにのみ予約されます。それはつまり、時間の経過とともにデータが変化していきます。静的なバージョンのアプリを作っている間はこれは必要のないものです。
-
-あなたはトップダウンでもボトムアップでも構築することができます。つまりあなたは階層の高い場所から(`FilterableProductTable`)でも、低い場所から(`ProductRow`)でもコンポーネントを構築し始めることができます。簡単な例ではトップダウンから行く方が簡単ですし、大規模なプロジェクトではボトムアップを行って、構築するテストを書く方が簡単です。
-
-この最後のステップは、データモデルをレンダリングできる再利用可能なコンポーネントのライブラリーを手に入れることです。これはあなたのアプリの静的なバージョンのため、コンポーネントは`render()`メソッドのみを持ちます。階層のトップのコンポーネント(`FilterableProductTable`)は部品としてデータモデルを持ちます。あなたが下の階層にあるデータモデルの変更を行い、`ReactDOM.render()`を呼ぶと、UIも更新されます。複雑なことは何もないので、どのようにあなたのUIが更新され、変更した場所を確認するのは簡単です。Reactの**1方向のデータフロー** (*１方向バインディング*ともよばれます。)はすべてのモジュール式と速さを保ちます。
-
-このステップでヘルプが必要な場合はここに簡単な説明があります。[React docs](/react/docs/)
-
-### コラム: props か state か？
-
-Reactにはpropsとstateの2つのタイプの"model"データがあります。この二つの違いを理解することは重要です。違いを明確に理解していない場合はここを参照してください。[the official React docs](/react/docs/interactivity-and-dynamic-uis.html)
-
-## ステップ3 : UI部品の最小限の(しかし完全な)表現を特定します
-
-UIをインタラクティブに作るために、下の階層のデータモデルを変更を行えるようにする必要があります。Reactでは **state** を使うことで簡単に行うことができます。
-
-アプリの構築を正しく行うために、まずそのアプリのニーズの可変状態の最小セットを考える必要があります。ここで重要なのはDRY、つまり繰り返さないこと、です。アプリケーションの状態の絶対的な最小表現を把握し、オンデマンドで必要他のすべてを計算します。たとえば、TODOリストを構築するとすると、TODOのリストを配列で保持し、個別にカウントの状態変数を保持しません。TODOの個数をレンダリングするときに、単にTODOのアイテムの長さを取得すればよいのです。
-
-今回のアプリケーションのデータのすべてを考えます。私たちは以下を持っています。
-
-  * 独自製品のリスト
-  * ユーザーが入力した検索テキスト
-  * チェックボックスの値
-  * 製品のフィルターリスト
-
-それぞれ一つを通し、それぞれの状態を把握しましょう。それぞれのデータに尋ねる質問は3つです。
-
-  1. それはpropを経由して、親から渡されますか？そうなら、おそらくstateではありません。
-  2. それは時間の経過とともに変化しますか？そうでないなら、おそらくstateではありません。
-  3. あなたはそれがコンポーネント内の他のstateやpropに基づいて計算することができますか？そうなら、おそらくstateではありません。
-
-その製品の独自のリストはpropとして渡されるので、stateではありません。検索テキストとチェックボックスは時間の経過とともに変化し、それを計算することはできないので、stateのように見えます。最後に、検索テキストとチェックボックスの値を持つ製品の独自のリストを組み合わせることによって計算することができるため、製品のフィルタリングされたリストはstateではありません。
-
-つまり最終的にstateはこうなります。
-
-  * ユーザーが入力した検索テキスト
-  * チェックボックスの値
-
-## ステップ4 : あなたのstateがあるべき場所を特定します。
-
-<iframe width="100%" height="600" src="https://jsfiddle.net/reactjs/zafjbw1e/embedded/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
-
-ここまでで、私たちはアプリの状態の最小セットが何であるかを認識することができました。次はコンポーネントの変化か、またはそれ自身の状態を特定する必要があります。
-
-メモ：Reactはすべてのデータがコンポーネントの階層が１方向に流れるものです。コンポーネントがどのような状況にあるかはすぐには明確にはならないかもしれません。** これはしばしば新しく学ぼうとする方には難しいものになるため** 把握するために次の手順に従います。
-
-アプリ内のそれぞれのstate
-
-  * 幾つかのstateに基づくレンダリングをするすべてのコンポーネントを識別する
-  * 共通の所有者を持つコンポーネント(階層内のstateを必要にするすべてのコンポーネント上にあるコンポーネント)
-  * 階層内の最大の、共通の所有者または別のコンポーネントのいずれか
-  * 意味のあるstateにコンポーネントを見つけることができない場合には、状態を保持するために、単純に新しいコンポーネントを作成し共通の所有者のコンポーネント上の階層のどこかに追加します。
-
-アプリケーションのためにこの戦略に沿って実行しましょう
-
-  * `ProductTable`はstateに基づいた製品リストのフィルターを必要とし、 `SearchBar`は検索テキストとチェックの状態を表示する必要があります。
-  * 共通のコンポーネントの所有者は`FilterableProductTable`です。
-  * `FilterableProductTable`にあるフィルタテキストと確認された値は概念的に理解する。
-
-stateは`FilterableProductTable`の中にあると決定しました。まずはアプリケーションの最初の状態を反映させるため、`FilterableProductTable`に `{filterText: '', inStockOnly: false}`を返す、`getInitialState()`という関数を追加します。次に、`ProductTable` と `SearchBar`にpropとして`filterText`と`inStockOnly`を通します。最後にこれらのpropを`ProductTable`の行のフィルターに使い、`SearchBar`のフォームのフィールドの値をセットします。
-
-アプリケーションがどのように動作(`"ball"`に`filterText`をセットし、アプリを更新する)するかを見て開始することができます。データテーブルが正しく更新されていることがわかるでしょう。
-
-## ステップ5 : 逆のデータフローを追加
-
-<iframe width="100%" height="600" src="https://jsfiddle.net/reactjs/n47gckhr/embedded/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
-
-ここまで、階層の下へ向かってpropやstateの関数として正しくレンダリングするアプリを構築しました。ここからは逆の方向へのデータのフローをサポートします。深い階層のフォームのコンポーネントは`FilterableProductTable`のstateを更新する必要があります。
-
-Reactは、このデータの流れがどのようにあなたのプログラムが動くのかの理解を簡単にする流れですが、それが伝統的な双方向のデータバインディングよりも少しタイピングを必要とします。Reactは`ReactLink`という双方向バインディングを便利に実装できるアドオンを提供していますが、この投稿の目的は私たちが全てを明確にすることです。
-
-例えば、あなたが入力するか現在のバージョンのチェックボックスをオンにしようとすると、あなたの入力をReactは無視することがわかります。これは意図的なもので、私たちは常に`FilterableProductTable` から渡された` state`に等しくなるように` input`の値を設定しているためです。
-
-何を起こしたいのかを考えましょう。私たちは確かにユーザーがどのようにフォームを変えても入力した値をstateに反映させようとしています。コンポーネントが自身のstateを更新する必要があるため、`FilterableProductTable`は`SearchBar`が更新するべき時にはいつでもコールバックを渡します。入力の通知に対して`onChange`イベントを使用できます。そして`FilterableProductTable`によって渡されたコールバックは`setState()`を呼び出し、アプリが更新されます。
-
-これは複雑に見えますが、それはわずか数行のコードのみです。そしてデータがどのようにアプリ内を流れているか、とても明白です。
-
-## 以上です。
-この記事を通してReactでコンポーネントとアプリケーションを構築するかをどのように考えるかのヒントになれば幸いです。あなたが今まで使ってきたものよりも少しタイピングが必要かもしれないが、そのコードは書かれているよりもはるかに多くを認識し、このモジュールを読むためにとても簡単でかつ明白なコードです。あなたが大きなコンポーネントのライブラリを構築するのなら、この明示性とモジュール性に感謝するでしょうし、コードの再利用性とコードのあなたのラインが縮小し始めます。 :)
diff --git a/docs/docs/thinking-in-react.ko-KR.md b/docs/docs/thinking-in-react.ko-KR.md
deleted file mode 100644
index 6476545a28a4..000000000000
--- a/docs/docs/thinking-in-react.ko-KR.md
+++ /dev/null
@@ -1,147 +0,0 @@
----
-id: thinking-in-react-ko-KR
-title: 리액트로 생각해보기
-permalink: thinking-in-react-ko-KR.html
-prev: tutorial-ko-KR.html
-next: videos-ko-KR.html
----
-
-Pete Hunt의 글입니다.
-
-제가 생각하기에, React는 JavaScript로 크고 빠른 웹 애플리케이션을 만드는데 최고입니다. 페이스북과 인스타그램에서 우리에게 잘 맞도록 조정되어 왔습니다.
-
-React의 많은 뛰어난 점들 중 하나는 생각을 하면서 애플리케이션을 만들게 한다는 겁니다. 이 포스트에서, React를 이용해 검색이 가능한 상품자료 테이블을 만드는 생각 과정을 이해할 수 있게 차근차근 설명할 겁니다.
-
-## 모형으로 시작해보기
-
-우리가 이미 JSON API와 디자이너로부터 넘겨받은 모형을 이미 가지고 있다고 생각해봅시다. 보시다시피 우리 디자이너는 별로 좋지 않습니다:
-
-![Mockup](/react/img/blog/thinking-in-react-mock.png)
-
-우리의 JSON API는 아래와 같은 데이터를 리턴합니다:
-
-```
-[
-  {category: "Sporting Goods", price: "$49.99", stocked: true, name: "Football"},
-  {category: "Sporting Goods", price: "$9.99", stocked: true, name: "Baseball"},
-  {category: "Sporting Goods", price: "$29.99", stocked: false, name: "Basketball"},
-  {category: "Electronics", price: "$99.99", stocked: true, name: "iPod Touch"},
-  {category: "Electronics", price: "$399.99", stocked: false, name: "iPhone 5"},
-  {category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7"}
-];
-```
-
-## 1단계: UI를 계층 구조의 컴포넌트로 분쇄하세요.
-
-당신이 하고싶은 첫번째는 모형에 있는 모든 컴포넌트 (그리고 자식엘리먼트) 주위에 상자를 그리고, 이름을 부여하는 것입니다. 만약 당신이 디자이너와 같이 작업중이라면, 그들은 이미 이 작업을 해놨을지도 모릅니다. 당장 가서 이야기해보세요. 그들의 포토샵 레이어 이름이 결국 당신의 React 컴포넌트들의 이름이 될 것입니다.
-
-그런데 무엇이 컴포넌트가 되어야 할까요? 당신이 새로운 함수나 객체를 만들어야만 한다면, 똑같이 적용하세요. 한가지 방법은 [단일 책임의 원칙](http://ko.wikipedia.org/wiki/%EB%8B%A8%EC%9D%BC_%EC%B1%85%EC%9E%84_%EC%9B%90%EC%B9%99) 입니다. 즉 하나의 컴포넌트는 이상적으로 한가지 작업만 수행해야 합니다. 컴포넌트가 결국 커진다면, 작은 자식 컴포넌트로 쪼개져야 합니다.
-
-주로 JSON 데이터 모델을 사용자에게 보여주기 때문에, 자료 모델이 잘 설계 되었다면, UI(혹은 컴포넌트 구조)가 잘 맞아 떨어진다는 것을 알게 될 겁니다. UI와 자료 모델은 같은 *정보 설계구조*로 따라가는 경향이 있기 때문입니다. 즉, UI를 컴포넌트들로 쪼개는 작업은 크게 어렵지 않습니다. 확실하게 각각 하나의 부분이 되도록 쪼개세요.
-
-![Component diagram](/react/img/blog/thinking-in-react-components.png)
-
-이 간단한 애플리케이션에는 다섯개의 컴포넌트가 있습니다. 각 컴포넌트들이 대표하는 자료를 기울여 표기했습니다.
-
-  1. **`FilterableProductTable` (오렌지):** 예제 전부를 포함합니다.
-  2. **`SearchBar` (파랑):** 모든 *사용자 입력* 을 받습니다.
-  3. **`ProductTable` (초록):** *자료 모음*을 *사용자 입력*에 맞게 거르고 보여줍니다.
-  4. **`ProductCategoryRow` (청록):** 각 *카테고리*의 제목을 보여줍니다.
-  5. **`ProductRow` (빨강):** 각 *프로덕트*를 보여줍니다.
-
-`ProductTable`을 보면, 테이블 제목("Name", "Price" 라벨들을 포함한)은 컴포넌트가 아닌것을 알 수 있습니다. 이건 기호의 문제이고, 어느쪽으로 만들던 논쟁거리입니다. 이 예제에서는, 저는 *자료 모음*을 그리는 `ProductTable`의 의무라고 생각했기 때문에 남겨 두었습니다. 하지만, 이 제목이 복잡해진다면 (예를 들어 정렬을 추가할 여유가 있다거나 하는), 이건 확실히 `ProductTableHeader` 컴포넌트로 만드는 것이 맞을 겁니다.
-
-이제 모형에 들어있는 컴포넌트들에 대해 알아보았으니, 계층 구조로 만들어 봅시다. 이건 쉽습니다. 다른 컴포넌트 속에 들어있는 컴포넌트를 자식으로 나타내기만 하면 됩니다.
-
-  * `FilterableProductTable`
-    * `SearchBar`
-    * `ProductTable`
-      * `ProductCategoryRow`
-      * `ProductRow`
-
-## 2단계: 정적 버전을 만드세요.
-
-<iframe width="100%" height="600" src="https://jsfiddle.net/reactjs/yun1vgqb/embedded/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
-
-계층구조의 컴포넌트들을 가지고 있으니, 이젠 애플리케이션을 구현할 시간입니다. 가장 쉬운 방법은 상호작용을 하지 않는 채로 자료 모델을 이용해 UI를 그리는 것입니다. 정적 버전을 만드는 데에는 적은 생각과 많은 노동이 필요하고, 상호작용을 추가하는 데에는 많은 생각과 적은 노동이 필요하기 때문에 둘을 분리하는 것이 가장 좋습니다. 왜 그런지 봅시다.
-
-자료 모델을 그리는 애플리케이션의 정적버전을 만들기 위해서, 다른 컴포넌트에 재사용할 컴포넌트를 만들고 자료 전달을 위해 *props*를 사용하고 싶을 것입니다. 만약 *상태*라는 개념에 익숙하다면, 정적 버전을 만들때 **절대 상태를 사용하지 마세요**. 상태는 오직 상호작용, 즉 가변적인 자료를 위해서만 준비되어 있습니다. 정적 버전을 만들 때는 필요가 없습니다.
-
-껍데기부터 혹은 속알맹이부터 만들 수 있습니다. 즉 계층구조상 위에서부터 (`FilterableProductTable` 부터) 혹은 아래에서부터 (`ProductRow`), 어느 방향에서든 시작해도 됩니다. 통상 큰 프로젝트에서는 계층구조상 위에서부터 시작하는 것이 쉽고, 테스트를 작성할때는, 아래에서부터 시작하는 것이 쉽습니다.
-
-이 단계의 결과, 자료 모델을 그리는 재활용 가능한 컴포넌트의 라이브러리를 갖게 되었습니다. 정적버전 이후로 컴포넌트들은 오직 `render()` 메소드만 갖고 있습니다. 계층구조상 가장 위의 컴포넌트 (`FilterableProductTable`)은 자료 모델을 prop으로 취할 것입니다. 자료 모델이 변했을 때, `ReactDOM.render()`를 다시 부르면 UI가 업데이트 됩니다. 어떻게 UI가 업데이트 되는지 참 알기 쉽습니다. 자료가 바뀌어도 처리해야 할 복잡한 일이 아무것도 없습니다. React의 **단일 방향 자료 흐름** (혹은 *단일방향 바인딩*)이 모든것을 모듈식으로, 추론하기 쉽게, 그리고 빠르게 유지해줍니다.
-
-이 단계를 진행하는 데에 도움이 필요하시다면, [React 문서](/react/docs/getting-started-ko-KR.html)를 참조하세요.
-
-### 잠시만: props vs state
-
-React 에는 두가지 타입의 자료 "모델"이 있습니다: props 와 state. 두가지의 구분점을 이해하는데 매우 중요합니다; 혹시 차이점을 확신하지 못한다면 걷어내세요 [공식 문서](/react/docs/interactivity-and-dynamic-uis-ko-KR.html).
-
-## 3단계: UI state 의 표현을 작지만 완전하도록 확인하세요.
-
-상호적인 UI를 만들기 위해서는, 자료 모델 변화에 반응할 수 있어야 합니다. React는 **state**로 이걸 쉽게 만들어주죠.
-
-올바르게 애플리케이션을 만들기 위해서는, 첫째로 애플리케이션에 필요한 변할 수 있는 state 들의 최소한의 집합에 대해서 생각해볼 필요가 있습니다. 여기 방법이 있습니다: *스스로 반복하지 마세요* (DRY). 애플리케이션의 상태를 나타낼 수 있는 가장 최소한의 표현 방식을 찾고, 그 밖의 것은 필요할 때 계산합니다. 예를들어 TODO 목록를 만든다고 칩시다. TODO 아이템들의 배열만 유지하세요; 갯수를 표현하기 위한 state 변수를 분리하지 마세요. 대신 TODO 아이템들 배열의 길이를 이용하세요.
-
-예제 애플리케이션에서의 모든 자료유형에 대해 생각해 봅시다:
-
-  * product 들의 원본 목록
-  * 사용자가 입력한 검색어
-  * 체크박스의 값
-  * product 들의 필터된 목록
-
-어느것이 state 가 될지 따져봅시다. 간단하게 각 자료에 대해 세가지만 생각해 보세요.
-
-  1. 만약 부모로부터 props 를 이용해 전달됩니까? 그렇다면 이건 state가 아닙니다.
-  2. 종종 바뀝니까? 아니라면 이것 역시 state가 아닙니다.
-  3. 컴포넌트에 있는 다른 state나 props를 통해서 계산되어질 수 있습니까? 역시 state가 아닙니다.
-
-product 들의 원본 목록은 props를 통해서 전달되기 때문에, state가 아닙니다. 검색어와 체크박스의 값은 다른것에 의해 계산될 수 있는 값이 아니고, 시시각각 변하기때문에 state가 맞습니다. 마지막으로 product 들의 걸러진 목록 역시 state가 아닙니다. 원본 목록과 검색어, 체크박스의 값 등에 의해 연산되어지는 값이기 때문이죠.
-
-결국, state는 다음과 같습니다:
-
-  * 사용자가 입력한 검색어
-  * 체크박스의 값
-
-## 4단계: 어디서 state가 유지되어야 하는지 확인하세요.
-
-<iframe width="100%" height="600" src="https://jsfiddle.net/reactjs/zafjbw1e/embedded/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
-
-이제 최소한의 state가 무엇인지 알아냈습니다. 다음은, 어떤 컴포넌트가 이 state를 변형하거나 만들어낼지 알아내야 합니다.
-
-기억하세요: React는 계층적 아래 컴포넌트로만 향하는 단일방향성 자료 흐름을 가집니다. 지금당장은 어떤 컴포넌트가 자기 자신의 state를 가져야 할지 명확하지 않을 것입니다. **이것이 초심자가 가장 이해하기 어려운 부분입니다**. 이제 개념을 명확히 하기 위해 다음으로 따라가 봅시다:
-
-애플리케이션에서 state의 경우:
-
-  * 모든 컴포넌트가 state를 통해 무언가를 그려냅니다.
-  * 대표 컴포넌트가 뭔지 찾으세요 (계층적으로 다른 컴포넌트들의 단일 상위 컴포넌트는 state를 가질 필요가 있습니다).
-  * 대표 컴포넌트 혹은 또다른 컴포넌트는 가능한 상위의 컴포넌트가 state를 소유해야 합니다.
-  * 만약 state를 가져야할 컴포넌트가 어느 것인지 모르겠으면, 새로운 컴포넌트를 만들어 state를 부여하고 기존의 대표 컴포넌트 위에 추가하세요.
-
-이 전략을 우리 애플리케이션에 적용해 봅시다.
-
-  * `ProductTable`은 state에 대해 걸러질 필요가 있고, `SearchBar` 역시 검색어 state와 체크박스 state를 보여줄 필요가 있습니다.
-  * 대표 컴포넌트는 `FilterableProductTable` 입니다.
-  * 개념적으로 검색어와 체크박스 값은 `FilterableProductTable`에 있어야 한다는 것이 명확합니다.
-
-좋습니다. state를 `FilterableProductTable`에서 관리하도록 결정했습니다. 먼저, `getInitialState()` 메소드를 `FilterableProductTable`에 추가하세요. 이 메소드는 애플리케이션의 초기 state를 갖도록 `{filterText: '', inStockOnly: false}`를 리턴하면 됩니다. 그리고, `filterText`와 `inStockOnly` 를 `ProductTable`과 `SearchBar`에 prop으로 전달하세요. 마지막으로, 이 prop들을 `ProductTable`을 걸러내는 데, 그리고 `SearchBar` form fields의 값을 세팅하는데 사용하세요.
-
-이제 어떻게 애플리케이션이 동작하는지 볼 수 있습니다: `filterText`를 `"ball"`로 설정하고 업데이트합니다. 자료 테이블이 제대로 업데이트 되는 것을 볼 수 있을 겁니다.
-
-## 5단계: 반대방향 자료 흐름을 추가하세요.
-
-<iframe width="100%" height="600" src="https://jsfiddle.net/reactjs/n47gckhr/embedded/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
-
-앞서 우리는 계층적으로 아랫방향 흐름의 props, state전달로 잘 동작하는 애플리케이션을 만들었습니다. 이제 다른방향의 자료 흐름을 지원할 시간입니다: form 컴포넌트들은 `FilterableProductTable`의 state를 업데이트할 필요성이 있죠.
-
-React는 어떻게 이 프로그램이 동작하는지 이해하기 쉽게 이 자료의 흐름을 명시적으로 만들어주지만 전통적인 두 방향의 자료 바인딩보다 다소 입력할 것이 많습니다. React는 이러한 패턴을 양방향 바인딩처럼 편하게 사용할 수 있도록 ReactLink를 제공하지만, 이 글의 목적상 명시적인 방식만 사용했습니다.
-
-지금 예제에 문자열을 입력하거나 체크박스를 체크하더라도, React가 입력을 무시하는것을 볼 수 있습니다. 의도적으로 `input`의 prop에 `value`를 세팅하면 항상 `state`가 `FilterableProductTable`로부터 전달되어야 합니다.
-
-우리가 원하는 것이 무엇인지 생각해 봅시다. 사용자 입력을 반영하기 위해, 사용자가 form을 바꿀때마다 업데이트 하기를 원하죠. 컴포넌트들이 오직 자기 자신의 state만 업데이트 하더라도 `FilterableProductTable`은 state가 변할때마다 반영되어야할 `SearchBar`에 콜백을 전달할 것입니다. 이 알림을 위해서 `onChange`이벤트를 사용할 수 있습니다. 그리고 `FilterableProductTable`으로부터 전달된 콜백은 `setState()`를 호출할 것이고, 애플리케이션은 업데이트될 것입니다.
-
-복잡하게 들릴 수 있지만, 실제로는 몇 줄 되지 않습니다. 그리고 애플리케이션의 구석구석에서 데이터가 어떻게 흐르는지 매우 명확해집니다.
-
-## 그리고
-
-이 글이 컴포넌트와 React로 애플리케이션을 어떻게 만들지에 대한 아이디어가 되길 바랍니다. 원래 하던 방식보다 조금 타이핑을 더 해야할지도 모르지만, 코드는 쓰는 경우보다 읽히는 경우가 많다는 점, 매우 읽기 편하고 명시적인 코드를 썼다는 점을 기억하세요. 컴포넌트로 큰 라이브러리를 만들기 시작할 때, 이 명시성과 모듈성에 감사하게 될 것이며, 재사용함에 따라 코드의 양도 줄어들 것입니다. :)
diff --git a/docs/docs/thinking-in-react.md b/docs/docs/thinking-in-react.md
index bdaf5ad3d196..daa833d1aa18 100644
--- a/docs/docs/thinking-in-react.md
+++ b/docs/docs/thinking-in-react.md
@@ -1,20 +1,20 @@
 ---
 id: thinking-in-react
 title: Thinking in React
-prev: tutorial.html
-next: conferences.html
-redirect_from: 'blog/2013/11/05/thinking-in-react.html'
+permalink: docs/thinking-in-react.html
+redirect_from:
+  - 'blog/2013/11/05/thinking-in-react.html'
+  - 'docs/thinking-in-react-zh-CN.html'
+prev: composition-vs-inheritance.html
 ---
 
-by Pete Hunt
+React is, in our opinion, the premier way to build big, fast Web apps with JavaScript. It has scaled very well for us at Facebook and Instagram.
 
-React is, in my opinion, the premier way to build big, fast Web apps with JavaScript. It has scaled very well for us at Facebook and Instagram.
+One of the many great parts of React is how it makes you think about apps as you build them. In this document, we'll walk you through the thought process of building a searchable product data table using React.
 
-One of the many great parts of React is how it makes you think about apps as you build them. In this post, I'll walk you through the thought process of building a searchable product data table using React.
+## Start With A Mock
 
-## Start with a mock
-
-Imagine that we already have a JSON API and a mock from our designer. Our designer apparently isn't very good because the mock looks like this:
+Imagine that we already have a JSON API and a mock from our designer. The mock looks like this:
 
 ![Mockup](/react/img/blog/thinking-in-react-mock.png)
 
@@ -31,7 +31,7 @@ Our JSON API returns some data that looks like this:
 ];
 ```
 
-## Step 1: Break the UI into a component hierarchy
+## Step 1: Break The UI Into A Component Hierarchy
 
 The first thing you'll want to do is to draw boxes around every component (and subcomponent) in the mock and give them all names. If you're working with a designer, they may have already done this, so go talk to them! Their Photoshop layer names may end up being the names of your React components!
 
@@ -41,7 +41,7 @@ Since you're often displaying a JSON data model to a user, you'll find that if y
 
 ![Component diagram](/react/img/blog/thinking-in-react-components.png)
 
-You'll see here that we have five components in our simple app. I've italicized the data each component represents.
+You'll see here that we have five components in our simple app. We've italicized the data each component represents.
 
   1. **`FilterableProductTable` (orange):** contains the entirety of the example
   2. **`SearchBar` (blue):** receives all *user input*
@@ -49,7 +49,7 @@ You'll see here that we have five components in our simple app. I've italicized
   4. **`ProductCategoryRow` (turquoise):** displays a heading for each *category*
   5. **`ProductRow` (red):** displays a row for each *product*
 
-If you look at `ProductTable`, you'll see that the table header (containing the "Name" and "Price" labels) isn't its own component. This is a matter of preference, and there's an argument to be made either way. For this example, I left it as part of `ProductTable` because it is part of rendering the *data collection* which is `ProductTable`'s responsibility. However, if this header grows to be complex (i.e. if we were to add affordances for sorting), it would certainly make sense to make this its own `ProductTableHeader` component.
+If you look at `ProductTable`, you'll see that the table header (containing the "Name" and "Price" labels) isn't its own component. This is a matter of preference, and there's an argument to be made either way. For this example, we left it as part of `ProductTable` because it is part of rendering the *data collection* which is `ProductTable`'s responsibility. However, if this header grows to be complex (i.e. if we were to add affordances for sorting), it would certainly make sense to make this its own `ProductTableHeader` component.
 
 Now that we've identified the components in our mock, let's arrange them into a hierarchy. This is easy. Components that appear within another component in the mock should appear as a child in the hierarchy:
 
@@ -59,9 +59,10 @@ Now that we've identified the components in our mock, let's arrange them into a
       * `ProductCategoryRow`
       * `ProductRow`
 
-## Step 2: Build a static version in React
+## Step 2: Build A Static Version in React
 
-<iframe width="100%" height="600" src="https://jsfiddle.net/reactjs/yun1vgqb/embedded/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
+<p data-height="600" data-theme-id="0" data-slug-hash="vXpAgj" data-default-tab="js" data-user="lacker" data-embed-version="2" class="codepen">See the Pen <a href="http://codepen.io/lacker/pen/vXpAgj/">Thinking In React: Step 2</a> on <a href="http://codepen.io">CodePen</a>.</p>
+<script async src="//assets.codepen.io/assets/embed/ei.js"></script>
 
 Now that you have your component hierarchy, it's time to implement your app. The easiest way is to build a version that takes your data model and renders the UI but has no interactivity. It's best to decouple these processes because building a static version requires a lot of typing and no thinking, and adding interactivity requires a lot of thinking and not a lot of typing. We'll see why.
 
@@ -73,11 +74,11 @@ At the end of this step, you'll have a library of reusable components that rende
 
 Simply refer to the [React docs](/react/docs/) if you need help executing this step.
 
-### A brief interlude: props vs state
+### A Brief Interlude: Props vs State
 
 There are two types of "model" data in React: props and state. It's important to understand the distinction between the two; skim [the official React docs](/react/docs/interactivity-and-dynamic-uis.html) if you aren't sure what the difference is.
 
-## Step 3: Identify the minimal (but complete) representation of UI state
+## Step 3: Identify The Minimal (but complete) Representation Of UI State
 
 To make your UI interactive, you need to be able to trigger changes to your underlying data model. React makes this easy with **state**.
 
@@ -93,8 +94,8 @@ Think of all of the pieces of data in our example application. We have:
 Let's go through each one and figure out which one is state. Simply ask three questions about each piece of data:
 
   1. Is it passed in from a parent via props? If so, it probably isn't state.
-  2. Does it change over time? If not, it probably isn't state.
-  3. Can you compute it based on any other state or props in your component? If so, it's not state.
+  2. Does it remain unchanged over time? If so, it probably isn't state.
+  3. Can you compute it based on any other state or props in your component? If so, it isn't state.
 
 The original list of products is passed in as props, so that's not state. The search text and the checkbox seem to be state since they change over time and can't be computed from anything. And finally, the filtered list of products isn't state because it can be computed by combining the original list of products with the search text and value of the checkbox.
 
@@ -103,9 +104,10 @@ So finally, our state is:
   * The search text the user has entered
   * The value of the checkbox
 
-## Step 4: Identify where your state should live
+## Step 4: Identify Where Your State Should Live
 
-<iframe width="100%" height="600" src="https://jsfiddle.net/reactjs/zafjbw1e/embedded/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
+<p data-height="600" data-theme-id="0" data-slug-hash="ORzEkG" data-default-tab="js" data-user="lacker" data-embed-version="2" class="codepen">See the Pen <a href="http://codepen.io/lacker/pen/ORzEkG/">Thinking In React: Step 4</a> by Kevin Lacker (<a href="http://codepen.io/lacker">@lacker</a>) on <a href="http://codepen.io">CodePen</a>.</p>
+<script async src="//assets.codepen.io/assets/embed/ei.js"></script>
 
 OK, so we've identified what the minimal set of app state is. Next, we need to identify which component mutates, or *owns*, this state.
 
@@ -124,24 +126,25 @@ Let's run through this strategy for our application:
   * The common owner component is `FilterableProductTable`.
   * It conceptually makes sense for the filter text and checked value to live in `FilterableProductTable`
 
-Cool, so we've decided that our state lives in `FilterableProductTable`. First, add a `getInitialState()` method to `FilterableProductTable` that returns `{filterText: '', inStockOnly: false}` to reflect the initial state of your application. Then, pass `filterText` and `inStockOnly` to `ProductTable` and `SearchBar` as a prop. Finally, use these props to filter the rows in `ProductTable` and set the values of the form fields in `SearchBar`.
+Cool, so we've decided that our state lives in `FilterableProductTable`. First, add an instance property `this.state = {filterText: '', inStockOnly: false}` to `FilterableProductTable`'s `constructor` to reflect the initial state of your application. Then, pass `filterText` and `inStockOnly` to `ProductTable` and `SearchBar` as a prop. Finally, use these props to filter the rows in `ProductTable` and set the values of the form fields in `SearchBar`.
 
 You can start seeing how your application will behave: set `filterText` to `"ball"` and refresh your app. You'll see that the data table is updated correctly.
 
-## Step 5: Add inverse data flow
+## Step 5: Add Inverse Data Flow
 
-<iframe width="100%" height="600" src="https://jsfiddle.net/reactjs/n47gckhr/embedded/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
+<p data-height="265" data-theme-id="0" data-slug-hash="qRqmjd" data-default-tab="js,result" data-user="rohan10" data-embed-version="2" data-pen-title="Thinking In React: Step 5" class="codepen">See the Pen <a href="http://codepen.io/rohan10/pen/qRqmjd">Thinking In React: Step 5</a> on <a href="http://codepen.io">CodePen</a>.</p>
+<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>
 
 So far, we've built an app that renders correctly as a function of props and state flowing down the hierarchy. Now it's time to support data flowing the other way: the form components deep in the hierarchy need to update the state in `FilterableProductTable`.
 
-React makes this data flow explicit to make it easy to understand how your program works, but it does require a little more typing than traditional two-way data binding. React provides an add-on called `ReactLink` to make this pattern as convenient as two-way binding, but for the purpose of this post, we'll keep everything explicit.
+React makes this data flow explicit to make it easy to understand how your program works, but it does require a little more typing than traditional two-way data binding.
 
 If you try to type or check the box in the current version of the example, you'll see that React ignores your input. This is intentional, as we've set the `value` prop of the `input` to always be equal to the `state` passed in from `FilterableProductTable`.
 
-Let's think about what we want to happen. We want to make sure that whenever the user changes the form, we update the state to reflect the user input. Since components should only update their own state, `FilterableProductTable` will pass a callback to `SearchBar` that will fire whenever the state should be updated. We can use the `onChange` event on the inputs to be notified of it. And the callback passed by `FilterableProductTable` will call `setState()`, and the app will be updated.
+Let's think about what we want to happen. We want to make sure that whenever the user changes the form, we update the state to reflect the user input. Since components should only update their own state, `FilterableProductTable` will pass callbacks to `SearchBar` that will fire whenever the state should be updated. We can use the `onChange` event on the inputs to be notified of it. The callbacks passed by `FilterableProductTable` will call `setState()`, and the app will be updated.
 
 Though this sounds complex, it's really just a few lines of code. And it's really explicit how your data is flowing throughout the app.
 
-## And that's it
+## And That's It
 
 Hopefully, this gives you an idea of how to think about building components and applications with React. While it may be a little more typing than you're used to, remember that code is read far more than it's written, and it's extremely easy to read this modular, explicit code. As you start to build large libraries of components, you'll appreciate this explicitness and modularity, and with code reuse, your lines of code will start to shrink. :)
diff --git a/docs/docs/thinking-in-react.zh-CN.md b/docs/docs/thinking-in-react.zh-CN.md
deleted file mode 100644
index 43cf114711a6..000000000000
--- a/docs/docs/thinking-in-react.zh-CN.md
+++ /dev/null
@@ -1,147 +0,0 @@
----
-id: thinking-in-react-zh-CN
-title: React 编程思想
-prev: tutorial-zh-CN.html
-next: conferences-zh-CN.html
-redirect_from: 'blog/2013/11/05/thinking-in-react.html'
----
-
-by Pete Hunt
-
-在我看来，React 是构建大型，快速 Web app 的首选方式。它已经在 Facebook 和 Instagram 被我们有了广泛的应用。
-
-React 许多优秀的部分之一，是它使得你在构建 app 的过程中不断思考。在本文里，我将带你经历一次使用 React 构建可搜索的商品数据表的思考过程。
-
-## 从模型（mock）开始
-
-想象我们已经有个一个 JSON API 和一个来自设计师的模型。我们的设计师显然做得不够好，因为模型看起来像这样：
-
-![Mockup](/react/img/blog/thinking-in-react-mock.png)
-
-我们的 JSON API 返回一些看起来像这样的数据：
-
-```
-[
-  {category: "Sporting Goods", price: "$49.99", stocked: true, name: "Football"},
-  {category: "Sporting Goods", price: "$9.99", stocked: true, name: "Baseball"},
-  {category: "Sporting Goods", price: "$29.99", stocked: false, name: "Basketball"},
-  {category: "Electronics", price: "$99.99", stocked: true, name: "iPod Touch"},
-  {category: "Electronics", price: "$399.99", stocked: false, name: "iPhone 5"},
-  {category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7"}
-];
-```
-
-## 第一步：把UI拆分为一个组件的层级
-
-首先你想要做的，是在模型里的每一个组件周围绘制边框，并给它们命名。如果你和设计师一起工作，他们应该已经完成这步了，所以去和他们谈谈！他们的 Photoshop 图层名也许最终会成为你的 React 组件名。
-
-但是你如何知道什么东西应该是独立的组件？只需在你创建一个函数或者对象时，根据是否使用过相同技术来做决定。一种这样的技术是[单一功能原则（single responsibility principle）](https://en.wikipedia.org/wiki/Single_responsibility_principle)，也就是一个组件在理想情况下只做一件事情。如果它最终增长了，它就应该被分解为更小的组件。
-
-既然你频繁显示一个 JSON 的数据模型给用户，你会发现，如果你的模型构建正确，你的 UI（因此也有你的组件结构）就将映射良好。那是因为 UI 和数据模型趋向附着于相同的 *信息架构*，这意味着，把你的 UI 分离为组件的工作通常是琐碎的，只需把 UI 拆分成能准确对应数据模型的每块组件。
-
-![Component diagram](/react/img/blog/thinking-in-react-components.png)
-
-在这里你会看到，在我们的简单 APP 里有五个组件。我用斜体表示每个组件的数据。
-
-  1. **`FilterableProductTable` (橙色):** 包含示例的整体
-  2. **`SearchBar` (蓝色):**  接收所有 *用户输入*
-  3. **`ProductTable` (绿色):** 基于 *用户输入* 显示和过滤 *数据集合(data collection)*
-  4. **`ProductCategoryRow` (蓝绿色):** 为每个 *分类* 显示一个列表头
-  5. **`ProductRow` (红色):** 为每个 *商品* 显示一行
-
-如果你看着 `ProductTable`，你会看到表头(包含了 "Name" 和 "Price" 标签) 不是独立的组件。这是一个个人喜好问题，并且无论采用哪种方式都有争论。对于这个例子，我把它留做 `ProductTable` 的一部分，因为它是 *data collection*渲染的一部分，而 *data collection* 渲染是 `ProductTable` 的职责。然而，当列表头增长到复杂的时候(例如 如果我们添加排序功能)，那么使它成为独立的 `ProductTableHeader` 组件无疑是有意义的。
-
-既然现在我们已经识别出了我们模型中的组件，让我们把他们安排到一个层级中。这很容易。在模型中，出现在一个组件里面的另一组件 ，应该在层级中表现为一种子级关系：
-
-  * `FilterableProductTable`
-    * `SearchBar`
-    * `ProductTable`
-      * `ProductCategoryRow`
-      * `ProductRow`
-
-## 第二步：用React创建一个静态版本
-
-<iframe width="100%" height="600" src="https://jsfiddle.net/reactjs/yun1vgqb/embedded/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
-
-既然你已经有了你的组件层级，是时候实现你的app了。简单的方式是构建一个版本，它取走你的数据模型并渲染UI，除了没有互动性。这是将过程解耦的最好办法，因为构建一个静态版本需要不假思索地写很多代码，而添加互动性需要很多思考但不需要太多代码。之后我们将会看到原因。
-
-要构建一个静态版本 app 来渲染你的数据模型，你将会想到构建一个重用其它组件并利用 *props* 传递数据的组件。*props* 是一种从父级传递数据到子级的方式。如果你对 *state* 的观念很熟悉，**绝不要用state** 来构建这个静态版本。State 仅仅是为互动性，也就是随时间变化的数据所预留的。由于这是一个静态版本，你还不需要用到它。
-
-你可以自顶向下或自底向上的构建。也就是说，你可以既从较高的层级（比如从 `FilterableProductTable` 开始）也可以从较低的层级（`ProductRow`）开始构建组件。在较简单的例子里，通常自顶向下要容易一些，然而在更大的项目上，自底向上地构建更容易，并且更方便伴随着构建写测试。
-
-在这一步的最后，你会获得一个渲染数据模型的可重用组件库。这些组件只有 `render()` 方法，因为这是一个静态版本。在层级顶端的组件 (`FilterableProductTable`) 将会接受你的数据模型，并将其作为一个prop。如果你改变了底层数据模型，并且再次调用 `React.render()` ，UI 将会更新。你可以很容易地看到 UI 是如何更新的，以及哪里变动了，因为这没什么复杂的。React的 **单向数据流** (也被称为 *单向绑定*)使一切保持了模块化和快速。
-
-如果你在执行这步时需要帮助，请参阅 [React 文档](/react/docs/)。
-
-### 小插曲: props vs state
-
-在React里有两种数据 "模型": props 和 state。明白这二者之间的区别是很重要的；如果你不是很确定它们之间的区别，请概览[React官方文档](/react/docs/interactivity-and-dynamic-uis-zh-CN.html)
-
-## 第三步：确定最小（但完备）的 UI state 表达
-
-要让你的 UI 互动，你需要做到触发底层数据模型发生变化。React用 **state** 来让此变得容易。
-
-要正确的构建你的 app，你首先需要思考你的 app 需要的可变 state 的最小组。这里的关键是 DRY 原则：*Don't Repeat Yourself(不要重复自己)*。想出哪些是你的应用需要的绝对最小 state 表达，并按需计算其他任何数据。例如，如果你要构建一个 TODO list，只要保持一个 TODO 项的数组；不要为了计数保持一个单独的 state 变量。当你想渲染 TODO 的计数时，简单的采用 TODO 项目的数组长度作为替代。
-
-考虑我们示例应用中的数据所有块，包括：
-
-  * 原始的商品列表
-  * 用户输入的搜索文本
-  * 复选框的值
-  * 商品的过滤列表
-
-让我们逐个检查出哪一个是state，只需要简单地问以下三个问题:
-
-  1. 它是通过props从父级传递来的吗？如果是，它可能不是 state。
-  2. 它随时间变化吗？如果不是,它可能不是 state。
-  3. 你能基于其他任何组件里的 state 或者 props 计算出它吗？如果是,它可能不是state.
-
-原始的商品列表以 props 传入，所以它不是 state。搜索文本和复选框看起来是 state，因为他们随时间变化并且不能从任何东西计算出。最后，过滤出的商品列表不是 state，因为它可以通过原始列表与搜索文本及复选框的值组合计算得出。
-
-所以最后,我们的 state 是:
-
-  * 用户输入的搜索文本
-  * checkbox 的值
-
-## 第四步：确定你的 state 应该存在于哪里
-
-<iframe width="100%" height="600" src="https://jsfiddle.net/reactjs/zafjbw1e/embedded/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
-
-OK，我们已经确定好应用的最小 state 集合是什么。接下来，我们需要确定哪个组件可以改变，或者 *拥有* 这个state.
-
-记住：React 总是在组件层级中单向数据流动的。可能不能立刻明白哪些组件应该拥有哪些 state。 **这对于新手在理解上经常是最具挑战的一部分，** 所以跟着这几步来弄明白它：
-
-对于你的应用里每一个数据块：
-
-  * 确定哪些组件要基于 state 来渲染内容。
-  * 找到一个共同的拥有者组件（在所有需要这个state组件的层次之上，找出共有的单一组件）。
-  * 要么是共同拥有者，要么是其他在层级里更高级的组件应该拥有这个state。
-  * 如果你不能找到一个组件让其可以有意义地拥有这个 state，可以简单地创建一个新的组件 hold 住这个state，并把它添加到比共同拥有者组件更高的层级上。
-
-让我们使用这个策略浏览一遍我们的应用：
-
-  * `ProductTable` 需要基于 state 过滤产品列表，`SearchBar` 需要显示搜索文本和选择状态。
-  * 共同拥有者组件是 `FilterableProductTable`。
-  * 对于过滤文本和选择框值存在于 `FilterableProductTable`，从概念上讲是有意义的。
-
-酷，我们已经决定了我们的 state 存在于 `FilterableProductTable`。首先，添加一个 `getInitialState()` 方法到  `FilterableProductTable`，返回 `{filterText: '', inStockOnly: false}` 来反映应用的初始状态。然后，传递`filterText` 和 `inStockOnly` 给 `ProductTable` 和 `SearchBar` 作为 prop。最后，使用这些 prop 来过滤 `ProductTable` 中的行和设置 `SearchBar` 的表单项的值。
-
-你可以开始看看你的应用将有怎样的行为了: 设置 `filterText` 为 `"ball"` 并刷新你的 app。你将可以看到数据表被正确地更新。
-
-## 第五步：添加反向数据流
-
-<iframe width="100%" height="600" src="https://jsfiddle.net/reactjs/n47gckhr/embedded/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
-
-到目前为止，我们已经构建了一个应用, 它以 props 和 state 沿着层级向下流动的功能正确渲染。现在是时候支持另一种数据流动了：在层级深处的表单组件需要更新 `FilterableProductTable` 里的 state。
-
-React 让数据显式流动，使你理解应用如何工作变得简单，但是相对于传统的双向数据绑定，确实需要多打一些字。React 提供了一个叫做 `ReactLink` 的插件来使这种模式和双向数据绑定一样方便，但是考虑到这篇文章的目的，我们将会保持所有东西都直截了当。
-
-如果你尝试在当前版本的示例中输入或者选中复选框，你会发现 React 忽略了你的输入。这是有意的，因为我们已经设置了 `input` 的 `value` prop 值总是与 `FilterableProductTable` 传递过来的 `state` 一致。
-
-让我们思考下希望发生什么。我们想确保每当用户改变表单，就通过更新 state 来反映用户的输入。由于组件应该只更新自己拥有的 state ， `FilterableProductTable` 将会传递一个回调函数给 `SearchBar` ，每当 state 应被更新时回调函数就会被调用。我们可以使用 input 的 `onChange` 事件来接受它的通知。 `FilterableProductTable` 传递的回调函数将会调用 `setState()` ，然后应用将会被更新。
-
-虽然这听起来复杂，但是实际上只是数行代码。并且这明确显示出了数据在应用中从始至终是如何流动的。
-
-## 好了，就是这样
-
-希望这给了你一个怎样思考用React构建组件和应用的概念。虽然可能比你过往的习惯要多敲一点代码，但记住，读代码的时间远比写代码的时间多，并且阅读这种模块化的、显式的代码是极为容易的。当你开始构建大型组件库时，你会非常感激这种清晰性和模块化，并且随着代码的重用，你的代码行数将会开始缩减。:)
diff --git a/docs/docs/tutorial.it-IT.md b/docs/docs/tutorial.it-IT.md
deleted file mode 100755
index 0746bf64fc6d..000000000000
--- a/docs/docs/tutorial.it-IT.md
+++ /dev/null
@@ -1,715 +0,0 @@
----
-id: tutorial-it-IT
-title: Tutorial
-prev: getting-started-it-IT.html
-next: thinking-in-react-it-IT.html
----
-
-Costruiremo una semplice ma realistica casella dei commenti che puoi inserire in un blog, una versione base dei commenti in tempo reale offerti da Disqus, LiveFyre o Facebook.
-
-Forniremo:
-
-* Una vista di tutti i commenti
-* Un modulo per inviare un commento
-* Hook perché tu fornisca un backend personalizzato
-
-Avrà anche un paio di caratteristiche interessanti:
-
-* **Commenti ottimistici:** i commenti appaiono nella lista prima che vengano salvati sul server, in modo da sembrare più veloce.
-* **Aggiornamenti in tempo reale:** i commenti degli altri utenti sono aggiunti alla vista dei commenti in tempo reale.
-* **Formattazione Markdown:** gli utenti possono utilizzare il Markdown per formattare il proprio testo.
-
-### Vuoi saltare tutto questo e vedere semplicemente il sorgente?
-
-[It's all on GitHub.](https://github.com/reactjs/react-tutorial)
-
-### Eseguire un server
-
-Per cominciare questo tutorial dobbiamo richiedere un server in esecuzione. Questo servirà puramente come un endpoint per le API che useremo per ottenere e salvare i dati. Per rendere questo compito il più semplice possibile, abbiamo creato un seplice server in un numero di linguaggi di scripting che fa esattamente ciò che ci serve. **Puoi [leggere il sorgente](https://github.com/reactjs/react-tutorial/) o [scaricare un file zip](https://github.com/reactjs/react-tutorial/archive/master.zip) contenente tutto ciò che ti serve per cominciare.**
-
-Per semplicità, il server che eseguiremo usa un file `JSON` come database. Non è ciò che eseguiresti in produzione, ma rende più facile simulare ciò che faresti per consumare una API. Non appena avvii il server, supporterà il nostro endpoint API e servirà anche le pagine statiche di cui abbiamo bisogno.
-
-### Per Cominciare
-
-Per questo tutorial renderemo il tutto il più semplice possibile. Incluso nel pacchetto del server discusso in precedenza si trova un file HTML su cui lavoreremo. Apri `public/index.html` nel tuo editor preferito. Dovrebbe apparire simile a quanto segue (con qualche piccola differenza, aggiungeremo un tag `<script>` aggiuntivo in seguito):
-
-```html
-<!-- index.html -->
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="utf-8" />
-    <title>React Tutorial</title>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/{{site.react_version}}/react.js"></script>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/{{site.react_version}}/react-dom.js"></script>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
-  </head>
-  <body>
-    <div id="content"></div>
-    <script type="text/babel" src="scripts/example.js"></script>
-    <script type="text/babel">
-      // To get started with this tutorial running your own code, simply remove
-      // the script tag loading scripts/example.js and start writing code here.
-    </script>
-  </body>
-</html>
-```
-
-Nel resto di questo tutorial, scriveremo il nostro codice JavaScript in questo tag script. Non disponiamo di alcun aggiornamento in tempo reale avanzato, quindi dovremo aggiornare il browser per vedere gli aggiornamenti dopo il salvataggio. Segui il tuo progresso aprendo `http://localhost:3000` nel tuo browser (dopo aver avviato il server). Quando carichi la pagina per la prima volta senza apportare cambiamenti, vedrai il risultato finale di ciò che ci apprestiamo a costruire. Quando sei pronto per cominciare a lavorare, elimina il tag `<script>` precedente e quindi sei pronto a continuare.
-
-> Nota:
->
-> Abbiamo incluso jQuery perché vogliamo semplificare il codice delle nostre chiamate ajax future, ma **NON** è richiesto per far funzionare React.
-
-### Il tuo primo componente
-
-In React ciò che importa sono i componenti modulari e componibili. Per il nostro esempio della casella dei commenti, avremo la seguente struttura dei componenti:
-
-```
-- CommentBox
-  - CommentList
-    - Comment
-  - CommentForm
-```
-
-Costruiamo il componente `CommentBox`, che consiste in un semplice `<div>`:
-
-```javascript
-// tutorial1.js
-var CommentBox = React.createClass({
-  render: function() {
-    return (
-      <div className="commentBox">
-        Ciao, mondo! Sono un CommentBox.
-      </div>
-    );
-  }
-});
-ReactDOM.render(
-  <CommentBox />,
-  document.getElementById('content')
-);
-```
-
-Nota che i nomi degli elementi nativi HTML cominciano con una lettera minuscola, mentre i nomi di classe personalizzati di React cominciano con una lettera maiuscola.
-
-#### Sintassi JSX
-
-La prima cosa che noterai è la sintassi simile a XML nel tuo JavaScript. Abbiamo un semplice preprocessore che traduce lo zucchero sintattico a questo semplice JavaScript:
-
-```javascript
-// tutorial1-raw.js
-var CommentBox = React.createClass({displayName: 'CommentBox',
-  render: function() {
-    return (
-      React.createElement('div', {className: "commentBox"},
-        "Ciao, mondo! Sono un CommentBox."
-      )
-    );
-  }
-});
-ReactDOM.render(
-  React.createElement(CommentBox, null),
-  document.getElementById('content')
-);
-```
-
-Il suo uso è opzionale ma abbiamo trovato la sintassi JSX più facile da usare del semplice JavaScript. Leggi maggiori dettagli sull'[articolo sulla sintassi JSX](/react/docs/jsx-in-depth.html).
-
-#### Cosa sta succedendo?
-
-Passiamo dei metodi in un oggetto JavaScript a `React.createClass()` per creare un nuovo componente React. Il più importante di questi metodi è chiamato `render` il quale restituisce un albero di componenti React che saranno eventualmente visualizzati come HTML.
-
-I tag `<div>` non sono veri nodi DOM; sono istanze dei componenti React `div`. Puoi pensare a questi come marcatori o a elementi di dati che React sa come gestire. React è **sicuro**. Non stiamo generando stringhe HTML quindi la protezione XSS è predefinita.
-
-Non devi necessariamente restituire semplice HTML. Puoi anche restituire un albero di componenti costruiti da te (o da qualcun altro). Questo è ciò che rende React **componibile**: una caratteristica chiave dei front-end manutenibili.
-
-`ReactDOM.render()` istanzia il componente radice, avvia il framework, e inietta il markup in un elemento DOM nativo, fornito come secondo argomento.
-
-## Comporre componenti
-
-Costruiamo degli scheletri per `CommentList` e `CommentForm` che saranno, nuovamente, dei semplici `<div>`. Aggiungi questi due componenti al tuo file, mantenendo la dichiarazione esistente di `CommentBox` e la chiamata a `ReactDOM.render`:
-
-```javascript
-// tutorial2.js
-var CommentList = React.createClass({
-  render: function() {
-    return (
-      <div className="commentList">
-        Hello, world! I am a CommentList.
-      </div>
-    );
-  }
-});
-
-var CommentForm = React.createClass({
-  render: function() {
-    return (
-      <div className="commentForm">
-        Hello, world! I am a CommentForm.
-      </div>
-    );
-  }
-});
-```
-
-Successivamente, aggiorna il componente `CommentBox` per utilizzare questi due nuovi componenti:
-
-```javascript{6-8}
-// tutorial3.js
-var CommentBox = React.createClass({
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>Commenti</h1>
-        <CommentList />
-        <CommentForm />
-      </div>
-    );
-  }
-});
-```
-
-Nota come stiamo mescolando tag HTML e i componenti che abbiamo costruito. I componenti HTML sono componenti regolari React, proprio come quelli che definisci, con una differenza. Il compilatore JSX riscriverà automaticamente i tag HTML come espressioni `React.createElement(tagName)` e lascerà tutto il resto inalterato. Questo è per impedire che il namespace globale venga inquinato.
-
-### Usare le proprietà
-
-Creiamo il componente `Comment`, che dipenderà dai dati passatigli dal suo genitore. I dati passati da un componente genitore sono disponibili come una 'proprietà' nel componente figlio. Queste 'proprietà' sono accessibili attraverso `this.props`. Usando le proprietà, saremo in grado di leggere i dati passati al componente `Comment` dal componente `CommentList`, e visualizzare del markup:
-
-```javascript
-// tutorial4.js
-var Comment = React.createClass({
-  render: function() {
-    return (
-      <div className="comment">
-        <h2 className="commentAuthor">
-          {this.props.author}
-        </h2>
-        {this.props.children}
-      </div>
-    );
-  }
-});
-```
-
-Racchiudendo un'espressione JavaScript dentro parentesi graffe all'interno di JSX (sia come attributo che come figlio), puoi inserire del testo o componenti React all'interno dell'albero. Accediamo per nome ad attributi passati al componente tramite chiavi in `this.props` e ciascun elemento annidato come `this.props.children`.
-
-### Proprietà dei Componenti
-
-Adesso che abbiamo definito il componente `Comment`, vogliamo passargli il nome dell'autore e il testo del commento. Questo ci permette di riutilizzare lo stesso codice per ciascun commento individuale. Ora aggiungiamo dei commenti all'interno del nostro `CommentList`:
-
-```javascript{6-7}
-// tutorial5.js
-var CommentList = React.createClass({
-  render: function() {
-    return (
-      <div className="commentList">
-        <Comment author="Pete Hunt">Questo è un commento</Comment>
-        <Comment author="Jordan Walke">Questo è un *altro* commento</Comment>
-      </div>
-    );
-  }
-});
-```
-
-Nota che abbiamo passato dei dati dal componente genitore `CommentList` al componente figlio `Comment`. Ad esempio, abbiamo passato *Pete Hunt* (tramite un attributo) e *Questo è un commento* (tramite un nodo figlio simil-XML) al primo `Comment`. Come detto in precedenza, il componente `Comment` accederà a queste 'proprietà' attraverso `this.props.author` e `this.props.children`.
-
-### Aggiungiamo il Markdown
-
-Il Markdown è una maniera semplice di formattare il tuo testo in linea. Ad esempio, racchiudendo il testo con asterischi gli aggiungerà dell'enfasi.
-
-Per prima cosa, aggiungiamo la libreria di terze parti **marked** alla tua applicazione. Questa è una libreria JavaScript che prende il testo Markdown e lo converte in HTML nativo. Per fare ciò è richiesto un tag script nel tag head (che abbiamo già incluso nel playground React):
-
-```html{9}
-<!-- index.html -->
-<head>
-  <meta charset="utf-8" />
-  <title>React Tutorial</title>
-  <script src="https://cdnjs.cloudflare.com/ajax/libs/react/{{site.react_version}}/react.js"></script>
-  <script src="https://cdnjs.cloudflare.com/ajax/libs/react/{{site.react_version}}/react-dom.js"></script>
-  <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
-  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
-  <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.5/marked.min.js"></script>
-</head>
-```
-
-Successivamente, convertiamo il testo del commento da Markdown e scriviamolo:
-
-```javascript{9}
-// tutorial6.js
-var Comment = React.createClass({
-  render: function() {
-    return (
-      <div className="comment">
-        <h2 className="commentAuthor">
-          {this.props.author}
-        </h2>
-        {marked(this.props.children.toString())}
-      </div>
-    );
-  }
-});
-```
-
-Tutto ciò che stiamo facendo qui è chiamare la libreria marked. Dobbiamo convertire `this.props.children` dal testo racchiuso di React a una stringa che marked è in grado di capire, quindi vi chiamiamo esplicitamente `toString()`.
-
-Ma c'è un problema! I nostri commenti visualizzati appaiono come segue nel browser: "`<p>`Questo è un `<em>`altro`</em>` commento`</p>`". Noi vogliamo che questi tag vengano in realtà visualizzati come HTML.
-
-Questo è il risultato della protezione di React da parte di un [attacco XSS](https://en.wikipedia.org/wiki/Cross-site_scripting). C'è una maniera di aggirare questo comportamento, ma il framework ti avvisa di non farlo:
-
-```javascript{3-6,14}
-// tutorial7.js
-var Comment = React.createClass({
-  rawMarkup: function() {
-    var rawMarkup = marked(this.props.children.toString(), {sanitize: true});
-    return { __html: rawMarkup };
-  },
-
-  render: function() {
-    return (
-      <div className="comment">
-        <h2 className="commentAuthor">
-          {this.props.author}
-        </h2>
-        <span dangerouslySetInnerHTML={this.rawMarkup()} />
-      </div>
-    );
-  }
-});
-```
-
-Questa è una speciale API che rende intenzionalmente difficile inserire HTML nativo, ma per marked ci avvantaggeremo di questa possibilità.
-
-**Ricorda:** usando questa funzionalità stai assumendo che marked sia sicuro. In questo caso, passiamo `sanitize: true` che istruisce marked a fare l'escape di ogni markup HTML nel sorgente, anziché restituirlo inalterato.
-
-### Collega il modello dei dati
-
-Finora abbiamo inserito i commenti direttamente nel codice sorgente. Invece, visualizziamo un pacchetto di dati JSON nella lista dei commenti. In seguito questi verranno restituiti dal server, ma per adesso scriviamoli nel tuo sorgente:
-
-```javascript
-// tutorial8.js
-var data = [
-  {author: "Pete Hunt", text: "Questo è un commento"},
-  {author: "Jordan Walke", text: "Questo è un *altro* commento"}
-];
-```
-
-Dobbiamo inserire questi dati in `CommentList` in maniera modulare. Modifica `CommentBox` e la chiamata a `ReactDOM.render()` per passare questi dati a `CommentList` tramite proprietà:
-
-```javascript{7,15}
-// tutorial9.js
-var CommentBox = React.createClass({
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>Commenti</h1>
-        <CommentList data={this.props.data} />
-        <CommentForm />
-      </div>
-    );
-  }
-});
-
-ReactDOM.render(
-  <CommentBox data={data} />,
-  document.getElementById('content')
-);
-```
-
-Adesso che i dati sono disponibili in `CommentList`, visualizziamo i commenti dinamicamente:
-
-```javascript{4-10,13}
-// tutorial10.js
-var CommentList = React.createClass({
-  render: function() {
-    var commentNodes = this.props.data.map(function (comment) {
-      return (
-        <Comment author={comment.author}>
-          {comment.text}
-        </Comment>
-      );
-    });
-    return (
-      <div className="commentList">
-        {commentNodes}
-      </div>
-    );
-  }
-});
-```
-
-Tutto qui!
-
-### Richiedere dati dal server
-
-Sostituiamo i dati scritti nel codice con dati dinamici ottenuti dal server. Rimuoveremo le proprietà dei dati e le sostituiremo con uno URL da richiedere:
-
-```javascript{3}
-// tutorial11.js
-ReactDOM.render(
-  <CommentBox url="/api/comments" />,
-  document.getElementById('content')
-);
-```
-
-Questo componente differisce dal precedente perché dovrà effettuare un nuovo rendering di se stesso. Il componente non avrà dati finché la risposta del server non sia disponibile, e a quel punto il componente potrebbe dover visualizzare dei nuovi commenti.
-
-Nota: il codice non funzionerà a questo passo.
-
-### Stato reattivo
-
-Finora, basandosi sulle sue proprietà, ogni componente si è visualizzato solo una volta. I valori di `props` sono immutabili: sono passati dal genitore e sono "posseduti" dal genitore. Per implementare le interazioni, introduciamo uno **stato** mutevole nel componente. `this.state` è privato al componente e può essere cambiato chiamando `this.setState()`. Quando lo stato si aggiorna, il componente effettua nuovamente il rendering di se stesso.
-
-I metodi `render()` sono scritti dichiarativamente come funzioni di `this.props` e `this.state`. Il framework garantisce che la UI sia sempre consistente con gli input.
-
-Quando il server ci fornisce i dati, dovremo cambiare i dati dei commenti in nostro possesso. Aggiungiamo un array di dati dei commenti al componente `CommentBox` come il suo stato:
-
-```javascript{3-5,10}
-// tutorial12.js
-var CommentBox = React.createClass({
-  getInitialState: function() {
-    return {data: []};
-  },
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>Commenti</h1>
-        <CommentList data={this.state.data} />
-        <CommentForm />
-      </div>
-    );
-  }
-});
-```
-
-`getInitialState()` viene eseguito esattamente una volta durante il ciclo di vita del componente e imposta lo stato iniziale del componente stesso.
-
-#### Aggiornare lo stato
-Quando il componente è creato per la prima volta, vogliamo richiedere tramite GET del JSON dal server e aggiornare lo stato per riflettere i dati più recenti. Useremo jQuery per effettuare una richiesta asincrona al server che abbiamo avviato in precedenza per richiedere i dati che ci servono. Somiglieranno a qualcosa di simile:
-
-```json
-[
-  {"author": "Pete Hunt", "text": "Questo è un commento"},
-  {"author": "Jordan Walke", "text": "Questo è un *altro* commento"}
-]
-```
-
-```javascript{6-18}
-// tutorial13.js
-var CommentBox = React.createClass({
-  getInitialState: function() {
-    return {data: []};
-  },
-  componentDidMount: function() {
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      cache: false,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>Commenti</h1>
-        <CommentList data={this.state.data} />
-        <CommentForm />
-      </div>
-    );
-  }
-});
-```
-
-Qui, `componentDidMount` è un metodo chiamato automaticamente da React quando un componente viene visualizzato. La chiave agli aggiornamenti dinamici è la chiamata a `this.setState()`. Sostituiamo il vecchio array di commenti con il nuovo ottenuto dal server e la UI si aggiorna automaticamente. Per via di questa reattività, è richiesto soltanto un piccolo cambiamento per aggiungere gli aggiornamenti in tempo reale. Qui useremo un semplice polling, ma potrai facilmente usare WebSockets o altre tecnologie.
-
-```javascript{3,15,20-21,35}
-// tutorial14.js
-var CommentBox = React.createClass({
-  loadCommentsFromServer: function() {
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      cache: false,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  getInitialState: function() {
-    return {data: []};
-  },
-  componentDidMount: function() {
-    this.loadCommentsFromServer();
-    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
-  },
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>Commenti</h1>
-        <CommentList data={this.state.data} />
-        <CommentForm />
-      </div>
-    );
-  }
-});
-
-ReactDOM.render(
-  <CommentBox url="/api/comments" pollInterval={2000} />,
-  document.getElementById('content')
-);
-
-```
-
-Tutto ciò che abbiamo fatto finora è spostare la chiamata AJAX in un metodo a parte e chiamarlo quando il componente viene caricato per la prima volta e successivamente ogni 2 secondi. Prova ad eseguire questa versione nel tuo browser e a cambiare il file `comments.json` (si trova nella stessa directory del tuo server); entro 2 secondi i cambiamenti saranno visibili!
-
-### Aggiungere nuovi commenti
-
-È giunto il momento di costruire il modulo. Il nostro componente `CommentForm` deve chiedere all'utente il nome e un testo del commento, e inviare una richiesta al server per salvare il commento.
-
-```javascript{5-9}
-// tutorial15.js
-var CommentForm = React.createClass({
-  render: function() {
-    return (
-      <form className="commentForm">
-        <input type="text" placeholder="Il tuo nome" />
-        <input type="text" placeholder="Di' qualcosa..." />
-        <input type="submit" value="Invia" />
-      </form>
-    );
-  }
-});
-```
-
-Rendiamo il modulo interattivo. Quando l'utente invia il modulo, dobbiamo ripulirlo, inviare una richiesta al server, e aggiornare la lista dei commenti. Per cominciare, ascoltiamo l'evento `submit` del modulo e ripuliamolo.
-
-```javascript{3-14,16-19}
-// tutorial16.js
-var CommentForm = React.createClass({
-  handleSubmit: function(e) {
-    e.preventDefault();
-    var author = ReactDOM.findDOMNode(this.refs.author).value.trim();
-    var text = ReactDOM.findDOMNode(this.refs.text).value.trim();
-    if (!text || !author) {
-      return;
-    }
-    // TODO: invia la richiesta al server
-    ReactDOM.findDOMNode(this.refs.author).value = '';
-    ReactDOM.findDOMNode(this.refs.text).value = '';
-    return;
-  },
-  render: function() {
-    return (
-      <form className="commentForm" onSubmit={this.handleSubmit}>
-        <input type="text" placeholder="Il tuo nome" ref="author" />
-        <input type="text" placeholder="Di' qualcosa..." ref="text" />
-        <input type="submit" value="Invia" />
-      </form>
-    );
-  }
-});
-```
-
-##### Eventi
-
-React assegna i gestori degli eventi ai componenti usando una convenzione di nomi  camelCased. Assegnamo un gestore `onSubmit` al modulo in maniera che ripulisca i campi del modulo quando il modulo stesso è inviato con un input valido.
-
-Chiamiamo `preventDefault()` sull'evento per prevenire l'azione predefinita del browser per l'invio del modulo.
-
-##### Refs
-
-Usiamo l'attributo `ref` per assegnare un nome a un componente figlio e  `this.refs` per riferirsi al componente. Possiamo chiamare `ReactDOM.findDOMNode(component)` su di un componente per ottenere l'elemento nativo del DOM del browser.
-
-##### Callback come proprietà
-
-Quando un utente invia un commento, dobbiamo aggiornare la lista dei commenti per includere il nuovo commento. Ha senso posizionare questa logica in `CommentBox` dal momento che `CommentBox` possiede lo stato che rappresenta la lista dei commenti.
-
-Dobbiamo passare i dati dal componente figlio su fino al suo genitore. Lo facciamo nel metodo `render` del nostro genitore passando una nuova callback  (`handleCommentSubmit`) al figlio, legandola all'evento `onCommentSubmit` del figlio. Quando questo evento viene emesso, la callback verrà eseguita:
-
-```javascript{16-18,31}
-// tutorial17.js
-var CommentBox = React.createClass({
-  loadCommentsFromServer: function() {
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      cache: false,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  handleCommentSubmit: function(comment) {
-    // TODO: invia al server e aggiorna la lista
-  },
-  getInitialState: function() {
-    return {data: []};
-  },
-  componentDidMount: function() {
-    this.loadCommentsFromServer();
-    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
-  },
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>Commenti</h1>
-        <CommentList data={this.state.data} />
-        <CommentForm onCommentSubmit={this.handleCommentSubmit} />
-      </div>
-    );
-  }
-});
-```
-
-Chiamiamo la callback da `CommentForm` quando l'utente invia il modulo:
-
-```javascript{10}
-// tutorial18.js
-var CommentForm = React.createClass({
-  handleSubmit: function(e) {
-    e.preventDefault();
-    var author = ReactDOM.findDOMNode(this.refs.author).value.trim();
-    var text = ReactDOM.findDOMNode(this.refs.text).value.trim();
-    if (!text || !author) {
-      return;
-    }
-    this.props.onCommentSubmit({author: author, text: text});
-    ReactDOM.findDOMNode(this.refs.author).value = '';
-    ReactDOM.findDOMNode(this.refs.text).value = '';
-    return;
-  },
-  render: function() {
-    return (
-      <form className="commentForm" onSubmit={this.handleSubmit}>
-        <input type="text" placeholder="Il tuo nome" ref="author" />
-        <input type="text" placeholder="Di' qualcosa..." ref="text" />
-        <input type="submit" value="Invia" />
-      </form>
-    );
-  }
-});
-```
-
-Adesso che le callback sono al loro posto, non ci resta che inviare al server e aggiornare la lista:
-
-```javascript{17-28}
-// tutorial19.js
-var CommentBox = React.createClass({
-  loadCommentsFromServer: function() {
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      cache: false,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  handleCommentSubmit: function(comment) {
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      type: 'POST',
-      data: comment,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  getInitialState: function() {
-    return {data: []};
-  },
-  componentDidMount: function() {
-    this.loadCommentsFromServer();
-    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
-  },
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>Commenti</h1>
-        <CommentList data={this.state.data} />
-        <CommentForm onCommentSubmit={this.handleCommentSubmit} />
-      </div>
-    );
-  }
-});
-```
-
-### Ottimizzazione: aggiornamenti ottimistici
-
-La nostra applicazione è adesso completa, ma aspettare che la richiesta completi prima di vedere il commento apparire nella lista la fa sembrare lenta. Possiamo aggiungere ottimisticamente questo commento alla lista per fare apparire l'applicazione più veloce.
-
-```javascript{17-19,29}
-// tutorial20.js
-var CommentBox = React.createClass({
-  loadCommentsFromServer: function() {
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      cache: false,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  handleCommentSubmit: function(comment) {
-    var comments = this.state.data;
-    var newComments = comments.concat([comment]);
-    this.setState({data: newComments});
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      type: 'POST',
-      data: comment,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        this.setState({data: comments});
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  getInitialState: function() {
-    return {data: []};
-  },
-  componentDidMount: function() {
-    this.loadCommentsFromServer();
-    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
-  },
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>Commenti</h1>
-        <CommentList data={this.state.data} />
-        <CommentForm onCommentSubmit={this.handleCommentSubmit} />
-      </div>
-    );
-  }
-});
-```
-
-### Congratulazioni!
-
-Hai appena costruito una casella di commenti in pochi semplici passi. Leggi maggiori dettagli sul [perché usare React](/react/docs/why-react.html), o approfondisci [la guida di riferimento dell'API](/react/docs/top-level-api.html) e comincia ad hackerare! In bocca al lupo!
diff --git a/docs/docs/tutorial.ja-JP.md b/docs/docs/tutorial.ja-JP.md
deleted file mode 100755
index 193ac6812cdd..000000000000
--- a/docs/docs/tutorial.ja-JP.md
+++ /dev/null
@@ -1,716 +0,0 @@
----
-id: tutorial-ja-JP
-title: チュートリアル
-permalink: tutorial-ja-JP.html
-prev: getting-started-ja-JP.html
-next: thinking-in-react-ja-JP.html
----
-
-これから、シンプルながらも現実的なコメントボックスを作ってみましょう。ブログにも設置できるようなもので、Disqus や LiveFyre、Facebook comments が採用しているリアルタイムコメントの基本機能を備えたものを想定しています。
-
-その機能とは次のようなものです。
-
-* コメント全件の表示欄
-* コメントの送信フォーム
-* 自作のバックエンドとの連携機能
-
-ついでに小洒落た機能もいくつか加えましょう。
-
-* **コメントの先読み:** 送信したコメントをサーバに保存される前に表示させることで、アプリ動作の体感速度をアップさせます。
-* **自動更新:** 他のユーザのコメントをリアルタイムで表示させます。
-* **Markdown 記法:** ユーザが Markdown 記法でコメントを書けるようにします。
-
-### 全部飛ばしてソースを見たいんだけど？
-
-[全部 GitHub にあります。](https://github.com/reactjs/react-tutorial)
-
-### サーバを動かす
-
-このチュートリアルを始めるにあたっては必要ないですが、後半ではサーバに POST を投げる機能を追加します。サーバのことは良く知っていて自分でサーバを建てたいのであれば、それでも構いません。そうではないけれども、サーバサイドは考えずに React のことだけに焦点を絞って学びたい方のため、シンプルなサーバのソースコードを書いておきました。言語は JavaScript （Node.js）または Python、Ruby、Go、ないし PHP で用意してあり、すべて GitHub にあります。[ソースを見る](https://github.com/reactjs/react-tutorial/) ことも出来ますし、 [zip ファイルでダウンロード](https://github.com/reactjs/react-tutorial/archive/master.zip)することも出来ます。
-
-それでは最初のチュートリアルとして、`public/index.html` の編集から始めましょう。
-
-### 始めてみましょう
-
-このチュートリアルでは、あらかじめビルドされた JavaScript ファイルを CDN から読み込むことになります。自分の好きなエディタを立ち上げて、次のように新規の HTML ドキュメントを作りましょう。
-
-```html
-<!-- index.html -->
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="UTF-8" />
-    <title>Hello React</title>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/{{site.react_version}}/react.js"></script>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/{{site.react_version}}/react-dom.js"></script>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
-  </head>
-  <body>
-    <div id="content"></div>
-    <script type="text/babel">
-      // ここにコードが入ります
-    </script>
-  </body>
-</html>
-```
-
-このチュートリアルに関しては、JavaScript コードを script タグの中へ書いていくことにします。
-
-> 確認:
->
-> 上のコードで jQuery を読み込んでいますが、これはチュートリアル後半で ajax のコードを簡潔に書きたいだけなので、React を動かすのに必要なものでは**ありません**。
-
-### 最初のコンポーネント
-
-React はすべて、モジュール単位で組み立てられる（composable）コンポーネントからなっています。今回取り上げるコメントボックスの例では、以下のようなコンポーネント構造をとります。
-
-```
-- CommentBox
-  - CommentList
-    - Comment
-  - CommentForm
-```
-
-それではまず `CommentBox` コンポーネントから作っていきましょう。とは言っても単なる `<div>` です。
-
-```javascript
-// tutorial1.js
-var CommentBox = React.createClass({
-  render: function() {
-    return (
-      <div className="commentBox">
-        Hello, world! I am a CommentBox.
-      </div>
-    );
-  }
-});
-ReactDOM.render(
-  <CommentBox />,
-  document.getElementById('content')
-);
-```
-
-#### JSX シンタックス
-
-先程書いた JavaScript の中に、XMLに似たシンタックスがあることに気付いたでしょうか。このシンタックスシュガーは、シンプルなプリコンパイラによって次のような生の JavaScript に変換されます。
-
-```javascript
-// tutorial1-raw.js
-var CommentBox = React.createClass({displayName: 'CommentBox',
-  render: function() {
-    return (
-      React.createElement('div', {className: "commentBox"},
-        "Hello, world! I am a CommentBox."
-      )
-    );
-  }
-});
-ReactDOM.render(
-  React.createElement(CommentBox, null),
-  document.getElementById('content')
-);
-```
-
-どちらを採るかは自由ですが、生の JavaScript よりも JSX シンタックスのほうが扱いやすいと考えています。詳しくは [JSX シンタックスの記事](/react/docs/jsx-in-depth.html) を読んでみてください。
-
-#### 何をしているのか
-
-先程のコードでは、とあるメソッドを持った JavaScript オブジェクトを `React.createClass()` に渡しています。これは新しい React コンポーネントを作るためです。このメソッドは `render` と呼ばれており、最終的に HTML へレンダリングされる React コンポーネントのツリーを返す点が肝になります。
-
-コードに書いた `<div>` タグは実際の DOM ノードではありません。これは React の `div` コンポーネントのインスタンスです。 これらは React が理解できるマーカーやデータの一部だと見なせます。React は **安全** です。デフォルトで XSS 対策を行っているので、HTML 文字列を生成することはありません。
-
-実際の HTML を返す必要はありません。 自分が（もしくは他の誰かが）組み立てたコンポーネントツリーを返せばいいのです。 これこそ React が **composable**な（組み立てられる）ものである理由であり、この大事なルールを守ればフロントエンドはメンテナンスしやすいものとなります。
-
-`ReactDOM.render()` はまずルートコンポーネントのインスタンスを作り、フレームワークを立ち上げます。そして、第2引数で与えられた実際の DOM 要素にマークアップを挿入します。
-
-## コンポーネントの組み立て
-
-それでは `CommentList` と `CommentForm` の骨組みを作りましょう。繰り返しになりますが、これらはただの `<div>` です。
-
-```javascript
-// tutorial2.js
-var CommentList = React.createClass({
-  render: function() {
-    return (
-      <div className="commentList">
-        Hello, world! I am a CommentList.
-      </div>
-    );
-  }
-});
-
-var CommentForm = React.createClass({
-  render: function() {
-    return (
-      <div className="commentForm">
-        Hello, world! I am a CommentForm.
-      </div>
-    );
-  }
-});
-```
-
-さて、この新しいコンポーネントを使えるように `CommentBox` コンポーネントを書き直しましょう。
-
-```javascript{6-8}
-// tutorial3.js
-var CommentBox = React.createClass({
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>Comments</h1>
-        <CommentList />
-        <CommentForm />
-      </div>
-    );
-  }
-});
-```
-
-ここで、HTML タグと組み立てているコンポーネントが、どのようにミックスされているかを確認しましょう。 HTML コンポーネントは既定の React コンポーネントですが、自分で定義したもの同士はそれぞれ別物になります。JSX コンパイラは HTML タグを自動的に `React.createElement(tagName)` の式に書き換え、それぞれを別々のものに変換します。これはグローバルの名前空間が汚染させるのを防ぐためです。
-
-### Props を使う
-
-次のステップは `Comment` コンポーネントの作成です。このコンポーネントは、自分の親にあたるコンポーネントから渡されたデータを扱います。親から渡されたデータは、子のコンポーネントで「プロパティ」として利用できます。この「プロパティ」には `this.props` を通してアクセスします。props（プロパティ）を使うと `CommentList` から `Comment` に渡されたデータの読み込み、マークアップのレンダリングが可能になります。
-
-```javascript
-// tutorial4.js
-var Comment = React.createClass({
-  render: function() {
-    return (
-      <div className="comment">
-        <h2 className="commentAuthor">
-          {this.props.author}
-        </h2>
-        {this.props.children}
-      </div>
-    );
-  }
-});
-```
-
-JSX の内側で（属性値または子要素として）JavaScript の式を波括弧で囲むと、テキストや React コンポーネントをツリーに加えることが出来ます。コンポーネントに渡された属性値には名前が付けられており、`this.props` をキーとしてアクセスできます。また、ネストされた子要素の値は `this.props.children` でアクセスが可能です。
-
-### コンポーネントのプロパティ
-
-さて、これまでに `Comment` コンポーネントを定義しました。これからこのコンポーネントに、コメントの著者名と内容を渡せるようにします。これを実装することで、それぞれ別のコメントに対して同じコードを使い回せるようになります。それでは早速 `CommentList` の中にコメントを追加していきましょう。
-
-```javascript{6-7}
-// tutorial5.js
-var CommentList = React.createClass({
-  render: function() {
-    return (
-      <div className="commentList">
-        <Comment author="Pete Hunt">This is one comment</Comment>
-        <Comment author="Jordan Walke">This is *another* comment</Comment>
-      </div>
-    );
-  }
-});
-```
-
-ここで確認してもらいたいのは、親の `CommentList` コンポーネントから、子の `Comment` コンポーネントにデータが渡されている点です。この例ではまず、*Pete Hunt*（属性値を通して）と *This is one comment*（XML のような子ノードを通して）といったデータを `Comment` コンポーネントに渡しています。少し前に確認した通り、`Comment` コンポーネントからこれらの「プロパティ」にアクセスするには、`this.props.author` と `this.props.children` を使います。
-
-### Markdown の追加
-
-Markdown はインラインでテキストをフォーマットする簡単な記法です。例えば、テキストをアスタリスクで挟むと強調されて表示されます。
-
-まず最初に、サードパーティ製の **marked** ライブラリをアプリケーションに追加します。 marked は Markdown テキストを生の HTML に変換する JavaScript ライブラリです。 既にある head タグの内側に script タグを書き込み、以下のように marked を読み込ませます。
-
-```html{9}
-<!-- index.html -->
-<head>
-  <meta charset="UTF-8" />
-  <title>Hello React</title>
-  <script src="https://cdnjs.cloudflare.com/ajax/libs/react/{{site.react_version}}/react.js"></script>
-  <script src="https://cdnjs.cloudflare.com/ajax/libs/react/{{site.react_version}}/react-dom.js"></script>
-  <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
-  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
-  <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.5/marked.min.js"></script>
-</head>
-```
-
-次に、Markdown で書かれたコメントを変換して出力してみましょう。
-
-```javascript{9}
-// tutorial6.js
-var Comment = React.createClass({
-  render: function() {
-    return (
-      <div className="comment">
-        <h2 className="commentAuthor">
-          {this.props.author}
-        </h2>
-        {marked(this.props.children.toString())}
-      </div>
-    );
-  }
-});
-```
-
-このコードでは marked のライブラリを呼び出すことしかしていません。`this.props.children` は React によってラップされたテキストですが、これを marked が理解できる生の文字列に変換する必要があります。そのため、上のコードでは明示的に `toString()` を呼び出しているのです。
-
-しかし問題があります！ブラウザがレンダリングしたコメントは次のように表示されているはずです -- "`<p>`This is `<em>`another`</em>` comment`</p>`" このようなタグは実際に HTML としてレンダリングさせたいですね。
-
-このような現象が起きるのは React が XSS 攻撃に対する防御を行っているからです。これを回避する方法はありますが、それを使うときにはフレームワークが警告をします。
-
-```javascript{3-6,14}
-// tutorial7.js
-var Comment = React.createClass({
-  rawMarkup: function() {
-    var rawMarkup = marked(this.props.children.toString(), {sanitize: true});
-    return { __html: rawMarkup };
-  },
-
-  render: function() {
-    return (
-      <div className="comment">
-        <h2 className="commentAuthor">
-          {this.props.author}
-        </h2>
-        <span dangerouslySetInnerHTML={this.rawMarkup()} />
-      </div>
-    );
-  }
-});
-```
-
-これは特別な API であり、生の HTML が挿入されにくくなるよう意図的に作ったものです。しかし、ここでは marked のためにこのバックドアを利用しています。
-
-**注意:** この機能を使うことで、marked は安全なものと信頼することになります。
-
-### データモデルとの連携
-
-これまではソースコードにコメントを直に書き込んでいました。その代わりに、これからは JSON の blob データをコメントリストにレンダリングしてみましょう。サーバからデータを取得するのが最後の目標ですが、とりあえず今はソースコードの中にデータを書いておくことにします。
-
-```javascript
-// tutorial8.js
-var data = [
-  {author: "Pete Hunt", text: "This is one comment"},
-  {author: "Jordan Walke", text: "This is *another* comment"}
-];
-```
-
-このデータはモジュールを使って `CommentList` に取り込む必要があります。`CommentBox` の `ReactDOM.render()` の部分を手直しして、props を通してデータが `CommentList` へ渡るようにしましょう。
-
-```javascript{7,15}
-// tutorial9.js
-var CommentBox = React.createClass({
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>Comments</h1>
-        <CommentList data={this.props.data} />
-        <CommentForm />
-      </div>
-    );
-  }
-});
-
-ReactDOM.render(
-  <CommentBox data={data} />,
-  document.getElementById('content')
-);
-```
-
-こうして `CommentList` がデータを扱えるようになりました。それでは、コメントを動的にレンダリングしてみましょう。
-
-```javascript{4-10,13}
-// tutorial10.js
-var CommentList = React.createClass({
-  render: function() {
-    var commentNodes = this.props.data.map(function (comment) {
-      return (
-        <Comment author={comment.author}>
-          {comment.text}
-        </Comment>
-      );
-    });
-    return (
-      <div className="commentList">
-        {commentNodes}
-      </div>
-    );
-  }
-});
-```
-
-これだけ！
-
-### サーバからのデータの取得
-
-続いて、ハードコーディングしていたデータを、サーバからの動的なデータに置き換えてみましょう。
-
-```javascript{3}
-// tutorial11.js
-ReactDOM.render(
-  <CommentBox url="api/comments" />,
-  document.getElementById('content')
-);
-```
-
-このコンポーネントは自身を再びレンダリングすることになるので、これまでのコンポーネントとは異なります。レスポンスがサーバから返ってくると、送られてきた新しいコメントをコンポーネントがレンダリングすることになります。ですが、その時点までコンポーネントには何もデータがないはずです。
-
-確認: 上のコードは、このステップではまだ動きません。
-
-### Reactive state
-
-これまで、それぞれのコンポーネントは自身の props の値を用いて、一度だけレンダリングしていました。`props` はイミュータブルです。つまり、props は親から渡されますが、同時に props は親の「所有物」なのです。データが相互にやり取りされるのを実現するため、ここでミュータブルな **state**（状態）をコンポーネントに取り入れましょう。コンポーネントは `this.state` というプライベートな値を持ち、`this.setState()` を呼び出すことで state を更新することが出来ます。コンポーネントの state が更新されれば、そのコンポーネントは自身を再びレンダリングし直します。
-
-`render()` メソッドは `this.props` や `this.state` と同じく宣言的に書かれています。このフレームワークによって、UI と入力が常に一致するようになります。
-
-サーバがデータを集めてくれば、今あるコメントのデータを更新することになるかもしれません。state を表すコメントのデータの配列を `CommentBox` コンポーネントに加えましょう。
-
-```javascript{3-5,10}
-// tutorial12.js
-var CommentBox = React.createClass({
-  getInitialState: function() {
-    return {data: []};
-  },
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>Comments</h1>
-        <CommentList data={this.state.data} />
-        <CommentForm />
-      </div>
-    );
-  }
-});
-```
-
-`getInitialState()` メソッドはコンポーネントのライフサイクル内で一回だけ実行され、コンポーネントの state における初期値を設定します。
-
-#### State の更新
-コンポーネントの作成と同時に、サーバから JSON データを GET で取得し、state を更新して最新のデータを反映させてみましょう。実際のアプリケーションでは動的なエンドポイントになるでしょうが、今回の例では話を簡単にするため、以下の静的な JSON ファイルを使います。
-
-```json
-[
-  {"author": "Pete Hunt", "text": "This is one comment"},
-  {"author": "Jordan Walke", "text": "This is *another* comment"}
-]
-```
-
-サーバへの非同期リクエストを作るため、ここでは jQuery を使います。
-
-注意: ここからは AJAX アプリケーションを作っていくので、自分のファイルシステム上ではなく Web サーバを使ってアプリを作る必要があります。残りのチュートリアルに必要な機能は [冒頭で紹介した](#running-a-server) サーバに含まれています。ソースコードは [GitHub に](https://github.com/reactjs/react-tutorial/)用意してあります。
-
-```javascript{6-18}
-// tutorial13.js
-var CommentBox = React.createClass({
-  getInitialState: function() {
-    return {data: []};
-  },
-  componentDidMount: function() {
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      cache: false,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>Comments</h1>
-        <CommentList data={this.state.data} />
-        <CommentForm />
-      </div>
-    );
-  }
-});
-```
-
-さて、`componentDidMount` はコンポーネントがレンダリングされたときに React が自動的に呼び出すメソッドです。動的な更新の鍵となるのは `this.setState()` の呼び出し方です。ここでは、古いコメントの配列をサーバから取ってきた新しい配列に置き換え、UI を自動的に更新させてみましょう。このような reactivity（反応性・柔軟性）のおかげで、リアルタイム更新を最小限にすることが出来ます。次のコードではシンプルなポーリングをしていますが、WebSockets や他の方法でも簡単に実現できます。
-
-```javascript{3,15,20-21,35}
-// tutorial14.js
-var CommentBox = React.createClass({
-  loadCommentsFromServer: function() {
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      cache: false,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  getInitialState: function() {
-    return {data: []};
-  },
-  componentDidMount: function() {
-    this.loadCommentsFromServer();
-    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
-  },
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>Comments</h1>
-        <CommentList data={this.state.data} />
-        <CommentForm />
-      </div>
-    );
-  }
-});
-
-ReactDOM.render(
-  <CommentBox url="comments.json" pollInterval={2000} />,
-  document.getElementById('content')
-);
-
-```
-
-ここまでに、AJAX を呼び出す部分を別のメソッド内に移動させました。加えて、コンポーネントが最初に読み込まれてから2秒ごとに AJAX のメソッドが呼び出されるようにしました。ぜひ自分のブラウザで実行させて、`comments.json` ファイルに変更を加えてみてください。2秒以内に表示が更新されるはずです！
-
-### 新しいコメントの追加
-
-いよいよフォームを作る段階に来ました。ここで `CommentForm` コンポーネントは、ユーザに自分の名前とコメントの内容を入力させ、コメントを保存させるためにサーバへリクエストを送る役割を果たすことになります。
-
-```javascript{5-9}
-// tutorial15.js
-var CommentForm = React.createClass({
-  render: function() {
-    return (
-      <form className="commentForm">
-        <input type="text" placeholder="Your name" />
-        <input type="text" placeholder="Say something..." />
-        <input type="submit" value="Post" />
-      </form>
-    );
-  }
-});
-```
-
-それでは、フォームを使ってデータをやり取りできるようにしましょう。ユーザがフォームから送信したら、フォームをクリアしてサーバにリクエストを送り、コメントリストをリフレッシュすることになります。まず手始めに、フォームからの送信イベントを受け取ってフォームをクリアできるようにしましょう。
-
-```javascript{3-13,16-19}
-// tutorial16.js
-var CommentForm = React.createClass({
-  handleSubmit: function(e) {
-    e.preventDefault();
-    var author = ReactDOM.findDOMNode(this.refs.author).value.trim();
-    var text = ReactDOM.findDOMNode(this.refs.text).value.trim();
-    if (!text || !author) {
-      return;
-    }
-    // TODO: サーバにリクエストを送信
-    ReactDOM.findDOMNode(this.refs.author).value = '';
-    ReactDOM.findDOMNode(this.refs.text).value = '';
-    return;
-  },
-  render: function() {
-    return (
-      <form className="commentForm" onSubmit={this.handleSubmit}>
-        <input type="text" placeholder="Your name" ref="author" />
-        <input type="text" placeholder="Say something..." ref="text" />
-        <input type="submit" value="Post" />
-      </form>
-    );
-  }
-});
-```
-
-##### イベント
-
-React がコンポーネントにイベントハンドラを登録する際は camelCase の命名規則に従います。上のコードではフォームに `onSubmit` ハンドラを登録し、フォームから妥当な入力が送信されたらフォームをクリアするようになっています。
-
-また `preventDefault()` を呼び出しているので、フォームからの送信に対してブラウザのデフォルト処理が反応することはありません。
-
-##### Refs
-
-先程のコードでは `ref` 属性値を使って子のコンポーネントに名前を付けており、`this.ref` でそのコンポーネントを参照しています。`ReactDOM.findDOMNode(component)` にコンポーネントを指定して呼び出すことで、ブラウザの持つ実際の DOM 要素を取得することが出来ます。
-
-##### Props としてのコールバック
-
-ユーザがコメントを送信したら、コメントリストをリフレッシュして新しいリストを読み込むことになります。コメントリストを表す state を保持しているのは `CommentBox` なので、必要なロジックは `CommentBox` の中に書くのが筋でしょう。
-
-ここでは子のコンポーネントから親に向かって、いつもとは逆方向にデータを返す必要があります。まず、親のコンポーネントに新しいコールバック関数（`handleCommentSubmit`）を定義します。続いて `render` メソッド内にある子のコンポーネントにコールバックを渡すことで、`onCommentSubmit` イベントとコールバックを結び付けています。こうすることで、イベントが発生するたびにコールバックが呼び出されます。
-
-```javascript{16-18,31}
-// tutorial17.js
-var CommentBox = React.createClass({
-  loadCommentsFromServer: function() {
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      cache: false,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  handleCommentSubmit: function(comment) {
-    // TODO: サーバに送信、リストをリフレッシュ
-  },
-  getInitialState: function() {
-    return {data: []};
-  },
-  componentDidMount: function() {
-    this.loadCommentsFromServer();
-    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
-  },
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>Comments</h1>
-        <CommentList data={this.state.data} />
-        <CommentForm onCommentSubmit={this.handleCommentSubmit} />
-      </div>
-    );
-  }
-});
-```
-
-それでは、ユーザがフォームから送信したら `CommentForm` がコールバックを呼び出せるようにしましょう。
-
-```javascript{10}
-// tutorial18.js
-var CommentForm = React.createClass({
-  handleSubmit: function(e) {
-    e.preventDefault();
-    var author = ReactDOM.findDOMNode(this.refs.author).value.trim();
-    var text = ReactDOM.findDOMNode(this.refs.text).value.trim();
-    if (!text || !author) {
-      return;
-    }
-    this.props.onCommentSubmit({author: author, text: text});
-    ReactDOM.findDOMNode(this.refs.author).value = '';
-    ReactDOM.findDOMNode(this.refs.text).value = '';
-    return;
-  },
-  render: function() {
-    return (
-      <form className="commentForm" onSubmit={this.handleSubmit}>
-        <input type="text" placeholder="Your name" ref="author" />
-        <input type="text" placeholder="Say something..." ref="text" />
-        <input type="submit" value="Post" />
-      </form>
-    );
-  }
-});
-```
-
-こうしてコールバックが出来たので、あとはサーバにコメントを送信してリストをリフレッシュすれば完璧です。
-
-```javascript{17-28}
-// tutorial19.js
-var CommentBox = React.createClass({
-  loadCommentsFromServer: function() {
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      cache: false,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  handleCommentSubmit: function(comment) {
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      type: 'POST',
-      data: comment,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  getInitialState: function() {
-    return {data: []};
-  },
-  componentDidMount: function() {
-    this.loadCommentsFromServer();
-    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
-  },
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>Comments</h1>
-        <CommentList data={this.state.data} />
-        <CommentForm onCommentSubmit={this.handleCommentSubmit} />
-      </div>
-    );
-  }
-});
-```
-
-### 最適化: 先読み更新
-
-アプリケーションに必要な機能は一通り実装できました。しかし、フォームからコメントを送信しても、サーバからのレスポンスが来るまで自分のコメントはリストに載らないため、アプリの動作は遅く感じます。ここでは、送信したコメントをリストに先読みさせて、アプリの体感速度をアップさせましょう。
-
-```javascript{17-19,29}
-// tutorial20.js
-var CommentBox = React.createClass({
-  loadCommentsFromServer: function() {
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      cache: false,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  handleCommentSubmit: function(comment) {
-    var comments = this.state.data;
-    var newComments = comments.concat([comment]);
-    this.setState({data: newComments});
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      type: 'POST',
-      data: comment,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        this.setState({data: comments});
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  getInitialState: function() {
-    return {data: []};
-  },
-  componentDidMount: function() {
-    this.loadCommentsFromServer();
-    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
-  },
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>Comments</h1>
-        <CommentList data={this.state.data} />
-        <CommentForm onCommentSubmit={this.handleCommentSubmit} />
-      </div>
-    );
-  }
-});
-```
-
-### おめでとう！
-
-シンプルな手順を追ううちにコメントボックスを作ることが出来ました。さらに詳しいことは[なぜ React を使うのか](/react/docs/why-react.html)を読んだり、[API リファレンス](/react/docs/top-level-api.html)を開いたりしてハッキングを始めましょう！幸運を祈ります！
diff --git a/docs/docs/tutorial.ko-KR.md b/docs/docs/tutorial.ko-KR.md
deleted file mode 100755
index fa297411a8f0..000000000000
--- a/docs/docs/tutorial.ko-KR.md
+++ /dev/null
@@ -1,720 +0,0 @@
----
-id: tutorial-ko-KR
-title: 튜토리얼
-permalink: tutorial-ko-KR.html
-prev: getting-started-ko-KR.html
-next: thinking-in-react-ko-KR.html
----
-
-블로그에 붙일만한 간단하지만 실용적인 댓글상자를 만들어 볼 것입니다. Disqus, LiveFyre, Facebook에서 제공하는 것 같은 실시간 댓글의 간단한 버전이죠.
-
-이런 기능을 넣겠습니다:
-
-* 댓글목록
-* 댓글작성폼
-* 커스텀 백엔드를 위한 Hooks
-
-멋진 기능도 조금 넣어보겠습니다:
-
-* **낙관적 댓글 달기:** 댓글은 서버에 저장되기도 전에 목록에 나타납니다. 그래서 빠르게 느껴집니다.
-* **실시간 업데이트:** 다른 사용자가 남기는 댓글이 실시간으로 나타납니다.
-* **Markdown 지원:** 사용자는 글을 꾸미기 위해 Markdown 형식을 사용할 수 있습니다.
-
-### 그냥 다 생략하고 소스만 보고 싶나요?
-
-[GitHub에 전부 있습니다.](https://github.com/reactjs/react-tutorial)
-
-### 서버 구동하기
-
-이 튜토리얼을 시작하기 위해, 서버를 구동할 필요가 있습니다. 이 서버는 순수하게 우리가 받고 저장할 데이터의 API 엔드포인트로써만 사용합니다. 이를 가능한한 쉽게하기 위해, 필요한 것만 제공하는 간단한 서버를 몇가지 스크립트 언어로 만들었습니다. **시작하는데 필요한 모든 것이 들어있는 [소스](https://github.com/reactjs/react-tutorial/)를 보시거나 [zip 파일](https://github.com/reactjs/react-tutorial/archive/master.zip)을 다운로드 할 수 있습니다.**
-
-단순하게 하기위해, 서버는 `JSON` 파일을 데이터베이스로 사용합니다. 프로덕션에서 사용할 수는 없지만 이렇게 하면 API를 사용할 때 시뮬레이션이 단순해집니다. 서버가 시작되면, API 엔드포인트를 제공하고 필요한 정적 페이지를 서빙합니다.
-
-### 시작하기
-
-이 튜토리얼에서는 가능한한 간단하게 만들겠습니다. 위에서 언급된 서버 패키지에 우리가 작업할 HTML 파일 포함되어 있습니다. 편한 편집기에서 `public/index.html`를 여세요. 이는 이런 내용이어야 합니다.(아마 조금 다를 수 있습니다만, 여기에 나중에 `<script>` 태그를 추가 할 것입니다.)
-
-```html
-<!-- index.html -->
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="utf-8" />
-    <title>React Tutorial</title>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/{{site.react_version}}/react.js"></script>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/{{site.react_version}}/react-dom.js"></script>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
-  </head>
-  <body>
-    <div id="content"></div>
-    <script type="text/babel" src="scripts/example.js"></script>
-    <script type="text/babel">
-      // 이 튜토리얼을 시작하려면, 그냥 scripts/example.js를 로드하는 스크립트
-      // 태그를 제거하고 여기에 코드를 적으세요.
-    </script>
-  </body>
-</html>
-```
-
-다음 진행을 위해, 위의 스크립트 태그안에 JavaScript 코드를 작성합니다. (이 튜토리얼에서는) 진보된 라이브 리로드가 없기 때문에, 수정 사항을 저장한 다음에는 브라우저를 새로고침해서 확인해야 합니다. 서버를 시작한 다음 브라우저에서 `http://localhost:3000`를 열어 따라해 보세요. 아무런 수정도 하지 않았다면, 최초 로드시 우리가 만들 제품의 완성품을 확인할 수 있을 것입니다. 작업할 준비가 되면, 이전의 `<script>` 태그를 삭제하고 진행하세요.
-
-> 주의:
->
-> 여기서는 ajax 요청 코드를 단순화 하기 위해 jQuery를 넣었지만, 이는 React의 동작에 필수적인 것은 **아닙니다**.
-
-### 첫 번째 컴포넌트
-
-모듈화 된, 조합가능한 컴포넌트가 React의 전부입니다. 댓글상자 예제에서 우리는 다음과 같은 컴포넌트 구조를 가질 것입니다:
-
-```
-- CommentBox
-  - CommentList
-    - Comment
-  - CommentForm
-```
-
-자, 이제 `CommentBox` 컴포넌트를 만들어 봅시다. `<div>` 하나로 구성되어 있습니다.
-
-```javascript
-// tutorial1.js
-var CommentBox = React.createClass({
-  render: function() {
-    return (
-      <div className="commentBox">
-        Hello, world! I am a CommentBox.
-      </div>
-    );
-  }
-});
-ReactDOM.render(
-  <CommentBox />,
-  document.getElementById('content')
-);
-```
-
-네이티브 HTML 엘리먼트 이름은 소문자로 시작하고 커스텀 React 클래스 이름은 대문자로 시작합니다.
-
-#### JSX 문법
-
-JavsScript 안의 유사 XML 구문이 먼저 눈에 띌 것입니다. 우리에겐 이를 JavaScript로 변환해주는 간단한 프리컴파일러(precompiler)가 있습니다.
-
-```javascript
-// tutorial1-raw.js
-var CommentBox = React.createClass({displayName: 'CommentBox',
-  render: function() {
-    return (
-      React.createElement('div', {className: "commentBox"},
-        "Hello, world! I am a CommentBox."
-      )
-    );
-  }
-});
-ReactDOM.render(
-  React.createElement(CommentBox, null),
-  document.getElementById('content')
-);
-```
-
-JSX의 사용은 선택적이지만 JSX 문법이 일반 JavsScript보다 사용하기 쉽습니다. [JSX 문법 문서](/react/docs/jsx-in-depth.html)에서 더 알아보세요.
-
-#### 무슨 일이 일어나고 있는가
-
-우리는 새로운 React 컴포넌트를 만들기 위해 `React.createClass()`로 JavaScript 객체에 몇 개의 메소드를 담아 넘겼습니다. 이 중 가장 중요한것은 `render` 메소드인데, 이는 React 컴포넌트 트리를 리턴해서 최종적으로 실제 HTML을 그려주게 됩니다.
-
-`<div>` 태그들은 실제 DOM 노드가 아니라 React `div` 컴포넌트의 인스턴스입니다. 이것은 React가 다룰 수 있는 데이터의 표시자(markers)나 조각이라 생각하셔도 됩니다. React는 **안전합니다**. 생(raw) HTML 문자열을 생성하는 것이 아니기 때문에 XSS을 기본적으로 방지합니다.
-
-일반적인 HTML만 리턴할 수 있는 것은 아닙니다. 여러분이 직접 만든 (또는 다른 사람들이 만들어 놓은) 컴포넌트의 트리를 리턴할 수도 있습니다. 이것이 React를 **조합가능(composable)하게 만듭니다**: 유지보수 가능한 프론트엔드를 위한 핵심 교리(key tenet)지요.
-
-`ReactDOM.render()`는 최상위 컴포넌트의 인스턴스를 만들고, 두 번째 인수로 전달받은 DOM 엘리먼트에 마크업을 삽입해 프레임워크를 시작합니다.
-
-`ReactDOM` 모듈은 DOM 특정 메소드를 노출해, `React`가 코어 툴을 다른 플렛폼(예를 들어, [React Native](http://facebook.github.io/react-native/))에 공유할 수 있게 합니다.
-
-## 컴포넌트 조합하기
-
-이제 `CommentList`와 `CommentForm`을 위한 뼈대를 구축해 봅시다. 이전과 마찬가지로 단순히 `<div>` 태그 하나 입니다. 파일에 두 컴포넌트를 추가해, 이미 있는 `CommentBox` 선언을 참고로 `ReactDOM.render`를 호출합시다.
-
-```javascript
-// tutorial2.js
-var CommentList = React.createClass({
-  render: function() {
-    return (
-      <div className="commentList">
-        안녕! 난 댓글목록이야.
-      </div>
-    );
-  }
-});
-
-var CommentForm = React.createClass({
-  render: function() {
-    return (
-      <div className="commentForm">
-        안녕! 난 댓글 폼이야.
-      </div>
-    );
-  }
-});
-```
-
-다음은 `CommentBox` 컴포넌트가 새로 만든 컴포넌트들을 사용하도록 수정합니다.
-
-```javascript{6-8}
-// tutorial3.js
-var CommentBox = React.createClass({
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>댓글</h1>
-        <CommentList />
-        <CommentForm />
-      </div>
-    );
-  }
-});
-```
-
-방금 만든 컴포넌트들을 어떻게 HTML 태그들과 섞어 사용하는지 살펴보세요. HTML 컴포넌트들도 한가지 차이만 제외한다면 우리가 정의한 것과 같은 표준적인 React 컴포넌트입니다. JSX 컴파일러가 자동으로 HTML 태그들을 `React.createElement(tagName)` 표현식으로 재작성하고 나머지는 그대로 둘 것입니다. 이는 전역 네임스페이스가 오염되는 것을 막아줍니다.
-
-### props 사용하기
-
-부모로 부터 받은 데이터에 의존하는 `Comment` 컴포넌트를 만들어 봅시다. 부모 컴포넌트로 부터 받은 데이터는 자식 컴포넌트에서 '프로퍼티'로 사용가능 합니다.  이 '프로퍼티들'은 `this.props`를 통해 접근합니다.  props를 사용해, `CommentList`에서 전달받은 데이터를 읽어들이고, 마크업을 렌더할 수 있을 것입니다.
-
-
-```javascript
-// tutorial4.js
-var Comment = React.createClass({
-  render: function() {
-    return (
-      <div className="comment">
-        <h2 className="commentAuthor">
-          {this.props.author}
-        </h2>
-        {this.props.children}
-      </div>
-    );
-  }
-});
-```
-
-JSX 내부의 중괄호로 둘러싸인 JavaScript 표현식(어트리뷰트나 엘리먼트의 자식으로 사용된)을 통해 텍스트나 React 컴포넌트를 트리에 더할 수 있습니다. `this.props`를 통해 컴포넌트에 전달된 특정한 어트리뷰트들에, `this.props.children`을 통해 중첩된 엘리먼트들에 접근할 수 있습니다.
-
-### 컴포넌트 프로퍼티 (Component Properties)
-
-`Comment` 컴포넌트를 만들었으니, 여기에 글쓴이와 내용을 넘겨보도록 합시다. 이렇게 함으로써 각 고유한 comment에서 같은 코드를 재사용할 수 있습니다. 먼저 댓글 몇 개를 `CommentList`에 추가해 봅시다:
-
-```javascript{6-7}
-// tutorial5.js
-var CommentList = React.createClass({
-  render: function() {
-    return (
-      <div className="commentList">
-        <Comment author="Pete Hunt">댓글입니다</Comment>
-        <Comment author="Jordan Walke">*또 다른* 댓글입니다</Comment>
-      </div>
-    );
-  }
-});
-```
-
-부모 컴포넌트인 `CommentList`에서 자식 컴포넌트인 `Comment`에 데이터들을 전달하고 있는것을 확인할 수 있습니다. 예를 들어, 우리는 어트리뷰트로 *Pete Hunt*를, XML 형식의 자식 노드로 *댓글입니다*를 첫 번째 `Comment`로 넘겼습니다. 위에서 언급했듯이 `Comment` 컴포넌트는 그들의 '프로퍼티'를 `this.props.author`, `this.props.children`를 통해 접근합니다.
-
-### Markdown 추가하기
-
-Markdown은 텍스트를 포맷팅하는 간단한 방식입니다. 예를 들어, 별표(`*`)로 텍스트를 둘러싸는 것은 강조의 의미입니다.
-
-먼저 서드파티 라이브러리인 **marked**를 애플리케이션에 추가합니다. 이 JavaScript 라이브러리는 Markdown 텍스트를 HTML 문법으로 변환해줍니다. head 태그안에 스크립트 태그를 추가해 주세요. (React playground에는 이미 포함되어 있습니다):
-
-```html{9}
-<!-- index.html -->
-<head>
-  <meta charset="utf-8" />
-  <title>React Tutorial</title>
-  <script src="https://cdnjs.cloudflare.com/ajax/libs/react/{{site.react_version}}/react.js"></script>
-  <script src="https://cdnjs.cloudflare.com/ajax/libs/react/{{site.react_version}}/react-dom.js"></script>
-  <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
-  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
-  <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.5/marked.min.js"></script>
-</head>
-```
-
-다음은, 댓글 텍스트를 Markdown으로 전환하고 출력해 봅시다.
-
-```javascript{9}
-// tutorial6.js
-var Comment = React.createClass({
-  render: function() {
-    return (
-      <div className="comment">
-        <h2 className="commentAuthor">
-          {this.props.author}
-        </h2>
-        {marked(this.props.children.toString())}
-      </div>
-    );
-  }
-});
-```
-
-우리가 한 일이라고는 marked 라이브러리를 호출한 것 뿐입니다. marked가 `this.props.children`에서 텍스트를 읽어들여 처리할 수 있도록 React 형식의 텍스트(React's wrapped text)를 단순 텍스트(raw string)으로 전환하기 위해 명시적으로 `toString()`을 호출했습니다.
-
-하지만 여기엔 문제가 있습니다! 우리는 HTML 태그들이 정상적으로 렌더되길 원하지만 브라우저에 출력된 결과물은 "`<p>``<em>`또 다른`</em>` 댓글입니다`</p>`"처럼 태그가 그대로 보일것입니다.
-
-React는 이런 식으로 [XSS 공격](https://en.wikipedia.org/wiki/Cross-site_scripting)을 예방합니다. 우회할 방법이 있긴 하지만 프레임워크는 사용하지 않도록 경고하고 있습니다:
-
-```javascript{3-6,14}
-// tutorial7.js
-var Comment = React.createClass({
-  rawMarkup: function() {
-    var rawMarkup = marked(this.props.children.toString(), {sanitize: true});
-    return { __html: rawMarkup };
-  },
-
-  render: function() {
-    return (
-      <div className="comment">
-        <h2 className="commentAuthor">
-          {this.props.author}
-        </h2>
-        <span dangerouslySetInnerHTML={this.rawMarkup()} />
-      </div>
-    );
-  }
-});
-```
-
-이는 의도적으로 생(raw) HTML을 넣기 힘들게 하려고 만든 특별한 API지만 marked를 사용하기 위해 이 백도어를 활용합시다.
-
-**잊지 마세요:** 이 기능은 marked가 안전한 것으로 믿고 사용하는 것입니다. 이 경우, 소스에 있는 그대로 넘겨 주는 대신, 모든 HTML 마크업을 이스케이프하도록 marked에게 `sanitize: true`를 넘겨 주었습니다.
-
-### 데이터 모델 연결하기
-
-지금까지는 소스코드에 직접 댓글을 넣었습니다. 이제부터는 JSON 데이터 덩어리를 댓글 목록에 렌더해보겠습니다. 최종적으로는 서버에서 데이터가 내려오겠지만, 지금은 소스에 직접 데이터를 넣어봅시다:
-
-```javascript
-// tutorial8.js
-var data = [
-  {author: "Pete Hunt", text: "댓글입니다"},
-  {author: "Jordan Walke", text: "*또 다른* 댓글입니다"}
-];
-```
-
-이 데이터를 모듈화된 방식으로 `CommentList`에 넣어야 합니다. props을 이용해 데이터를 넘기도록 `CommentBox`와 `ReactDOM.render()` 호출 코드를 수정합시다.
-
-```javascript{7,15}
-// tutorial9.js
-var CommentBox = React.createClass({
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>댓글</h1>
-        <CommentList data={this.props.data} />
-        <CommentForm />
-      </div>
-    );
-  }
-});
-
-ReactDOM.render(
-  <CommentBox data={data} />,
-  document.getElementById('content')
-);
-```
-
-이제 `CommentList`에서 데이터를 다룰 수 있습니다. 댓글을 동적으로 렌더해봅시다:
-
-```javascript{4-10,13}
-// tutorial10.js
-var CommentList = React.createClass({
-  render: function() {
-    var commentNodes = this.props.data.map(function (comment) {
-      return (
-        <Comment author={comment.author}>
-          {comment.text}
-        </Comment>
-      );
-    });
-    return (
-      <div className="commentList">
-        {commentNodes}
-      </div>
-    );
-  }
-});
-```
-
-이게 전부입니다!
-
-### 서버에서 가져오기(Fetching)
-
-이제 데이터를 소스에 직접 넣는 방식에서 서버에서 동적으로 받아서 처리하는 방식으로 바꿔봅시다. 데이터 prop을 삭제하고 처리할 URL로 변경해 줍시다.
-
-```javascript{3}
-// tutorial11.js
-ReactDOM.render(
-  <CommentBox url="/api/comments" />,
-  document.getElementById('content')
-);
-```
-
-이 컴포넌트는 이전 것과 다르게, 스스로 다시 렌더링해야 합니다. 컴포넌트는 서버에서 요청이 들어올때까지는 아무 데이터도 가지고 있지 않다가, 특정한 시점에서 새로운 댓글을 렌더할 필요가 있을 것입니다.
-
-주의: 이 단계에서 코드는 아직 동작하지 않습니다.
-
-### 반응적 state
-
-지금까지, 각각의 컴포넌트는 props를 기반으로 한번 렌더되었습니다. `props`는 불변성을 갖습니다: 그것들은 부모에서 전달되어 부모에게 "소유" 되어 있습니다. 컴포넌트에 상호작용을 구현하기 위해서, 가변성을 갖는 **state**를 소개합니다. `this.state`는 컴포넌트에 한정(private)되며 `this.setState()`를 통해 변경할 수 있습니다. state가 업데이트 되면, 컴포넌트는 자신을 스스로 다시 렌더링합니다.
-
-`render()` 메소드는 `this.props`와 `this.state`를 위한 함수로 선언적으로 작성됩니다. 프레임워크에서 입력값에 따른 UI가 항상 일관성 있음을 보장해줍니다.
-
-서버가 데이터를 가져오면 댓글 데이터가 변경될 것입니다. 댓글 데이터의 배열을 `CommentBox`의 state로 추가해봅시다:
-
-```javascript{3-5,10}
-// tutorial12.js
-var CommentBox = React.createClass({
-  getInitialState: function() {
-    return {data: []};
-  },
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>댓글</h1>
-        <CommentList data={this.state.data} />
-        <CommentForm />
-      </div>
-    );
-  }
-});
-```
-
-`getInitialState()` 는 컴포넌트의 생명주기동안 한 번만 실행되며 컴포넌트의 초기 state를 설정합니다.
-
-### state 업데이트하기
-
-컴포넌트의 최초 생성 시에, 서버에서 GET 방식으로 JSON을 넘겨받아 최신의 데이터가 state에 반영되길 원했습니다. jQuery를 사용해 서버에 비동기 요청을 만들어 필요한 데이터를 빨리 가져올 수 있게 하겠습니다. 이런 식입니다.
-
-```json
-[
-  {"author": "Pete Hunt", "text": "댓글입니다"},
-  {"author": "Jordan Walke", "text": "*또 다른* 댓글입니다"}
-]
-```
-
-```javascript{6-18}
-// tutorial13.js
-var CommentBox = React.createClass({
-  getInitialState: function() {
-    return {data: []};
-  },
-  componentDidMount: function() {
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      cache: false,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>댓글</h1>
-        <CommentList data={this.state.data} />
-        <CommentForm />
-      </div>
-    );
-  }
-});
-```
-
-여기서 `componentDidMount`는 컴포넌트가 렌더링 된 다음 React에 의해 자동으로 호출되는 메소드입니다. 동적 업데이트의 핵심은 `this.setState()`의 호출입니다. 우리가 이전의 댓글 목록을 서버에서 넘어온 새로운 목록으로 변경하면 자동으로 UI가 업데이트 될 것입니다. 이 반응성 덕분에 실시간 업데이트에 아주 작은 수정만 가해집니다. 우리는 여기선 간단한 폴링을 사용할 것이지만 웹소켓등의 다른 기술도 쉽게 사용할 수 있습니다.
-
-```javascript{3,15,20-21,35}
-// tutorial14.js
-var CommentBox = React.createClass({
-  loadCommentsFromServer: function() {
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      cache: false,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  getInitialState: function() {
-    return {data: []};
-  },
-  componentDidMount: function() {
-    this.loadCommentsFromServer();
-    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
-  },
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>댓글</h1>
-        <CommentList data={this.state.data} />
-        <CommentForm />
-      </div>
-    );
-  }
-});
-
-ReactDOM.render(
-  <CommentBox url="/api/comments" pollInterval={2000} />,
-  document.getElementById('content')
-);
-
-```
-
-우리가 여기서 한것은 AJAX 호출을 별도의 메소드로 분리하고 컴포넌트가 처음 로드된 시점부터 2초 간격으로 계속 호출되도록 한 것입니다. 브라우저에서 직접 돌려보고 `comments.json` 파일(서버의 같은 디렉토리에 있습니다)을 수정해보세요. 2초 간격으로 변화되는 모습이 보일 것입니다!
-
-### 새로운 댓글 추가하기
-
-이제 폼을 만들어볼 시간입니다. 우리의 `CommentForm` 컴포넌트는 사용자에게 이름과 내용을 입력받고 댓글을 저장하기 위해 서버에 요청을 전송해야 합니다.
-
-```javascript{5-9}
-// tutorial15.js
-var CommentForm = React.createClass({
-  render: function() {
-    return (
-      <form className="commentForm">
-        <input type="text" placeholder="이름" />
-        <input type="text" placeholder="내용을 입력하세요..." />
-        <input type="submit" value="올리기" />
-      </form>
-    );
-  }
-});
-```
-
-이제 폼의 상호작용을 만들어 보겠습니다. 사용자가 폼을 전송하는 시점에 우리는 폼을 초기화하고 서버에 요청을 전송하고 댓글목록을 업데이트해야 합니다. 폼의 submit 이벤트를 감시하고 초기화 해주는 부분부터 시작해 보죠.
-
-```javascript{3-13,16-19}
-// tutorial16.js
-var CommentForm = React.createClass({
-  handleSubmit: function(e) {
-    e.preventDefault();
-    var author = this.refs.author.value.trim();
-    var text = this.refs.text.value.trim();
-    if (!text || !author) {
-      return;
-    }
-    // TODO: 서버에 요청을 전송합니다
-    this.refs.author.value = '';
-    this.refs.text.value = '';
-    return;
-  },
-  render: function() {
-    return (
-      <form className="commentForm" onSubmit={this.handleSubmit}>
-        <input type="text" placeholder="이름" ref="author" />
-        <input type="text" placeholder="내용을 입력하세요..." ref="text" />
-        <input type="submit" value="올리기" />
-      </form>
-    );
-  }
-});
-```
-
-##### 이벤트
-
-React는 카멜케이스 네이밍 컨벤션으로 컴포넌트에 이벤트 핸들러를 등록합니다. 폼이 유효한 값으로 submit되었을 때 폼필드들을 초기화하도록 `onSubmit` 핸들러를 등록합니다.
-
-폼 submit에 대한 브라우저의 기본동작을 막기 위해 이벤트시점에 `preventDefault()`를 호출합니다.
-
-##### Refs
-
-자식 컴포넌트의 이름을 지정하기 위해 `ref` 어트리뷰트를, DOM 노드를 참조하기 위해 `this.refs`를 사용합니다.
-
-##### props으로 콜백 처리하기
-
-사용자가 댓글을 등록할 때, 새로운 댓글을 추가하기 위해 댓글목록을 업데이트해주어야 합니다. `CommentBox`가 댓글목록의 state를 소유하고 있기 때문에 이 로직 또한 `CommentBox`에 있는것이 타당합니다.
-
-자식 컴포넌트가 그의 부모에게 데이터를 넘겨줄 필요가 있습니다. 부모의 `render` 메소드에서 새로운 콜백(`handleCommentSubmit`)을 자식에게 넘겨주고, 자식의 `onCommentSubmit` 이벤트에 그것을 바인딩해주는 식으로 구현합니다. 이벤트가 작동될때(triggered)마다, 콜백이 호출됩니다:
-
-```javascript{16-18,31}
-// tutorial17.js
-var CommentBox = React.createClass({
-  loadCommentsFromServer: function() {
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      cache: false,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  handleCommentSubmit: function(comment) {
-    // TODO: 서버에 요청을 수행하고 목록을 업데이트한다
-  },
-  getInitialState: function() {
-    return {data: []};
-  },
-  componentDidMount: function() {
-    this.loadCommentsFromServer();
-    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
-  },
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>댓글</h1>
-        <CommentList data={this.state.data} />
-        <CommentForm onCommentSubmit={this.handleCommentSubmit} />
-      </div>
-    );
-  }
-});
-```
-
-사용자가 폼을 전송할 때, `CommentForm`에서 콜백을 호출해 봅시다:
-
-```javascript{10}
-// tutorial18.js
-var CommentForm = React.createClass({
-  handleSubmit: function(e) {
-    e.preventDefault();
-    var author = this.refs.author.value.trim();
-    var text = this.refs.text.value.trim();
-    if (!text || !author) {
-      return;
-    }
-    this.props.onCommentSubmit({author: author, text: text});
-    this.refs.author.value = '';
-    this.refs.text.value = '';
-    return;
-  },
-  render: function() {
-    return (
-      <form className="commentForm" onSubmit={this.handleSubmit}>
-        <input type="text" placeholder="이름" ref="author" />
-        <input type="text" placeholder="이름을 입력하세요..." ref="text" />
-        <input type="submit" value="올리기" />
-      </form>
-    );
-  }
-});
-```
-
-이제 콜백이 제자리를 찾았습니다. 우리가 할 일은 서버에 요청을 날리고 목록을 업데이트하는 것 뿐입니다:
-
-```javascript{17-28}
-// tutorial19.js
-var CommentBox = React.createClass({
-  loadCommentsFromServer: function() {
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      cache: false,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  handleCommentSubmit: function(comment) {
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      type: 'POST',
-      data: comment,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  getInitialState: function() {
-    return {data: []};
-  },
-  componentDidMount: function() {
-    this.loadCommentsFromServer();
-    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
-  },
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>댓글</h1>
-        <CommentList data={this.state.data} />
-        <CommentForm onCommentSubmit={this.handleCommentSubmit} />
-      </div>
-    );
-  }
-});
-```
-
-### 최적화: 낙관적 업데이트
-
-우리의 애플리케이션은 이제 모든 기능을 갖추었습니다. 하지만 댓글이 목록에 업데이트되기 전에 완료요청을 기다리는 게 조금 느린듯한 느낌이 드네요. 우리는 낙관적 업데이트를 통해 댓글이 목록에 추가되도록 함으로써 앱이 좀 더 빨라진 것처럼 느껴지도록 할 수 있습니다.
-
-```javascript{17-19,29}
-// tutorial20.js
-var CommentBox = React.createClass({
-  loadCommentsFromServer: function() {
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      cache: false,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  handleCommentSubmit: function(comment) {
-    var comments = this.state.data;
-    var newComments = comments.concat([comment]);
-    this.setState({data: newComments});
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      type: 'POST',
-      data: comment,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        this.setState({data: comments});
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  getInitialState: function() {
-    return {data: []};
-  },
-  componentDidMount: function() {
-    this.loadCommentsFromServer();
-    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
-  },
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>댓글</h1>
-        <CommentList data={this.state.data} />
-        <CommentForm onCommentSubmit={this.handleCommentSubmit} />
-      </div>
-    );
-  }
-});
-```
-
-### 축하합니다!
-
-몇 단계를 거쳐 간단하게 댓글창을 만들어 보았습니다. [왜 React인가](/react/docs/why-react-ko-KR.html)에서 더 알아보거나, 혹은 [API 레퍼런스](/react/docs/top-level-api-ko-KR.html)에 뛰어들어 해킹을 시작하세요! 행운을 빕니다!
diff --git a/docs/docs/tutorial.md b/docs/docs/tutorial.md
deleted file mode 100755
index 0878bd6d6c0c..000000000000
--- a/docs/docs/tutorial.md
+++ /dev/null
@@ -1,783 +0,0 @@
----
-id: tutorial
-title: Tutorial
-prev: getting-started.html
-next: thinking-in-react.html
----
-
-We'll be building a simple but realistic comments box that you can drop into a blog, a basic version of the realtime comments offered by Disqus, LiveFyre or Facebook comments.
-
-We'll provide:
-
-* A view of all of the comments
-* A form to submit a comment
-* Hooks for you to provide a custom backend
-
-It'll also have a few neat features:
-
-* **Optimistic commenting:** comments appear in the list before they're saved on the server so it feels fast.
-* **Live updates:** other users' comments are popped into the comment view in real time.
-* **Markdown formatting:** users can use Markdown to format their text.
-
-### Want to skip all this and just see the source?
-
-[It's all on GitHub.](https://github.com/reactjs/react-tutorial)
-
-### Running a server
-
-In order to start this tutorial, we're going to require a running server. This will serve purely as an API endpoint which we'll use for getting and saving data. In order to make this as easy as possible, we've created a simple server in a number of scripting languages that does exactly what we need it to do. **You can [view the source](https://github.com/reactjs/react-tutorial/) or [download a zip file](https://github.com/reactjs/react-tutorial/archive/master.zip) containing everything needed to get started.**
-
-For sake of simplicity, the server we will run uses a `JSON` file as a database. You would not run this in production but it makes it easy to simulate what you might do when consuming an API. Once you start the server, it will support our API endpoint and it will also serve the static pages we need.
-
-### Getting started
-
-For this tutorial, we're going to make it as easy as possible. Included in the server package discussed above is an HTML file which we'll work in. Open up `public/index.html` in your favorite editor. It should look something like this:
-
-```html
-<!-- index.html -->
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="utf-8" />
-    <title>React Tutorial</title>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/{{site.react_version}}/react.js"></script>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/{{site.react_version}}/react-dom.js"></script>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.5/marked.min.js"></script>
-  </head>
-  <body>
-    <div id="content"></div>
-    <script type="text/babel" src="scripts/example.js"></script>
-    <script type="text/babel">
-      // To get started with this tutorial running your own code, simply remove
-      // the script tag loading scripts/example.js and start writing code here.
-    </script>
-  </body>
-</html>
-```
-
-For the remainder of this tutorial, we'll be writing our JavaScript code in this script tag. We don't have any advanced live-reloading so you'll need to refresh your browser to see updates after saving. Follow your progress by opening `http://localhost:3000` in your browser (after starting the server). When you load this for the first time without any changes, you'll see the finished product of what we're going to build. When you're ready to start working, just delete the preceding `<script>` tag and then you can continue.
-
-> Note:
->
-> We included jQuery here because we want to simplify the code of our future ajax calls, but it's **NOT** mandatory for React to work.
-
-### Your first component
-
-React is all about modular, composable components. For our comment box example, we'll have the following component structure:
-
-```
-- CommentBox
-  - CommentList
-    - Comment
-  - CommentForm
-```
-
-Let's build the `CommentBox` component, which is just a simple `<div>`:
-
-```javascript
-// tutorial1.js
-var CommentBox = React.createClass({
-  render: function() {
-    return (
-      <div className="commentBox">
-        Hello, world! I am a CommentBox.
-      </div>
-    );
-  }
-});
-ReactDOM.render(
-  <CommentBox />,
-  document.getElementById('content')
-);
-```
-
-Note that native HTML element names start with a lowercase letter, while custom React class names begin with an uppercase letter.
-
-#### JSX Syntax
-
-The first thing you'll notice is the XML-ish syntax in your JavaScript. We have a simple precompiler that translates the syntactic sugar to this plain JavaScript:
-
-```javascript
-// tutorial1-raw.js
-var CommentBox = React.createClass({displayName: 'CommentBox',
-  render: function() {
-    return (
-      React.createElement('div', {className: "commentBox"},
-        "Hello, world! I am a CommentBox."
-      )
-    );
-  }
-});
-ReactDOM.render(
-  React.createElement(CommentBox, null),
-  document.getElementById('content')
-);
-```
-
-Its use is optional but we've found JSX syntax easier to use than plain JavaScript. Read more on the [JSX Syntax article](/react/docs/jsx-in-depth.html).
-
-#### What's going on
-
-We pass some methods in a JavaScript object to `React.createClass()` to create a new React component. The most important of these methods is called `render` which returns a tree of React components that will eventually render to HTML.
-
-The `<div>` tags are not actual DOM nodes; they are instantiations of React `div` components. You can think of these as markers or pieces of data that React knows how to handle. React is **safe**. We are not generating HTML strings so XSS protection is the default.
-
-You do not have to return basic HTML. You can return a tree of components that you (or someone else) built. This is what makes React **composable**: a key tenet of maintainable frontends.
-
-`ReactDOM.render()` instantiates the root component, starts the framework, and injects the markup into a raw DOM element, provided as the second argument.
-
-The `ReactDOM` module exposes DOM-specific methods, while `React` has the core tools shared by React on different platforms (e.g., [React Native](http://facebook.github.io/react-native/)).
-
-It is important that `ReactDOM.render` remain at the bottom of the script for this tutorial. `ReactDOM.render` should only be called after the composite components have been defined.
-
-## Composing components
-
-Let's build skeletons for `CommentList` and `CommentForm` which will, again, be simple `<div>`s. Add these two components to your file, keeping the existing `CommentBox` declaration and `ReactDOM.render` call:
-
-```javascript
-// tutorial2.js
-var CommentList = React.createClass({
-  render: function() {
-    return (
-      <div className="commentList">
-        Hello, world! I am a CommentList.
-      </div>
-    );
-  }
-});
-
-var CommentForm = React.createClass({
-  render: function() {
-    return (
-      <div className="commentForm">
-        Hello, world! I am a CommentForm.
-      </div>
-    );
-  }
-});
-```
-
-Next, update the `CommentBox` component to use these new components:
-
-```javascript{6-8}
-// tutorial3.js
-var CommentBox = React.createClass({
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>Comments</h1>
-        <CommentList />
-        <CommentForm />
-      </div>
-    );
-  }
-});
-```
-
-Notice how we're mixing HTML tags and components we've built. HTML components are regular React components, just like the ones you define, with one difference. The JSX compiler will automatically rewrite HTML tags to `React.createElement(tagName)` expressions and leave everything else alone. This is to prevent the pollution of the global namespace.
-
-### Using props
-
-Let's create the `Comment` component, which will depend on data passed in from its parent. Data passed in from a parent component is available as a 'property' on the child component. These 'properties' are accessed through `this.props`. Using props, we will be able to read the data passed to the `Comment` from the `CommentList`, and render some markup:
-
-```javascript
-// tutorial4.js
-var Comment = React.createClass({
-  render: function() {
-    return (
-      <div className="comment">
-        <h2 className="commentAuthor">
-          {this.props.author}
-        </h2>
-        {this.props.children}
-      </div>
-    );
-  }
-});
-```
-
-By surrounding a JavaScript expression in braces inside JSX (as either an attribute or child), you can drop text or React components into the tree. We access named attributes passed to the component as keys on `this.props` and any nested elements as `this.props.children`.
-
-### Component Properties
-
-Now that we have defined the `Comment` component, we will want to pass it the author name and comment text. This allows us to reuse the same code for each unique comment. Now let's add some comments within our `CommentList`:
-
-```javascript{6-7}
-// tutorial5.js
-var CommentList = React.createClass({
-  render: function() {
-    return (
-      <div className="commentList">
-        <Comment author="Pete Hunt">This is one comment</Comment>
-        <Comment author="Jordan Walke">This is *another* comment</Comment>
-      </div>
-    );
-  }
-});
-```
-
-Note that we have passed some data from the parent `CommentList` component to the child `Comment` components. For example, we passed *Pete Hunt* (via an attribute) and *This is one comment* (via an XML-like child node) to the first `Comment`. As noted above, the `Comment` component will access these 'properties' through `this.props.author`, and `this.props.children`.
-
-### Adding Markdown
-
-Markdown is a simple way to format your text inline. For example, surrounding text with asterisks will make it emphasized.
-
-In this tutorial we use a third-party library **marked** which takes Markdown text and converts it to raw HTML. We already included this library with the original markup for the page, so we can just start using it. Let's convert the comment text to Markdown and output it:
-
-```javascript{9}
-// tutorial6.js
-var Comment = React.createClass({
-  render: function() {
-    return (
-      <div className="comment">
-        <h2 className="commentAuthor">
-          {this.props.author}
-        </h2>
-        {marked(this.props.children.toString())}
-      </div>
-    );
-  }
-});
-```
-
-All we're doing here is calling the marked library. We need to convert `this.props.children` from React's wrapped text to a raw string that marked will understand so we explicitly call `toString()`.
-
-But there's a problem! Our rendered comments look like this in the browser: "`<p>`This is `<em>`another`</em>` comment`</p>`". We want those tags to actually render as HTML.
-
-That's React protecting you from an [XSS attack](https://en.wikipedia.org/wiki/Cross-site_scripting). There's a way to get around it but the framework warns you not to use it:
-
-```javascript{3-6,14}
-// tutorial7.js
-var Comment = React.createClass({
-  rawMarkup: function() {
-    var rawMarkup = marked(this.props.children.toString(), {sanitize: true});
-    return { __html: rawMarkup };
-  },
-
-  render: function() {
-    return (
-      <div className="comment">
-        <h2 className="commentAuthor">
-          {this.props.author}
-        </h2>
-        <span dangerouslySetInnerHTML={this.rawMarkup()} />
-      </div>
-    );
-  }
-});
-```
-
-This is a special API that intentionally makes it difficult to insert raw HTML, but for marked we'll take advantage of this backdoor.
-
-**Remember:** by using this feature you're relying on marked to be secure. In this case, we pass `sanitize: true` which tells marked to escape any HTML markup in the source instead of passing it through unchanged.
-
-### Hook up the data model
-
-So far we've been inserting the comments directly in the source code. Instead, let's render a blob of JSON data into the comment list. Eventually this will come from the server, but for now, write it in your source:
-
-```javascript
-// tutorial8.js
-var data = [
-  {id: 1, author: "Pete Hunt", text: "This is one comment"},
-  {id: 2, author: "Jordan Walke", text: "This is *another* comment"}
-];
-```
-
-We need to get this data into `CommentList` in a modular way. Modify `CommentBox` and the `ReactDOM.render()` call to pass this data into the `CommentList` via props:
-
-```javascript{7,15}
-// tutorial9.js
-var CommentBox = React.createClass({
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>Comments</h1>
-        <CommentList data={this.props.data} />
-        <CommentForm />
-      </div>
-    );
-  }
-});
-
-ReactDOM.render(
-  <CommentBox data={data} />,
-  document.getElementById('content')
-);
-```
-
-Now that the data is available in the `CommentList`, let's render the comments dynamically:
-
-```javascript{4-10,13}
-// tutorial10.js
-var CommentList = React.createClass({
-  render: function() {
-    var commentNodes = this.props.data.map(function(comment) {
-      return (
-        <Comment author={comment.author} key={comment.id}>
-          {comment.text}
-        </Comment>
-      );
-    });
-    return (
-      <div className="commentList">
-        {commentNodes}
-      </div>
-    );
-  }
-});
-```
-
-That's it!
-
-### Fetching from the server
-
-Let's replace the hard-coded data with some dynamic data from the server. We will remove the data prop and replace it with a URL to fetch:
-
-```javascript{3}
-// tutorial11.js
-ReactDOM.render(
-  <CommentBox url="/api/comments" />,
-  document.getElementById('content')
-);
-```
-
-This component is different from the prior components because it will have to re-render itself. The component won't have any data until the request from the server comes back, at which point the component may need to render some new comments.
-
-Note: the code will not be working at this step.
-
-### Reactive state
-
-So far, based on its props, each component has rendered itself once. `props` are immutable: they are passed from the parent and are "owned" by the parent. To implement interactions, we introduce mutable **state** to the component. `this.state` is private to the component and can be changed by calling `this.setState()`. When the state updates, the component re-renders itself.
-
-`render()` methods are written declaratively as functions of `this.props` and `this.state`. The framework guarantees the UI is always consistent with the inputs.
-
-When the server fetches data, we will be changing the comment data we have. Let's add an array of comment data to the `CommentBox` component as its state:
-
-```javascript{3-5,10}
-// tutorial12.js
-var CommentBox = React.createClass({
-  getInitialState: function() {
-    return {data: []};
-  },
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>Comments</h1>
-        <CommentList data={this.state.data} />
-        <CommentForm />
-      </div>
-    );
-  }
-});
-```
-
-`getInitialState()` executes exactly once during the lifecycle of the component and sets up the initial state of the component.
-
-#### Updating state
-When the component is first created, we want to GET some JSON from the server and update the state to reflect the latest data. We're going to use jQuery to make an asynchronous request to the server we started earlier to fetch the data we need. The data is already included in the server you started (based on the `comments.json` file), so once it's fetched, `this.state.data` will look something like this:
-
-```json
-[
-  {"author": "Pete Hunt", "text": "This is one comment"},
-  {"author": "Jordan Walke", "text": "This is *another* comment"}
-]
-```
-
-```javascript{6-18}
-// tutorial13.js
-var CommentBox = React.createClass({
-  getInitialState: function() {
-    return {data: []};
-  },
-  componentDidMount: function() {
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      cache: false,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>Comments</h1>
-        <CommentList data={this.state.data} />
-        <CommentForm />
-      </div>
-    );
-  }
-});
-```
-
-Here, `componentDidMount` is a method called automatically by React after a component is rendered for the first time. The key to dynamic updates is the call to `this.setState()`. We replace the old array of comments with the new one from the server and the UI automatically updates itself. Because of this reactivity, it is only a minor change to add live updates. We will use simple polling here but you could easily use WebSockets or other technologies.
-
-```javascript{3,15,20-21,35}
-// tutorial14.js
-var CommentBox = React.createClass({
-  loadCommentsFromServer: function() {
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      cache: false,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  getInitialState: function() {
-    return {data: []};
-  },
-  componentDidMount: function() {
-    this.loadCommentsFromServer();
-    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
-  },
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>Comments</h1>
-        <CommentList data={this.state.data} />
-        <CommentForm />
-      </div>
-    );
-  }
-});
-
-ReactDOM.render(
-  <CommentBox url="/api/comments" pollInterval={2000} />,
-  document.getElementById('content')
-);
-
-```
-
-All we have done here is move the AJAX call to a separate method and call it when the component is first loaded and every 2 seconds after that. Try running this in your browser and changing the `comments.json` file (in the same directory as your server); within 2 seconds, the changes will show!
-
-### Adding new comments
-
-Now it's time to build the form. Our `CommentForm` component should ask the user for their name and comment text and send a request to the server to save the comment.
-
-```javascript{5-9}
-// tutorial15.js
-var CommentForm = React.createClass({
-  render: function() {
-    return (
-      <form className="commentForm">
-        <input type="text" placeholder="Your name" />
-        <input type="text" placeholder="Say something..." />
-        <input type="submit" value="Post" />
-      </form>
-    );
-  }
-});
-```
-
-#### Controlled components
-
-With the traditional DOM, `input` elements are rendered and the browser manages the state (its rendered value). As a result, the state of the actual DOM will differ from that of the component. This is not ideal as the state of the view will differ from that of the component. In React, components should always represent the state of the view and not only at the point of initialization.
-
-Hence, we will be using `this.state` to save the user's input as it is entered. We define an initial `state` with two properties `author` and `text` and set them to be empty strings. In our `<input>` elements, we set the `value` prop to reflect the `state` of the component and attach `onChange` handlers to them. These `<input>` elements with a `value` set are called controlled components. Read more about controlled components on the [Forms article](/react/docs/forms.html#controlled-components).
-
-```javascript{3-11,15-26}
-// tutorial16.js
-var CommentForm = React.createClass({
-  getInitialState: function() {
-    return {author: '', text: ''};
-  },
-  handleAuthorChange: function(e) {
-    this.setState({author: e.target.value});
-  },
-  handleTextChange: function(e) {
-    this.setState({text: e.target.value});
-  },
-  render: function() {
-    return (
-      <form className="commentForm">
-        <input
-          type="text"
-          placeholder="Your name"
-          value={this.state.author}
-          onChange={this.handleAuthorChange}
-        />
-        <input
-          type="text"
-          placeholder="Say something..."
-          value={this.state.text}
-          onChange={this.handleTextChange}
-        />
-        <input type="submit" value="Post" />
-      </form>
-    );
-  }
-});
-```
-
-#### Events
-
-React attaches event handlers to components using a camelCase naming convention. We attach `onChange` handlers to the two `<input>` elements. Now, as the user enters text into the `<input>` fields, the attached `onChange` callbacks are fired and the `state` of the component is modified. Subsequently, the rendered value of the `input` element will be updated to reflect the current component `state`.
-
-#### Submitting the form
-
-Let's make the form interactive. When the user submits the form, we should clear it, submit a request to the server, and refresh the list of comments. To start, let's listen for the form's submit event and clear it.
-
-```javascript{12-21,24}
-// tutorial17.js
-var CommentForm = React.createClass({
-  getInitialState: function() {
-    return {author: '', text: ''};
-  },
-  handleAuthorChange: function(e) {
-    this.setState({author: e.target.value});
-  },
-  handleTextChange: function(e) {
-    this.setState({text: e.target.value});
-  },
-  handleSubmit: function(e) {
-    e.preventDefault();
-    var author = this.state.author.trim();
-    var text = this.state.text.trim();
-    if (!text || !author) {
-      return;
-    }
-    // TODO: send request to the server
-    this.setState({author: '', text: ''});
-  },
-  render: function() {
-    return (
-      <form className="commentForm" onSubmit={this.handleSubmit}>
-        <input
-          type="text"
-          placeholder="Your name"
-          value={this.state.author}
-          onChange={this.handleAuthorChange}
-        />
-        <input
-          type="text"
-          placeholder="Say something..."
-          value={this.state.text}
-          onChange={this.handleTextChange}
-        />
-        <input type="submit" value="Post" />
-      </form>
-    );
-  }
-});
-```
-
-We attach an `onSubmit` handler to the form that clears the form fields when the form is submitted with valid input.
-
-Call `preventDefault()` on the event to prevent the browser's default action of submitting the form.
-
-#### Callbacks as props
-
-When a user submits a comment, we will need to refresh the list of comments to include the new one. It makes sense to do all of this logic in `CommentBox` since `CommentBox` owns the state that represents the list of comments.
-
-We need to pass data from the child component back up to its parent. We do this in our parent's `render` method by passing a new callback (`handleCommentSubmit`) into the child, binding it to the child's `onCommentSubmit` event. Whenever the event is triggered, the callback will be invoked:
-
-```javascript{16-18,31}
-// tutorial18.js
-var CommentBox = React.createClass({
-  loadCommentsFromServer: function() {
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      cache: false,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  handleCommentSubmit: function(comment) {
-    // TODO: submit to the server and refresh the list
-  },
-  getInitialState: function() {
-    return {data: []};
-  },
-  componentDidMount: function() {
-    this.loadCommentsFromServer();
-    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
-  },
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>Comments</h1>
-        <CommentList data={this.state.data} />
-        <CommentForm onCommentSubmit={this.handleCommentSubmit} />
-      </div>
-    );
-  }
-});
-```
-
-Now that `CommentBox` has made the callback available to `CommentForm` via the `onCommentSubmit` prop, the `CommentForm` can call the callback when the user submits the form:
-
-```javascript{19}
-// tutorial19.js
-var CommentForm = React.createClass({
-  getInitialState: function() {
-    return {author: '', text: ''};
-  },
-  handleAuthorChange: function(e) {
-    this.setState({author: e.target.value});
-  },
-  handleTextChange: function(e) {
-    this.setState({text: e.target.value});
-  },
-  handleSubmit: function(e) {
-    e.preventDefault();
-    var author = this.state.author.trim();
-    var text = this.state.text.trim();
-    if (!text || !author) {
-      return;
-    }
-    this.props.onCommentSubmit({author: author, text: text});
-    this.setState({author: '', text: ''});
-  },
-  render: function() {
-    return (
-      <form className="commentForm" onSubmit={this.handleSubmit}>
-        <input
-          type="text"
-          placeholder="Your name"
-          value={this.state.author}
-          onChange={this.handleAuthorChange}
-        />
-        <input
-          type="text"
-          placeholder="Say something..."
-          value={this.state.text}
-          onChange={this.handleTextChange}
-        />
-        <input type="submit" value="Post" />
-      </form>
-    );
-  }
-});
-```
-
-Now that the callbacks are in place, all we have to do is submit to the server and refresh the list:
-
-```javascript{17-28}
-// tutorial20.js
-var CommentBox = React.createClass({
-  loadCommentsFromServer: function() {
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      cache: false,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  handleCommentSubmit: function(comment) {
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      type: 'POST',
-      data: comment,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  getInitialState: function() {
-    return {data: []};
-  },
-  componentDidMount: function() {
-    this.loadCommentsFromServer();
-    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
-  },
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>Comments</h1>
-        <CommentList data={this.state.data} />
-        <CommentForm onCommentSubmit={this.handleCommentSubmit} />
-      </div>
-    );
-  }
-});
-```
-
-### Optimization: optimistic updates
-
-Our application is now feature complete but it feels slow to have to wait for the request to complete before your comment appears in the list. We can optimistically add this comment to the list to make the app feel faster.
-
-```javascript{17-23,33}
-// tutorial21.js
-var CommentBox = React.createClass({
-  loadCommentsFromServer: function() {
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      cache: false,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  handleCommentSubmit: function(comment) {
-    var comments = this.state.data;
-    // Optimistically set an id on the new comment. It will be replaced by an
-    // id generated by the server. In a production application you would likely
-    // not use Date.now() for this and would have a more robust system in place.
-    comment.id = Date.now();
-    var newComments = comments.concat([comment]);
-    this.setState({data: newComments});
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      type: 'POST',
-      data: comment,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        this.setState({data: comments});
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  getInitialState: function() {
-    return {data: []};
-  },
-  componentDidMount: function() {
-    this.loadCommentsFromServer();
-    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
-  },
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>Comments</h1>
-        <CommentList data={this.state.data} />
-        <CommentForm onCommentSubmit={this.handleCommentSubmit} />
-      </div>
-    );
-  }
-});
-```
-
-### Congrats!
-
-You have just built a comment box in a few simple steps. Learn more about [why to use React](/react/docs/why-react.html), or dive into the [API reference](/react/docs/top-level-api.html) and start hacking! Good luck!
diff --git a/docs/docs/tutorial.zh-CN.md b/docs/docs/tutorial.zh-CN.md
deleted file mode 100755
index 6f09154b7e1f..000000000000
--- a/docs/docs/tutorial.zh-CN.md
+++ /dev/null
@@ -1,783 +0,0 @@
----
-id: tutorial-zh-CN
-title: 教程
-prev: getting-started-zh-CN.html
-next: thinking-in-react-zh-CN.html
----
-
-我们将建立一个你可以放进博客的简单却真实的评论框，一个 Disqus、LiveFyre 或 Facebook comments 提供的实时评论的基础版本。
-
-我们将提供：
-
-* 一个所有评论的视图
-* 一个用于提交评论的表单
-* 为你提供制定后台的挂钩(Hooks)
-
-同时也会有一些简洁的功能：
-
-* **优化的评论：** 评论在它们保存到服务器之前就显示在列表里,所以感觉很快。
-* **实时更新：** 其他用户的评论被实时浮现到评论中。
-* **Markdown格式化：** 用户可以用Markdown格式化它们的文字。
-
-### 想要跳过所有内容，只查看源代码？
-
-[全在 GitHub .](https://github.com/reactjs/react-tutorial)
-
-### 运行服务器
-
-为了开始本教程，我们将要需要一个运行着的服务器。这将是我们纯粹用来获取和保存数据的伺服终端。为了让这尽可能的容易，我们已经用许多不同的语言编写了简单的服务器，它正好完成我们需要的事。    **你可以[查看源代码](https://github.com/reactjs/react-tutorial/) 或者 [下载 zip 文件](https://github.com/reactjs/react-tutorial/archive/master.zip) 包括了所有你开始学习需要的东西**
-
-为了简单起见，我们将要运行的服务器使用 `JSON` 文件作为数据库。你不会在生产环境运行这个，但是它让我们更容易模拟使用一个API时你可能会做的事。一旦你启动服务器，它将会支持我们的API终端,同时也将伺服我们需要的静态页面。
-
-### 开始
-
-对于此教程,我们将使它尽可能的容易。被包括在上面讨论的服务器包里的是一个我们将在其中工作的 HTML 文件。在你最喜欢的编辑器里打开 `public/index.html`。它应该看起来像这样 （可能有一些小的不同，稍后我们将添加一个额外的 `<script>` 标签）：
-
-```html
-<!-- index.html -->
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="utf-8" />
-    <title>React Tutorial</title>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/{{site.react_version}}/react.js"></script>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/{{site.react_version}}/react-dom.js"></script>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.5/marked.min.js"></script>
-  </head>
-  <body>
-    <div id="content"></div>
-    <script type="text/babel" src="scripts/example.js"></script>
-    <script type="text/babel">
-      // To get started with this tutorial running your own code, simply remove
-      // the script tag loading scripts/example.js and start writing code here.
-    </script>
-  </body>
-</html>
-```
-
-在本教程剩余的部分，我们将在此 script 标签中编写我们的 JavaScript 代码。我们没有任何高级的实时加载所以在保存以后你需要刷新你的浏览器来观察更新。通过在浏览器打开 `http://localhost:3000` 关注你的进展。当你没有任何修改第一次加载时，你将看到我们将要准备建立的已经完成的产品。当你准备开始工作，请删除前面的 `<script>` 标签然后你就可以继续了。
-
-> 注意：
->
-> 我们在这里引入 jQuery 是因为我们想简化我们未来的 ajax 请求，但这对React的正常工作 **不是** 必要的。
-
-### 你的第一个组件
-
-React 中都是关于模块化、可组装的组件。以我们的评论框为例，我们将有如下的组件结构：
-
-```
-- CommentBox
-  - CommentList
-    - Comment
-  - CommentForm
-```
-
-让我们构造 `CommentBox` 组件，仅是一个简单的 `<div>` ：
-
-```javascript
-// tutorial1.js
-var CommentBox = React.createClass({
-  render: function() {
-    return (
-      <div className="commentBox">
-        Hello, world! I am a CommentBox.
-      </div>
-    );
-  }
-});
-ReactDOM.render(
-  <CommentBox />,
-  document.getElementById('content')
-);
-```
-
-注意原生的HTML元素以小写开头，而制定的 React 类以大写开头。
-
-#### JSX 语法
-
-首先你会注意到你的 JavaScript 中 XML 式的语法。我们有一个简单的预编译器，将语法糖转换成这种纯的JavaScript：
-
-```javascript
-// tutorial1-raw.js
-var CommentBox = React.createClass({displayName: 'CommentBox',
-  render: function() {
-    return (
-      React.createElement('div', {className: "commentBox"},
-        "Hello, world! I am a CommentBox."
-      )
-    );
-  }
-});
-ReactDOM.render(
-  React.createElement(CommentBox, null),
-  document.getElementById('content')
-);
-```
-
-它的使用是可选的，但是我们发现 JSX 语法比单纯的 JavaScript 更加容易使用。阅读更多关于[JSX 语法的文章](/react/docs/jsx-in-depth-zh-CN.html)。
-
-#### What's going on
-
-我们在一个 JavaScript 对象中传递一些方法到 `React.createClass()` 来创建一个新的React组件。这些方法中最重要的是 `render`，该方法返回一颗 React 组件树，这棵树最终将会渲染成 HTML。
-
-这个 `<div>` 标签不是真实的DOM节点；他们是 React `div` 组件的实例化。你可以把这些看做是React知道如何处理的标记或者是一些数据 。React 是**安全的**。我们不生成 HTML 字符串，因此XSS防护是默认特性。
-
-你没有必要返回基本的 HTML。你可以返回一个你（或者其他人）创建的组件树。这就使 React **组件化**：一个可维护前端的关键原则。
-
-`ReactDOM.render()` 实例化根组件，启动框架，注入标记到原始的 DOM 元素中，作为第二个参数提供。
-
-`ReactDOM` 模块暴露了 DOM 相关的方法， 而 `React` 保有被不同平台的 React 共享的核心工具 （例如 [React Native](http://facebook.github.io/react-native/)）。
-
-对于本教程 `ReactDOM.render` 保持在脚本底部是很重要的。`ReactDOM.render` 应该只在复合组件被定义之后被调用。
-
-## 组合组件
-
-让我们为 `CommentList` 和 `CommentForm` 建造骨架，它们将会，再一次的，是一些简单的 `<div>`。添加这两个组件到你的文件里，保持现存的 `CommentBox` 声明和 `ReactDOM.render` 调用:
-
-```javascript
-// tutorial2.js
-var CommentList = React.createClass({
-  render: function() {
-    return (
-      <div className="commentList">
-        Hello, world! I am a CommentList.
-      </div>
-    );
-  }
-});
-
-var CommentForm = React.createClass({
-  render: function() {
-    return (
-      <div className="commentForm">
-        Hello, world! I am a CommentForm.
-      </div>
-    );
-  }
-});
-```
-
-接着，更新 `CommentBox` 以使用这些新的组件：
-
-```javascript{6-8}
-// tutorial3.js
-var CommentBox = React.createClass({
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>Comments</h1>
-        <CommentList />
-        <CommentForm />
-      </div>
-    );
-  }
-});
-```
-
-注意我们是如何混合 HTML 标签和我们建立的组件。HTML 组件是正常的 React 组件，就和你定义的一样，只有一个区别。JSX 编译器会自动重写 HTML 标签为 `React.createElement(tagName)` 表达式，其它什么都不做。这是为了避免污染全局命名空间。
-
-### 使用 props
-
-让我们创建 `Comment` 组件，它将依赖于从父级传来的数据。从父级传来的数据在子组件里作为 '属性' 可供使用。 这些 '属性' 可以通过 `this.props` 访问。使用属性，我们将能读取从 `CommentList` 传递给 `Comment` 的数据，并且渲染一些标记：
-
-```javascript
-// tutorial4.js
-var Comment = React.createClass({
-  render: function() {
-    return (
-      <div className="comment">
-        <h2 className="commentAuthor">
-          {this.props.author}
-        </h2>
-        {this.props.children}
-      </div>
-    );
-  }
-});
-```
-
-在 JSX 中,通过将 JavaScript 表达式放在大括号中（作为属性或者子节点）,你可以把文本或者 React 组件放置到树中。我们以 `this.props` 的 keys 访问传递给组件的命名属性，以 `this.props.children` 访问任何嵌套的元素。
-
-### 组件的属性
-
-既然我们已经定义了 `Comment` 组件，我们将要传递作者名和评论文字给它。这允许我们为每个评论重用相同的代码。现在让我们在我们的 `CommentList` 里添加一些评论。
-
-```javascript{6-7}
-// tutorial5.js
-var CommentList = React.createClass({
-  render: function() {
-    return (
-      <div className="commentList">
-        <Comment author="Pete Hunt">This is one comment</Comment>
-        <Comment author="Jordan Walke">This is *another* comment</Comment>
-      </div>
-    );
-  }
-});
-```
-
-注意，我们已经从 `CommentList`  组件传递了一些数据到 `Comment` 组件。例如，我们传递了 *Pete Hunt* （通过属性）和 *This is one comment* (通过 XML-风格的子节点)给第一个 `Comment`。如上面提到的那样， `Comment` 组件将会通过 `this.props.author` 和 `this.props.children` 访问 这些 '属性'。
-
-### 添加 Markdown
-
-Markdown 是一种简单的内联格式化你的文字的方法。例如，用星号包围文本将会使其强调突出。
-
-在本教程中我们使用第三方库 **marked**，它接受 Markdown 文本并且转换为原始的 HTML。我们已经在初始的页面标记里包含了这个库，所以我们可以直接开始使用它，让我们转换评论文本为 Markdown 并输出它：
-
-```javascript{9}
-// tutorial6.js
-var Comment = React.createClass({
-  render: function() {
-    return (
-      <div className="comment">
-        <h2 className="commentAuthor">
-          {this.props.author}
-        </h2>
-        {marked(this.props.children.toString())}
-      </div>
-    );
-  }
-});
-```
-
-我们在这里唯一做的就是调用 marked 库。我们需要把 从 React 的包裹文本来的 `this.props.children` 转换成 marked 能理解的原始字符串，所以我们显示地调用了`toString()`。
-
-但是这里有一个问题！我们渲染的评论在浏览器里看起来像这样： "`<p>`This is `<em>`another`</em>` comment`</p>`" 。我们想让这些标签真正地渲染为 HTML。
-
-那是 React 在保护你免受 [XSS 攻击](https://en.wikipedia.org/wiki/Cross-site_scripting)。有一个方法解决这个问题，但是框架会警告你别使用这种方法：
-
-```javascript{3-6,14}
-// tutorial7.js
-var Comment = React.createClass({
-  rawMarkup: function() {
-    var rawMarkup = marked(this.props.children.toString(), {sanitize: true});
-    return { __html: rawMarkup };
-  },
-
-  render: function() {
-    return (
-      <div className="comment">
-        <h2 className="commentAuthor">
-          {this.props.author}
-        </h2>
-        <span dangerouslySetInnerHTML={this.rawMarkup()} />
-      </div>
-    );
-  }
-});
-```
-
-这是一个特殊的 API，故意让插入原始的 HTML 变得困难，但是对于 marked 我们将利用这个后门。
-
-**记住：** 使用这个功能你会依赖于 marked 是安全的。既然如此，我们传递 `sanitize: true` 告诉 marked escape 源码里任何的 HTML 标记，而不是直接不变的让他们通过。
-
-### 挂钩数据模型
-
-到目前为止我们已经完成了在源码里直接插入评论。作为替代，让我们渲染一团 JSON 数据到评论列表里。最终数据将会来自服务器，但是现在，写在你的源代码中：
-
-```javascript
-// tutorial8.js
-var data = [
-  {id: 1, author: "Pete Hunt", text: "This is one comment"},
-  {id: 2, author: "Jordan Walke", text: "This is *another* comment"}
-];
-```
-
-我们需要以一种模块化的方式将这个数据传入到 `CommentList`。修改 `CommentBox` 和 `ReactDOM.render()` 方法，以便于通过 props 传入数据到 `CommentList`：
-
-```javascript{7,15}
-// tutorial9.js
-var CommentBox = React.createClass({
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>Comments</h1>
-        <CommentList data={this.props.data} />
-        <CommentForm />
-      </div>
-    );
-  }
-});
-
-ReactDOM.render(
-  <CommentBox data={data} />,
-  document.getElementById('content')
-);
-```
-
-既然现在数据在 `CommentList` 中可用了，让我们动态地渲染评论：
-
-```javascript{4-10,13}
-// tutorial10.js
-var CommentList = React.createClass({
-  render: function() {
-    var commentNodes = this.props.data.map(function(comment) {
-      return (
-        <Comment author={comment.author} key={comment.id}>
-          {comment.text}
-        </Comment>
-      );
-    });
-    return (
-      <div className="commentList">
-        {commentNodes}
-      </div>
-    );
-  }
-});
-```
-
-就是这样！
-
-### 从服务器获取数据
-
-让我们用一些来自服务器的动态数据替换硬编码的数据。我们将移除数据的prop，用获取数据的URL来替换它：
-
-```javascript{3}
-// tutorial11.js
-ReactDOM.render(
-  <CommentBox url="/api/comments" />,
-  document.getElementById('content')
-);
-```
-
-这个组件不同于和前面的组件，因为它必须重新渲染自己。该组件将不会有任何数据，直到请求从服务器返回，此时该组件或许需要渲染一些新的评论。
-
-注意： 此代码在这个阶段不会工作。
-
-### Reactive state
-
-迄今为止,基于它自己的props，每个组件都渲染了自己一次。`props` 是不可变的：它们从父级传来并被父级“拥有”。为了实现交互，我们给组件引进了可变的 **state**。`this.state` 是组件私有的，可以通过调用 `this.setState()` 改变它。每当state更新，组件就重新渲染自己。
-
-`render()` 方法被声明为一个带有 `this.props` 和 `this.state` 的函数。框架保证了 UI 总是与输入一致。
-
-当服务器获取数据时，我们将会改变我们已有的评论数据。让我们给 `CommentBox` 组件添加一组评论数据作为它的状态：
-
-```javascript{3-5,10}
-// tutorial12.js
-var CommentBox = React.createClass({
-  getInitialState: function() {
-    return {data: []};
-  },
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>Comments</h1>
-        <CommentList data={this.state.data} />
-        <CommentForm />
-      </div>
-    );
-  }
-});
-```
-
-`getInitialState()` 在生命周期里只执行一次，并设置组件的初始状态。
-
-#### 更新状态
-当组件第一次创建时，我们想从服务器获取一些 JSON 并且更新状态以反映最新的数据。我们将用 jQuery 来发送一个异步请求到我们刚才启动的服务器以获取我们需要的数据。这些数据已经被包含在了你已启动的服务器里（基于`comments.json`文件），所以一旦被获取，`this.state.data` 会看起来像这样：
-
-```json
-[
-  {"author": "Pete Hunt", "text": "This is one comment"},
-  {"author": "Jordan Walke", "text": "This is *another* comment"}
-]
-```
-
-```javascript{6-18}
-// tutorial13.js
-var CommentBox = React.createClass({
-  getInitialState: function() {
-    return {data: []};
-  },
-  componentDidMount: function() {
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      cache: false,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>Comments</h1>
-        <CommentList data={this.state.data} />
-        <CommentForm />
-      </div>
-    );
-  }
-});
-```
-
-这里， `componentDidMount` 是一个当组件被渲染时被Ｒeact自动调用的方法。动态更新的关键是对 `this.setState()` 的调用。我们用新的从服务器来的替换掉旧的评论组，然后UI自动更新自己。因为这种反应性，仅是一个微小的变化就添加了实时更新。我们这里将用简单的轮询，但是你可以容易的使用 WebSockets 或者其他技术。
-
-```javascript{3,15,20-21,35}
-// tutorial14.js
-var CommentBox = React.createClass({
-  loadCommentsFromServer: function() {
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      cache: false,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  getInitialState: function() {
-    return {data: []};
-  },
-  componentDidMount: function() {
-    this.loadCommentsFromServer();
-    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
-  },
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>Comments</h1>
-        <CommentList data={this.state.data} />
-        <CommentForm />
-      </div>
-    );
-  }
-});
-
-ReactDOM.render(
-  <CommentBox url="/api/comments" pollInterval={2000} />,
-  document.getElementById('content')
-);
-
-```
-
-我们在这里做的全部事情是把 AJAX 调用移动到独立的方法里，然后在组件第一次加载时及其后每2秒 调用它。试着在你的浏览器里运行它并且改变 `comments.json` 文件（在你的服务器的相同目录）；2秒内，变化将会显现！
-
-### 添加新评论
-
-现在是时候建立表单了，我们的 `CommentForm` 组件应该询问用户他们的名字和评论文本然后发送一个请求到服务器来保存评论.
-
-```javascript{5-9}
-// tutorial15.js
-var CommentForm = React.createClass({
-  render: function() {
-    return (
-      <form className="commentForm">
-        <input type="text" placeholder="Your name" />
-        <input type="text" placeholder="Say something..." />
-        <input type="submit" value="Post" />
-      </form>
-    );
-  }
-});
-```
-
-#### 受控组件
-
-对于传统的 DOM， `input` 元素被渲染并且浏览器管理它的状态（它的渲染值）。结果是，DOM的实际值会和组件不同。这是不理想的，因为视图的值会和组件的值不同。在React中，组件应该总是表示视图的值而不只是在初始化时。
-
-因此，我们将使用 `this.state` 来在用户输入时保存输入。我们定义一个初始 `state`，它带有 `author` 和 `text` 两个属性并将他们设置为空字符串。在我们的 `<input>` 元素里，我们设置 `value` prop 来反映组件的 `state` 并给他们附加 `onChange` 事件处理。这些带有设置了 `value` 的  `<input>` 元素被称为受控组件。更多关于受控组件请阅读 [Forms article](/react/docs/forms.html#controlled-components)。
-
-```javascript{3-11,15-26}
-// tutorial16.js
-var CommentForm = React.createClass({
-  getInitialState: function() {
-    return {author: '', text: ''};
-  },
-  handleAuthorChange: function(e) {
-    this.setState({author: e.target.value});
-  },
-  handleTextChange: function(e) {
-    this.setState({text: e.target.value});
-  },
-  render: function() {
-    return (
-      <form className="commentForm">
-        <input
-          type="text"
-          placeholder="Your name"
-          value={this.state.author}
-          onChange={this.handleAuthorChange}
-        />
-        <input
-          type="text"
-          placeholder="Say something..."
-          value={this.state.text}
-          onChange={this.handleTextChange}
-        />
-        <input type="submit" value="Post" />
-      </form>
-    );
-  }
-});
-```
-
-##### 事件
-
-React使用小驼峰命名规范(camelCase)给组件绑定事件处理器。我们附加 `onChange` 给两个 `<input>` 元素。现在，当用户输入文本到 `<input>` 中，被附加的 `onChange` 回调函数被激发并且组件的 `state` 被修改。然后，被渲染的 `input` 元素的值将会更新以反映当前组件的 `state`。
-
-#### 提交表单
-
-让我们使表单具有交互性。当用户提交表单时，我们应该清除它，提交一个请求到服务器，并刷新评论列表。让我们监听表单的提交事件并清除它。
-
-```javascript{12-21,24}
-// tutorial17.js
-var CommentForm = React.createClass({
-  getInitialState: function() {
-    return {author: '', text: ''};
-  },
-  handleAuthorChange: function(e) {
-    this.setState({author: e.target.value});
-  },
-  handleTextChange: function(e) {
-    this.setState({text: e.target.value});
-  },
-  handleSubmit: function(e) {
-    e.preventDefault();
-    var author = this.state.author.trim();
-    var text = this.state.text.trim();
-    if (!text || !author) {
-      return;
-    }
-    // TODO: send request to the server
-    this.setState({author: '', text: ''});
-  },
-  render: function() {
-    return (
-      <form className="commentForm" onSubmit={this.handleSubmit}>
-        <input
-          type="text"
-          placeholder="Your name"
-          value={this.state.author}
-          onChange={this.handleAuthorChange}
-        />
-        <input
-          type="text"
-          placeholder="Say something..."
-          value={this.state.text}
-          onChange={this.handleTextChange}
-        />
-        <input type="submit" value="Post" />
-      </form>
-    );
-  }
-});
-```
-
-我们给表单绑定一个`onSubmit`处理器，它在表单提交了合法的输入后清空表单字段。
-
-在事件中调用`preventDefault()`来阻止浏览器提交表单的默认行为。
-
-##### 回调函数作为属性
-
-当用户提交评论时，我们需要刷新评论列表来包含这条新评论。在`CommentBox`中完成所有逻辑是有道理的，因为`CommentBox` 拥有代表了评论列表的状态(state)。
-
-我们需要从子组件传回数据到它的父组件。我们在父组件的`render`方法中以传递一个新的回调函数（`handleCommentSubmit`）到子组件完成这件事，绑定它到子组件的 `onCommentSubmit` 事件上。无论事件什么时候触发，回调函数都将被调用：
-
-```javascript{16-18,31}
-// tutorial18.js
-var CommentBox = React.createClass({
-  loadCommentsFromServer: function() {
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      cache: false,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  handleCommentSubmit: function(comment) {
-    // TODO: submit to the server and refresh the list
-  },
-  getInitialState: function() {
-    return {data: []};
-  },
-  componentDidMount: function() {
-    this.loadCommentsFromServer();
-    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
-  },
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>Comments</h1>
-        <CommentList data={this.state.data} />
-        <CommentForm onCommentSubmit={this.handleCommentSubmit} />
-      </div>
-    );
-  }
-});
-```
-
-既然 `CommentBox` 已经通过 `onCommentSubmit` prop 使回调函数对于 `CommentForm` 可用，`CommentForm` 就可以在用户提交表单时调用回调函数：
-
-```javascript{19}
-// tutorial19.js
-var CommentForm = React.createClass({
-  getInitialState: function() {
-    return {author: '', text: ''};
-  },
-  handleAuthorChange: function(e) {
-    this.setState({author: e.target.value});
-  },
-  handleTextChange: function(e) {
-    this.setState({text: e.target.value});
-  },
-  handleSubmit: function(e) {
-    e.preventDefault();
-    var author = this.state.author.trim();
-    var text = this.state.text.trim();
-    if (!text || !author) {
-      return;
-    }
-    this.props.onCommentSubmit({author: author, text: text});
-    this.setState({author: '', text: ''});
-  },
-  render: function() {
-    return (
-      <form className="commentForm" onSubmit={this.handleSubmit}>
-        <input
-          type="text"
-          placeholder="Your name"
-          value={this.state.author}
-          onChange={this.handleAuthorChange}
-        />
-        <input
-          type="text"
-          placeholder="Say something..."
-          value={this.state.text}
-          onChange={this.handleTextChange}
-        />
-        <input type="submit" value="Post" />
-      </form>
-    );
-  }
-});
-```
-
-既然现在回调函数已经就绪，我们所需要做的就是提交到服务器然后刷新列表：
-
-```javascript{17-28}
-// tutorial20.js
-var CommentBox = React.createClass({
-  loadCommentsFromServer: function() {
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      cache: false,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  handleCommentSubmit: function(comment) {
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      type: 'POST',
-      data: comment,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  getInitialState: function() {
-    return {data: []};
-  },
-  componentDidMount: function() {
-    this.loadCommentsFromServer();
-    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
-  },
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>Comments</h1>
-        <CommentList data={this.state.data} />
-        <CommentForm onCommentSubmit={this.handleCommentSubmit} />
-      </div>
-    );
-  }
-});
-```
-
-### 优化: 优化的更新
-
-我们的应用现在已经功能完备，但是它感觉很慢，因为在评论出现在列表前必须等待请求完成。我们可以优化添加这条评论到列表以使应用感觉更快。
-
-```javascript{17-23,33}
-// tutorial21.js
-var CommentBox = React.createClass({
-  loadCommentsFromServer: function() {
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      cache: false,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  handleCommentSubmit: function(comment) {
-    var comments = this.state.data;
-    // Optimistically set an id on the new comment. It will be replaced by an
-    // id generated by the server. In a production application you would likely
-    // not use Date.now() for this and would have a more robust system in place.
-    comment.id = Date.now();
-    var newComments = comments.concat([comment]);
-    this.setState({data: newComments});
-    $.ajax({
-      url: this.props.url,
-      dataType: 'json',
-      type: 'POST',
-      data: comment,
-      success: function(data) {
-        this.setState({data: data});
-      }.bind(this),
-      error: function(xhr, status, err) {
-        this.setState({data: comments});
-        console.error(this.props.url, status, err.toString());
-      }.bind(this)
-    });
-  },
-  getInitialState: function() {
-    return {data: []};
-  },
-  componentDidMount: function() {
-    this.loadCommentsFromServer();
-    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
-  },
-  render: function() {
-    return (
-      <div className="commentBox">
-        <h1>Comments</h1>
-        <CommentList data={this.state.data} />
-        <CommentForm onCommentSubmit={this.handleCommentSubmit} />
-      </div>
-    );
-  }
-});
-```
-
-### 祝贺!
-
-你刚刚通过几个简单的步骤建立了一个评论框。学习更多关于[为什么使用 React](/react/docs/why-react-zh-CN.html), 或者深入 [API 参考](/react/docs/top-level-api.html) 开始钻研！祝你好运！
diff --git a/docs/docs/typechecking-with-proptypes.md b/docs/docs/typechecking-with-proptypes.md
new file mode 100644
index 000000000000..85c128d3a909
--- /dev/null
+++ b/docs/docs/typechecking-with-proptypes.md
@@ -0,0 +1,168 @@
+---
+id: typechecking-with-proptypes
+title: Typechecking With PropTypes
+permalink: docs/typechecking-with-proptypes.html
+redirect_from:
+  - "docs/react-api.html#typechecking-with-proptypes"
+---
+
+> Note:
+> `React.PropTypes` is deprecated as of React v15.5. Please use [the `prop-types` library instead](https://www.npmjs.com/package/prop-types).
+
+As your app grows, you can catch a lot of bugs with typechecking. For some applications, you can use JavaScript extensions like [Flow](https://flowtype.org/) or [TypeScript](https://www.typescriptlang.org/) to typecheck your whole application. But even if you don't use those, React has some built-in typechecking abilities. To run typechecking on the props for a component, you can assign the special `propTypes` property:
+
+```javascript
+import PropTypes from 'prop-types';
+
+class Greeting extends React.Component {
+  render() {
+    return (
+      <h1>Hello, {this.props.name}</h1>
+    );
+  }
+}
+
+Greeting.propTypes = {
+  name: PropTypes.string
+};
+```
+
+`PropTypes` exports a range of validators that can be used to make sure the data you receive is valid. In this example, we're using `PropTypes.string`. When an invalid value is provided for a prop, a warning will be shown in the JavaScript console. For performance reasons, `propTypes` is only checked in development mode.
+
+### PropTypes
+
+Here is an example documenting the different validators provided:
+
+```javascript
+import PropTypes from 'prop-types';
+
+MyComponent.propTypes = {
+  // You can declare that a prop is a specific JS primitive. By default, these
+  // are all optional.
+  optionalArray: PropTypes.array,
+  optionalBool: PropTypes.bool,
+  optionalFunc: PropTypes.func,
+  optionalNumber: PropTypes.number,
+  optionalObject: PropTypes.object,
+  optionalString: PropTypes.string,
+  optionalSymbol: PropTypes.symbol,
+
+  // Anything that can be rendered: numbers, strings, elements or an array
+  // (or fragment) containing these types.
+  optionalNode: PropTypes.node,
+
+  // A React element.
+  optionalElement: PropTypes.element,
+
+  // You can also declare that a prop is an instance of a class. This uses
+  // JS's instanceof operator.
+  optionalMessage: PropTypes.instanceOf(Message),
+
+  // You can ensure that your prop is limited to specific values by treating
+  // it as an enum.
+  optionalEnum: PropTypes.oneOf(['News', 'Photos']),
+
+  // An object that could be one of many types
+  optionalUnion: PropTypes.oneOfType([
+    PropTypes.string,
+    PropTypes.number,
+    PropTypes.instanceOf(Message)
+  ]),
+
+  // An array of a certain type
+  optionalArrayOf: PropTypes.arrayOf(PropTypes.number),
+
+  // An object with property values of a certain type
+  optionalObjectOf: PropTypes.objectOf(PropTypes.number),
+
+  // An object taking on a particular shape
+  optionalObjectWithShape: PropTypes.shape({
+    color: PropTypes.string,
+    fontSize: PropTypes.number
+  }),
+
+  // You can chain any of the above with `isRequired` to make sure a warning
+  // is shown if the prop isn't provided.
+  requiredFunc: PropTypes.func.isRequired,
+
+  // A value of any data type
+  requiredAny: PropTypes.any.isRequired,
+
+  // You can also specify a custom validator. It should return an Error
+  // object if the validation fails. Don't `console.warn` or throw, as this
+  // won't work inside `oneOfType`.
+  customProp: function(props, propName, componentName) {
+    if (!/matchme/.test(props[propName])) {
+      return new Error(
+        'Invalid prop `' + propName + '` supplied to' +
+        ' `' + componentName + '`. Validation failed.'
+      );
+    }
+  },
+
+  // You can also supply a custom validator to `arrayOf` and `objectOf`.
+  // It should return an Error object if the validation fails. The validator
+  // will be called for each key in the array or object. The first two
+  // arguments of the validator are the array or object itself, and the
+  // current item's key.
+  customArrayProp: PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) {
+    if (!/matchme/.test(propValue[key])) {
+      return new Error(
+        'Invalid prop `' + propFullName + '` supplied to' +
+        ' `' + componentName + '`. Validation failed.'
+      );
+    }
+  })
+};
+```
+
+### Requiring Single Child
+
+With `PropTypes.element` you can specify that only a single child can be passed to a component as children.
+
+```javascript
+import PropTypes from 'prop-types';
+
+class MyComponent extends React.Component {
+  render() {
+    // This must be exactly one element or it will warn.
+    const children = this.props.children;
+    return (
+      <div>
+        {children}
+      </div>
+    );
+  }
+}
+
+MyComponent.propTypes = {
+  children: PropTypes.element.isRequired
+};
+```
+
+### Default Prop Values
+
+You can define default values for your `props` by assigning to the special `defaultProps` property:
+
+```javascript
+class Greeting extends React.Component {
+  render() {
+    return (
+      <h1>Hello, {this.props.name}</h1>
+    );
+  }
+}
+
+// Specifies the default values for props:
+Greeting.defaultProps = {
+  name: 'Stranger'
+};
+
+// Renders "Hello, Stranger":
+ReactDOM.render(
+  <Greeting />,
+  document.getElementById('example')
+);
+```
+
+The `defaultProps` will be used to ensure that `this.props.name` will have a value if it was not specified by the parent component. The `propTypes` typechecking happens after `defaultProps` are resolved, so typechecking will also apply to the `defaultProps`.
diff --git a/docs/docs/uncontrolled-components.md b/docs/docs/uncontrolled-components.md
new file mode 100644
index 000000000000..d9fa20ac80a5
--- /dev/null
+++ b/docs/docs/uncontrolled-components.md
@@ -0,0 +1,66 @@
+---
+id: uncontrolled-components
+title: Uncontrolled Components
+permalink: docs/uncontrolled-components.html
+---
+
+In most cases, we recommend using [controlled components](/react/docs/forms.html) to implement forms. In a controlled component, form data is handled by a React component. The alternative is uncontrolled components, where form data is handled by the DOM itself.
+
+To write an uncontrolled component, instead of writing an event handler for every state update, you can [use a ref](/react/docs/refs-and-the-dom.html) to get form values from the DOM.
+
+For example, this code accepts a single name in an uncontrolled component:
+
+```javascript{8,17}
+class NameForm extends React.Component {
+  constructor(props) {
+    super(props);
+    this.handleSubmit = this.handleSubmit.bind(this);
+  }
+
+  handleSubmit(event) {
+    alert('A name was submitted: ' + this.input.value);
+    event.preventDefault();
+  }
+
+  render() {
+    return (
+      <form onSubmit={this.handleSubmit}>
+        <label>
+          Name:
+          <input type="text" ref={(input) => this.input = input} />
+        </label>
+        <input type="submit" value="Submit" />
+      </form>
+    );
+  }
+}
+```
+
+[Try it on CodePen.](https://codepen.io/gaearon/pen/WooRWa?editors=0010)
+
+Since an uncontrolled component keeps the source of truth in the DOM, it is sometimes easier to integrate React and non-React code when using uncontrolled components. It can also be slightly less code if you want to be quick and dirty. Otherwise, you should usually use controlled components.
+
+If it's still not clear which type of component you should use for a particular situation, you might find [this article on controlled versus uncontrolled inputs](http://goshakkk.name/controlled-vs-uncontrolled-inputs-react/) to be helpful.
+
+### Default Values
+
+In the React rendering lifecycle, the `value` attribute on form elements will override the value in the DOM. With an uncontrolled component, you often want React to specify the initial value, but leave subsequent updates uncontrolled. To handle this case, you can specify a `defaultValue` attribute instead of `value`.
+
+```javascript{7}
+render() {
+  return (
+    <form onSubmit={this.handleSubmit}>
+      <label>
+        Name:
+        <input
+          defaultValue="Bob"
+          type="text"
+          ref={(input) => this.input = input} />
+      </label>
+      <input type="submit" value="Submit" />
+    </form>
+  );
+}
+```
+
+Likewise, `<input type="checkbox">` and `<input type="radio">` support `defaultChecked`, and `<select>` and `<textarea>` supports `defaultValue`.
diff --git a/docs/docs/videos.md b/docs/docs/videos.md
deleted file mode 100644
index 89f69b54f253..000000000000
--- a/docs/docs/videos.md
+++ /dev/null
@@ -1,173 +0,0 @@
----
-id: videos
-title: Videos
-permalink: videos.html
-prev: conferences.html
-next: complementary-tools.html
----
-
-### Rethinking best practices - JSConf.eu
-
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/x7cQ3mrcKaY" frameborder="0" allowfullscreen></iframe>
-
-"At Facebook and Instagram, we’re trying to push the limits of what’s possible on the web with React. My talk will start with a brief introduction to the framework, and then dive into three controversial topics: Throwing out the notion of templates and building views with JavaScript, “re-rendering” your entire application when your data changes, and a lightweight implementation of the DOM and events." -- [Pete Hunt](http://www.petehunt.net/)
-
-* * *
-
-### Thinking in react - tagtree.tv
-
-A [tagtree.tv](http://tagtree.tv/) video conveying the principles of [Thinking in React](/react/docs/thinking-in-react.html) while building a simple app
-<figure>[![](/react/img/docs/thinking-in-react-tagtree.png)](http://tagtree.tv/thinking-in-react)</figure>
-
-* * *
-
-### Secrets of the Virtual DOM - MtnWest JS
-
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/h3KksH8gfcQ" frameborder="0" allowfullscreen></iframe>
-
-"In this talk I’ll be discussing why we built a virtual DOM, how it compares to other systems, and its relevance to the future of browser technologies." -- [Pete Hunt](http://www.petehunt.net/)
-
-* * *
-
-### Going big with React
-
-"On paper, all those JS frameworks look promising: clean implementations, quick code design, flawless execution. But what happens when you stress test Javascript? What happens when you throw 6 megabytes of code at it? In this talk, we'll investigate how React performs in a high stress situation, and how it has helped our team build safe code on a massive scale."
-<figure>[![](https://i.vimeocdn.com/video/481670116_650.jpg)](https://skillsmatter.com/skillscasts/5429-going-big-with-react#video)</figure>
-
-* * *
-
-### CodeWinds
-
-[Pete Hunt](http://www.petehunt.net/) talked with [Jeff Barczewski](http://jeff.barczewski.com/) about React in CodeWinds Episode 4.
-<figure>[![](/react/img/docs/codewinds-004.png)](http://codewinds.com/4)</figure>
-
-<table width="100%"><tr><td>
-02:08 - What is React and why use it?<br />
-03:08 - The symbiotic relationship of ClojureScript and React<br />
-04:54 - The history of React and why it was created<br />
-09:43 - Updating web page with React without using data binding<br />
-13:11 - Using the virtual DOM to change the browser DOM<br />
-13:57 - Programming with React, render targets HTML, canvas, other<br />
-16:45 - Working with designers. Contrasted with Ember and AngularJS<br />
-21:45 - JSX Compiler bridging HTML and React javascript<br />
-23:50 - Autobuilding JSX and in browser tools for React<br />
-24:50 - Tips and tricks to working with React, getting started<br />
-</td><td>
-27:17 - Rendering HTML on the server with Node.js. Rendering backends<br />
-29:20 - React evolved through survival of the fittest at Facebook<br />
-30:15 - Ideas for having state on server and client, using web sockets.<br />
-32:05 - React-multiuser - distributed shared mutable state using Firebase<br />
-33:03 - Better debugging with React using the state transitions, replaying events<br />
-34:08 - Differences from Web Components<br />
-34:25 - Notable companies using React<br />
-35:16 - Could a React backend plugin be created to target PDF?<br />
-36:30 - Future of React, what's next?<br />
-39:38 - Contributing and getting help<br />
-</td></tr></table>
-
-[Read the episode notes](http://codewinds.com/4)
-
-* * *
-
-### JavaScript Jabber
-
-[Pete Hunt](http://www.petehunt.net/) and [Jordan Walke](https://github.com/jordwalke) talked about React in JavaScript Jabber 73.
-<figure>[![](/react/img/docs/javascript-jabber.png)](http://javascriptjabber.com/073-jsj-react-with-pete-hunt-and-jordan-walke/#content)</figure>
-
-<table width="100%"><tr><td>
-01:34 – Pete Hunt Introduction<br />
-02:45 – Jordan Walke Introduction<br />
-04:15 – React<br />
-06:38 – 60 Frames Per Second<br />
-09:34 – Data Binding<br />
-12:31 – Performance<br />
-17:39 – Diffing Algorithm<br />
-19:36 – DOM Manipulation
-</td><td>
-23:06 – Supporting node.js<br />
-24:03 – rendr<br />
-26:02 – JSX<br />
-30:31 – requestAnimationFrame<br />
-34:15 – React and Applications<br />
-38:12 – React Users Khan Academy<br />
-39:53 – Making it work
-</td></tr></table>
-
-[Read the full transcript](http://javascriptjabber.com/073-jsj-react-with-pete-hunt-and-jordan-walke/)
-
-* * *
-
-### Introduction to React.js - Facebook Seattle
-
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/XxVg_s8xAms" frameborder="0" allowfullscreen></iframe>
-
-By [Tom Occhino](http://tomocchino.com/) and [Jordan Walke](https://github.com/jordwalke)
-
-* * *
-
-### Backbone + React + Middleman Screencast
-<iframe width="650" height="488" src="https://www.youtube-nocookie.com/embed/iul1fWHVU6A" frameborder="0" allowfullscreen></iframe>
-
-Backbone is a great way in interface a REST API with React. This screencast shows how to integrate the two using [Backbone-React-Component](https://github.com/magalhas/backbone-react-component). Middleman is the framework used in this example but could easily be replaced with other frameworks. A supported template of this can be found [here](https://github.com/jbhatab/middleman-backbone-react-template). -- [Open Minded Innovations](http://www.openmindedinnovations.com/)
-
-* * *
-
-### Developing User Interfaces With React - Super VanJS
-
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/1OeXsL5mr4g" frameborder="0" allowfullscreen></iframe>
-
-By [Steven Luscher](https://github.com/steveluscher)
-
-* * *
-
-### Introduction to React - LAWebSpeed meetup
-
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/SMMRJif5QW0" frameborder="0" allowfullscreen></iframe>
-
-by [Stoyan Stefanov](http://www.phpied.com/)
-
-* * *
-
-### React, or how to make life simpler - FrontEnd Dev Conf '14
-
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/YJNUK0EA_Jo" frameborder="0" allowfullscreen></iframe>
-
-**In Russian** by [Alexander Solovyov](http://solovyov.net/)
-
-* * *
-
-### "Functional DOM programming" - Meteor DevShop 11
-
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/qqVbr_LaCIo" frameborder="0" allowfullscreen></iframe>
-
-* * *
-
-### "Rethinking Web App Development at Facebook" - Facebook F8 Conference 2014
-
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/nYkdrAPrdcw" frameborder="0" allowfullscreen></iframe>
-
-* * *
-
-### React and Flux: Building Applications with a Unidirectional Data Flow - Forward JS 2014
-
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/i__969noyAM" frameborder="0" allowfullscreen></iframe>
-
-Facebook engineers [Bill Fisher](https://twitter.com/fisherwebdev) and [Jing Chen](https://twitter.com/jingc) talk about Flux and React, and how using an application architecture with a unidirectional data flow cleans up a lot of their code.
-
-* * *
-
-### Server-Side Rendering of Isomorphic Apps at SoundCloud
-
-<iframe src="https://player.vimeo.com/video/108488724" width="650" height="365" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
-
-Walk-through by [Andres Suarez](https://github.com/zertosh) on how [SoundCloud](https://developers.soundcloud.com/blog/) is using React and Flux for server-side rendering.
-
-[Slides and sample code](https://github.com/zertosh/ssr-demo-kit)
-
-* * *
-
-### Introducing React Native (+Playlist) - React.js Conf 2015
-
-<iframe width="650" height="366" src="https://www.youtube-nocookie.com/embed/KVZ-P-ZI6W4?list=PLb0IAmt7-GS1cbw4qonlQztYV1TAW0sCr" frameborder="0" allowfullscreen></iframe>
-
-[Tom Occhino](https://twitter.com/tomocchino) reviews the past and present of React in 2015, and teases where it's going next.
diff --git a/docs/docs/web-components.md b/docs/docs/web-components.md
new file mode 100644
index 000000000000..1012ea795b69
--- /dev/null
+++ b/docs/docs/web-components.md
@@ -0,0 +1,58 @@
+---
+id: web-components
+title: Web Components
+permalink: docs/web-components.html
+redirect_from: "docs/webcomponents.html"
+---
+
+React and [Web Components](https://developer.mozilla.org/en-US/docs/Web/Web_Components) are built to solve different problems.  Web Components provide strong encapsulation for reusable components, while React provides a declarative library that keeps the DOM in sync with your data. The two goals are complementary. As a developer, you are free to use React in your Web Components, or to use Web Components in React, or both.
+
+Most people who use React don't use Web Components, but you may want to, especially if you are using third-party UI components that are written using Web Components.
+
+## Using Web Components in React
+
+```javascript
+class HelloMessage extends React.Component {
+  render() {
+    return <div>Hello <x-search>{this.props.name}</x-search>!</div>;
+  }
+}
+```
+
+> Note:
+>
+> Web Components often expose an imperative API. For instance, a `video` Web Component might expose `play()` and `pause()` functions. To access the imperative APIs of a Web Component, you will need to use a ref to interact with the DOM node directly. If you are using third-party Web Components, the best solution is to write a React component that behaves as a wrapper for your Web Component.
+>
+> Events emitted by a Web Component may not properly propagate through a React render tree.
+> You will need to manually attach event handlers to handle these events within your React components.
+
+One common confusion is that Web Components use "class" instead of "className".
+
+```javascript
+function BrickFlipbox() {
+  return (
+    <brick-flipbox class="demo">
+      <div>front</div>
+      <div>back</div>
+    </brick-flipbox>
+  );
+}
+```
+
+## Using React in your Web Components
+
+```javascript
+const proto = Object.create(HTMLElement.prototype, {
+  attachedCallback: {
+    value: function() {
+      const mountPoint = document.createElement('span');
+      this.createShadowRoot().appendChild(mountPoint);
+
+      const name = this.getAttribute('name');
+      const url = 'https://www.google.com/search?q=' + encodeURIComponent(name);
+      ReactDOM.render(<a href={url}>{name}</a>, mountPoint);
+    }
+  }
+});
+document.registerElement('x-search', {prototype: proto});
+```
diff --git a/docs/downloads.md b/docs/downloads.md
deleted file mode 100644
index 7a89c59d289e..000000000000
--- a/docs/downloads.md
+++ /dev/null
@@ -1,75 +0,0 @@
----
-id: downloads
-title: Downloads
-layout: single
----
-Download the starter kit to get everything you need to
-[get started with React](/react/docs/getting-started.html). The starter kit includes React and some simple example apps.
-
-<div class="buttons-unit downloads">
-  <a href="/react/downloads/react-{{site.react_version}}.zip" class="button">
-    Download Starter Kit {{site.react_version}}
-  </a>
-</div>
-
-## Development vs. Production Builds
-
-We provide two versions of React: an uncompressed version for development and a minified version for production. The development version includes extra warnings about common mistakes, whereas the production version includes extra performance optimizations and strips all error messages.
-
-If you're just starting out, make sure to use the development version.
-
-## Individual Downloads
-
-#### React {{site.react_version}} (development)
-The uncompressed, development version of [react.js](https://fb.me/react-{{site.react_version}}.js) and [react-dom.js](https://fb.me/react-dom-{{site.react_version}}.js) with inline documentation (you need both files).
-
-```html
-<script src="https://fb.me/react-{{site.react_version}}.js"></script>
-<script src="https://fb.me/react-dom-{{site.react_version}}.js"></script>
-```
-
-#### React {{site.react_version}} (production)
-The compressed, production version of [react.js](https://fb.me/react-{{site.react_version}}.min.js) and [react-dom.js](https://fb.me/react-dom-{{site.react_version}}.min.js) (you need both).
-
-```html
-<script src="https://fb.me/react-{{site.react_version}}.min.js"></script>
-<script src="https://fb.me/react-dom-{{site.react_version}}.min.js"></script>
-```
-
-#### React with Add-Ons {{site.react_version}} (development)
-The uncompressed, development version of React with [optional add-ons](/react/docs/addons.html).
-
-```html
-<script src="https://fb.me/react-with-addons-{{site.react_version}}.js"></script>
-<script src="https://fb.me/react-dom-{{site.react_version}}.js"></script>
-```
-
-#### React with Add-Ons {{site.react_version}} (production)
-The compressed, production version of React with [optional add-ons](/react/docs/addons.html).
-
-```html
-<script src="https://fb.me/react-with-addons-{{site.react_version}}.min.js"></script>
-<script src="https://fb.me/react-dom-{{site.react_version}}.min.js"></script>
-```
-
-All scripts are also available via [CDNJS](https://cdnjs.com/libraries/react/).
-
-## npm
-
-We recommend using React from npm with a bundler like [browserify](http://browserify.org/) or [webpack](https://webpack.github.io/). You can use the `react` and `react-dom` packages. After installing it using `npm install --save react react-dom`, you can use:
-
-```js
-var React = require('react');
-var ReactDOM = require('react-dom');
-ReactDOM.render(<App />, ...);
-```
-
-Each of the [add-ons](/react/docs/addons.html) lives in its own package.
-
-**Note:** by default, React will be in development mode. To use React in production mode, set the environment variable `NODE_ENV` to `production` (using envify or webpack's DefinePlugin). A minifier that performs dead-code elimination such as [UglifyJS](https://github.com/mishoo/UglifyJS2) is recommended to completely remove the extra code present in development mode.
-
-## Bower
-
-```sh
-$ bower install --save react
-```
diff --git a/docs/downloads/react-0.14.8.zip b/docs/downloads/react-0.14.8.zip
new file mode 100644
index 000000000000..2e8e57d187fb
Binary files /dev/null and b/docs/downloads/react-0.14.8.zip differ
diff --git a/docs/downloads/react-15.0.0.zip b/docs/downloads/react-15.0.0.zip
new file mode 100644
index 000000000000..05503065e3c8
Binary files /dev/null and b/docs/downloads/react-15.0.0.zip differ
diff --git a/docs/downloads/react-15.0.1.zip b/docs/downloads/react-15.0.1.zip
new file mode 100644
index 000000000000..c1f2bda4e332
Binary files /dev/null and b/docs/downloads/react-15.0.1.zip differ
diff --git a/docs/downloads/react-15.0.2.zip b/docs/downloads/react-15.0.2.zip
new file mode 100644
index 000000000000..4b4ba5275c54
Binary files /dev/null and b/docs/downloads/react-15.0.2.zip differ
diff --git a/docs/downloads/react-15.1.0.zip b/docs/downloads/react-15.1.0.zip
new file mode 100644
index 000000000000..488253aaf0c9
Binary files /dev/null and b/docs/downloads/react-15.1.0.zip differ
diff --git a/docs/downloads/react-15.2.0.zip b/docs/downloads/react-15.2.0.zip
new file mode 100644
index 000000000000..dff9d71408c3
Binary files /dev/null and b/docs/downloads/react-15.2.0.zip differ
diff --git a/docs/downloads/react-15.2.1.zip b/docs/downloads/react-15.2.1.zip
new file mode 100644
index 000000000000..83ead5d39034
Binary files /dev/null and b/docs/downloads/react-15.2.1.zip differ
diff --git a/docs/downloads/react-15.3.0.zip b/docs/downloads/react-15.3.0.zip
new file mode 100644
index 000000000000..8947442c422c
Binary files /dev/null and b/docs/downloads/react-15.3.0.zip differ
diff --git a/docs/downloads/react-15.3.1.zip b/docs/downloads/react-15.3.1.zip
new file mode 100644
index 000000000000..54acad868256
Binary files /dev/null and b/docs/downloads/react-15.3.1.zip differ
diff --git a/docs/downloads/react-15.3.2.zip b/docs/downloads/react-15.3.2.zip
new file mode 100644
index 000000000000..bde0e3276aa1
Binary files /dev/null and b/docs/downloads/react-15.3.2.zip differ
diff --git a/docs/downloads/react-15.4.0.zip b/docs/downloads/react-15.4.0.zip
new file mode 100644
index 000000000000..0de62c083da6
Binary files /dev/null and b/docs/downloads/react-15.4.0.zip differ
diff --git a/docs/downloads/react-15.4.1.zip b/docs/downloads/react-15.4.1.zip
new file mode 100644
index 000000000000..c29baf37e112
Binary files /dev/null and b/docs/downloads/react-15.4.1.zip differ
diff --git a/docs/downloads/single-file-example.html b/docs/downloads/single-file-example.html
new file mode 100644
index 000000000000..11b83bf02fde
--- /dev/null
+++ b/docs/downloads/single-file-example.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="UTF-8" />
+    <title>Hello World</title>
+    <script src="https://unpkg.com/react@latest/dist/react.js"></script>
+    <script src="https://unpkg.com/react-dom@latest/dist/react-dom.js"></script>
+    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
+  </head>
+  <body>
+    <div id="root"></div>
+    <script type="text/babel">
+
+      ReactDOM.render(
+        <h1>Hello, world!</h1>,
+        document.getElementById('root')
+      );
+
+    </script>
+  </body>
+</html>
diff --git a/docs/feed.xml b/docs/feed.xml
index ddd764e32a2c..0d9c1e65c054 100644
--- a/docs/feed.xml
+++ b/docs/feed.xml
@@ -1,5 +1,4 @@
 ---
-layout: none
 ---
 <?xml version="1.0" encoding="UTF-8"?>
 <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
diff --git a/docs/html-jsx.html b/docs/html-jsx.html
new file mode 100644
index 000000000000..cd977bb089bc
--- /dev/null
+++ b/docs/html-jsx.html
@@ -0,0 +1,5 @@
+---
+permalink: html-jsx.html
+layout: redirect
+dest_url: http://magic.reactjs.net/htmltojsx.htm
+---
diff --git a/docs/html-jsx.md b/docs/html-jsx.md
deleted file mode 100644
index 56e84c47bbec..000000000000
--- a/docs/html-jsx.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-layout: default
-title: HTML to JSX
-id: html-jsx
----
-<div class="jsxCompiler">
-  <h1>HTML to JSX Compiler</h1>
-  <div id="jsxCompiler"></div>
-  <script src="https://reactcommunity.org/react-magic/htmltojsx.min.js"></script>
-  <script src="js/html-jsx.js"></script>
-</div>
diff --git a/docs/img/blog/cra-better-output.png b/docs/img/blog/cra-better-output.png
new file mode 100644
index 000000000000..26ecbc5e931e
Binary files /dev/null and b/docs/img/blog/cra-better-output.png differ
diff --git a/docs/img/blog/cra-dynamic-import.gif b/docs/img/blog/cra-dynamic-import.gif
new file mode 100644
index 000000000000..88db2896fa46
Binary files /dev/null and b/docs/img/blog/cra-dynamic-import.gif differ
diff --git a/docs/img/blog/cra-jest-search.gif b/docs/img/blog/cra-jest-search.gif
new file mode 100644
index 000000000000..ed6819d896ab
Binary files /dev/null and b/docs/img/blog/cra-jest-search.gif differ
diff --git a/docs/img/blog/cra-pwa.png b/docs/img/blog/cra-pwa.png
new file mode 100644
index 000000000000..e1ae17cd0dd6
Binary files /dev/null and b/docs/img/blog/cra-pwa.png differ
diff --git a/docs/img/blog/cra-runtime-error.gif b/docs/img/blog/cra-runtime-error.gif
new file mode 100644
index 000000000000..7b4405f62e7c
Binary files /dev/null and b/docs/img/blog/cra-runtime-error.gif differ
diff --git a/docs/img/blog/cra-update-exports.gif b/docs/img/blog/cra-update-exports.gif
new file mode 100644
index 000000000000..2820d63dfb38
Binary files /dev/null and b/docs/img/blog/cra-update-exports.gif differ
diff --git a/docs/img/blog/create-apps-with-no-configuration/compiled-successfully.png b/docs/img/blog/create-apps-with-no-configuration/compiled-successfully.png
new file mode 100644
index 000000000000..ab3f011a447c
Binary files /dev/null and b/docs/img/blog/create-apps-with-no-configuration/compiled-successfully.png differ
diff --git a/docs/img/blog/create-apps-with-no-configuration/compiled-with-warnings.png b/docs/img/blog/create-apps-with-no-configuration/compiled-with-warnings.png
new file mode 100644
index 000000000000..fe7bd1ba8ed2
Binary files /dev/null and b/docs/img/blog/create-apps-with-no-configuration/compiled-with-warnings.png differ
diff --git a/docs/img/blog/create-apps-with-no-configuration/created-folder.png b/docs/img/blog/create-apps-with-no-configuration/created-folder.png
new file mode 100644
index 000000000000..b0d0e1c48317
Binary files /dev/null and b/docs/img/blog/create-apps-with-no-configuration/created-folder.png differ
diff --git a/docs/img/blog/create-apps-with-no-configuration/failed-to-compile.png b/docs/img/blog/create-apps-with-no-configuration/failed-to-compile.png
new file mode 100644
index 000000000000..8e21c8a9f75b
Binary files /dev/null and b/docs/img/blog/create-apps-with-no-configuration/failed-to-compile.png differ
diff --git a/docs/img/blog/create-apps-with-no-configuration/npm-run-build.png b/docs/img/blog/create-apps-with-no-configuration/npm-run-build.png
new file mode 100644
index 000000000000..e52b5d42b1ec
Binary files /dev/null and b/docs/img/blog/create-apps-with-no-configuration/npm-run-build.png differ
diff --git a/docs/img/blog/react-50k-mock-full.jpg b/docs/img/blog/react-50k-mock-full.jpg
new file mode 100644
index 000000000000..9aa8d3a50354
Binary files /dev/null and b/docs/img/blog/react-50k-mock-full.jpg differ
diff --git a/docs/img/blog/react-50k-mock.jpg b/docs/img/blog/react-50k-mock.jpg
new file mode 100644
index 000000000000..d26a6d8d63a7
Binary files /dev/null and b/docs/img/blog/react-50k-mock.jpg differ
diff --git a/docs/img/blog/react-50k-tshirt.jpg b/docs/img/blog/react-50k-tshirt.jpg
new file mode 100644
index 000000000000..1b402f46e85c
Binary files /dev/null and b/docs/img/blog/react-50k-tshirt.jpg differ
diff --git a/docs/img/blog/react-perf-chrome-timeline.png b/docs/img/blog/react-perf-chrome-timeline.png
new file mode 100644
index 000000000000..ab1e70513681
Binary files /dev/null and b/docs/img/blog/react-perf-chrome-timeline.png differ
diff --git a/docs/img/docs/devtools-dev.png b/docs/img/docs/devtools-dev.png
new file mode 100644
index 000000000000..626fef032c8f
Binary files /dev/null and b/docs/img/docs/devtools-dev.png differ
diff --git a/docs/img/docs/devtools-prod.png b/docs/img/docs/devtools-prod.png
new file mode 100644
index 000000000000..dea99a1b0ead
Binary files /dev/null and b/docs/img/docs/devtools-prod.png differ
diff --git a/docs/img/docs/granular-dom-updates.gif b/docs/img/docs/granular-dom-updates.gif
new file mode 100644
index 000000000000..1651b0daefcf
Binary files /dev/null and b/docs/img/docs/granular-dom-updates.gif differ
diff --git a/docs/img/docs/implementation-notes-tree.png b/docs/img/docs/implementation-notes-tree.png
new file mode 100644
index 000000000000..637dcb483792
Binary files /dev/null and b/docs/img/docs/implementation-notes-tree.png differ
diff --git a/docs/img/docs/react-devtools-state.gif b/docs/img/docs/react-devtools-state.gif
new file mode 100644
index 000000000000..c9ff6cd35236
Binary files /dev/null and b/docs/img/docs/react-devtools-state.gif differ
diff --git a/docs/img/logo_og.png b/docs/img/logo_og.png
index b7b6e151bac7..182beec51f33 100644
Binary files a/docs/img/logo_og.png and b/docs/img/logo_og.png differ
diff --git a/docs/img/logo_small.png b/docs/img/logo_small.png
index eea1f6744ae2..a6041b64f479 100644
Binary files a/docs/img/logo_small.png and b/docs/img/logo_small.png differ
diff --git a/docs/img/logo_small_2x.png b/docs/img/logo_small_2x.png
index 398e5df3f884..cfe63a394f8e 100644
Binary files a/docs/img/logo_small_2x.png and b/docs/img/logo_small_2x.png differ
diff --git a/docs/img/logo_small_gray.png b/docs/img/logo_small_gray.png
new file mode 100644
index 000000000000..f3cecb6092e8
Binary files /dev/null and b/docs/img/logo_small_gray.png differ
diff --git a/docs/img/logo_small_gray_2x.png b/docs/img/logo_small_gray_2x.png
new file mode 100644
index 000000000000..394d2199781c
Binary files /dev/null and b/docs/img/logo_small_gray_2x.png differ
diff --git a/docs/img/oss_logo.png b/docs/img/oss_logo.png
new file mode 100644
index 000000000000..8183e289b139
Binary files /dev/null and b/docs/img/oss_logo.png differ
diff --git a/docs/img/tutorial/devtools.png b/docs/img/tutorial/devtools.png
new file mode 100644
index 000000000000..c0482c093ac3
Binary files /dev/null and b/docs/img/tutorial/devtools.png differ
diff --git a/docs/img/tutorial/tictac-empty.png b/docs/img/tutorial/tictac-empty.png
new file mode 100644
index 000000000000..fabe3f03464b
Binary files /dev/null and b/docs/img/tutorial/tictac-empty.png differ
diff --git a/docs/img/tutorial/tictac-numbers.png b/docs/img/tutorial/tictac-numbers.png
new file mode 100644
index 000000000000..69d163f4532b
Binary files /dev/null and b/docs/img/tutorial/tictac-numbers.png differ
diff --git a/docs/index.md b/docs/index.md
index b0d7cb3426a6..bc737d447f83 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,5 +1,5 @@
 ---
-layout: page
+layout: hero
 title: A JavaScript library for building user interfaces
 id: home
 ---
@@ -7,25 +7,19 @@ id: home
 <section class="light home-section">
   <div class="marketing-row">
     <div class="marketing-col">
-      <h3>Just the UI</h3>
-      <p>
-        Lots of people use React as the V in MVC.
-        Since React makes no assumptions about the rest of your technology stack,
-        it&apos;s easy to try it out on a small feature in an existing project.
-      </p>
+      <h3>Declarative</h3>
+      <p>React makes it painless to create interactive UIs. Design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes.</p>
+      <p>Declarative views make your code more predictable and easier to debug.</p>
     </div>
     <div class="marketing-col">
-      <h3>Virtual DOM</h3>
-      <p>
-        React abstracts away the DOM from you, giving a simpler programming model and better performance. React can also render on the server using Node, and it can power native apps using <a href="https://facebook.github.io/react-native/">React Native</a>.
-      </p>
+      <h3>Component-Based</h3>
+      <p>Build encapsulated components that manage their own state, then compose them to make complex UIs.</p>
+      <p>Since component logic is written in JavaScript instead of templates, you can easily pass rich data through your app and keep state out of the DOM.</p>
     </div>
     <div class="marketing-col">
-      <h3>Data flow</h3>
-      <p>
-        React implements one-way reactive data flow which reduces boilerplate and is
-        easier to reason about than traditional data binding.
-      </p>
+      <h3>Learn Once, Write Anywhere</h3>
+      <p>We don't make assumptions about the rest of your technology stack, so you can develop new features in React without rewriting existing code.</p>
+      <p>React can also render on the server using Node and power mobile apps using <a href="https://facebook.github.io/react-native/">React Native</a>.</p>
     </div>
   </div>
 </section>
@@ -72,13 +66,13 @@ id: home
       <h3>A Component Using External Plugins</h3>
       <p>
         React is flexible and provides hooks that allow you to interface with
-        other libraries and frameworks. This example uses **marked**, an external
-        Markdown library, to convert the textarea's value in real-time.
+        other libraries and frameworks. This example uses **remarkable**, an
+        external Markdown library, to convert the textarea's value in real time.
       </p>
       <div id="markdownExample"></div>
     </div>
   </div>
-  <script src="/react/js/marked.min.js"></script>
+  <script src="https://unpkg.com/remarkable@1.7.1/dist/remarkable.min.js"></script>
   <script src="/react/js/examples/hello.js"></script>
   <script src="/react/js/examples/timer.js"></script>
   <script src="/react/js/examples/todo.js"></script>
@@ -87,7 +81,7 @@ id: home
 <hr class="home-divider" />
 <section class="home-bottom-section">
   <div class="buttons-unit">
-    <a href="docs/getting-started.html" class="button">Get Started</a>
-    <a href="downloads.html" class="button">Download React v{{site.react_version}}</a>
+    <a href="docs/hello-world.html" class="button">Get Started</a>
+    <a href="tutorial/tutorial.html" class="button">Take the Tutorial</a>
   </div>
 </section>
diff --git a/docs/js/codemirror.js b/docs/js/codemirror.js
deleted file mode 100644
index 086f84151ee2..000000000000
--- a/docs/js/codemirror.js
+++ /dev/null
@@ -1,6027 +0,0 @@
-// CodeMirror is the only global var we claim
-window.CodeMirror = (function() {
-  "use strict";
-
-  // BROWSER SNIFFING
-
-  // Crude, but necessary to handle a number of hard-to-feature-detect
-  // bugs and behavior differences.
-  var gecko = /gecko\/\d/i.test(navigator.userAgent);
-  // IE11 currently doesn't count as 'ie', since it has almost none of
-  // the same bugs as earlier versions. Use ie_gt10 to handle
-  // incompatibilities in that version.
-  var ie = /MSIE \d/.test(navigator.userAgent);
-  var ie_lt8 = ie && (document.documentMode == null || document.documentMode < 8);
-  var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9);
-  var ie_gt10 = /Trident\/([7-9]|\d{2,})\./.test(navigator.userAgent);
-  var webkit = /WebKit\//.test(navigator.userAgent);
-  var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent);
-  var chrome = /Chrome\//.test(navigator.userAgent);
-  var opera = /Opera\//.test(navigator.userAgent);
-  var safari = /Apple Computer/.test(navigator.vendor);
-  var khtml = /KHTML\//.test(navigator.userAgent);
-  var mac_geLion = /Mac OS X 1\d\D([7-9]|\d\d)\D/.test(navigator.userAgent);
-  var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent);
-  var phantom = /PhantomJS/.test(navigator.userAgent);
-
-  var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent);
-  // This is woefully incomplete. Suggestions for alternative methods welcome.
-  var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent);
-  var mac = ios || /Mac/.test(navigator.platform);
-  var windows = /win/i.test(navigator.platform);
-
-  var opera_version = opera && navigator.userAgent.match(/Version\/(\d*\.\d*)/);
-  if (opera_version) opera_version = Number(opera_version[1]);
-  if (opera_version && opera_version >= 15) { opera = false; webkit = true; }
-  // Some browsers use the wrong event properties to signal cmd/ctrl on OS X
-  var flipCtrlCmd = mac && (qtwebkit || opera && (opera_version == null || opera_version < 12.11));
-  var captureMiddleClick = gecko || (ie && !ie_lt9);
-
-  // Optimize some code when these features are not used
-  var sawReadOnlySpans = false, sawCollapsedSpans = false;
-
-  // CONSTRUCTOR
-
-  function CodeMirror(place, options) {
-    if (!(this instanceof CodeMirror)) return new CodeMirror(place, options);
-
-    this.options = options = options || {};
-    // Determine effective options based on given values and defaults.
-    for (var opt in defaults) if (!options.hasOwnProperty(opt) && defaults.hasOwnProperty(opt))
-      options[opt] = defaults[opt];
-    setGuttersForLineNumbers(options);
-
-    var docStart = typeof options.value == "string" ? 0 : options.value.first;
-    var display = this.display = makeDisplay(place, docStart);
-    display.wrapper.CodeMirror = this;
-    updateGutters(this);
-    if (options.autofocus && !mobile) focusInput(this);
-
-    this.state = {keyMaps: [],
-                  overlays: [],
-                  modeGen: 0,
-                  overwrite: false, focused: false,
-                  suppressEdits: false, pasteIncoming: false,
-                  draggingText: false,
-                  highlight: new Delayed()};
-
-    themeChanged(this);
-    if (options.lineWrapping)
-      this.display.wrapper.className += " CodeMirror-wrap";
-
-    var doc = options.value;
-    if (typeof doc == "string") doc = new Doc(options.value, options.mode);
-    operation(this, attachDoc)(this, doc);
-
-    // Override magic textarea content restore that IE sometimes does
-    // on our hidden textarea on reload
-    if (ie) setTimeout(bind(resetInput, this, true), 20);
-
-    registerEventHandlers(this);
-    // IE throws unspecified error in certain cases, when
-    // trying to access activeElement before onload
-    var hasFocus; try { hasFocus = (document.activeElement == display.input); } catch(e) { }
-    if (hasFocus || (options.autofocus && !mobile)) setTimeout(bind(onFocus, this), 20);
-    else onBlur(this);
-
-    operation(this, function() {
-      for (var opt in optionHandlers)
-        if (optionHandlers.propertyIsEnumerable(opt))
-          optionHandlers[opt](this, options[opt], Init);
-      for (var i = 0; i < initHooks.length; ++i) initHooks[i](this);
-    })();
-  }
-
-  // DISPLAY CONSTRUCTOR
-
-  function makeDisplay(place, docStart) {
-    var d = {};
-
-    var input = d.input = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em; outline: none; font-size: 4px;");
-    if (webkit) input.style.width = "1000px";
-    else input.setAttribute("wrap", "off");
-    // if border: 0; -- iOS fails to open keyboard (issue #1287)
-    if (ios) input.style.border = "1px solid black";
-    input.setAttribute("autocorrect", "off"); input.setAttribute("autocapitalize", "off"); input.setAttribute("spellcheck", "false");
-
-    // Wraps and hides input textarea
-    d.inputDiv = elt("div", [input], null, "overflow: hidden; position: relative; width: 3px; height: 0px;");
-    // The actual fake scrollbars.
-    d.scrollbarH = elt("div", [elt("div", null, null, "height: 1px")], "CodeMirror-hscrollbar");
-    d.scrollbarV = elt("div", [elt("div", null, null, "width: 1px")], "CodeMirror-vscrollbar");
-    d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler");
-    d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler");
-    // DIVs containing the selection and the actual code
-    d.lineDiv = elt("div", null, "CodeMirror-code");
-    d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1");
-    // Blinky cursor, and element used to ensure cursor fits at the end of a line
-    d.cursor = elt("div", "\u00a0", "CodeMirror-cursor");
-    // Secondary cursor, shown when on a 'jump' in bi-directional text
-    d.otherCursor = elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor");
-    // Used to measure text size
-    d.measure = elt("div", null, "CodeMirror-measure");
-    // Wraps everything that needs to exist inside the vertically-padded coordinate system
-    d.lineSpace = elt("div", [d.measure, d.selectionDiv, d.lineDiv, d.cursor, d.otherCursor],
-                         null, "position: relative; outline: none");
-    // Moved around its parent to cover visible view
-    d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative");
-    // Set to the height of the text, causes scrolling
-    d.sizer = elt("div", [d.mover], "CodeMirror-sizer");
-    // D is needed because behavior of elts with overflow: auto and padding is inconsistent across browsers
-    d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerCutOff + "px; width: 1px;");
-    // Will contain the gutters, if any
-    d.gutters = elt("div", null, "CodeMirror-gutters");
-    d.lineGutter = null;
-    // Provides scrolling
-    d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll");
-    d.scroller.setAttribute("tabIndex", "-1");
-    // The element in which the editor lives.
-    d.wrapper = elt("div", [d.inputDiv, d.scrollbarH, d.scrollbarV,
-                            d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror");
-    // Work around IE7 z-index bug
-    if (ie_lt8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }
-    if (place.appendChild) place.appendChild(d.wrapper); else place(d.wrapper);
-
-    // Needed to hide big blue blinking cursor on Mobile Safari
-    if (ios) input.style.width = "0px";
-    if (!webkit) d.scroller.draggable = true;
-    // Needed to handle Tab key in KHTML
-    if (khtml) { d.inputDiv.style.height = "1px"; d.inputDiv.style.position = "absolute"; }
-    // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
-    else if (ie_lt8) d.scrollbarH.style.minWidth = d.scrollbarV.style.minWidth = "18px";
-
-    // Current visible range (may be bigger than the view window).
-    d.viewOffset = d.lastSizeC = 0;
-    d.showingFrom = d.showingTo = docStart;
-
-    // Used to only resize the line number gutter when necessary (when
-    // the amount of lines crosses a boundary that makes its width change)
-    d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;
-    // See readInput and resetInput
-    d.prevInput = "";
-    // Set to true when a non-horizontal-scrolling widget is added. As
-    // an optimization, widget aligning is skipped when d is false.
-    d.alignWidgets = false;
-    // Flag that indicates whether we currently expect input to appear
-    // (after some event like 'keypress' or 'input') and are polling
-    // intensively.
-    d.pollingFast = false;
-    // Self-resetting timeout for the poller
-    d.poll = new Delayed();
-
-    d.cachedCharWidth = d.cachedTextHeight = null;
-    d.measureLineCache = [];
-    d.measureLineCachePos = 0;
-
-    // Tracks when resetInput has punted to just putting a short
-    // string instead of the (large) selection.
-    d.inaccurateSelection = false;
-
-    // Tracks the maximum line length so that the horizontal scrollbar
-    // can be kept static when scrolling.
-    d.maxLine = null;
-    d.maxLineLength = 0;
-    d.maxLineChanged = false;
-
-    // Used for measuring wheel scrolling granularity
-    d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null;
-
-    return d;
-  }
-
-  // STATE UPDATES
-
-  // Used to get the editor into a consistent state again when options change.
-
-  function loadMode(cm) {
-    cm.doc.mode = CodeMirror.getMode(cm.options, cm.doc.modeOption);
-    cm.doc.iter(function(line) {
-      if (line.stateAfter) line.stateAfter = null;
-      if (line.styles) line.styles = null;
-    });
-    cm.doc.frontier = cm.doc.first;
-    startWorker(cm, 100);
-    cm.state.modeGen++;
-    if (cm.curOp) regChange(cm);
-  }
-
-  function wrappingChanged(cm) {
-    if (cm.options.lineWrapping) {
-      cm.display.wrapper.className += " CodeMirror-wrap";
-      cm.display.sizer.style.minWidth = "";
-    } else {
-      cm.display.wrapper.className = cm.display.wrapper.className.replace(" CodeMirror-wrap", "");
-      computeMaxLength(cm);
-    }
-    estimateLineHeights(cm);
-    regChange(cm);
-    clearCaches(cm);
-    setTimeout(function(){updateScrollbars(cm);}, 100);
-  }
-
-  function estimateHeight(cm) {
-    var th = textHeight(cm.display), wrapping = cm.options.lineWrapping;
-    var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3);
-    return function(line) {
-      if (lineIsHidden(cm.doc, line))
-        return 0;
-      else if (wrapping)
-        return (Math.ceil(line.text.length / perLine) || 1) * th;
-      else
-        return th;
-    };
-  }
-
-  function estimateLineHeights(cm) {
-    var doc = cm.doc, est = estimateHeight(cm);
-    doc.iter(function(line) {
-      var estHeight = est(line);
-      if (estHeight != line.height) updateLineHeight(line, estHeight);
-    });
-  }
-
-  function keyMapChanged(cm) {
-    var map = keyMap[cm.options.keyMap], style = map.style;
-    cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-keymap-\S+/g, "") +
-      (style ? " cm-keymap-" + style : "");
-    if (cm.state.disableInput && !map.disableInput) resetInput(cm, true);
-    cm.state.disableInput = map.disableInput;
-  }
-
-  function themeChanged(cm) {
-    cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") +
-      cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-");
-    clearCaches(cm);
-  }
-
-  function guttersChanged(cm) {
-    updateGutters(cm);
-    regChange(cm);
-    setTimeout(function(){alignHorizontally(cm);}, 20);
-  }
-
-  function updateGutters(cm) {
-    var gutters = cm.display.gutters, specs = cm.options.gutters;
-    removeChildren(gutters);
-    for (var i = 0; i < specs.length; ++i) {
-      var gutterClass = specs[i];
-      var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass));
-      if (gutterClass == "CodeMirror-linenumbers") {
-        cm.display.lineGutter = gElt;
-        gElt.style.width = (cm.display.lineNumWidth || 1) + "px";
-      }
-    }
-    gutters.style.display = i ? "" : "none";
-  }
-
-  function lineLength(doc, line) {
-    if (line.height == 0) return 0;
-    var len = line.text.length, merged, cur = line;
-    while (merged = collapsedSpanAtStart(cur)) {
-      var found = merged.find();
-      cur = getLine(doc, found.from.line);
-      len += found.from.ch - found.to.ch;
-    }
-    cur = line;
-    while (merged = collapsedSpanAtEnd(cur)) {
-      var found = merged.find();
-      len -= cur.text.length - found.from.ch;
-      cur = getLine(doc, found.to.line);
-      len += cur.text.length - found.to.ch;
-    }
-    return len;
-  }
-
-  function computeMaxLength(cm) {
-    var d = cm.display, doc = cm.doc;
-    d.maxLine = getLine(doc, doc.first);
-    d.maxLineLength = lineLength(doc, d.maxLine);
-    d.maxLineChanged = true;
-    doc.iter(function(line) {
-      var len = lineLength(doc, line);
-      if (len > d.maxLineLength) {
-        d.maxLineLength = len;
-        d.maxLine = line;
-      }
-    });
-  }
-
-  // Make sure the gutters options contains the element
-  // "CodeMirror-linenumbers" when the lineNumbers option is true.
-  function setGuttersForLineNumbers(options) {
-    var found = indexOf(options.gutters, "CodeMirror-linenumbers");
-    if (found == -1 && options.lineNumbers) {
-      options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]);
-    } else if (found > -1 && !options.lineNumbers) {
-      options.gutters = options.gutters.slice(0);
-      options.gutters.splice(found, 1);
-    }
-  }
-
-  // SCROLLBARS
-
-  // Re-synchronize the fake scrollbars with the actual size of the
-  // content. Optionally force a scrollTop.
-  function updateScrollbars(cm) {
-    var d = cm.display, docHeight = cm.doc.height;
-    var totalHeight = docHeight + paddingVert(d);
-    d.sizer.style.minHeight = d.heightForcer.style.top = totalHeight + "px";
-    d.gutters.style.height = Math.max(totalHeight, d.scroller.clientHeight - scrollerCutOff) + "px";
-    var scrollHeight = Math.max(totalHeight, d.scroller.scrollHeight);
-    var needsH = d.scroller.scrollWidth > (d.scroller.clientWidth + 1);
-    var needsV = scrollHeight > (d.scroller.clientHeight + 1);
-    if (needsV) {
-      d.scrollbarV.style.display = "block";
-      d.scrollbarV.style.bottom = needsH ? scrollbarWidth(d.measure) + "px" : "0";
-      d.scrollbarV.firstChild.style.height =
-        (scrollHeight - d.scroller.clientHeight + d.scrollbarV.clientHeight) + "px";
-    } else {
-      d.scrollbarV.style.display = "";
-      d.scrollbarV.firstChild.style.height = "0";
-    }
-    if (needsH) {
-      d.scrollbarH.style.display = "block";
-      d.scrollbarH.style.right = needsV ? scrollbarWidth(d.measure) + "px" : "0";
-      d.scrollbarH.firstChild.style.width =
-        (d.scroller.scrollWidth - d.scroller.clientWidth + d.scrollbarH.clientWidth) + "px";
-    } else {
-      d.scrollbarH.style.display = "";
-      d.scrollbarH.firstChild.style.width = "0";
-    }
-    if (needsH && needsV) {
-      d.scrollbarFiller.style.display = "block";
-      d.scrollbarFiller.style.height = d.scrollbarFiller.style.width = scrollbarWidth(d.measure) + "px";
-    } else d.scrollbarFiller.style.display = "";
-    if (needsH && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
-      d.gutterFiller.style.display = "block";
-      d.gutterFiller.style.height = scrollbarWidth(d.measure) + "px";
-      d.gutterFiller.style.width = d.gutters.offsetWidth + "px";
-    } else d.gutterFiller.style.display = "";
-
-    if (mac_geLion && scrollbarWidth(d.measure) === 0) {
-      d.scrollbarV.style.minWidth = d.scrollbarH.style.minHeight = mac_geMountainLion ? "18px" : "12px";
-      d.scrollbarV.style.pointerEvents = d.scrollbarH.style.pointerEvents = "none";
-    }
-  }
-
-  function visibleLines(display, doc, viewPort) {
-    var top = display.scroller.scrollTop, height = display.wrapper.clientHeight;
-    if (typeof viewPort == "number") top = viewPort;
-    else if (viewPort) {top = viewPort.top; height = viewPort.bottom - viewPort.top;}
-    top = Math.floor(top - paddingTop(display));
-    var bottom = Math.ceil(top + height);
-    return {from: lineAtHeight(doc, top), to: lineAtHeight(doc, bottom)};
-  }
-
-  // LINE NUMBERS
-
-  function alignHorizontally(cm) {
-    var display = cm.display;
-    if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return;
-    var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft;
-    var gutterW = display.gutters.offsetWidth, l = comp + "px";
-    for (var n = display.lineDiv.firstChild; n; n = n.nextSibling) if (n.alignable) {
-      for (var i = 0, a = n.alignable; i < a.length; ++i) a[i].style.left = l;
-    }
-    if (cm.options.fixedGutter)
-      display.gutters.style.left = (comp + gutterW) + "px";
-  }
-
-  function maybeUpdateLineNumberWidth(cm) {
-    if (!cm.options.lineNumbers) return false;
-    var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display;
-    if (last.length != display.lineNumChars) {
-      var test = display.measure.appendChild(elt("div", [elt("div", last)],
-                                                 "CodeMirror-linenumber CodeMirror-gutter-elt"));
-      var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;
-      display.lineGutter.style.width = "";
-      display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding);
-      display.lineNumWidth = display.lineNumInnerWidth + padding;
-      display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;
-      display.lineGutter.style.width = display.lineNumWidth + "px";
-      return true;
-    }
-    return false;
-  }
-
-  function lineNumberFor(options, i) {
-    return String(options.lineNumberFormatter(i + options.firstLineNumber));
-  }
-  function compensateForHScroll(display) {
-    return getRect(display.scroller).left - getRect(display.sizer).left;
-  }
-
-  // DISPLAY DRAWING
-
-  function updateDisplay(cm, changes, viewPort, forced) {
-    var oldFrom = cm.display.showingFrom, oldTo = cm.display.showingTo, updated;
-    var visible = visibleLines(cm.display, cm.doc, viewPort);
-    for (var first = true;; first = false) {
-      var oldWidth = cm.display.scroller.clientWidth;
-      if (!updateDisplayInner(cm, changes, visible, forced)) break;
-      updated = true;
-      changes = [];
-      updateSelection(cm);
-      updateScrollbars(cm);
-      if (first && cm.options.lineWrapping && oldWidth != cm.display.scroller.clientWidth) {
-        forced = true;
-        continue;
-      }
-      forced = false;
-
-      // Clip forced viewport to actual scrollable area
-      if (viewPort)
-        viewPort = Math.min(cm.display.scroller.scrollHeight - cm.display.scroller.clientHeight,
-                            typeof viewPort == "number" ? viewPort : viewPort.top);
-      visible = visibleLines(cm.display, cm.doc, viewPort);
-      if (visible.from >= cm.display.showingFrom && visible.to <= cm.display.showingTo)
-        break;
-    }
-
-    if (updated) {
-      signalLater(cm, "update", cm);
-      if (cm.display.showingFrom != oldFrom || cm.display.showingTo != oldTo)
-        signalLater(cm, "viewportChange", cm, cm.display.showingFrom, cm.display.showingTo);
-    }
-    return updated;
-  }
-
-  // Uses a set of changes plus the current scroll position to
-  // determine which DOM updates have to be made, and makes the
-  // updates.
-  function updateDisplayInner(cm, changes, visible, forced) {
-    var display = cm.display, doc = cm.doc;
-    if (!display.wrapper.offsetWidth) {
-      display.showingFrom = display.showingTo = doc.first;
-      display.viewOffset = 0;
-      return;
-    }
-
-    // Bail out if the visible area is already rendered and nothing changed.
-    if (!forced && changes.length == 0 &&
-        visible.from > display.showingFrom && visible.to < display.showingTo)
-      return;
-
-    if (maybeUpdateLineNumberWidth(cm))
-      changes = [{from: doc.first, to: doc.first + doc.size}];
-    var gutterW = display.sizer.style.marginLeft = display.gutters.offsetWidth + "px";
-    display.scrollbarH.style.left = cm.options.fixedGutter ? gutterW : "0";
-
-    // Used to determine which lines need their line numbers updated
-    var positionsChangedFrom = Infinity;
-    if (cm.options.lineNumbers)
-      for (var i = 0; i < changes.length; ++i)
-        if (changes[i].diff && changes[i].from < positionsChangedFrom) { positionsChangedFrom = changes[i].from; }
-
-    var end = doc.first + doc.size;
-    var from = Math.max(visible.from - cm.options.viewportMargin, doc.first);
-    var to = Math.min(end, visible.to + cm.options.viewportMargin);
-    if (display.showingFrom < from && from - display.showingFrom < 20) from = Math.max(doc.first, display.showingFrom);
-    if (display.showingTo > to && display.showingTo - to < 20) to = Math.min(end, display.showingTo);
-    if (sawCollapsedSpans) {
-      from = lineNo(visualLine(doc, getLine(doc, from)));
-      while (to < end && lineIsHidden(doc, getLine(doc, to))) ++to;
-    }
-
-    // Create a range of theoretically intact lines, and punch holes
-    // in that using the change info.
-    var intact = [{from: Math.max(display.showingFrom, doc.first),
-                   to: Math.min(display.showingTo, end)}];
-    if (intact[0].from >= intact[0].to) intact = [];
-    else intact = computeIntact(intact, changes);
-    // When merged lines are present, we might have to reduce the
-    // intact ranges because changes in continued fragments of the
-    // intact lines do require the lines to be redrawn.
-    if (sawCollapsedSpans)
-      for (var i = 0; i < intact.length; ++i) {
-        var range = intact[i], merged;
-        while (merged = collapsedSpanAtEnd(getLine(doc, range.to - 1))) {
-          var newTo = merged.find().from.line;
-          if (newTo > range.from) range.to = newTo;
-          else { intact.splice(i--, 1); break; }
-        }
-      }
-
-    // Clip off the parts that won't be visible
-    var intactLines = 0;
-    for (var i = 0; i < intact.length; ++i) {
-      var range = intact[i];
-      if (range.from < from) range.from = from;
-      if (range.to > to) range.to = to;
-      if (range.from >= range.to) intact.splice(i--, 1);
-      else intactLines += range.to - range.from;
-    }
-    if (!forced && intactLines == to - from && from == display.showingFrom && to == display.showingTo) {
-      updateViewOffset(cm);
-      return;
-    }
-    intact.sort(function(a, b) {return a.from - b.from;});
-
-    // Avoid crashing on IE's "unspecified error" when in iframes
-    try {
-      var focused = document.activeElement;
-    } catch(e) {}
-    if (intactLines < (to - from) * .7) display.lineDiv.style.display = "none";
-    patchDisplay(cm, from, to, intact, positionsChangedFrom);
-    display.lineDiv.style.display = "";
-    if (focused && document.activeElement != focused && focused.offsetHeight) focused.focus();
-
-    var different = from != display.showingFrom || to != display.showingTo ||
-      display.lastSizeC != display.wrapper.clientHeight;
-    // This is just a bogus formula that detects when the editor is
-    // resized or the font size changes.
-    if (different) {
-      display.lastSizeC = display.wrapper.clientHeight;
-      startWorker(cm, 400);
-    }
-    display.showingFrom = from; display.showingTo = to;
-
-    display.gutters.style.height = "";
-    updateHeightsInViewport(cm);
-    updateViewOffset(cm);
-
-    return true;
-  }
-
-  function updateHeightsInViewport(cm) {
-    var display = cm.display;
-    var prevBottom = display.lineDiv.offsetTop;
-    for (var node = display.lineDiv.firstChild, height; node; node = node.nextSibling) if (node.lineObj) {
-      if (ie_lt8) {
-        var bot = node.offsetTop + node.offsetHeight;
-        height = bot - prevBottom;
-        prevBottom = bot;
-      } else {
-        var box = getRect(node);
-        height = box.bottom - box.top;
-      }
-      var diff = node.lineObj.height - height;
-      if (height < 2) height = textHeight(display);
-      if (diff > .001 || diff < -.001) {
-        updateLineHeight(node.lineObj, height);
-        var widgets = node.lineObj.widgets;
-        if (widgets) for (var i = 0; i < widgets.length; ++i)
-          widgets[i].height = widgets[i].node.offsetHeight;
-      }
-    }
-  }
-
-  function updateViewOffset(cm) {
-    var off = cm.display.viewOffset = heightAtLine(cm, getLine(cm.doc, cm.display.showingFrom));
-    // Position the mover div to align with the current virtual scroll position
-    cm.display.mover.style.top = off + "px";
-  }
-
-  function computeIntact(intact, changes) {
-    for (var i = 0, l = changes.length || 0; i < l; ++i) {
-      var change = changes[i], intact2 = [], diff = change.diff || 0;
-      for (var j = 0, l2 = intact.length; j < l2; ++j) {
-        var range = intact[j];
-        if (change.to <= range.from && change.diff) {
-          intact2.push({from: range.from + diff, to: range.to + diff});
-        } else if (change.to <= range.from || change.from >= range.to) {
-          intact2.push(range);
-        } else {
-          if (change.from > range.from)
-            intact2.push({from: range.from, to: change.from});
-          if (change.to < range.to)
-            intact2.push({from: change.to + diff, to: range.to + diff});
-        }
-      }
-      intact = intact2;
-    }
-    return intact;
-  }
-
-  function getDimensions(cm) {
-    var d = cm.display, left = {}, width = {};
-    for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
-      left[cm.options.gutters[i]] = n.offsetLeft;
-      width[cm.options.gutters[i]] = n.offsetWidth;
-    }
-    return {fixedPos: compensateForHScroll(d),
-            gutterTotalWidth: d.gutters.offsetWidth,
-            gutterLeft: left,
-            gutterWidth: width,
-            wrapperWidth: d.wrapper.clientWidth};
-  }
-
-  function patchDisplay(cm, from, to, intact, updateNumbersFrom) {
-    var dims = getDimensions(cm);
-    var display = cm.display, lineNumbers = cm.options.lineNumbers;
-    if (!intact.length && (!webkit || !cm.display.currentWheelTarget))
-      removeChildren(display.lineDiv);
-    var container = display.lineDiv, cur = container.firstChild;
-
-    function rm(node) {
-      var next = node.nextSibling;
-      if (webkit && mac && cm.display.currentWheelTarget == node) {
-        node.style.display = "none";
-        node.lineObj = null;
-      } else {
-        node.parentNode.removeChild(node);
-      }
-      return next;
-    }
-
-    var nextIntact = intact.shift(), lineN = from;
-    cm.doc.iter(from, to, function(line) {
-      if (nextIntact && nextIntact.to == lineN) nextIntact = intact.shift();
-      if (lineIsHidden(cm.doc, line)) {
-        if (line.height != 0) updateLineHeight(line, 0);
-        if (line.widgets && cur && cur.previousSibling) for (var i = 0; i < line.widgets.length; ++i) {
-          var w = line.widgets[i];
-          if (w.showIfHidden) {
-            var prev = cur.previousSibling;
-            if (/pre/i.test(prev.nodeName)) {
-              var wrap = elt("div", null, null, "position: relative");
-              prev.parentNode.replaceChild(wrap, prev);
-              wrap.appendChild(prev);
-              prev = wrap;
-            }
-            var wnode = prev.appendChild(elt("div", [w.node], "CodeMirror-linewidget"));
-            if (!w.handleMouseEvents) wnode.ignoreEvents = true;
-            positionLineWidget(w, wnode, prev, dims);
-          }
-        }
-      } else if (nextIntact && nextIntact.from <= lineN && nextIntact.to > lineN) {
-        // This line is intact. Skip to the actual node. Update its
-        // line number if needed.
-        while (cur.lineObj != line) cur = rm(cur);
-        if (lineNumbers && updateNumbersFrom <= lineN && cur.lineNumber)
-          setTextContent(cur.lineNumber, lineNumberFor(cm.options, lineN));
-        cur = cur.nextSibling;
-      } else {
-        // For lines with widgets, make an attempt to find and reuse
-        // the existing element, so that widgets aren't needlessly
-        // removed and re-inserted into the dom
-        if (line.widgets) for (var j = 0, search = cur, reuse; search && j < 20; ++j, search = search.nextSibling)
-          if (search.lineObj == line && /div/i.test(search.nodeName)) { reuse = search; break; }
-        // This line needs to be generated.
-        var lineNode = buildLineElement(cm, line, lineN, dims, reuse);
-        if (lineNode != reuse) {
-          container.insertBefore(lineNode, cur);
-        } else {
-          while (cur != reuse) cur = rm(cur);
-          cur = cur.nextSibling;
-        }
-
-        lineNode.lineObj = line;
-      }
-      ++lineN;
-    });
-    while (cur) cur = rm(cur);
-  }
-
-  function buildLineElement(cm, line, lineNo, dims, reuse) {
-    var built = buildLineContent(cm, line), lineElement = built.pre;
-    var markers = line.gutterMarkers, display = cm.display, wrap;
-
-    var bgClass = built.bgClass ? built.bgClass + " " + (line.bgClass || "") : line.bgClass;
-    if (!cm.options.lineNumbers && !markers && !bgClass && !line.wrapClass && !line.widgets)
-      return lineElement;
-
-    // Lines with gutter elements, widgets or a background class need
-    // to be wrapped again, and have the extra elements added to the
-    // wrapper div
-
-    if (reuse) {
-      reuse.alignable = null;
-      var isOk = true, widgetsSeen = 0, insertBefore = null;
-      for (var n = reuse.firstChild, next; n; n = next) {
-        next = n.nextSibling;
-        if (!/\bCodeMirror-linewidget\b/.test(n.className)) {
-          reuse.removeChild(n);
-        } else {
-          for (var i = 0; i < line.widgets.length; ++i) {
-            var widget = line.widgets[i];
-            if (widget.node == n.firstChild) {
-              if (!widget.above && !insertBefore) insertBefore = n;
-              positionLineWidget(widget, n, reuse, dims);
-              ++widgetsSeen;
-              break;
-            }
-          }
-          if (i == line.widgets.length) { isOk = false; break; }
-        }
-      }
-      reuse.insertBefore(lineElement, insertBefore);
-      if (isOk && widgetsSeen == line.widgets.length) {
-        wrap = reuse;
-        reuse.className = line.wrapClass || "";
-      }
-    }
-    if (!wrap) {
-      wrap = elt("div", null, line.wrapClass, "position: relative");
-      wrap.appendChild(lineElement);
-    }
-    // Kludge to make sure the styled element lies behind the selection (by z-index)
-    if (bgClass)
-      wrap.insertBefore(elt("div", null, bgClass + " CodeMirror-linebackground"), wrap.firstChild);
-    if (cm.options.lineNumbers || markers) {
-      var gutterWrap = wrap.insertBefore(elt("div", null, "CodeMirror-gutter-wrapper", "position: absolute; left: " +
-                                             (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px"),
-                                         lineElement);
-      if (cm.options.fixedGutter) (wrap.alignable || (wrap.alignable = [])).push(gutterWrap);
-      if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
-        wrap.lineNumber = gutterWrap.appendChild(
-          elt("div", lineNumberFor(cm.options, lineNo),
-              "CodeMirror-linenumber CodeMirror-gutter-elt",
-              "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width: "
-              + display.lineNumInnerWidth + "px"));
-      if (markers)
-        for (var k = 0; k < cm.options.gutters.length; ++k) {
-          var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id];
-          if (found)
-            gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", "left: " +
-                                       dims.gutterLeft[id] + "px; width: " + dims.gutterWidth[id] + "px"));
-        }
-    }
-    if (ie_lt8) wrap.style.zIndex = 2;
-    if (line.widgets && wrap != reuse) for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
-      var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget");
-      if (!widget.handleMouseEvents) node.ignoreEvents = true;
-      positionLineWidget(widget, node, wrap, dims);
-      if (widget.above)
-        wrap.insertBefore(node, cm.options.lineNumbers && line.height != 0 ? gutterWrap : lineElement);
-      else
-        wrap.appendChild(node);
-      signalLater(widget, "redraw");
-    }
-    return wrap;
-  }
-
-  function positionLineWidget(widget, node, wrap, dims) {
-    if (widget.noHScroll) {
-      (wrap.alignable || (wrap.alignable = [])).push(node);
-      var width = dims.wrapperWidth;
-      node.style.left = dims.fixedPos + "px";
-      if (!widget.coverGutter) {
-        width -= dims.gutterTotalWidth;
-        node.style.paddingLeft = dims.gutterTotalWidth + "px";
-      }
-      node.style.width = width + "px";
-    }
-    if (widget.coverGutter) {
-      node.style.zIndex = 5;
-      node.style.position = "relative";
-      if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + "px";
-    }
-  }
-
-  // SELECTION / CURSOR
-
-  function updateSelection(cm) {
-    var display = cm.display;
-    var collapsed = posEq(cm.doc.sel.from, cm.doc.sel.to);
-    if (collapsed || cm.options.showCursorWhenSelecting)
-      updateSelectionCursor(cm);
-    else
-      display.cursor.style.display = display.otherCursor.style.display = "none";
-    if (!collapsed)
-      updateSelectionRange(cm);
-    else
-      display.selectionDiv.style.display = "none";
-
-    // Move the hidden textarea near the cursor to prevent scrolling artifacts
-    if (cm.options.moveInputWithCursor) {
-      var headPos = cursorCoords(cm, cm.doc.sel.head, "div");
-      var wrapOff = getRect(display.wrapper), lineOff = getRect(display.lineDiv);
-      display.inputDiv.style.top = Math.max(0, Math.min(display.wrapper.clientHeight - 10,
-                                                        headPos.top + lineOff.top - wrapOff.top)) + "px";
-      display.inputDiv.style.left = Math.max(0, Math.min(display.wrapper.clientWidth - 10,
-                                                         headPos.left + lineOff.left - wrapOff.left)) + "px";
-    }
-  }
-
-  // No selection, plain cursor
-  function updateSelectionCursor(cm) {
-    var display = cm.display, pos = cursorCoords(cm, cm.doc.sel.head, "div");
-    display.cursor.style.left = pos.left + "px";
-    display.cursor.style.top = pos.top + "px";
-    display.cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px";
-    display.cursor.style.display = "";
-
-    if (pos.other) {
-      display.otherCursor.style.display = "";
-      display.otherCursor.style.left = pos.other.left + "px";
-      display.otherCursor.style.top = pos.other.top + "px";
-      display.otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px";
-    } else { display.otherCursor.style.display = "none"; }
-  }
-
-  // Highlight selection
-  function updateSelectionRange(cm) {
-    var display = cm.display, doc = cm.doc, sel = cm.doc.sel;
-    var fragment = document.createDocumentFragment();
-    var clientWidth = display.lineSpace.offsetWidth, pl = paddingLeft(cm.display);
-
-    function add(left, top, width, bottom) {
-      if (top < 0) top = 0;
-      fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left +
-                               "px; top: " + top + "px; width: " + (width == null ? clientWidth - left : width) +
-                               "px; height: " + (bottom - top) + "px"));
-    }
-
-    function drawForLine(line, fromArg, toArg) {
-      var lineObj = getLine(doc, line);
-      var lineLen = lineObj.text.length;
-      var start, end;
-      function coords(ch, bias) {
-        return charCoords(cm, Pos(line, ch), "div", lineObj, bias);
-      }
-
-      iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function(from, to, dir) {
-        var leftPos = coords(from, "left"), rightPos, left, right;
-        if (from == to) {
-          rightPos = leftPos;
-          left = right = leftPos.left;
-        } else {
-          rightPos = coords(to - 1, "right");
-          if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp; }
-          left = leftPos.left;
-          right = rightPos.right;
-        }
-        if (fromArg == null && from == 0) left = pl;
-        if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part
-          add(left, leftPos.top, null, leftPos.bottom);
-          left = pl;
-          if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top);
-        }
-        if (toArg == null && to == lineLen) right = clientWidth;
-        if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left)
-          start = leftPos;
-        if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right)
-          end = rightPos;
-        if (left < pl + 1) left = pl;
-        add(left, rightPos.top, right - left, rightPos.bottom);
-      });
-      return {start: start, end: end};
-    }
-
-    if (sel.from.line == sel.to.line) {
-      drawForLine(sel.from.line, sel.from.ch, sel.to.ch);
-    } else {
-      var fromLine = getLine(doc, sel.from.line), toLine = getLine(doc, sel.to.line);
-      var singleVLine = visualLine(doc, fromLine) == visualLine(doc, toLine);
-      var leftEnd = drawForLine(sel.from.line, sel.from.ch, singleVLine ? fromLine.text.length : null).end;
-      var rightStart = drawForLine(sel.to.line, singleVLine ? 0 : null, sel.to.ch).start;
-      if (singleVLine) {
-        if (leftEnd.top < rightStart.top - 2) {
-          add(leftEnd.right, leftEnd.top, null, leftEnd.bottom);
-          add(pl, rightStart.top, rightStart.left, rightStart.bottom);
-        } else {
-          add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom);
-        }
-      }
-      if (leftEnd.bottom < rightStart.top)
-        add(pl, leftEnd.bottom, null, rightStart.top);
-    }
-
-    removeChildrenAndAdd(display.selectionDiv, fragment);
-    display.selectionDiv.style.display = "";
-  }
-
-  // Cursor-blinking
-  function restartBlink(cm) {
-    if (!cm.state.focused) return;
-    var display = cm.display;
-    clearInterval(display.blinker);
-    var on = true;
-    display.cursor.style.visibility = display.otherCursor.style.visibility = "";
-    if (cm.options.cursorBlinkRate > 0)
-      display.blinker = setInterval(function() {
-        display.cursor.style.visibility = display.otherCursor.style.visibility = (on = !on) ? "" : "hidden";
-      }, cm.options.cursorBlinkRate);
-  }
-
-  // HIGHLIGHT WORKER
-
-  function startWorker(cm, time) {
-    if (cm.doc.mode.startState && cm.doc.frontier < cm.display.showingTo)
-      cm.state.highlight.set(time, bind(highlightWorker, cm));
-  }
-
-  function highlightWorker(cm) {
-    var doc = cm.doc;
-    if (doc.frontier < doc.first) doc.frontier = doc.first;
-    if (doc.frontier >= cm.display.showingTo) return;
-    var end = +new Date + cm.options.workTime;
-    var state = copyState(doc.mode, getStateBefore(cm, doc.frontier));
-    var changed = [], prevChange;
-    doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.showingTo + 500), function(line) {
-      if (doc.frontier >= cm.display.showingFrom) { // Visible
-        var oldStyles = line.styles;
-        line.styles = highlightLine(cm, line, state, true);
-        var ischange = !oldStyles || oldStyles.length != line.styles.length;
-        for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i];
-        if (ischange) {
-          if (prevChange && prevChange.end == doc.frontier) prevChange.end++;
-          else changed.push(prevChange = {start: doc.frontier, end: doc.frontier + 1});
-        }
-        line.stateAfter = copyState(doc.mode, state);
-      } else {
-        processLine(cm, line.text, state);
-        line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null;
-      }
-      ++doc.frontier;
-      if (+new Date > end) {
-        startWorker(cm, cm.options.workDelay);
-        return true;
-      }
-    });
-    if (changed.length)
-      operation(cm, function() {
-        for (var i = 0; i < changed.length; ++i)
-          regChange(this, changed[i].start, changed[i].end);
-      })();
-  }
-
-  // Finds the line to start with when starting a parse. Tries to
-  // find a line with a stateAfter, so that it can start with a
-  // valid state. If that fails, it returns the line with the
-  // smallest indentation, which tends to need the least context to
-  // parse correctly.
-  function findStartLine(cm, n, precise) {
-    var minindent, minline, doc = cm.doc;
-    var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100);
-    for (var search = n; search > lim; --search) {
-      if (search <= doc.first) return doc.first;
-      var line = getLine(doc, search - 1);
-      if (line.stateAfter && (!precise || search <= doc.frontier)) return search;
-      var indented = countColumn(line.text, null, cm.options.tabSize);
-      if (minline == null || minindent > indented) {
-        minline = search - 1;
-        minindent = indented;
-      }
-    }
-    return minline;
-  }
-
-  function getStateBefore(cm, n, precise) {
-    var doc = cm.doc, display = cm.display;
-    if (!doc.mode.startState) return true;
-    var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos-1).stateAfter;
-    if (!state) state = startState(doc.mode);
-    else state = copyState(doc.mode, state);
-    doc.iter(pos, n, function(line) {
-      processLine(cm, line.text, state);
-      var save = pos == n - 1 || pos % 5 == 0 || pos >= display.showingFrom && pos < display.showingTo;
-      line.stateAfter = save ? copyState(doc.mode, state) : null;
-      ++pos;
-    });
-    if (precise) doc.frontier = pos;
-    return state;
-  }
-
-  // POSITION MEASUREMENT
-
-  function paddingTop(display) {return display.lineSpace.offsetTop;}
-  function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight;}
-  function paddingLeft(display) {
-    var e = removeChildrenAndAdd(display.measure, elt("pre", null, null, "text-align: left")).appendChild(elt("span", "x"));
-    return e.offsetLeft;
-  }
-
-  function measureChar(cm, line, ch, data, bias) {
-    var dir = -1;
-    data = data || measureLine(cm, line);
-    if (data.crude) {
-      var left = data.left + ch * data.width;
-      return {left: left, right: left + data.width, top: data.top, bottom: data.bottom};
-    }
-
-    for (var pos = ch;; pos += dir) {
-      var r = data[pos];
-      if (r) break;
-      if (dir < 0 && pos == 0) dir = 1;
-    }
-    bias = pos > ch ? "left" : pos < ch ? "right" : bias;
-    if (bias == "left" && r.leftSide) r = r.leftSide;
-    else if (bias == "right" && r.rightSide) r = r.rightSide;
-    return {left: pos < ch ? r.right : r.left,
-            right: pos > ch ? r.left : r.right,
-            top: r.top,
-            bottom: r.bottom};
-  }
-
-  function findCachedMeasurement(cm, line) {
-    var cache = cm.display.measureLineCache;
-    for (var i = 0; i < cache.length; ++i) {
-      var memo = cache[i];
-      if (memo.text == line.text && memo.markedSpans == line.markedSpans &&
-          cm.display.scroller.clientWidth == memo.width &&
-          memo.classes == line.textClass + "|" + line.wrapClass)
-        return memo;
-    }
-  }
-
-  function clearCachedMeasurement(cm, line) {
-    var exists = findCachedMeasurement(cm, line);
-    if (exists) exists.text = exists.measure = exists.markedSpans = null;
-  }
-
-  function measureLine(cm, line) {
-    // First look in the cache
-    var cached = findCachedMeasurement(cm, line);
-    if (cached) return cached.measure;
-
-    // Failing that, recompute and store result in cache
-    var measure = measureLineInner(cm, line);
-    var cache = cm.display.measureLineCache;
-    var memo = {text: line.text, width: cm.display.scroller.clientWidth,
-                markedSpans: line.markedSpans, measure: measure,
-                classes: line.textClass + "|" + line.wrapClass};
-    if (cache.length == 16) cache[++cm.display.measureLineCachePos % 16] = memo;
-    else cache.push(memo);
-    return measure;
-  }
-
-  function measureLineInner(cm, line) {
-    if (!cm.options.lineWrapping && line.text.length >= cm.options.crudeMeasuringFrom)
-      return crudelyMeasureLine(cm, line);
-
-    var display = cm.display, measure = emptyArray(line.text.length);
-    var pre = buildLineContent(cm, line, measure, true).pre;
-
-    // IE does not cache element positions of inline elements between
-    // calls to getBoundingClientRect. This makes the loop below,
-    // which gathers the positions of all the characters on the line,
-    // do an amount of layout work quadratic to the number of
-    // characters. When line wrapping is off, we try to improve things
-    // by first subdividing the line into a bunch of inline blocks, so
-    // that IE can reuse most of the layout information from caches
-    // for those blocks. This does interfere with line wrapping, so it
-    // doesn't work when wrapping is on, but in that case the
-    // situation is slightly better, since IE does cache line-wrapping
-    // information and only recomputes per-line.
-    if (ie && !ie_lt8 && !cm.options.lineWrapping && pre.childNodes.length > 100) {
-      var fragment = document.createDocumentFragment();
-      var chunk = 10, n = pre.childNodes.length;
-      for (var i = 0, chunks = Math.ceil(n / chunk); i < chunks; ++i) {
-        var wrap = elt("div", null, null, "display: inline-block");
-        for (var j = 0; j < chunk && n; ++j) {
-          wrap.appendChild(pre.firstChild);
-          --n;
-        }
-        fragment.appendChild(wrap);
-      }
-      pre.appendChild(fragment);
-    }
-
-    removeChildrenAndAdd(display.measure, pre);
-
-    var outer = getRect(display.lineDiv);
-    var vranges = [], data = emptyArray(line.text.length), maxBot = pre.offsetHeight;
-    // Work around an IE7/8 bug where it will sometimes have randomly
-    // replaced our pre with a clone at this point.
-    if (ie_lt9 && display.measure.first != pre)
-      removeChildrenAndAdd(display.measure, pre);
-
-    function measureRect(rect) {
-      var top = rect.top - outer.top, bot = rect.bottom - outer.top;
-      if (bot > maxBot) bot = maxBot;
-      if (top < 0) top = 0;
-      for (var i = vranges.length - 2; i >= 0; i -= 2) {
-        var rtop = vranges[i], rbot = vranges[i+1];
-        if (rtop > bot || rbot < top) continue;
-        if (rtop <= top && rbot >= bot ||
-            top <= rtop && bot >= rbot ||
-            Math.min(bot, rbot) - Math.max(top, rtop) >= (bot - top) >> 1) {
-          vranges[i] = Math.min(top, rtop);
-          vranges[i+1] = Math.max(bot, rbot);
-          break;
-        }
-      }
-      if (i < 0) { i = vranges.length; vranges.push(top, bot); }
-      return {left: rect.left - outer.left,
-              right: rect.right - outer.left,
-              top: i, bottom: null};
-    }
-    function finishRect(rect) {
-      rect.bottom = vranges[rect.top+1];
-      rect.top = vranges[rect.top];
-    }
-
-    for (var i = 0, cur; i < measure.length; ++i) if (cur = measure[i]) {
-      var node = cur, rect = null;
-      // A widget might wrap, needs special care
-      if (/\bCodeMirror-widget\b/.test(cur.className) && cur.getClientRects) {
-        if (cur.firstChild.nodeType == 1) node = cur.firstChild;
-        var rects = node.getClientRects();
-        if (rects.length > 1) {
-          rect = data[i] = measureRect(rects[0]);
-          rect.rightSide = measureRect(rects[rects.length - 1]);
-        }
-      }
-      if (!rect) rect = data[i] = measureRect(getRect(node));
-      if (cur.measureRight) rect.right = getRect(cur.measureRight).left - outer.left;
-      if (cur.leftSide) rect.leftSide = measureRect(getRect(cur.leftSide));
-    }
-    removeChildren(cm.display.measure);
-    for (var i = 0, cur; i < data.length; ++i) if (cur = data[i]) {
-      finishRect(cur);
-      if (cur.leftSide) finishRect(cur.leftSide);
-      if (cur.rightSide) finishRect(cur.rightSide);
-    }
-    return data;
-  }
-
-  function crudelyMeasureLine(cm, line) {
-    var copy = new Line(line.text.slice(0, 100), null);
-    if (line.textClass) copy.textClass = line.textClass;
-    var measure = measureLineInner(cm, copy);
-    var left = measureChar(cm, copy, 0, measure, "left");
-    var right = measureChar(cm, copy, 99, measure, "right");
-    return {crude: true, top: left.top, left: left.left, bottom: left.bottom, width: (right.right - left.left) / 100};
-  }
-
-  function measureLineWidth(cm, line) {
-    var hasBadSpan = false;
-    if (line.markedSpans) for (var i = 0; i < line.markedSpans; ++i) {
-      var sp = line.markedSpans[i];
-      if (sp.collapsed && (sp.to == null || sp.to == line.text.length)) hasBadSpan = true;
-    }
-    var cached = !hasBadSpan && findCachedMeasurement(cm, line);
-    if (cached || line.text.length >= cm.options.crudeMeasuringFrom)
-      return measureChar(cm, line, line.text.length, cached && cached.measure, "right").right;
-
-    var pre = buildLineContent(cm, line, null, true).pre;
-    var end = pre.appendChild(zeroWidthElement(cm.display.measure));
-    removeChildrenAndAdd(cm.display.measure, pre);
-    return getRect(end).right - getRect(cm.display.lineDiv).left;
-  }
-
-  function clearCaches(cm) {
-    cm.display.measureLineCache.length = cm.display.measureLineCachePos = 0;
-    cm.display.cachedCharWidth = cm.display.cachedTextHeight = null;
-    if (!cm.options.lineWrapping) cm.display.maxLineChanged = true;
-    cm.display.lineNumChars = null;
-  }
-
-  function pageScrollX() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft; }
-  function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop; }
-
-  // Context is one of "line", "div" (display.lineDiv), "local"/null (editor), or "page"
-  function intoCoordSystem(cm, lineObj, rect, context) {
-    if (lineObj.widgets) for (var i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) {
-      var size = widgetHeight(lineObj.widgets[i]);
-      rect.top += size; rect.bottom += size;
-    }
-    if (context == "line") return rect;
-    if (!context) context = "local";
-    var yOff = heightAtLine(cm, lineObj);
-    if (context == "local") yOff += paddingTop(cm.display);
-    else yOff -= cm.display.viewOffset;
-    if (context == "page" || context == "window") {
-      var lOff = getRect(cm.display.lineSpace);
-      yOff += lOff.top + (context == "window" ? 0 : pageScrollY());
-      var xOff = lOff.left + (context == "window" ? 0 : pageScrollX());
-      rect.left += xOff; rect.right += xOff;
-    }
-    rect.top += yOff; rect.bottom += yOff;
-    return rect;
-  }
-
-  // Context may be "window", "page", "div", or "local"/null
-  // Result is in "div" coords
-  function fromCoordSystem(cm, coords, context) {
-    if (context == "div") return coords;
-    var left = coords.left, top = coords.top;
-    // First move into "page" coordinate system
-    if (context == "page") {
-      left -= pageScrollX();
-      top -= pageScrollY();
-    } else if (context == "local" || !context) {
-      var localBox = getRect(cm.display.sizer);
-      left += localBox.left;
-      top += localBox.top;
-    }
-
-    var lineSpaceBox = getRect(cm.display.lineSpace);
-    return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top};
-  }
-
-  function charCoords(cm, pos, context, lineObj, bias) {
-    if (!lineObj) lineObj = getLine(cm.doc, pos.line);
-    return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, null, bias), context);
-  }
-
-  function cursorCoords(cm, pos, context, lineObj, measurement) {
-    lineObj = lineObj || getLine(cm.doc, pos.line);
-    if (!measurement) measurement = measureLine(cm, lineObj);
-    function get(ch, right) {
-      var m = measureChar(cm, lineObj, ch, measurement, right ? "right" : "left");
-      if (right) m.left = m.right; else m.right = m.left;
-      return intoCoordSystem(cm, lineObj, m, context);
-    }
-    function getBidi(ch, partPos) {
-      var part = order[partPos], right = part.level % 2;
-      if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].level) {
-        part = order[--partPos];
-        ch = bidiRight(part) - (part.level % 2 ? 0 : 1);
-        right = true;
-      } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.level < order[partPos + 1].level) {
-        part = order[++partPos];
-        ch = bidiLeft(part) - part.level % 2;
-        right = false;
-      }
-      if (right && ch == part.to && ch > part.from) return get(ch - 1);
-      return get(ch, right);
-    }
-    var order = getOrder(lineObj), ch = pos.ch;
-    if (!order) return get(ch);
-    var partPos = getBidiPartAt(order, ch);
-    var val = getBidi(ch, partPos);
-    if (bidiOther != null) val.other = getBidi(ch, bidiOther);
-    return val;
-  }
-
-  function PosWithInfo(line, ch, outside, xRel) {
-    var pos = new Pos(line, ch);
-    pos.xRel = xRel;
-    if (outside) pos.outside = true;
-    return pos;
-  }
-
-  // Coords must be lineSpace-local
-  function coordsChar(cm, x, y) {
-    var doc = cm.doc;
-    y += cm.display.viewOffset;
-    if (y < 0) return PosWithInfo(doc.first, 0, true, -1);
-    var lineNo = lineAtHeight(doc, y), last = doc.first + doc.size - 1;
-    if (lineNo > last)
-      return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, true, 1);
-    if (x < 0) x = 0;
-
-    for (;;) {
-      var lineObj = getLine(doc, lineNo);
-      var found = coordsCharInner(cm, lineObj, lineNo, x, y);
-      var merged = collapsedSpanAtEnd(lineObj);
-      var mergedPos = merged && merged.find();
-      if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0))
-        lineNo = mergedPos.to.line;
-      else
-        return found;
-    }
-  }
-
-  function coordsCharInner(cm, lineObj, lineNo, x, y) {
-    var innerOff = y - heightAtLine(cm, lineObj);
-    var wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth;
-    var measurement = measureLine(cm, lineObj);
-
-    function getX(ch) {
-      var sp = cursorCoords(cm, Pos(lineNo, ch), "line",
-                            lineObj, measurement);
-      wrongLine = true;
-      if (innerOff > sp.bottom) return sp.left - adjust;
-      else if (innerOff < sp.top) return sp.left + adjust;
-      else wrongLine = false;
-      return sp.left;
-    }
-
-    var bidi = getOrder(lineObj), dist = lineObj.text.length;
-    var from = lineLeft(lineObj), to = lineRight(lineObj);
-    var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine;
-
-    if (x > toX) return PosWithInfo(lineNo, to, toOutside, 1);
-    // Do a binary search between these bounds.
-    for (;;) {
-      if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) {
-        var ch = x < fromX || x - fromX <= toX - x ? from : to;
-        var xDiff = x - (ch == from ? fromX : toX);
-        while (isExtendingChar.test(lineObj.text.charAt(ch))) ++ch;
-        var pos = PosWithInfo(lineNo, ch, ch == from ? fromOutside : toOutside,
-                              xDiff < 0 ? -1 : xDiff ? 1 : 0);
-        return pos;
-      }
-      var step = Math.ceil(dist / 2), middle = from + step;
-      if (bidi) {
-        middle = from;
-        for (var i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1);
-      }
-      var middleX = getX(middle);
-      if (middleX > x) {to = middle; toX = middleX; if (toOutside = wrongLine) toX += 1000; dist = step;}
-      else {from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step;}
-    }
-  }
-
-  var measureText;
-  function textHeight(display) {
-    if (display.cachedTextHeight != null) return display.cachedTextHeight;
-    if (measureText == null) {
-      measureText = elt("pre");
-      // Measure a bunch of lines, for browsers that compute
-      // fractional heights.
-      for (var i = 0; i < 49; ++i) {
-        measureText.appendChild(document.createTextNode("x"));
-        measureText.appendChild(elt("br"));
-      }
-      measureText.appendChild(document.createTextNode("x"));
-    }
-    removeChildrenAndAdd(display.measure, measureText);
-    var height = measureText.offsetHeight / 50;
-    if (height > 3) display.cachedTextHeight = height;
-    removeChildren(display.measure);
-    return height || 1;
-  }
-
-  function charWidth(display) {
-    if (display.cachedCharWidth != null) return display.cachedCharWidth;
-    var anchor = elt("span", "x");
-    var pre = elt("pre", [anchor]);
-    removeChildrenAndAdd(display.measure, pre);
-    var width = anchor.offsetWidth;
-    if (width > 2) display.cachedCharWidth = width;
-    return width || 10;
-  }
-
-  // OPERATIONS
-
-  // Operations are used to wrap changes in such a way that each
-  // change won't have to update the cursor and display (which would
-  // be awkward, slow, and error-prone), but instead updates are
-  // batched and then all combined and executed at once.
-
-  var nextOpId = 0;
-  function startOperation(cm) {
-    cm.curOp = {
-      // An array of ranges of lines that have to be updated. See
-      // updateDisplay.
-      changes: [],
-      forceUpdate: false,
-      updateInput: null,
-      userSelChange: null,
-      textChanged: null,
-      selectionChanged: false,
-      cursorActivity: false,
-      updateMaxLine: false,
-      updateScrollPos: false,
-      id: ++nextOpId
-    };
-    if (!delayedCallbackDepth++) delayedCallbacks = [];
-  }
-
-  function endOperation(cm) {
-    var op = cm.curOp, doc = cm.doc, display = cm.display;
-    cm.curOp = null;
-
-    if (op.updateMaxLine) computeMaxLength(cm);
-    if (display.maxLineChanged && !cm.options.lineWrapping && display.maxLine) {
-      var width = measureLineWidth(cm, display.maxLine);
-      display.sizer.style.minWidth = Math.max(0, width + 3 + scrollerCutOff) + "px";
-      display.maxLineChanged = false;
-      var maxScrollLeft = Math.max(0, display.sizer.offsetLeft + display.sizer.offsetWidth - display.scroller.clientWidth);
-      if (maxScrollLeft < doc.scrollLeft && !op.updateScrollPos)
-        setScrollLeft(cm, Math.min(display.scroller.scrollLeft, maxScrollLeft), true);
-    }
-    var newScrollPos, updated;
-    if (op.updateScrollPos) {
-      newScrollPos = op.updateScrollPos;
-    } else if (op.selectionChanged && display.scroller.clientHeight) { // don't rescroll if not visible
-      var coords = cursorCoords(cm, doc.sel.head);
-      newScrollPos = calculateScrollPos(cm, coords.left, coords.top, coords.left, coords.bottom);
-    }
-    if (op.changes.length || op.forceUpdate || newScrollPos && newScrollPos.scrollTop != null) {
-      updated = updateDisplay(cm, op.changes, newScrollPos && newScrollPos.scrollTop, op.forceUpdate);
-      if (cm.display.scroller.offsetHeight) cm.doc.scrollTop = cm.display.scroller.scrollTop;
-    }
-    if (!updated && op.selectionChanged) updateSelection(cm);
-    if (op.updateScrollPos) {
-      var top = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, newScrollPos.scrollTop));
-      var left = Math.max(0, Math.min(display.scroller.scrollWidth - display.scroller.clientWidth, newScrollPos.scrollLeft));
-      display.scroller.scrollTop = display.scrollbarV.scrollTop = doc.scrollTop = top;
-      display.scroller.scrollLeft = display.scrollbarH.scrollLeft = doc.scrollLeft = left;
-      alignHorizontally(cm);
-      if (op.scrollToPos)
-        scrollPosIntoView(cm, clipPos(cm.doc, op.scrollToPos.from),
-                          clipPos(cm.doc, op.scrollToPos.to), op.scrollToPos.margin);
-    } else if (newScrollPos) {
-      scrollCursorIntoView(cm);
-    }
-    if (op.selectionChanged) restartBlink(cm);
-
-    if (cm.state.focused && op.updateInput)
-      resetInput(cm, op.userSelChange);
-
-    var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers;
-    if (hidden) for (var i = 0; i < hidden.length; ++i)
-      if (!hidden[i].lines.length) signal(hidden[i], "hide");
-    if (unhidden) for (var i = 0; i < unhidden.length; ++i)
-      if (unhidden[i].lines.length) signal(unhidden[i], "unhide");
-
-    var delayed;
-    if (!--delayedCallbackDepth) {
-      delayed = delayedCallbacks;
-      delayedCallbacks = null;
-    }
-    if (op.textChanged)
-      signal(cm, "change", cm, op.textChanged);
-    if (op.cursorActivity) signal(cm, "cursorActivity", cm);
-    if (delayed) for (var i = 0; i < delayed.length; ++i) delayed[i]();
-  }
-
-  // Wraps a function in an operation. Returns the wrapped function.
-  function operation(cm1, f) {
-    return function() {
-      var cm = cm1 || this, withOp = !cm.curOp;
-      if (withOp) startOperation(cm);
-      try { var result = f.apply(cm, arguments); }
-      finally { if (withOp) endOperation(cm); }
-      return result;
-    };
-  }
-  function docOperation(f) {
-    return function() {
-      var withOp = this.cm && !this.cm.curOp, result;
-      if (withOp) startOperation(this.cm);
-      try { result = f.apply(this, arguments); }
-      finally { if (withOp) endOperation(this.cm); }
-      return result;
-    };
-  }
-  function runInOp(cm, f) {
-    var withOp = !cm.curOp, result;
-    if (withOp) startOperation(cm);
-    try { result = f(); }
-    finally { if (withOp) endOperation(cm); }
-    return result;
-  }
-
-  function regChange(cm, from, to, lendiff) {
-    if (from == null) from = cm.doc.first;
-    if (to == null) to = cm.doc.first + cm.doc.size;
-    cm.curOp.changes.push({from: from, to: to, diff: lendiff});
-  }
-
-  // INPUT HANDLING
-
-  function slowPoll(cm) {
-    if (cm.display.pollingFast) return;
-    cm.display.poll.set(cm.options.pollInterval, function() {
-      readInput(cm);
-      if (cm.state.focused) slowPoll(cm);
-    });
-  }
-
-  function fastPoll(cm) {
-    var missed = false;
-    cm.display.pollingFast = true;
-    function p() {
-      var changed = readInput(cm);
-      if (!changed && !missed) {missed = true; cm.display.poll.set(60, p);}
-      else {cm.display.pollingFast = false; slowPoll(cm);}
-    }
-    cm.display.poll.set(20, p);
-  }
-
-  // prevInput is a hack to work with IME. If we reset the textarea
-  // on every change, that breaks IME. So we look for changes
-  // compared to the previous content instead. (Modern browsers have
-  // events that indicate IME taking place, but these are not widely
-  // supported or compatible enough yet to rely on.)
-  function readInput(cm) {
-    var input = cm.display.input, prevInput = cm.display.prevInput, doc = cm.doc, sel = doc.sel;
-    if (!cm.state.focused || hasSelection(input) || isReadOnly(cm) || cm.state.disableInput) return false;
-    if (cm.state.pasteIncoming && cm.state.fakedLastChar) {
-      input.value = input.value.substring(0, input.value.length - 1);
-      cm.state.fakedLastChar = false;
-    }
-    var text = input.value;
-    if (text == prevInput && posEq(sel.from, sel.to)) return false;
-    if (ie && !ie_lt9 && cm.display.inputHasSelection === text) {
-      resetInput(cm, true);
-      return false;
-    }
-
-    var withOp = !cm.curOp;
-    if (withOp) startOperation(cm);
-    sel.shift = false;
-    var same = 0, l = Math.min(prevInput.length, text.length);
-    while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same;
-    var from = sel.from, to = sel.to;
-    var inserted = text.slice(same);
-    if (same < prevInput.length)
-      from = Pos(from.line, from.ch - (prevInput.length - same));
-    else if (cm.state.overwrite && posEq(from, to) && !cm.state.pasteIncoming)
-      to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + inserted.length));
-
-    var updateInput = cm.curOp.updateInput;
-    var changeEvent = {from: from, to: to, text: splitLines(inserted),
-                       origin: cm.state.pasteIncoming ? "paste" : "+input"};
-    makeChange(cm.doc, changeEvent, "end");
-    cm.curOp.updateInput = updateInput;
-    signalLater(cm, "inputRead", cm, changeEvent);
-    if (!cm.state.pasteIncoming && cm.options.electricChars &&
-        cm.options.smartIndent && sel.head.ch < 100) {
-      var electric = cm.getModeAt(sel.head).electricChars;
-      if (electric) for (var i = 0; i < electric.length; i++)
-        if (inserted.indexOf(electric.charAt(i)) > -1) {
-          indentLine(cm, sel.head.line, "smart");
-          break;
-        }
-    }
-
-    if (text.length > 1000 || text.indexOf("\n") > -1) input.value = cm.display.prevInput = "";
-    else cm.display.prevInput = text;
-    if (withOp) endOperation(cm);
-    cm.state.pasteIncoming = false;
-    return true;
-  }
-
-  function resetInput(cm, user) {
-    var minimal, selected, doc = cm.doc;
-    if (!posEq(doc.sel.from, doc.sel.to)) {
-      cm.display.prevInput = "";
-      minimal = hasCopyEvent &&
-        (doc.sel.to.line - doc.sel.from.line > 100 || (selected = cm.getSelection()).length > 1000);
-      var content = minimal ? "-" : selected || cm.getSelection();
-      cm.display.input.value = content;
-      if (cm.state.focused) selectInput(cm.display.input);
-      if (ie && !ie_lt9) cm.display.inputHasSelection = content;
-    } else if (user) {
-      cm.display.prevInput = cm.display.input.value = "";
-      if (ie && !ie_lt9) cm.display.inputHasSelection = null;
-    }
-    cm.display.inaccurateSelection = minimal;
-  }
-
-  function focusInput(cm) {
-    if (cm.options.readOnly != "nocursor" && (!mobile || document.activeElement != cm.display.input))
-      cm.display.input.focus();
-  }
-
-  function isReadOnly(cm) {
-    return cm.options.readOnly || cm.doc.cantEdit;
-  }
-
-  // EVENT HANDLERS
-
-  function registerEventHandlers(cm) {
-    var d = cm.display;
-    on(d.scroller, "mousedown", operation(cm, onMouseDown));
-    if (ie)
-      on(d.scroller, "dblclick", operation(cm, function(e) {
-        if (signalDOMEvent(cm, e)) return;
-        var pos = posFromMouse(cm, e);
-        if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return;
-        e_preventDefault(e);
-        var word = findWordAt(getLine(cm.doc, pos.line).text, pos);
-        extendSelection(cm.doc, word.from, word.to);
-      }));
-    else
-      on(d.scroller, "dblclick", function(e) { signalDOMEvent(cm, e) || e_preventDefault(e); });
-    on(d.lineSpace, "selectstart", function(e) {
-      if (!eventInWidget(d, e)) e_preventDefault(e);
-    });
-    // Gecko browsers fire contextmenu *after* opening the menu, at
-    // which point we can't mess with it anymore. Context menu is
-    // handled in onMouseDown for Gecko.
-    if (!captureMiddleClick) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e);});
-
-    on(d.scroller, "scroll", function() {
-      if (d.scroller.clientHeight) {
-        setScrollTop(cm, d.scroller.scrollTop);
-        setScrollLeft(cm, d.scroller.scrollLeft, true);
-        signal(cm, "scroll", cm);
-      }
-    });
-    on(d.scrollbarV, "scroll", function() {
-      if (d.scroller.clientHeight) setScrollTop(cm, d.scrollbarV.scrollTop);
-    });
-    on(d.scrollbarH, "scroll", function() {
-      if (d.scroller.clientHeight) setScrollLeft(cm, d.scrollbarH.scrollLeft);
-    });
-
-    on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);});
-    on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e);});
-
-    function reFocus() { if (cm.state.focused) setTimeout(bind(focusInput, cm), 0); }
-    on(d.scrollbarH, "mousedown", reFocus);
-    on(d.scrollbarV, "mousedown", reFocus);
-    // Prevent wrapper from ever scrolling
-    on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });
-
-    var resizeTimer;
-    function onResize() {
-      if (resizeTimer == null) resizeTimer = setTimeout(function() {
-        resizeTimer = null;
-        // Might be a text scaling operation, clear size caches.
-        d.cachedCharWidth = d.cachedTextHeight = knownScrollbarWidth = null;
-        clearCaches(cm);
-        runInOp(cm, bind(regChange, cm));
-      }, 100);
-    }
-    on(window, "resize", onResize);
-    // Above handler holds on to the editor and its data structures.
-    // Here we poll to unregister it when the editor is no longer in
-    // the document, so that it can be garbage-collected.
-    function unregister() {
-      for (var p = d.wrapper.parentNode; p && p != document.body; p = p.parentNode) {}
-      if (p) setTimeout(unregister, 5000);
-      else off(window, "resize", onResize);
-    }
-    setTimeout(unregister, 5000);
-
-    on(d.input, "keyup", operation(cm, function(e) {
-      if (signalDOMEvent(cm, e) || cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return;
-      if (e.keyCode == 16) cm.doc.sel.shift = false;
-    }));
-    on(d.input, "input", function() {
-      if (ie && !ie_lt9 && cm.display.inputHasSelection) cm.display.inputHasSelection = null;
-      fastPoll(cm);
-    });
-    on(d.input, "keydown", operation(cm, onKeyDown));
-    on(d.input, "keypress", operation(cm, onKeyPress));
-    on(d.input, "focus", bind(onFocus, cm));
-    on(d.input, "blur", bind(onBlur, cm));
-
-    function drag_(e) {
-      if (signalDOMEvent(cm, e) || cm.options.onDragEvent && cm.options.onDragEvent(cm, addStop(e))) return;
-      e_stop(e);
-    }
-    if (cm.options.dragDrop) {
-      on(d.scroller, "dragstart", function(e){onDragStart(cm, e);});
-      on(d.scroller, "dragenter", drag_);
-      on(d.scroller, "dragover", drag_);
-      on(d.scroller, "drop", operation(cm, onDrop));
-    }
-    on(d.scroller, "paste", function(e) {
-      if (eventInWidget(d, e)) return;
-      focusInput(cm);
-      fastPoll(cm);
-    });
-    on(d.input, "paste", function() {
-      // Workaround for webkit bug https://bugs.webkit.org/show_bug.cgi?id=90206
-      // Add a char to the end of textarea before paste occur so that
-      // selection doesn't span to the end of textarea.
-      if (webkit && !cm.state.fakedLastChar && !(new Date - cm.state.lastMiddleDown < 200)) {
-        var start = d.input.selectionStart, end = d.input.selectionEnd;
-        d.input.value += "$";
-        d.input.selectionStart = start;
-        d.input.selectionEnd = end;
-        cm.state.fakedLastChar = true;
-      }
-      cm.state.pasteIncoming = true;
-      fastPoll(cm);
-    });
-
-    function prepareCopy() {
-      if (d.inaccurateSelection) {
-        d.prevInput = "";
-        d.inaccurateSelection = false;
-        d.input.value = cm.getSelection();
-        selectInput(d.input);
-      }
-    }
-    on(d.input, "cut", prepareCopy);
-    on(d.input, "copy", prepareCopy);
-
-    // Needed to handle Tab key in KHTML
-    if (khtml) on(d.sizer, "mouseup", function() {
-        if (document.activeElement == d.input) d.input.blur();
-        focusInput(cm);
-    });
-  }
-
-  function eventInWidget(display, e) {
-    for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {
-      if (!n || n.ignoreEvents || n.parentNode == display.sizer && n != display.mover) return true;
-    }
-  }
-
-  function posFromMouse(cm, e, liberal) {
-    var display = cm.display;
-    if (!liberal) {
-      var target = e_target(e);
-      if (target == display.scrollbarH || target == display.scrollbarH.firstChild ||
-          target == display.scrollbarV || target == display.scrollbarV.firstChild ||
-          target == display.scrollbarFiller || target == display.gutterFiller) return null;
-    }
-    var x, y, space = getRect(display.lineSpace);
-    // Fails unpredictably on IE[67] when mouse is dragged around quickly.
-    try { x = e.clientX; y = e.clientY; } catch (e) { return null; }
-    return coordsChar(cm, x - space.left, y - space.top);
-  }
-
-  var lastClick, lastDoubleClick;
-  function onMouseDown(e) {
-    if (signalDOMEvent(this, e)) return;
-    var cm = this, display = cm.display, doc = cm.doc, sel = doc.sel;
-    sel.shift = e.shiftKey;
-
-    if (eventInWidget(display, e)) {
-      if (!webkit) {
-        display.scroller.draggable = false;
-        setTimeout(function(){display.scroller.draggable = true;}, 100);
-      }
-      return;
-    }
-    if (clickInGutter(cm, e)) return;
-    var start = posFromMouse(cm, e);
-
-    switch (e_button(e)) {
-    case 3:
-      if (captureMiddleClick) onContextMenu.call(cm, cm, e);
-      return;
-    case 2:
-      if (webkit) cm.state.lastMiddleDown = +new Date;
-      if (start) extendSelection(cm.doc, start);
-      setTimeout(bind(focusInput, cm), 20);
-      e_preventDefault(e);
-      return;
-    }
-    // For button 1, if it was clicked inside the editor
-    // (posFromMouse returning non-null), we have to adjust the
-    // selection.
-    if (!start) {if (e_target(e) == display.scroller) e_preventDefault(e); return;}
-
-    if (!cm.state.focused) onFocus(cm);
-
-    var now = +new Date, type = "single";
-    if (lastDoubleClick && lastDoubleClick.time > now - 400 && posEq(lastDoubleClick.pos, start)) {
-      type = "triple";
-      e_preventDefault(e);
-      setTimeout(bind(focusInput, cm), 20);
-      selectLine(cm, start.line);
-    } else if (lastClick && lastClick.time > now - 400 && posEq(lastClick.pos, start)) {
-      type = "double";
-      lastDoubleClick = {time: now, pos: start};
-      e_preventDefault(e);
-      var word = findWordAt(getLine(doc, start.line).text, start);
-      extendSelection(cm.doc, word.from, word.to);
-    } else { lastClick = {time: now, pos: start}; }
-
-    var last = start;
-    if (cm.options.dragDrop && dragAndDrop && !isReadOnly(cm) && !posEq(sel.from, sel.to) &&
-        !posLess(start, sel.from) && !posLess(sel.to, start) && type == "single") {
-      var dragEnd = operation(cm, function(e2) {
-        if (webkit) display.scroller.draggable = false;
-        cm.state.draggingText = false;
-        off(document, "mouseup", dragEnd);
-        off(display.scroller, "drop", dragEnd);
-        if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) {
-          e_preventDefault(e2);
-          extendSelection(cm.doc, start);
-          focusInput(cm);
-        }
-      });
-      // Let the drag handler handle this.
-      if (webkit) display.scroller.draggable = true;
-      cm.state.draggingText = dragEnd;
-      // IE's approach to draggable
-      if (display.scroller.dragDrop) display.scroller.dragDrop();
-      on(document, "mouseup", dragEnd);
-      on(display.scroller, "drop", dragEnd);
-      return;
-    }
-    e_preventDefault(e);
-    if (type == "single") extendSelection(cm.doc, clipPos(doc, start));
-
-    var startstart = sel.from, startend = sel.to, lastPos = start;
-
-    function doSelect(cur) {
-      if (posEq(lastPos, cur)) return;
-      lastPos = cur;
-
-      if (type == "single") {
-        extendSelection(cm.doc, clipPos(doc, start), cur);
-        return;
-      }
-
-      startstart = clipPos(doc, startstart);
-      startend = clipPos(doc, startend);
-      if (type == "double") {
-        var word = findWordAt(getLine(doc, cur.line).text, cur);
-        if (posLess(cur, startstart)) extendSelection(cm.doc, word.from, startend);
-        else extendSelection(cm.doc, startstart, word.to);
-      } else if (type == "triple") {
-        if (posLess(cur, startstart)) extendSelection(cm.doc, startend, clipPos(doc, Pos(cur.line, 0)));
-        else extendSelection(cm.doc, startstart, clipPos(doc, Pos(cur.line + 1, 0)));
-      }
-    }
-
-    var editorSize = getRect(display.wrapper);
-    // Used to ensure timeout re-tries don't fire when another extend
-    // happened in the meantime (clearTimeout isn't reliable -- at
-    // least on Chrome, the timeouts still happen even when cleared,
-    // if the clear happens after their scheduled firing time).
-    var counter = 0;
-
-    function extend(e) {
-      var curCount = ++counter;
-      var cur = posFromMouse(cm, e, true);
-      if (!cur) return;
-      if (!posEq(cur, last)) {
-        if (!cm.state.focused) onFocus(cm);
-        last = cur;
-        doSelect(cur);
-        var visible = visibleLines(display, doc);
-        if (cur.line >= visible.to || cur.line < visible.from)
-          setTimeout(operation(cm, function(){if (counter == curCount) extend(e);}), 150);
-      } else {
-        var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0;
-        if (outside) setTimeout(operation(cm, function() {
-          if (counter != curCount) return;
-          display.scroller.scrollTop += outside;
-          extend(e);
-        }), 50);
-      }
-    }
-
-    function done(e) {
-      counter = Infinity;
-      e_preventDefault(e);
-      focusInput(cm);
-      off(document, "mousemove", move);
-      off(document, "mouseup", up);
-    }
-
-    var move = operation(cm, function(e) {
-      if (!ie && !e_button(e)) done(e);
-      else extend(e);
-    });
-    var up = operation(cm, done);
-    on(document, "mousemove", move);
-    on(document, "mouseup", up);
-  }
-
-  function gutterEvent(cm, e, type, prevent, signalfn) {
-    try { var mX = e.clientX, mY = e.clientY; }
-    catch(e) { return false; }
-    if (mX >= Math.floor(getRect(cm.display.gutters).right)) return false;
-    if (prevent) e_preventDefault(e);
-
-    var display = cm.display;
-    var lineBox = getRect(display.lineDiv);
-
-    if (mY > lineBox.bottom || !hasHandler(cm, type)) return e_defaultPrevented(e);
-    mY -= lineBox.top - display.viewOffset;
-
-    for (var i = 0; i < cm.options.gutters.length; ++i) {
-      var g = display.gutters.childNodes[i];
-      if (g && getRect(g).right >= mX) {
-        var line = lineAtHeight(cm.doc, mY);
-        var gutter = cm.options.gutters[i];
-        signalfn(cm, type, cm, line, gutter, e);
-        return e_defaultPrevented(e);
-      }
-    }
-  }
-
-  function contextMenuInGutter(cm, e) {
-    if (!hasHandler(cm, "gutterContextMenu")) return false;
-    return gutterEvent(cm, e, "gutterContextMenu", false, signal);
-  }
-
-  function clickInGutter(cm, e) {
-    return gutterEvent(cm, e, "gutterClick", true, signalLater);
-  }
-
-  // Kludge to work around strange IE behavior where it'll sometimes
-  // re-fire a series of drag-related events right after the drop (#1551)
-  var lastDrop = 0;
-
-  function onDrop(e) {
-    var cm = this;
-    if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e) || (cm.options.onDragEvent && cm.options.onDragEvent(cm, addStop(e))))
-      return;
-    e_preventDefault(e);
-    if (ie) lastDrop = +new Date;
-    var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;
-    if (!pos || isReadOnly(cm)) return;
-    if (files && files.length && window.FileReader && window.File) {
-      var n = files.length, text = Array(n), read = 0;
-      var loadFile = function(file, i) {
-        var reader = new FileReader;
-        reader.onload = function() {
-          text[i] = reader.result;
-          if (++read == n) {
-            pos = clipPos(cm.doc, pos);
-            makeChange(cm.doc, {from: pos, to: pos, text: splitLines(text.join("\n")), origin: "paste"}, "around");
-          }
-        };
-        reader.readAsText(file);
-      };
-      for (var i = 0; i < n; ++i) loadFile(files[i], i);
-    } else {
-      // Don't do a replace if the drop happened inside of the selected text.
-      if (cm.state.draggingText && !(posLess(pos, cm.doc.sel.from) || posLess(cm.doc.sel.to, pos))) {
-        cm.state.draggingText(e);
-        // Ensure the editor is re-focused
-        setTimeout(bind(focusInput, cm), 20);
-        return;
-      }
-      try {
-        var text = e.dataTransfer.getData("Text");
-        if (text) {
-          var curFrom = cm.doc.sel.from, curTo = cm.doc.sel.to;
-          setSelection(cm.doc, pos, pos);
-          if (cm.state.draggingText) replaceRange(cm.doc, "", curFrom, curTo, "paste");
-          cm.replaceSelection(text, null, "paste");
-          focusInput(cm);
-        }
-      }
-      catch(e){}
-    }
-  }
-
-  function onDragStart(cm, e) {
-    if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return; }
-    if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return;
-
-    var txt = cm.getSelection();
-    e.dataTransfer.setData("Text", txt);
-
-    // Use dummy image instead of default browsers image.
-    // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.
-    if (e.dataTransfer.setDragImage && !safari) {
-      var img = elt("img", null, null, "position: fixed; left: 0; top: 0;");
-      img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
-      if (opera) {
-        img.width = img.height = 1;
-        cm.display.wrapper.appendChild(img);
-        // Force a relayout, or Opera won't use our image for some obscure reason
-        img._top = img.offsetTop;
-      }
-      e.dataTransfer.setDragImage(img, 0, 0);
-      if (opera) img.parentNode.removeChild(img);
-    }
-  }
-
-  function setScrollTop(cm, val) {
-    if (Math.abs(cm.doc.scrollTop - val) < 2) return;
-    cm.doc.scrollTop = val;
-    if (!gecko) updateDisplay(cm, [], val);
-    if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val;
-    if (cm.display.scrollbarV.scrollTop != val) cm.display.scrollbarV.scrollTop = val;
-    if (gecko) updateDisplay(cm, []);
-    startWorker(cm, 100);
-  }
-  function setScrollLeft(cm, val, isScroller) {
-    if (isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) return;
-    val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth);
-    cm.doc.scrollLeft = val;
-    alignHorizontally(cm);
-    if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val;
-    if (cm.display.scrollbarH.scrollLeft != val) cm.display.scrollbarH.scrollLeft = val;
-  }
-
-  // Since the delta values reported on mouse wheel events are
-  // unstandardized between browsers and even browser versions, and
-  // generally horribly unpredictable, this code starts by measuring
-  // the scroll effect that the first few mouse wheel events have,
-  // and, from that, detects the way it can convert deltas to pixel
-  // offsets afterwards.
-  //
-  // The reason we want to know the amount a wheel event will scroll
-  // is that it gives us a chance to update the display before the
-  // actual scrolling happens, reducing flickering.
-
-  var wheelSamples = 0, wheelPixelsPerUnit = null;
-  // Fill in a browser-detected starting value on browsers where we
-  // know one. These don't have to be accurate -- the result of them
-  // being wrong would just be a slight flicker on the first wheel
-  // scroll (if it is large enough).
-  if (ie) wheelPixelsPerUnit = -.53;
-  else if (gecko) wheelPixelsPerUnit = 15;
-  else if (chrome) wheelPixelsPerUnit = -.7;
-  else if (safari) wheelPixelsPerUnit = -1/3;
-
-  function onScrollWheel(cm, e) {
-    var dx = e.wheelDeltaX, dy = e.wheelDeltaY;
-    if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail;
-    if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail;
-    else if (dy == null) dy = e.wheelDelta;
-
-    var display = cm.display, scroll = display.scroller;
-    // Quit if there's nothing to scroll here
-    if (!(dx && scroll.scrollWidth > scroll.clientWidth ||
-          dy && scroll.scrollHeight > scroll.clientHeight)) return;
-
-    // Webkit browsers on OS X abort momentum scrolls when the target
-    // of the scroll event is removed from the scrollable element.
-    // This hack (see related code in patchDisplay) makes sure the
-    // element is kept around.
-    if (dy && mac && webkit) {
-      for (var cur = e.target; cur != scroll; cur = cur.parentNode) {
-        if (cur.lineObj) {
-          cm.display.currentWheelTarget = cur;
-          break;
-        }
-      }
-    }
-
-    // On some browsers, horizontal scrolling will cause redraws to
-    // happen before the gutter has been realigned, causing it to
-    // wriggle around in a most unseemly way. When we have an
-    // estimated pixels/delta value, we just handle horizontal
-    // scrolling entirely here. It'll be slightly off from native, but
-    // better than glitching out.
-    if (dx && !gecko && !opera && wheelPixelsPerUnit != null) {
-      if (dy)
-        setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight)));
-      setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth)));
-      e_preventDefault(e);
-      display.wheelStartX = null; // Abort measurement, if in progress
-      return;
-    }
-
-    if (dy && wheelPixelsPerUnit != null) {
-      var pixels = dy * wheelPixelsPerUnit;
-      var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight;
-      if (pixels < 0) top = Math.max(0, top + pixels - 50);
-      else bot = Math.min(cm.doc.height, bot + pixels + 50);
-      updateDisplay(cm, [], {top: top, bottom: bot});
-    }
-
-    if (wheelSamples < 20) {
-      if (display.wheelStartX == null) {
-        display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop;
-        display.wheelDX = dx; display.wheelDY = dy;
-        setTimeout(function() {
-          if (display.wheelStartX == null) return;
-          var movedX = scroll.scrollLeft - display.wheelStartX;
-          var movedY = scroll.scrollTop - display.wheelStartY;
-          var sample = (movedY && display.wheelDY && movedY / display.wheelDY) ||
-            (movedX && display.wheelDX && movedX / display.wheelDX);
-          display.wheelStartX = display.wheelStartY = null;
-          if (!sample) return;
-          wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1);
-          ++wheelSamples;
-        }, 200);
-      } else {
-        display.wheelDX += dx; display.wheelDY += dy;
-      }
-    }
-  }
-
-  function doHandleBinding(cm, bound, dropShift) {
-    if (typeof bound == "string") {
-      bound = commands[bound];
-      if (!bound) return false;
-    }
-    // Ensure previous input has been read, so that the handler sees a
-    // consistent view of the document
-    if (cm.display.pollingFast && readInput(cm)) cm.display.pollingFast = false;
-    var doc = cm.doc, prevShift = doc.sel.shift, done = false;
-    try {
-      if (isReadOnly(cm)) cm.state.suppressEdits = true;
-      if (dropShift) doc.sel.shift = false;
-      done = bound(cm) != Pass;
-    } finally {
-      doc.sel.shift = prevShift;
-      cm.state.suppressEdits = false;
-    }
-    return done;
-  }
-
-  function allKeyMaps(cm) {
-    var maps = cm.state.keyMaps.slice(0);
-    if (cm.options.extraKeys) maps.push(cm.options.extraKeys);
-    maps.push(cm.options.keyMap);
-    return maps;
-  }
-
-  var maybeTransition;
-  function handleKeyBinding(cm, e) {
-    // Handle auto keymap transitions
-    var startMap = getKeyMap(cm.options.keyMap), next = startMap.auto;
-    clearTimeout(maybeTransition);
-    if (next && !isModifierKey(e)) maybeTransition = setTimeout(function() {
-      if (getKeyMap(cm.options.keyMap) == startMap) {
-        cm.options.keyMap = (next.call ? next.call(null, cm) : next);
-        keyMapChanged(cm);
-      }
-    }, 50);
-
-    var name = keyName(e, true), handled = false;
-    if (!name) return false;
-    var keymaps = allKeyMaps(cm);
-
-    if (e.shiftKey) {
-      // First try to resolve full name (including 'Shift-'). Failing
-      // that, see if there is a cursor-motion command (starting with
-      // 'go') bound to the keyname without 'Shift-'.
-      handled = lookupKey("Shift-" + name, keymaps, function(b) {return doHandleBinding(cm, b, true);})
-             || lookupKey(name, keymaps, function(b) {
-                  if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion)
-                    return doHandleBinding(cm, b);
-                });
-    } else {
-      handled = lookupKey(name, keymaps, function(b) { return doHandleBinding(cm, b); });
-    }
-
-    if (handled) {
-      e_preventDefault(e);
-      restartBlink(cm);
-      if (ie_lt9) { e.oldKeyCode = e.keyCode; e.keyCode = 0; }
-      signalLater(cm, "keyHandled", cm, name, e);
-    }
-    return handled;
-  }
-
-  function handleCharBinding(cm, e, ch) {
-    var handled = lookupKey("'" + ch + "'", allKeyMaps(cm),
-                            function(b) { return doHandleBinding(cm, b, true); });
-    if (handled) {
-      e_preventDefault(e);
-      restartBlink(cm);
-      signalLater(cm, "keyHandled", cm, "'" + ch + "'", e);
-    }
-    return handled;
-  }
-
-  var lastStoppedKey = null;
-  function onKeyDown(e) {
-    var cm = this;
-    if (!cm.state.focused) onFocus(cm);
-    if (signalDOMEvent(cm, e) || cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return;
-    if (ie && e.keyCode == 27) e.returnValue = false;
-    var code = e.keyCode;
-    // IE does strange things with escape.
-    cm.doc.sel.shift = code == 16 || e.shiftKey;
-    // First give onKeyEvent option a chance to handle this.
-    var handled = handleKeyBinding(cm, e);
-    if (opera) {
-      lastStoppedKey = handled ? code : null;
-      // Opera has no cut event... we try to at least catch the key combo
-      if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey))
-        cm.replaceSelection("");
-    }
-  }
-
-  function onKeyPress(e) {
-    var cm = this;
-    if (signalDOMEvent(cm, e) || cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return;
-    var keyCode = e.keyCode, charCode = e.charCode;
-    if (opera && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;}
-    if (((opera && (!e.which || e.which < 10)) || khtml) && handleKeyBinding(cm, e)) return;
-    var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
-    if (handleCharBinding(cm, e, ch)) return;
-    if (ie && !ie_lt9) cm.display.inputHasSelection = null;
-    fastPoll(cm);
-  }
-
-  function onFocus(cm) {
-    if (cm.options.readOnly == "nocursor") return;
-    if (!cm.state.focused) {
-      signal(cm, "focus", cm);
-      cm.state.focused = true;
-      if (cm.display.wrapper.className.search(/\bCodeMirror-focused\b/) == -1)
-        cm.display.wrapper.className += " CodeMirror-focused";
-      if (!cm.curOp) {
-        resetInput(cm, true);
-        if (webkit) setTimeout(bind(resetInput, cm, true), 0); // Issue #1730
-      }
-    }
-    slowPoll(cm);
-    restartBlink(cm);
-  }
-  function onBlur(cm) {
-    if (cm.state.focused) {
-      signal(cm, "blur", cm);
-      cm.state.focused = false;
-      cm.display.wrapper.className = cm.display.wrapper.className.replace(" CodeMirror-focused", "");
-    }
-    clearInterval(cm.display.blinker);
-    setTimeout(function() {if (!cm.state.focused) cm.doc.sel.shift = false;}, 150);
-  }
-
-  var detectingSelectAll;
-  function onContextMenu(cm, e) {
-    if (signalDOMEvent(cm, e, "contextmenu")) return;
-    var display = cm.display, sel = cm.doc.sel;
-    if (eventInWidget(display, e) || contextMenuInGutter(cm, e)) return;
-
-    var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
-    if (!pos || opera) return; // Opera is difficult.
-
-    // Reset the current text selection only if the click is done outside of the selection
-    // and 'resetSelectionOnContextMenu' option is true.
-    var reset = cm.options.resetSelectionOnContextMenu;
-    if (reset && (posEq(sel.from, sel.to) || posLess(pos, sel.from) || !posLess(pos, sel.to)))
-      operation(cm, setSelection)(cm.doc, pos, pos);
-
-    var oldCSS = display.input.style.cssText;
-    display.inputDiv.style.position = "absolute";
-    display.input.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) +
-      "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: transparent; outline: none;" +
-      "border-width: 0; outline: none; overflow: hidden; opacity: .05; -ms-opacity: .05; filter: alpha(opacity=5);";
-    focusInput(cm);
-    resetInput(cm, true);
-    // Adds "Select all" to context menu in FF
-    if (posEq(sel.from, sel.to)) display.input.value = display.prevInput = " ";
-
-    function prepareSelectAllHack() {
-      if (display.input.selectionStart != null) {
-        var extval = display.input.value = "\u200b" + (posEq(sel.from, sel.to) ? "" : display.input.value);
-        display.prevInput = "\u200b";
-        display.input.selectionStart = 1; display.input.selectionEnd = extval.length;
-      }
-    }
-    function rehide() {
-      display.inputDiv.style.position = "relative";
-      display.input.style.cssText = oldCSS;
-      if (ie_lt9) display.scrollbarV.scrollTop = display.scroller.scrollTop = scrollPos;
-      slowPoll(cm);
-
-      // Try to detect the user choosing select-all
-      if (display.input.selectionStart != null) {
-        if (!ie || ie_lt9) prepareSelectAllHack();
-        clearTimeout(detectingSelectAll);
-        var i = 0, poll = function(){
-          if (display.prevInput == "\u200b" && display.input.selectionStart == 0)
-            operation(cm, commands.selectAll)(cm);
-          else if (i++ < 10) detectingSelectAll = setTimeout(poll, 500);
-          else resetInput(cm);
-        };
-        detectingSelectAll = setTimeout(poll, 200);
-      }
-    }
-
-    if (ie && !ie_lt9) prepareSelectAllHack();
-    if (captureMiddleClick) {
-      e_stop(e);
-      var mouseup = function() {
-        off(window, "mouseup", mouseup);
-        setTimeout(rehide, 20);
-      };
-      on(window, "mouseup", mouseup);
-    } else {
-      setTimeout(rehide, 50);
-    }
-  }
-
-  // UPDATING
-
-  var changeEnd = CodeMirror.changeEnd = function(change) {
-    if (!change.text) return change.to;
-    return Pos(change.from.line + change.text.length - 1,
-               lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0));
-  };
-
-  // Make sure a position will be valid after the given change.
-  function clipPostChange(doc, change, pos) {
-    if (!posLess(change.from, pos)) return clipPos(doc, pos);
-    var diff = (change.text.length - 1) - (change.to.line - change.from.line);
-    if (pos.line > change.to.line + diff) {
-      var preLine = pos.line - diff, lastLine = doc.first + doc.size - 1;
-      if (preLine > lastLine) return Pos(lastLine, getLine(doc, lastLine).text.length);
-      return clipToLen(pos, getLine(doc, preLine).text.length);
-    }
-    if (pos.line == change.to.line + diff)
-      return clipToLen(pos, lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0) +
-                       getLine(doc, change.to.line).text.length - change.to.ch);
-    var inside = pos.line - change.from.line;
-    return clipToLen(pos, change.text[inside].length + (inside ? 0 : change.from.ch));
-  }
-
-  // Hint can be null|"end"|"start"|"around"|{anchor,head}
-  function computeSelAfterChange(doc, change, hint) {
-    if (hint && typeof hint == "object") // Assumed to be {anchor, head} object
-      return {anchor: clipPostChange(doc, change, hint.anchor),
-              head: clipPostChange(doc, change, hint.head)};
-
-    if (hint == "start") return {anchor: change.from, head: change.from};
-
-    var end = changeEnd(change);
-    if (hint == "around") return {anchor: change.from, head: end};
-    if (hint == "end") return {anchor: end, head: end};
-
-    // hint is null, leave the selection alone as much as possible
-    var adjustPos = function(pos) {
-      if (posLess(pos, change.from)) return pos;
-      if (!posLess(change.to, pos)) return end;
-
-      var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch;
-      if (pos.line == change.to.line) ch += end.ch - change.to.ch;
-      return Pos(line, ch);
-    };
-    return {anchor: adjustPos(doc.sel.anchor), head: adjustPos(doc.sel.head)};
-  }
-
-  function filterChange(doc, change, update) {
-    var obj = {
-      canceled: false,
-      from: change.from,
-      to: change.to,
-      text: change.text,
-      origin: change.origin,
-      cancel: function() { this.canceled = true; }
-    };
-    if (update) obj.update = function(from, to, text, origin) {
-      if (from) this.from = clipPos(doc, from);
-      if (to) this.to = clipPos(doc, to);
-      if (text) this.text = text;
-      if (origin !== undefined) this.origin = origin;
-    };
-    signal(doc, "beforeChange", doc, obj);
-    if (doc.cm) signal(doc.cm, "beforeChange", doc.cm, obj);
-
-    if (obj.canceled) return null;
-    return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin};
-  }
-
-  // Replace the range from from to to by the strings in replacement.
-  // change is a {from, to, text [, origin]} object
-  function makeChange(doc, change, selUpdate, ignoreReadOnly) {
-    if (doc.cm) {
-      if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, selUpdate, ignoreReadOnly);
-      if (doc.cm.state.suppressEdits) return;
-    }
-
-    if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) {
-      change = filterChange(doc, change, true);
-      if (!change) return;
-    }
-
-    // Possibly split or suppress the update based on the presence
-    // of read-only spans in its range.
-    var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to);
-    if (split) {
-      for (var i = split.length - 1; i >= 1; --i)
-        makeChangeNoReadonly(doc, {from: split[i].from, to: split[i].to, text: [""]});
-      if (split.length)
-        makeChangeNoReadonly(doc, {from: split[0].from, to: split[0].to, text: change.text}, selUpdate);
-    } else {
-      makeChangeNoReadonly(doc, change, selUpdate);
-    }
-  }
-
-  function makeChangeNoReadonly(doc, change, selUpdate) {
-    if (change.text.length == 1 && change.text[0] == "" && posEq(change.from, change.to)) return;
-    var selAfter = computeSelAfterChange(doc, change, selUpdate);
-    addToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN);
-
-    makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change));
-    var rebased = [];
-
-    linkedDocs(doc, function(doc, sharedHist) {
-      if (!sharedHist && indexOf(rebased, doc.history) == -1) {
-        rebaseHist(doc.history, change);
-        rebased.push(doc.history);
-      }
-      makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change));
-    });
-  }
-
-  function makeChangeFromHistory(doc, type) {
-    if (doc.cm && doc.cm.state.suppressEdits) return;
-
-    var hist = doc.history;
-    var event = (type == "undo" ? hist.done : hist.undone).pop();
-    if (!event) return;
-
-    var anti = {changes: [], anchorBefore: event.anchorAfter, headBefore: event.headAfter,
-                anchorAfter: event.anchorBefore, headAfter: event.headBefore,
-                generation: hist.generation};
-    (type == "undo" ? hist.undone : hist.done).push(anti);
-    hist.generation = event.generation || ++hist.maxGeneration;
-
-    var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange");
-
-    for (var i = event.changes.length - 1; i >= 0; --i) {
-      var change = event.changes[i];
-      change.origin = type;
-      if (filter && !filterChange(doc, change, false)) {
-        (type == "undo" ? hist.done : hist.undone).length = 0;
-        return;
-      }
-
-      anti.changes.push(historyChangeFromChange(doc, change));
-
-      var after = i ? computeSelAfterChange(doc, change, null)
-                    : {anchor: event.anchorBefore, head: event.headBefore};
-      makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change));
-      var rebased = [];
-
-      linkedDocs(doc, function(doc, sharedHist) {
-        if (!sharedHist && indexOf(rebased, doc.history) == -1) {
-          rebaseHist(doc.history, change);
-          rebased.push(doc.history);
-        }
-        makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change));
-      });
-    }
-  }
-
-  function shiftDoc(doc, distance) {
-    function shiftPos(pos) {return Pos(pos.line + distance, pos.ch);}
-    doc.first += distance;
-    if (doc.cm) regChange(doc.cm, doc.first, doc.first, distance);
-    doc.sel.head = shiftPos(doc.sel.head); doc.sel.anchor = shiftPos(doc.sel.anchor);
-    doc.sel.from = shiftPos(doc.sel.from); doc.sel.to = shiftPos(doc.sel.to);
-  }
-
-  function makeChangeSingleDoc(doc, change, selAfter, spans) {
-    if (doc.cm && !doc.cm.curOp)
-      return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans);
-
-    if (change.to.line < doc.first) {
-      shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line));
-      return;
-    }
-    if (change.from.line > doc.lastLine()) return;
-
-    // Clip the change to the size of this doc
-    if (change.from.line < doc.first) {
-      var shift = change.text.length - 1 - (doc.first - change.from.line);
-      shiftDoc(doc, shift);
-      change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch),
-                text: [lst(change.text)], origin: change.origin};
-    }
-    var last = doc.lastLine();
-    if (change.to.line > last) {
-      change = {from: change.from, to: Pos(last, getLine(doc, last).text.length),
-                text: [change.text[0]], origin: change.origin};
-    }
-
-    change.removed = getBetween(doc, change.from, change.to);
-
-    if (!selAfter) selAfter = computeSelAfterChange(doc, change, null);
-    if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans, selAfter);
-    else updateDoc(doc, change, spans, selAfter);
-  }
-
-  function makeChangeSingleDocInEditor(cm, change, spans, selAfter) {
-    var doc = cm.doc, display = cm.display, from = change.from, to = change.to;
-
-    var recomputeMaxLength = false, checkWidthStart = from.line;
-    if (!cm.options.lineWrapping) {
-      checkWidthStart = lineNo(visualLine(doc, getLine(doc, from.line)));
-      doc.iter(checkWidthStart, to.line + 1, function(line) {
-        if (line == display.maxLine) {
-          recomputeMaxLength = true;
-          return true;
-        }
-      });
-    }
-
-    if (!posLess(doc.sel.head, change.from) && !posLess(change.to, doc.sel.head))
-      cm.curOp.cursorActivity = true;
-
-    updateDoc(doc, change, spans, selAfter, estimateHeight(cm));
-
-    if (!cm.options.lineWrapping) {
-      doc.iter(checkWidthStart, from.line + change.text.length, function(line) {
-        var len = lineLength(doc, line);
-        if (len > display.maxLineLength) {
-          display.maxLine = line;
-          display.maxLineLength = len;
-          display.maxLineChanged = true;
-          recomputeMaxLength = false;
-        }
-      });
-      if (recomputeMaxLength) cm.curOp.updateMaxLine = true;
-    }
-
-    // Adjust frontier, schedule worker
-    doc.frontier = Math.min(doc.frontier, from.line);
-    startWorker(cm, 400);
-
-    var lendiff = change.text.length - (to.line - from.line) - 1;
-    // Remember that these lines changed, for updating the display
-    regChange(cm, from.line, to.line + 1, lendiff);
-
-    if (hasHandler(cm, "change")) {
-      var changeObj = {from: from, to: to,
-                       text: change.text,
-                       removed: change.removed,
-                       origin: change.origin};
-      if (cm.curOp.textChanged) {
-        for (var cur = cm.curOp.textChanged; cur.next; cur = cur.next) {}
-        cur.next = changeObj;
-      } else cm.curOp.textChanged = changeObj;
-    }
-  }
-
-  function replaceRange(doc, code, from, to, origin) {
-    if (!to) to = from;
-    if (posLess(to, from)) { var tmp = to; to = from; from = tmp; }
-    if (typeof code == "string") code = splitLines(code);
-    makeChange(doc, {from: from, to: to, text: code, origin: origin}, null);
-  }
-
-  // POSITION OBJECT
-
-  function Pos(line, ch) {
-    if (!(this instanceof Pos)) return new Pos(line, ch);
-    this.line = line; this.ch = ch;
-  }
-  CodeMirror.Pos = Pos;
-
-  function posEq(a, b) {return a.line == b.line && a.ch == b.ch;}
-  function posLess(a, b) {return a.line < b.line || (a.line == b.line && a.ch < b.ch);}
-  function cmp(a, b) {return a.line - b.line || a.ch - b.ch;}
-  function copyPos(x) {return Pos(x.line, x.ch);}
-
-  // SELECTION
-
-  function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1));}
-  function clipPos(doc, pos) {
-    if (pos.line < doc.first) return Pos(doc.first, 0);
-    var last = doc.first + doc.size - 1;
-    if (pos.line > last) return Pos(last, getLine(doc, last).text.length);
-    return clipToLen(pos, getLine(doc, pos.line).text.length);
-  }
-  function clipToLen(pos, linelen) {
-    var ch = pos.ch;
-    if (ch == null || ch > linelen) return Pos(pos.line, linelen);
-    else if (ch < 0) return Pos(pos.line, 0);
-    else return pos;
-  }
-  function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size;}
-
-  // If shift is held, this will move the selection anchor. Otherwise,
-  // it'll set the whole selection.
-  function extendSelection(doc, pos, other, bias) {
-    if (doc.sel.shift || doc.sel.extend) {
-      var anchor = doc.sel.anchor;
-      if (other) {
-        var posBefore = posLess(pos, anchor);
-        if (posBefore != posLess(other, anchor)) {
-          anchor = pos;
-          pos = other;
-        } else if (posBefore != posLess(pos, other)) {
-          pos = other;
-        }
-      }
-      setSelection(doc, anchor, pos, bias);
-    } else {
-      setSelection(doc, pos, other || pos, bias);
-    }
-    if (doc.cm) doc.cm.curOp.userSelChange = true;
-  }
-
-  function filterSelectionChange(doc, anchor, head) {
-    var obj = {anchor: anchor, head: head};
-    signal(doc, "beforeSelectionChange", doc, obj);
-    if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj);
-    obj.anchor = clipPos(doc, obj.anchor); obj.head = clipPos(doc, obj.head);
-    return obj;
-  }
-
-  // Update the selection. Last two args are only used by
-  // updateDoc, since they have to be expressed in the line
-  // numbers before the update.
-  function setSelection(doc, anchor, head, bias, checkAtomic) {
-    if (!checkAtomic && hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange")) {
-      var filtered = filterSelectionChange(doc, anchor, head);
-      head = filtered.head;
-      anchor = filtered.anchor;
-    }
-
-    var sel = doc.sel;
-    sel.goalColumn = null;
-    if (bias == null) bias = posLess(head, sel.head) ? -1 : 1;
-    // Skip over atomic spans.
-    if (checkAtomic || !posEq(anchor, sel.anchor))
-      anchor = skipAtomic(doc, anchor, bias, checkAtomic != "push");
-    if (checkAtomic || !posEq(head, sel.head))
-      head = skipAtomic(doc, head, bias, checkAtomic != "push");
-
-    if (posEq(sel.anchor, anchor) && posEq(sel.head, head)) return;
-
-    sel.anchor = anchor; sel.head = head;
-    var inv = posLess(head, anchor);
-    sel.from = inv ? head : anchor;
-    sel.to = inv ? anchor : head;
-
-    if (doc.cm)
-      doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged =
-        doc.cm.curOp.cursorActivity = true;
-
-    signalLater(doc, "cursorActivity", doc);
-  }
-
-  function reCheckSelection(cm) {
-    setSelection(cm.doc, cm.doc.sel.from, cm.doc.sel.to, null, "push");
-  }
-
-  function skipAtomic(doc, pos, bias, mayClear) {
-    var flipped = false, curPos = pos;
-    var dir = bias || 1;
-    doc.cantEdit = false;
-    search: for (;;) {
-      var line = getLine(doc, curPos.line);
-      if (line.markedSpans) {
-        for (var i = 0; i < line.markedSpans.length; ++i) {
-          var sp = line.markedSpans[i], m = sp.marker;
-          if ((sp.from == null || (m.inclusiveLeft ? sp.from <= curPos.ch : sp.from < curPos.ch)) &&
-              (sp.to == null || (m.inclusiveRight ? sp.to >= curPos.ch : sp.to > curPos.ch))) {
-            if (mayClear) {
-              signal(m, "beforeCursorEnter");
-              if (m.explicitlyCleared) {
-                if (!line.markedSpans) break;
-                else {--i; continue;}
-              }
-            }
-            if (!m.atomic) continue;
-            var newPos = m.find()[dir < 0 ? "from" : "to"];
-            if (posEq(newPos, curPos)) {
-              newPos.ch += dir;
-              if (newPos.ch < 0) {
-                if (newPos.line > doc.first) newPos = clipPos(doc, Pos(newPos.line - 1));
-                else newPos = null;
-              } else if (newPos.ch > line.text.length) {
-                if (newPos.line < doc.first + doc.size - 1) newPos = Pos(newPos.line + 1, 0);
-                else newPos = null;
-              }
-              if (!newPos) {
-                if (flipped) {
-                  // Driven in a corner -- no valid cursor position found at all
-                  // -- try again *with* clearing, if we didn't already
-                  if (!mayClear) return skipAtomic(doc, pos, bias, true);
-                  // Otherwise, turn off editing until further notice, and return the start of the doc
-                  doc.cantEdit = true;
-                  return Pos(doc.first, 0);
-                }
-                flipped = true; newPos = pos; dir = -dir;
-              }
-            }
-            curPos = newPos;
-            continue search;
-          }
-        }
-      }
-      return curPos;
-    }
-  }
-
-  // SCROLLING
-
-  function scrollCursorIntoView(cm) {
-    var coords = scrollPosIntoView(cm, cm.doc.sel.head, null, cm.options.cursorScrollMargin);
-    if (!cm.state.focused) return;
-    var display = cm.display, box = getRect(display.sizer), doScroll = null;
-    if (coords.top + box.top < 0) doScroll = true;
-    else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false;
-    if (doScroll != null && !phantom) {
-      var scrollNode = elt("div", "\u200b", null, "position: absolute; top: " +
-                           (coords.top - display.viewOffset) + "px; height: " +
-                           (coords.bottom - coords.top + scrollerCutOff) + "px; left: " +
-                           coords.left + "px; width: 2px;");
-      cm.display.lineSpace.appendChild(scrollNode);
-      scrollNode.scrollIntoView(doScroll);
-      cm.display.lineSpace.removeChild(scrollNode);
-    }
-  }
-
-  function scrollPosIntoView(cm, pos, end, margin) {
-    if (margin == null) margin = 0;
-    for (;;) {
-      var changed = false, coords = cursorCoords(cm, pos);
-      var endCoords = !end || end == pos ? coords : cursorCoords(cm, end);
-      var scrollPos = calculateScrollPos(cm, Math.min(coords.left, endCoords.left),
-                                         Math.min(coords.top, endCoords.top) - margin,
-                                         Math.max(coords.left, endCoords.left),
-                                         Math.max(coords.bottom, endCoords.bottom) + margin);
-      var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft;
-      if (scrollPos.scrollTop != null) {
-        setScrollTop(cm, scrollPos.scrollTop);
-        if (Math.abs(cm.doc.scrollTop - startTop) > 1) changed = true;
-      }
-      if (scrollPos.scrollLeft != null) {
-        setScrollLeft(cm, scrollPos.scrollLeft);
-        if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) changed = true;
-      }
-      if (!changed) return coords;
-    }
-  }
-
-  function scrollIntoView(cm, x1, y1, x2, y2) {
-    var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2);
-    if (scrollPos.scrollTop != null) setScrollTop(cm, scrollPos.scrollTop);
-    if (scrollPos.scrollLeft != null) setScrollLeft(cm, scrollPos.scrollLeft);
-  }
-
-  function calculateScrollPos(cm, x1, y1, x2, y2) {
-    var display = cm.display, snapMargin = textHeight(cm.display);
-    if (y1 < 0) y1 = 0;
-    var screen = display.scroller.clientHeight - scrollerCutOff, screentop = display.scroller.scrollTop, result = {};
-    var docBottom = cm.doc.height + paddingVert(display);
-    var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin;
-    if (y1 < screentop) {
-      result.scrollTop = atTop ? 0 : y1;
-    } else if (y2 > screentop + screen) {
-      var newTop = Math.min(y1, (atBottom ? docBottom : y2) - screen);
-      if (newTop != screentop) result.scrollTop = newTop;
-    }
-
-    var screenw = display.scroller.clientWidth - scrollerCutOff, screenleft = display.scroller.scrollLeft;
-    x1 += display.gutters.offsetWidth; x2 += display.gutters.offsetWidth;
-    var gutterw = display.gutters.offsetWidth;
-    var atLeft = x1 < gutterw + 10;
-    if (x1 < screenleft + gutterw || atLeft) {
-      if (atLeft) x1 = 0;
-      result.scrollLeft = Math.max(0, x1 - 10 - gutterw);
-    } else if (x2 > screenw + screenleft - 3) {
-      result.scrollLeft = x2 + 10 - screenw;
-    }
-    return result;
-  }
-
-  function updateScrollPos(cm, left, top) {
-    cm.curOp.updateScrollPos = {scrollLeft: left == null ? cm.doc.scrollLeft : left,
-                                scrollTop: top == null ? cm.doc.scrollTop : top};
-  }
-
-  function addToScrollPos(cm, left, top) {
-    var pos = cm.curOp.updateScrollPos || (cm.curOp.updateScrollPos = {scrollLeft: cm.doc.scrollLeft, scrollTop: cm.doc.scrollTop});
-    var scroll = cm.display.scroller;
-    pos.scrollTop = Math.max(0, Math.min(scroll.scrollHeight - scroll.clientHeight, pos.scrollTop + top));
-    pos.scrollLeft = Math.max(0, Math.min(scroll.scrollWidth - scroll.clientWidth, pos.scrollLeft + left));
-  }
-
-  // API UTILITIES
-
-  function indentLine(cm, n, how, aggressive) {
-    var doc = cm.doc;
-    if (how == null) how = "add";
-    if (how == "smart") {
-      if (!cm.doc.mode.indent) how = "prev";
-      else var state = getStateBefore(cm, n);
-    }
-
-    var tabSize = cm.options.tabSize;
-    var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize);
-    var curSpaceString = line.text.match(/^\s*/)[0], indentation;
-    if (!aggressive && !/\S/.test(line.text)) {
-      indentation = 0;
-      how = "not";
-    } else if (how == "smart") {
-      indentation = cm.doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);
-      if (indentation == Pass) {
-        if (!aggressive) return;
-        how = "prev";
-      }
-    }
-    if (how == "prev") {
-      if (n > doc.first) indentation = countColumn(getLine(doc, n-1).text, null, tabSize);
-      else indentation = 0;
-    } else if (how == "add") {
-      indentation = curSpace + cm.options.indentUnit;
-    } else if (how == "subtract") {
-      indentation = curSpace - cm.options.indentUnit;
-    } else if (typeof how == "number") {
-      indentation = curSpace + how;
-    }
-    indentation = Math.max(0, indentation);
-
-    var indentString = "", pos = 0;
-    if (cm.options.indentWithTabs)
-      for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";}
-    if (pos < indentation) indentString += spaceStr(indentation - pos);
-
-    if (indentString != curSpaceString)
-      replaceRange(cm.doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input");
-    else if (doc.sel.head.line == n && doc.sel.head.ch < curSpaceString.length)
-      setSelection(doc, Pos(n, curSpaceString.length), Pos(n, curSpaceString.length), 1);
-    line.stateAfter = null;
-  }
-
-  function changeLine(cm, handle, op) {
-    var no = handle, line = handle, doc = cm.doc;
-    if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle));
-    else no = lineNo(handle);
-    if (no == null) return null;
-    if (op(line, no)) regChange(cm, no, no + 1);
-    else return null;
-    return line;
-  }
-
-  function findPosH(doc, pos, dir, unit, visually) {
-    var line = pos.line, ch = pos.ch, origDir = dir;
-    var lineObj = getLine(doc, line);
-    var possible = true;
-    function findNextLine() {
-      var l = line + dir;
-      if (l < doc.first || l >= doc.first + doc.size) return (possible = false);
-      line = l;
-      return lineObj = getLine(doc, l);
-    }
-    function moveOnce(boundToLine) {
-      var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true);
-      if (next == null) {
-        if (!boundToLine && findNextLine()) {
-          if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj);
-          else ch = dir < 0 ? lineObj.text.length : 0;
-        } else return (possible = false);
-      } else ch = next;
-      return true;
-    }
-
-    if (unit == "char") moveOnce();
-    else if (unit == "column") moveOnce(true);
-    else if (unit == "word" || unit == "group") {
-      var sawType = null, group = unit == "group";
-      for (var first = true;; first = false) {
-        if (dir < 0 && !moveOnce(!first)) break;
-        var cur = lineObj.text.charAt(ch) || "\n";
-        var type = isWordChar(cur) ? "w"
-          : !group ? null
-          : /\s/.test(cur) ? null
-          : "p";
-        if (sawType && sawType != type) {
-          if (dir < 0) {dir = 1; moveOnce();}
-          break;
-        }
-        if (type) sawType = type;
-        if (dir > 0 && !moveOnce(!first)) break;
-      }
-    }
-    var result = skipAtomic(doc, Pos(line, ch), origDir, true);
-    if (!possible) result.hitSide = true;
-    return result;
-  }
-
-  function findPosV(cm, pos, dir, unit) {
-    var doc = cm.doc, x = pos.left, y;
-    if (unit == "page") {
-      var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight);
-      y = pos.top + dir * (pageSize - (dir < 0 ? 1.5 : .5) * textHeight(cm.display));
-    } else if (unit == "line") {
-      y = dir > 0 ? pos.bottom + 3 : pos.top - 3;
-    }
-    for (;;) {
-      var target = coordsChar(cm, x, y);
-      if (!target.outside) break;
-      if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break; }
-      y += dir * 5;
-    }
-    return target;
-  }
-
-  function findWordAt(line, pos) {
-    var start = pos.ch, end = pos.ch;
-    if (line) {
-      if ((pos.xRel < 0 || end == line.length) && start) --start; else ++end;
-      var startChar = line.charAt(start);
-      var check = isWordChar(startChar) ? isWordChar
-        : /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);}
-        : function(ch) {return !/\s/.test(ch) && !isWordChar(ch);};
-      while (start > 0 && check(line.charAt(start - 1))) --start;
-      while (end < line.length && check(line.charAt(end))) ++end;
-    }
-    return {from: Pos(pos.line, start), to: Pos(pos.line, end)};
-  }
-
-  function selectLine(cm, line) {
-    extendSelection(cm.doc, Pos(line, 0), clipPos(cm.doc, Pos(line + 1, 0)));
-  }
-
-  // PROTOTYPE
-
-  // The publicly visible API. Note that operation(null, f) means
-  // 'wrap f in an operation, performed on its `this` parameter'
-
-  CodeMirror.prototype = {
-    constructor: CodeMirror,
-    focus: function(){window.focus(); focusInput(this); fastPoll(this);},
-
-    setOption: function(option, value) {
-      var options = this.options, old = options[option];
-      if (options[option] == value && option != "mode") return;
-      options[option] = value;
-      if (optionHandlers.hasOwnProperty(option))
-        operation(this, optionHandlers[option])(this, value, old);
-    },
-
-    getOption: function(option) {return this.options[option];},
-    getDoc: function() {return this.doc;},
-
-    addKeyMap: function(map, bottom) {
-      this.state.keyMaps[bottom ? "push" : "unshift"](map);
-    },
-    removeKeyMap: function(map) {
-      var maps = this.state.keyMaps;
-      for (var i = 0; i < maps.length; ++i)
-        if (maps[i] == map || (typeof maps[i] != "string" && maps[i].name == map)) {
-          maps.splice(i, 1);
-          return true;
-        }
-    },
-
-    addOverlay: operation(null, function(spec, options) {
-      var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec);
-      if (mode.startState) throw new Error("Overlays may not be stateful.");
-      this.state.overlays.push({mode: mode, modeSpec: spec, opaque: options && options.opaque});
-      this.state.modeGen++;
-      regChange(this);
-    }),
-    removeOverlay: operation(null, function(spec) {
-      var overlays = this.state.overlays;
-      for (var i = 0; i < overlays.length; ++i) {
-        var cur = overlays[i].modeSpec;
-        if (cur == spec || typeof spec == "string" && cur.name == spec) {
-          overlays.splice(i, 1);
-          this.state.modeGen++;
-          regChange(this);
-          return;
-        }
-      }
-    }),
-
-    indentLine: operation(null, function(n, dir, aggressive) {
-      if (typeof dir != "string" && typeof dir != "number") {
-        if (dir == null) dir = this.options.smartIndent ? "smart" : "prev";
-        else dir = dir ? "add" : "subtract";
-      }
-      if (isLine(this.doc, n)) indentLine(this, n, dir, aggressive);
-    }),
-    indentSelection: operation(null, function(how) {
-      var sel = this.doc.sel;
-      if (posEq(sel.from, sel.to)) return indentLine(this, sel.from.line, how, true);
-      var e = sel.to.line - (sel.to.ch ? 0 : 1);
-      for (var i = sel.from.line; i <= e; ++i) indentLine(this, i, how);
-    }),
-
-    // Fetch the parser token for a given character. Useful for hacks
-    // that want to inspect the mode state (say, for completion).
-    getTokenAt: function(pos, precise) {
-      var doc = this.doc;
-      pos = clipPos(doc, pos);
-      var state = getStateBefore(this, pos.line, precise), mode = this.doc.mode;
-      var line = getLine(doc, pos.line);
-      var stream = new StringStream(line.text, this.options.tabSize);
-      while (stream.pos < pos.ch && !stream.eol()) {
-        stream.start = stream.pos;
-        var style = mode.token(stream, state);
-      }
-      return {start: stream.start,
-              end: stream.pos,
-              string: stream.current(),
-              className: style || null, // Deprecated, use 'type' instead
-              type: style || null,
-              state: state};
-    },
-
-    getTokenTypeAt: function(pos) {
-      pos = clipPos(this.doc, pos);
-      var styles = getLineStyles(this, getLine(this.doc, pos.line));
-      var before = 0, after = (styles.length - 1) / 2, ch = pos.ch;
-      if (ch == 0) return styles[2];
-      for (;;) {
-        var mid = (before + after) >> 1;
-        if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid;
-        else if (styles[mid * 2 + 1] < ch) before = mid + 1;
-        else return styles[mid * 2 + 2];
-      }
-    },
-
-    getModeAt: function(pos) {
-      var mode = this.doc.mode;
-      if (!mode.innerMode) return mode;
-      return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode;
-    },
-
-    getHelper: function(pos, type) {
-      return this.getHelpers(pos, type)[0];
-    },
-
-    getHelpers: function(pos, type) {
-      var found = [];
-      if (!helpers.hasOwnProperty(type)) return helpers;
-      var help = helpers[type], mode = this.getModeAt(pos);
-      if (typeof mode[type] == "string") {
-        if (help[mode[type]]) found.push(help[mode[type]]);
-      } else if (mode[type]) {
-        for (var i = 0; i < mode[type].length; i++) {
-          var val = help[mode[type][i]];
-          if (val) found.push(val);
-        }
-      } else if (mode.helperType && help[mode.helperType]) {
-        found.push(help[mode.helperType]);
-      } else if (help[mode.name]) {
-        found.push(help[mode.name]);
-      }
-      for (var i = 0; i < help._global.length; i++) {
-        var cur = help._global[i];
-        if (cur.pred(mode, this) && indexOf(found, cur.val) == -1)
-          found.push(cur.val);
-      }
-      return found;
-    },
-
-    getStateAfter: function(line, precise) {
-      var doc = this.doc;
-      line = clipLine(doc, line == null ? doc.first + doc.size - 1: line);
-      return getStateBefore(this, line + 1, precise);
-    },
-
-    cursorCoords: function(start, mode) {
-      var pos, sel = this.doc.sel;
-      if (start == null) pos = sel.head;
-      else if (typeof start == "object") pos = clipPos(this.doc, start);
-      else pos = start ? sel.from : sel.to;
-      return cursorCoords(this, pos, mode || "page");
-    },
-
-    charCoords: function(pos, mode) {
-      return charCoords(this, clipPos(this.doc, pos), mode || "page");
-    },
-
-    coordsChar: function(coords, mode) {
-      coords = fromCoordSystem(this, coords, mode || "page");
-      return coordsChar(this, coords.left, coords.top);
-    },
-
-    lineAtHeight: function(height, mode) {
-      height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top;
-      return lineAtHeight(this.doc, height + this.display.viewOffset);
-    },
-    heightAtLine: function(line, mode) {
-      var end = false, last = this.doc.first + this.doc.size - 1;
-      if (line < this.doc.first) line = this.doc.first;
-      else if (line > last) { line = last; end = true; }
-      var lineObj = getLine(this.doc, line);
-      return intoCoordSystem(this, getLine(this.doc, line), {top: 0, left: 0}, mode || "page").top +
-        (end ? lineObj.height : 0);
-    },
-
-    defaultTextHeight: function() { return textHeight(this.display); },
-    defaultCharWidth: function() { return charWidth(this.display); },
-
-    setGutterMarker: operation(null, function(line, gutterID, value) {
-      return changeLine(this, line, function(line) {
-        var markers = line.gutterMarkers || (line.gutterMarkers = {});
-        markers[gutterID] = value;
-        if (!value && isEmpty(markers)) line.gutterMarkers = null;
-        return true;
-      });
-    }),
-
-    clearGutter: operation(null, function(gutterID) {
-      var cm = this, doc = cm.doc, i = doc.first;
-      doc.iter(function(line) {
-        if (line.gutterMarkers && line.gutterMarkers[gutterID]) {
-          line.gutterMarkers[gutterID] = null;
-          regChange(cm, i, i + 1);
-          if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null;
-        }
-        ++i;
-      });
-    }),
-
-    addLineClass: operation(null, function(handle, where, cls) {
-      return changeLine(this, handle, function(line) {
-        var prop = where == "text" ? "textClass" : where == "background" ? "bgClass" : "wrapClass";
-        if (!line[prop]) line[prop] = cls;
-        else if (new RegExp("(?:^|\\s)" + cls + "(?:$|\\s)").test(line[prop])) return false;
-        else line[prop] += " " + cls;
-        return true;
-      });
-    }),
-
-    removeLineClass: operation(null, function(handle, where, cls) {
-      return changeLine(this, handle, function(line) {
-        var prop = where == "text" ? "textClass" : where == "background" ? "bgClass" : "wrapClass";
-        var cur = line[prop];
-        if (!cur) return false;
-        else if (cls == null) line[prop] = null;
-        else {
-          var found = cur.match(new RegExp("(?:^|\\s+)" + cls + "(?:$|\\s+)"));
-          if (!found) return false;
-          var end = found.index + found[0].length;
-          line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null;
-        }
-        return true;
-      });
-    }),
-
-    addLineWidget: operation(null, function(handle, node, options) {
-      return addLineWidget(this, handle, node, options);
-    }),
-
-    removeLineWidget: function(widget) { widget.clear(); },
-
-    lineInfo: function(line) {
-      if (typeof line == "number") {
-        if (!isLine(this.doc, line)) return null;
-        var n = line;
-        line = getLine(this.doc, line);
-        if (!line) return null;
-      } else {
-        var n = lineNo(line);
-        if (n == null) return null;
-      }
-      return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers,
-              textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass,
-              widgets: line.widgets};
-    },
-
-    getViewport: function() { return {from: this.display.showingFrom, to: this.display.showingTo};},
-
-    addWidget: function(pos, node, scroll, vert, horiz) {
-      var display = this.display;
-      pos = cursorCoords(this, clipPos(this.doc, pos));
-      var top = pos.bottom, left = pos.left;
-      node.style.position = "absolute";
-      display.sizer.appendChild(node);
-      if (vert == "over") {
-        top = pos.top;
-      } else if (vert == "above" || vert == "near") {
-        var vspace = Math.max(display.wrapper.clientHeight, this.doc.height),
-        hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth);
-        // Default to positioning above (if specified and possible); otherwise default to positioning below
-        if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight)
-          top = pos.top - node.offsetHeight;
-        else if (pos.bottom + node.offsetHeight <= vspace)
-          top = pos.bottom;
-        if (left + node.offsetWidth > hspace)
-          left = hspace - node.offsetWidth;
-      }
-      node.style.top = top + "px";
-      node.style.left = node.style.right = "";
-      if (horiz == "right") {
-        left = display.sizer.clientWidth - node.offsetWidth;
-        node.style.right = "0px";
-      } else {
-        if (horiz == "left") left = 0;
-        else if (horiz == "middle") left = (display.sizer.clientWidth - node.offsetWidth) / 2;
-        node.style.left = left + "px";
-      }
-      if (scroll)
-        scrollIntoView(this, left, top, left + node.offsetWidth, top + node.offsetHeight);
-    },
-
-    triggerOnKeyDown: operation(null, onKeyDown),
-
-    execCommand: function(cmd) {return commands[cmd](this);},
-
-    findPosH: function(from, amount, unit, visually) {
-      var dir = 1;
-      if (amount < 0) { dir = -1; amount = -amount; }
-      for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) {
-        cur = findPosH(this.doc, cur, dir, unit, visually);
-        if (cur.hitSide) break;
-      }
-      return cur;
-    },
-
-    moveH: operation(null, function(dir, unit) {
-      var sel = this.doc.sel, pos;
-      if (sel.shift || sel.extend || posEq(sel.from, sel.to))
-        pos = findPosH(this.doc, sel.head, dir, unit, this.options.rtlMoveVisually);
-      else
-        pos = dir < 0 ? sel.from : sel.to;
-      extendSelection(this.doc, pos, pos, dir);
-    }),
-
-    deleteH: operation(null, function(dir, unit) {
-      var sel = this.doc.sel;
-      if (!posEq(sel.from, sel.to)) replaceRange(this.doc, "", sel.from, sel.to, "+delete");
-      else replaceRange(this.doc, "", sel.from, findPosH(this.doc, sel.head, dir, unit, false), "+delete");
-      this.curOp.userSelChange = true;
-    }),
-
-    findPosV: function(from, amount, unit, goalColumn) {
-      var dir = 1, x = goalColumn;
-      if (amount < 0) { dir = -1; amount = -amount; }
-      for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) {
-        var coords = cursorCoords(this, cur, "div");
-        if (x == null) x = coords.left;
-        else coords.left = x;
-        cur = findPosV(this, coords, dir, unit);
-        if (cur.hitSide) break;
-      }
-      return cur;
-    },
-
-    moveV: operation(null, function(dir, unit) {
-      var sel = this.doc.sel, target, goal;
-      if (sel.shift || sel.extend || posEq(sel.from, sel.to)) {
-        var pos = cursorCoords(this, sel.head, "div");
-        if (sel.goalColumn != null) pos.left = sel.goalColumn;
-        target = findPosV(this, pos, dir, unit);
-        if (unit == "page") addToScrollPos(this, 0, charCoords(this, target, "div").top - pos.top);
-        goal = pos.left;
-      } else {
-        target = dir < 0 ? sel.from : sel.to;
-      }
-      extendSelection(this.doc, target, target, dir);
-      if (goal != null) sel.goalColumn = goal;
-    }),
-
-    toggleOverwrite: function(value) {
-      if (value != null && value == this.state.overwrite) return;
-      if (this.state.overwrite = !this.state.overwrite)
-        this.display.cursor.className += " CodeMirror-overwrite";
-      else
-        this.display.cursor.className = this.display.cursor.className.replace(" CodeMirror-overwrite", "");
-    },
-    hasFocus: function() { return this.state.focused; },
-
-    scrollTo: operation(null, function(x, y) {
-      updateScrollPos(this, x, y);
-    }),
-    getScrollInfo: function() {
-      var scroller = this.display.scroller, co = scrollerCutOff;
-      return {left: scroller.scrollLeft, top: scroller.scrollTop,
-              height: scroller.scrollHeight - co, width: scroller.scrollWidth - co,
-              clientHeight: scroller.clientHeight - co, clientWidth: scroller.clientWidth - co};
-    },
-
-    scrollIntoView: operation(null, function(range, margin) {
-      if (range == null) range = {from: this.doc.sel.head, to: null};
-      else if (typeof range == "number") range = {from: Pos(range, 0), to: null};
-      else if (range.from == null) range = {from: range, to: null};
-      if (!range.to) range.to = range.from;
-      if (!margin) margin = 0;
-
-      var coords = range;
-      if (range.from.line != null) {
-        this.curOp.scrollToPos = {from: range.from, to: range.to, margin: margin};
-        coords = {from: cursorCoords(this, range.from),
-                  to: cursorCoords(this, range.to)};
-      }
-      var sPos = calculateScrollPos(this, Math.min(coords.from.left, coords.to.left),
-                                    Math.min(coords.from.top, coords.to.top) - margin,
-                                    Math.max(coords.from.right, coords.to.right),
-                                    Math.max(coords.from.bottom, coords.to.bottom) + margin);
-      updateScrollPos(this, sPos.scrollLeft, sPos.scrollTop);
-    }),
-
-    setSize: operation(null, function(width, height) {
-      function interpret(val) {
-        return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val;
-      }
-      if (width != null) this.display.wrapper.style.width = interpret(width);
-      if (height != null) this.display.wrapper.style.height = interpret(height);
-      if (this.options.lineWrapping)
-        this.display.measureLineCache.length = this.display.measureLineCachePos = 0;
-      this.curOp.forceUpdate = true;
-    }),
-
-    operation: function(f){return runInOp(this, f);},
-
-    refresh: operation(null, function() {
-      var badHeight = this.display.cachedTextHeight == null;
-      clearCaches(this);
-      updateScrollPos(this, this.doc.scrollLeft, this.doc.scrollTop);
-      regChange(this);
-      if (badHeight) estimateLineHeights(this);
-    }),
-
-    swapDoc: operation(null, function(doc) {
-      var old = this.doc;
-      old.cm = null;
-      attachDoc(this, doc);
-      clearCaches(this);
-      resetInput(this, true);
-      updateScrollPos(this, doc.scrollLeft, doc.scrollTop);
-      signalLater(this, "swapDoc", this, old);
-      return old;
-    }),
-
-    getInputField: function(){return this.display.input;},
-    getWrapperElement: function(){return this.display.wrapper;},
-    getScrollerElement: function(){return this.display.scroller;},
-    getGutterElement: function(){return this.display.gutters;}
-  };
-  eventMixin(CodeMirror);
-
-  // OPTION DEFAULTS
-
-  var optionHandlers = CodeMirror.optionHandlers = {};
-
-  // The default configuration options.
-  var defaults = CodeMirror.defaults = {};
-
-  function option(name, deflt, handle, notOnInit) {
-    CodeMirror.defaults[name] = deflt;
-    if (handle) optionHandlers[name] =
-      notOnInit ? function(cm, val, old) {if (old != Init) handle(cm, val, old);} : handle;
-  }
-
-  var Init = CodeMirror.Init = {toString: function(){return "CodeMirror.Init";}};
-
-  // These two are, on init, called from the constructor because they
-  // have to be initialized before the editor can start at all.
-  option("value", "", function(cm, val) {
-    cm.setValue(val);
-  }, true);
-  option("mode", null, function(cm, val) {
-    cm.doc.modeOption = val;
-    loadMode(cm);
-  }, true);
-
-  option("indentUnit", 2, loadMode, true);
-  option("indentWithTabs", false);
-  option("smartIndent", true);
-  option("tabSize", 4, function(cm) {
-    loadMode(cm);
-    clearCaches(cm);
-    regChange(cm);
-  }, true);
-  option("specialChars", /[\t\u0000-\u0019\u00ad\u200b\u2028\u2029\ufeff]/g, function(cm, val) {
-    cm.options.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g");
-    cm.refresh();
-  }, true);
-  option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function(cm) {cm.refresh();}, true);
-  option("electricChars", true);
-  option("rtlMoveVisually", !windows);
-  option("wholeLineUpdateBefore", true);
-
-  option("theme", "default", function(cm) {
-    themeChanged(cm);
-    guttersChanged(cm);
-  }, true);
-  option("keyMap", "default", keyMapChanged);
-  option("extraKeys", null);
-
-  option("onKeyEvent", null);
-  option("onDragEvent", null);
-
-  option("lineWrapping", false, wrappingChanged, true);
-  option("gutters", [], function(cm) {
-    setGuttersForLineNumbers(cm.options);
-    guttersChanged(cm);
-  }, true);
-  option("fixedGutter", true, function(cm, val) {
-    cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0";
-    cm.refresh();
-  }, true);
-  option("coverGutterNextToScrollbar", false, updateScrollbars, true);
-  option("lineNumbers", false, function(cm) {
-    setGuttersForLineNumbers(cm.options);
-    guttersChanged(cm);
-  }, true);
-  option("firstLineNumber", 1, guttersChanged, true);
-  option("lineNumberFormatter", function(integer) {return integer;}, guttersChanged, true);
-  option("showCursorWhenSelecting", false, updateSelection, true);
-
-  option("resetSelectionOnContextMenu", true);
-
-  option("readOnly", false, function(cm, val) {
-    if (val == "nocursor") {
-      onBlur(cm);
-      cm.display.input.blur();
-      cm.display.disabled = true;
-    } else {
-      cm.display.disabled = false;
-      if (!val) resetInput(cm, true);
-    }
-  });
-  option("dragDrop", true);
-
-  option("cursorBlinkRate", 530);
-  option("cursorScrollMargin", 0);
-  option("cursorHeight", 1);
-  option("workTime", 100);
-  option("workDelay", 100);
-  option("flattenSpans", true);
-  option("pollInterval", 100);
-  option("undoDepth", 40, function(cm, val){cm.doc.history.undoDepth = val;});
-  option("historyEventDelay", 500);
-  option("viewportMargin", 10, function(cm){cm.refresh();}, true);
-  option("maxHighlightLength", 10000, function(cm){loadMode(cm); cm.refresh();}, true);
-  option("crudeMeasuringFrom", 10000);
-  option("moveInputWithCursor", true, function(cm, val) {
-    if (!val) cm.display.inputDiv.style.top = cm.display.inputDiv.style.left = 0;
-  });
-
-  option("tabindex", null, function(cm, val) {
-    cm.display.input.tabIndex = val || "";
-  });
-  option("autofocus", null);
-
-  // MODE DEFINITION AND QUERYING
-
-  // Known modes, by name and by MIME
-  var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {};
-
-  CodeMirror.defineMode = function(name, mode) {
-    if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name;
-    if (arguments.length > 2) {
-      mode.dependencies = [];
-      for (var i = 2; i < arguments.length; ++i) mode.dependencies.push(arguments[i]);
-    }
-    modes[name] = mode;
-  };
-
-  CodeMirror.defineMIME = function(mime, spec) {
-    mimeModes[mime] = spec;
-  };
-
-  CodeMirror.resolveMode = function(spec) {
-    if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
-      spec = mimeModes[spec];
-    } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
-      var found = mimeModes[spec.name];
-      spec = createObj(found, spec);
-      spec.name = found.name;
-    } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) {
-      return CodeMirror.resolveMode("application/xml");
-    }
-    if (typeof spec == "string") return {name: spec};
-    else return spec || {name: "null"};
-  };
-
-  CodeMirror.getMode = function(options, spec) {
-    var spec = CodeMirror.resolveMode(spec);
-    var mfactory = modes[spec.name];
-    if (!mfactory) return CodeMirror.getMode(options, "text/plain");
-    var modeObj = mfactory(options, spec);
-    if (modeExtensions.hasOwnProperty(spec.name)) {
-      var exts = modeExtensions[spec.name];
-      for (var prop in exts) {
-        if (!exts.hasOwnProperty(prop)) continue;
-        if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop];
-        modeObj[prop] = exts[prop];
-      }
-    }
-    modeObj.name = spec.name;
-    if (spec.helperType) modeObj.helperType = spec.helperType;
-    if (spec.modeProps) for (var prop in spec.modeProps)
-      modeObj[prop] = spec.modeProps[prop];
-
-    return modeObj;
-  };
-
-  CodeMirror.defineMode("null", function() {
-    return {token: function(stream) {stream.skipToEnd();}};
-  });
-  CodeMirror.defineMIME("text/plain", "null");
-
-  var modeExtensions = CodeMirror.modeExtensions = {};
-  CodeMirror.extendMode = function(mode, properties) {
-    var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
-    copyObj(properties, exts);
-  };
-
-  // EXTENSIONS
-
-  CodeMirror.defineExtension = function(name, func) {
-    CodeMirror.prototype[name] = func;
-  };
-  CodeMirror.defineDocExtension = function(name, func) {
-    Doc.prototype[name] = func;
-  };
-  CodeMirror.defineOption = option;
-
-  var initHooks = [];
-  CodeMirror.defineInitHook = function(f) {initHooks.push(f);};
-
-  var helpers = CodeMirror.helpers = {};
-  CodeMirror.registerHelper = function(type, name, value) {
-    if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = {_global: []};
-    helpers[type][name] = value;
-  };
-  CodeMirror.registerGlobalHelper = function(type, name, predicate, value) {
-    CodeMirror.registerHelper(type, name, value);
-    helpers[type]._global.push({pred: predicate, val: value});
-  };
-
-  // UTILITIES
-
-  CodeMirror.isWordChar = isWordChar;
-
-  // MODE STATE HANDLING
-
-  // Utility functions for working with state. Exported because modes
-  // sometimes need to do this.
-  function copyState(mode, state) {
-    if (state === true) return state;
-    if (mode.copyState) return mode.copyState(state);
-    var nstate = {};
-    for (var n in state) {
-      var val = state[n];
-      if (val instanceof Array) val = val.concat([]);
-      nstate[n] = val;
-    }
-    return nstate;
-  }
-  CodeMirror.copyState = copyState;
-
-  function startState(mode, a1, a2) {
-    return mode.startState ? mode.startState(a1, a2) : true;
-  }
-  CodeMirror.startState = startState;
-
-  CodeMirror.innerMode = function(mode, state) {
-    while (mode.innerMode) {
-      var info = mode.innerMode(state);
-      if (!info || info.mode == mode) break;
-      state = info.state;
-      mode = info.mode;
-    }
-    return info || {mode: mode, state: state};
-  };
-
-  // STANDARD COMMANDS
-
-  var commands = CodeMirror.commands = {
-    selectAll: function(cm) {cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()));},
-    killLine: function(cm) {
-      var from = cm.getCursor(true), to = cm.getCursor(false), sel = !posEq(from, to);
-      if (!sel && cm.getLine(from.line).length == from.ch)
-        cm.replaceRange("", from, Pos(from.line + 1, 0), "+delete");
-      else cm.replaceRange("", from, sel ? to : Pos(from.line), "+delete");
-    },
-    deleteLine: function(cm) {
-      var l = cm.getCursor().line;
-      cm.replaceRange("", Pos(l, 0), Pos(l), "+delete");
-    },
-    delLineLeft: function(cm) {
-      var cur = cm.getCursor();
-      cm.replaceRange("", Pos(cur.line, 0), cur, "+delete");
-    },
-    undo: function(cm) {cm.undo();},
-    redo: function(cm) {cm.redo();},
-    goDocStart: function(cm) {cm.extendSelection(Pos(cm.firstLine(), 0));},
-    goDocEnd: function(cm) {cm.extendSelection(Pos(cm.lastLine()));},
-    goLineStart: function(cm) {
-      cm.extendSelection(lineStart(cm, cm.getCursor().line));
-    },
-    goLineStartSmart: function(cm) {
-      var cur = cm.getCursor(), start = lineStart(cm, cur.line);
-      var line = cm.getLineHandle(start.line);
-      var order = getOrder(line);
-      if (!order || order[0].level == 0) {
-        var firstNonWS = Math.max(0, line.text.search(/\S/));
-        var inWS = cur.line == start.line && cur.ch <= firstNonWS && cur.ch;
-        cm.extendSelection(Pos(start.line, inWS ? 0 : firstNonWS));
-      } else cm.extendSelection(start);
-    },
-    goLineEnd: function(cm) {
-      cm.extendSelection(lineEnd(cm, cm.getCursor().line));
-    },
-    goLineRight: function(cm) {
-      var top = cm.charCoords(cm.getCursor(), "div").top + 5;
-      cm.extendSelection(cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div"));
-    },
-    goLineLeft: function(cm) {
-      var top = cm.charCoords(cm.getCursor(), "div").top + 5;
-      cm.extendSelection(cm.coordsChar({left: 0, top: top}, "div"));
-    },
-    goLineUp: function(cm) {cm.moveV(-1, "line");},
-    goLineDown: function(cm) {cm.moveV(1, "line");},
-    goPageUp: function(cm) {cm.moveV(-1, "page");},
-    goPageDown: function(cm) {cm.moveV(1, "page");},
-    goCharLeft: function(cm) {cm.moveH(-1, "char");},
-    goCharRight: function(cm) {cm.moveH(1, "char");},
-    goColumnLeft: function(cm) {cm.moveH(-1, "column");},
-    goColumnRight: function(cm) {cm.moveH(1, "column");},
-    goWordLeft: function(cm) {cm.moveH(-1, "word");},
-    goGroupRight: function(cm) {cm.moveH(1, "group");},
-    goGroupLeft: function(cm) {cm.moveH(-1, "group");},
-    goWordRight: function(cm) {cm.moveH(1, "word");},
-    delCharBefore: function(cm) {cm.deleteH(-1, "char");},
-    delCharAfter: function(cm) {cm.deleteH(1, "char");},
-    delWordBefore: function(cm) {cm.deleteH(-1, "word");},
-    delWordAfter: function(cm) {cm.deleteH(1, "word");},
-    delGroupBefore: function(cm) {cm.deleteH(-1, "group");},
-    delGroupAfter: function(cm) {cm.deleteH(1, "group");},
-    indentAuto: function(cm) {cm.indentSelection("smart");},
-    indentMore: function(cm) {cm.indentSelection("add");},
-    indentLess: function(cm) {cm.indentSelection("subtract");},
-    insertTab: function(cm) {cm.replaceSelection("\t", "end", "+input");},
-    defaultTab: function(cm) {
-      if (cm.somethingSelected()) cm.indentSelection("add");
-      else cm.replaceSelection("\t", "end", "+input");
-    },
-    transposeChars: function(cm) {
-      var cur = cm.getCursor(), line = cm.getLine(cur.line);
-      if (cur.ch > 0 && cur.ch < line.length - 1)
-        cm.replaceRange(line.charAt(cur.ch) + line.charAt(cur.ch - 1),
-                        Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1));
-    },
-    newlineAndIndent: function(cm) {
-      operation(cm, function() {
-        cm.replaceSelection("\n", "end", "+input");
-        cm.indentLine(cm.getCursor().line, null, true);
-      })();
-    },
-    toggleOverwrite: function(cm) {cm.toggleOverwrite();}
-  };
-
-  // STANDARD KEYMAPS
-
-  var keyMap = CodeMirror.keyMap = {};
-  keyMap.basic = {
-    "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
-    "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
-    "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore",
-    "Tab": "defaultTab", "Shift-Tab": "indentAuto",
-    "Enter": "newlineAndIndent", "Insert": "toggleOverwrite"
-  };
-  // Note that the save and find-related commands aren't defined by
-  // default. Unknown commands are simply ignored.
-  keyMap.pcDefault = {
-    "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo",
-    "Ctrl-Home": "goDocStart", "Alt-Up": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Down": "goDocEnd",
-    "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
-    "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find",
-    "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
-    "Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
-    fallthrough: "basic"
-  };
-  keyMap.macDefault = {
-    "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
-    "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft",
-    "Alt-Right": "goGroupRight", "Cmd-Left": "goLineStart", "Cmd-Right": "goLineEnd", "Alt-Backspace": "delGroupBefore",
-    "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find",
-    "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
-    "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delLineLeft",
-    fallthrough: ["basic", "emacsy"]
-  };
-  keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
-  keyMap.emacsy = {
-    "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
-    "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
-    "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore",
-    "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars"
-  };
-
-  // KEYMAP DISPATCH
-
-  function getKeyMap(val) {
-    if (typeof val == "string") return keyMap[val];
-    else return val;
-  }
-
-  function lookupKey(name, maps, handle) {
-    function lookup(map) {
-      map = getKeyMap(map);
-      var found = map[name];
-      if (found === false) return "stop";
-      if (found != null && handle(found)) return true;
-      if (map.nofallthrough) return "stop";
-
-      var fallthrough = map.fallthrough;
-      if (fallthrough == null) return false;
-      if (Object.prototype.toString.call(fallthrough) != "[object Array]")
-        return lookup(fallthrough);
-      for (var i = 0, e = fallthrough.length; i < e; ++i) {
-        var done = lookup(fallthrough[i]);
-        if (done) return done;
-      }
-      return false;
-    }
-
-    for (var i = 0; i < maps.length; ++i) {
-      var done = lookup(maps[i]);
-      if (done) return done != "stop";
-    }
-  }
-  function isModifierKey(event) {
-    var name = keyNames[event.keyCode];
-    return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod";
-  }
-  function keyName(event, noShift) {
-    if (opera && event.keyCode == 34 && event["char"]) return false;
-    var name = keyNames[event.keyCode];
-    if (name == null || event.altGraphKey) return false;
-    if (event.altKey) name = "Alt-" + name;
-    if (flipCtrlCmd ? event.metaKey : event.ctrlKey) name = "Ctrl-" + name;
-    if (flipCtrlCmd ? event.ctrlKey : event.metaKey) name = "Cmd-" + name;
-    if (!noShift && event.shiftKey) name = "Shift-" + name;
-    return name;
-  }
-  CodeMirror.lookupKey = lookupKey;
-  CodeMirror.isModifierKey = isModifierKey;
-  CodeMirror.keyName = keyName;
-
-  // FROMTEXTAREA
-
-  CodeMirror.fromTextArea = function(textarea, options) {
-    if (!options) options = {};
-    options.value = textarea.value;
-    if (!options.tabindex && textarea.tabindex)
-      options.tabindex = textarea.tabindex;
-    if (!options.placeholder && textarea.placeholder)
-      options.placeholder = textarea.placeholder;
-    // Set autofocus to true if this textarea is focused, or if it has
-    // autofocus and no other element is focused.
-    if (options.autofocus == null) {
-      var hasFocus = document.body;
-      // doc.activeElement occasionally throws on IE
-      try { hasFocus = document.activeElement; } catch(e) {}
-      options.autofocus = hasFocus == textarea ||
-        textarea.getAttribute("autofocus") != null && hasFocus == document.body;
-    }
-
-    function save() {textarea.value = cm.getValue();}
-    if (textarea.form) {
-      on(textarea.form, "submit", save);
-      // Deplorable hack to make the submit method do the right thing.
-      if (!options.leaveSubmitMethodAlone) {
-        var form = textarea.form, realSubmit = form.submit;
-        try {
-          var wrappedSubmit = form.submit = function() {
-            save();
-            form.submit = realSubmit;
-            form.submit();
-            form.submit = wrappedSubmit;
-          };
-        } catch(e) {}
-      }
-    }
-
-    textarea.style.display = "none";
-    var cm = CodeMirror(function(node) {
-      textarea.parentNode.insertBefore(node, textarea.nextSibling);
-    }, options);
-    cm.save = save;
-    cm.getTextArea = function() { return textarea; };
-    cm.toTextArea = function() {
-      save();
-      textarea.parentNode.removeChild(cm.getWrapperElement());
-      textarea.style.display = "";
-      if (textarea.form) {
-        off(textarea.form, "submit", save);
-        if (typeof textarea.form.submit == "function")
-          textarea.form.submit = realSubmit;
-      }
-    };
-    return cm;
-  };
-
-  // STRING STREAM
-
-  // Fed to the mode parsers, provides helper functions to make
-  // parsers more succinct.
-
-  // The character stream used by a mode's parser.
-  function StringStream(string, tabSize) {
-    this.pos = this.start = 0;
-    this.string = string;
-    this.tabSize = tabSize || 8;
-    this.lastColumnPos = this.lastColumnValue = 0;
-    this.lineStart = 0;
-  }
-
-  StringStream.prototype = {
-    eol: function() {return this.pos >= this.string.length;},
-    sol: function() {return this.pos == this.lineStart;},
-    peek: function() {return this.string.charAt(this.pos) || undefined;},
-    next: function() {
-      if (this.pos < this.string.length)
-        return this.string.charAt(this.pos++);
-    },
-    eat: function(match) {
-      var ch = this.string.charAt(this.pos);
-      if (typeof match == "string") var ok = ch == match;
-      else var ok = ch && (match.test ? match.test(ch) : match(ch));
-      if (ok) {++this.pos; return ch;}
-    },
-    eatWhile: function(match) {
-      var start = this.pos;
-      while (this.eat(match)){}
-      return this.pos > start;
-    },
-    eatSpace: function() {
-      var start = this.pos;
-      while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos;
-      return this.pos > start;
-    },
-    skipToEnd: function() {this.pos = this.string.length;},
-    skipTo: function(ch) {
-      var found = this.string.indexOf(ch, this.pos);
-      if (found > -1) {this.pos = found; return true;}
-    },
-    backUp: function(n) {this.pos -= n;},
-    column: function() {
-      if (this.lastColumnPos < this.start) {
-        this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);
-        this.lastColumnPos = this.start;
-      }
-      return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
-    },
-    indentation: function() {
-      return countColumn(this.string, null, this.tabSize) -
-        (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
-    },
-    match: function(pattern, consume, caseInsensitive) {
-      if (typeof pattern == "string") {
-        var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;};
-        var substr = this.string.substr(this.pos, pattern.length);
-        if (cased(substr) == cased(pattern)) {
-          if (consume !== false) this.pos += pattern.length;
-          return true;
-        }
-      } else {
-        var match = this.string.slice(this.pos).match(pattern);
-        if (match && match.index > 0) return null;
-        if (match && consume !== false) this.pos += match[0].length;
-        return match;
-      }
-    },
-    current: function(){return this.string.slice(this.start, this.pos);},
-    hideFirstChars: function(n, inner) {
-      this.lineStart += n;
-      try { return inner(); }
-      finally { this.lineStart -= n; }
-    }
-  };
-  CodeMirror.StringStream = StringStream;
-
-  // TEXTMARKERS
-
-  function TextMarker(doc, type) {
-    this.lines = [];
-    this.type = type;
-    this.doc = doc;
-  }
-  CodeMirror.TextMarker = TextMarker;
-  eventMixin(TextMarker);
-
-  TextMarker.prototype.clear = function() {
-    if (this.explicitlyCleared) return;
-    var cm = this.doc.cm, withOp = cm && !cm.curOp;
-    if (withOp) startOperation(cm);
-    if (hasHandler(this, "clear")) {
-      var found = this.find();
-      if (found) signalLater(this, "clear", found.from, found.to);
-    }
-    var min = null, max = null;
-    for (var i = 0; i < this.lines.length; ++i) {
-      var line = this.lines[i];
-      var span = getMarkedSpanFor(line.markedSpans, this);
-      if (span.to != null) max = lineNo(line);
-      line.markedSpans = removeMarkedSpan(line.markedSpans, span);
-      if (span.from != null)
-        min = lineNo(line);
-      else if (this.collapsed && !lineIsHidden(this.doc, line) && cm)
-        updateLineHeight(line, textHeight(cm.display));
-    }
-    if (cm && this.collapsed && !cm.options.lineWrapping) for (var i = 0; i < this.lines.length; ++i) {
-      var visual = visualLine(cm.doc, this.lines[i]), len = lineLength(cm.doc, visual);
-      if (len > cm.display.maxLineLength) {
-        cm.display.maxLine = visual;
-        cm.display.maxLineLength = len;
-        cm.display.maxLineChanged = true;
-      }
-    }
-
-    if (min != null && cm) regChange(cm, min, max + 1);
-    this.lines.length = 0;
-    this.explicitlyCleared = true;
-    if (this.atomic && this.doc.cantEdit) {
-      this.doc.cantEdit = false;
-      if (cm) reCheckSelection(cm);
-    }
-    if (withOp) endOperation(cm);
-  };
-
-  TextMarker.prototype.find = function(bothSides) {
-    var from, to;
-    for (var i = 0; i < this.lines.length; ++i) {
-      var line = this.lines[i];
-      var span = getMarkedSpanFor(line.markedSpans, this);
-      if (span.from != null || span.to != null) {
-        var found = lineNo(line);
-        if (span.from != null) from = Pos(found, span.from);
-        if (span.to != null) to = Pos(found, span.to);
-      }
-    }
-    if (this.type == "bookmark" && !bothSides) return from;
-    return from && {from: from, to: to};
-  };
-
-  TextMarker.prototype.changed = function() {
-    var pos = this.find(), cm = this.doc.cm;
-    if (!pos || !cm) return;
-    if (this.type != "bookmark") pos = pos.from;
-    var line = getLine(this.doc, pos.line);
-    clearCachedMeasurement(cm, line);
-    if (pos.line >= cm.display.showingFrom && pos.line < cm.display.showingTo) {
-      for (var node = cm.display.lineDiv.firstChild; node; node = node.nextSibling) if (node.lineObj == line) {
-        if (node.offsetHeight != line.height) updateLineHeight(line, node.offsetHeight);
-        break;
-      }
-      runInOp(cm, function() {
-        cm.curOp.selectionChanged = cm.curOp.forceUpdate = cm.curOp.updateMaxLine = true;
-      });
-    }
-  };
-
-  TextMarker.prototype.attachLine = function(line) {
-    if (!this.lines.length && this.doc.cm) {
-      var op = this.doc.cm.curOp;
-      if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1)
-        (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this);
-    }
-    this.lines.push(line);
-  };
-  TextMarker.prototype.detachLine = function(line) {
-    this.lines.splice(indexOf(this.lines, line), 1);
-    if (!this.lines.length && this.doc.cm) {
-      var op = this.doc.cm.curOp;
-      (op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this);
-    }
-  };
-
-  var nextMarkerId = 0;
-
-  function markText(doc, from, to, options, type) {
-    if (options && options.shared) return markTextShared(doc, from, to, options, type);
-    if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type);
-
-    var marker = new TextMarker(doc, type);
-    if (options) copyObj(options, marker);
-    if (posLess(to, from) || posEq(from, to) && marker.clearWhenEmpty !== false)
-      return marker;
-    if (marker.replacedWith) {
-      marker.collapsed = true;
-      marker.replacedWith = elt("span", [marker.replacedWith], "CodeMirror-widget");
-      if (!options.handleMouseEvents) marker.replacedWith.ignoreEvents = true;
-    }
-    if (marker.collapsed) {
-      if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||
-          from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))
-        throw new Error("Inserting collapsed marker partially overlapping an existing one");
-      sawCollapsedSpans = true;
-    }
-
-    if (marker.addToHistory)
-      addToHistory(doc, {from: from, to: to, origin: "markText"},
-                   {head: doc.sel.head, anchor: doc.sel.anchor}, NaN);
-
-    var curLine = from.line, cm = doc.cm, updateMaxLine;
-    doc.iter(curLine, to.line + 1, function(line) {
-      if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(doc, line) == cm.display.maxLine)
-        updateMaxLine = true;
-      var span = {from: null, to: null, marker: marker};
-      if (curLine == from.line) span.from = from.ch;
-      if (curLine == to.line) span.to = to.ch;
-      if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0);
-      addMarkedSpan(line, span);
-      ++curLine;
-    });
-    if (marker.collapsed) doc.iter(from.line, to.line + 1, function(line) {
-      if (lineIsHidden(doc, line)) updateLineHeight(line, 0);
-    });
-
-    if (marker.clearOnEnter) on(marker, "beforeCursorEnter", function() { marker.clear(); });
-
-    if (marker.readOnly) {
-      sawReadOnlySpans = true;
-      if (doc.history.done.length || doc.history.undone.length)
-        doc.clearHistory();
-    }
-    if (marker.collapsed) {
-      marker.id = ++nextMarkerId;
-      marker.atomic = true;
-    }
-    if (cm) {
-      if (updateMaxLine) cm.curOp.updateMaxLine = true;
-      if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.collapsed)
-        regChange(cm, from.line, to.line + 1);
-      if (marker.atomic) reCheckSelection(cm);
-    }
-    return marker;
-  }
-
-  // SHARED TEXTMARKERS
-
-  function SharedTextMarker(markers, primary) {
-    this.markers = markers;
-    this.primary = primary;
-    for (var i = 0, me = this; i < markers.length; ++i) {
-      markers[i].parent = this;
-      on(markers[i], "clear", function(){me.clear();});
-    }
-  }
-  CodeMirror.SharedTextMarker = SharedTextMarker;
-  eventMixin(SharedTextMarker);
-
-  SharedTextMarker.prototype.clear = function() {
-    if (this.explicitlyCleared) return;
-    this.explicitlyCleared = true;
-    for (var i = 0; i < this.markers.length; ++i)
-      this.markers[i].clear();
-    signalLater(this, "clear");
-  };
-  SharedTextMarker.prototype.find = function() {
-    return this.primary.find();
-  };
-
-  function markTextShared(doc, from, to, options, type) {
-    options = copyObj(options);
-    options.shared = false;
-    var markers = [markText(doc, from, to, options, type)], primary = markers[0];
-    var widget = options.replacedWith;
-    linkedDocs(doc, function(doc) {
-      if (widget) options.replacedWith = widget.cloneNode(true);
-      markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type));
-      for (var i = 0; i < doc.linked.length; ++i)
-        if (doc.linked[i].isParent) return;
-      primary = lst(markers);
-    });
-    return new SharedTextMarker(markers, primary);
-  }
-
-  // TEXTMARKER SPANS
-
-  function getMarkedSpanFor(spans, marker) {
-    if (spans) for (var i = 0; i < spans.length; ++i) {
-      var span = spans[i];
-      if (span.marker == marker) return span;
-    }
-  }
-  function removeMarkedSpan(spans, span) {
-    for (var r, i = 0; i < spans.length; ++i)
-      if (spans[i] != span) (r || (r = [])).push(spans[i]);
-    return r;
-  }
-  function addMarkedSpan(line, span) {
-    line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span];
-    span.marker.attachLine(line);
-  }
-
-  function markedSpansBefore(old, startCh, isInsert) {
-    if (old) for (var i = 0, nw; i < old.length; ++i) {
-      var span = old[i], marker = span.marker;
-      var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);
-      if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) {
-        var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh);
-        (nw || (nw = [])).push({from: span.from,
-                                to: endsAfter ? null : span.to,
-                                marker: marker});
-      }
-    }
-    return nw;
-  }
-
-  function markedSpansAfter(old, endCh, isInsert) {
-    if (old) for (var i = 0, nw; i < old.length; ++i) {
-      var span = old[i], marker = span.marker;
-      var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);
-      if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) {
-        var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh);
-        (nw || (nw = [])).push({from: startsBefore ? null : span.from - endCh,
-                                to: span.to == null ? null : span.to - endCh,
-                                marker: marker});
-      }
-    }
-    return nw;
-  }
-
-  function stretchSpansOverChange(doc, change) {
-    var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans;
-    var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans;
-    if (!oldFirst && !oldLast) return null;
-
-    var startCh = change.from.ch, endCh = change.to.ch, isInsert = posEq(change.from, change.to);
-    // Get the spans that 'stick out' on both sides
-    var first = markedSpansBefore(oldFirst, startCh, isInsert);
-    var last = markedSpansAfter(oldLast, endCh, isInsert);
-
-    // Next, merge those two ends
-    var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0);
-    if (first) {
-      // Fix up .to properties of first
-      for (var i = 0; i < first.length; ++i) {
-        var span = first[i];
-        if (span.to == null) {
-          var found = getMarkedSpanFor(last, span.marker);
-          if (!found) span.to = startCh;
-          else if (sameLine) span.to = found.to == null ? null : found.to + offset;
-        }
-      }
-    }
-    if (last) {
-      // Fix up .from in last (or move them into first in case of sameLine)
-      for (var i = 0; i < last.length; ++i) {
-        var span = last[i];
-        if (span.to != null) span.to += offset;
-        if (span.from == null) {
-          var found = getMarkedSpanFor(first, span.marker);
-          if (!found) {
-            span.from = offset;
-            if (sameLine) (first || (first = [])).push(span);
-          }
-        } else {
-          span.from += offset;
-          if (sameLine) (first || (first = [])).push(span);
-        }
-      }
-    }
-    // Make sure we didn't create any zero-length spans
-    if (first) first = clearEmptySpans(first);
-    if (last && last != first) last = clearEmptySpans(last);
-
-    var newMarkers = [first];
-    if (!sameLine) {
-      // Fill gap with whole-line-spans
-      var gap = change.text.length - 2, gapMarkers;
-      if (gap > 0 && first)
-        for (var i = 0; i < first.length; ++i)
-          if (first[i].to == null)
-            (gapMarkers || (gapMarkers = [])).push({from: null, to: null, marker: first[i].marker});
-      for (var i = 0; i < gap; ++i)
-        newMarkers.push(gapMarkers);
-      newMarkers.push(last);
-    }
-    return newMarkers;
-  }
-
-  function clearEmptySpans(spans) {
-    for (var i = 0; i < spans.length; ++i) {
-      var span = spans[i];
-      if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)
-        spans.splice(i--, 1);
-    }
-    if (!spans.length) return null;
-    return spans;
-  }
-
-  function mergeOldSpans(doc, change) {
-    var old = getOldSpans(doc, change);
-    var stretched = stretchSpansOverChange(doc, change);
-    if (!old) return stretched;
-    if (!stretched) return old;
-
-    for (var i = 0; i < old.length; ++i) {
-      var oldCur = old[i], stretchCur = stretched[i];
-      if (oldCur && stretchCur) {
-        spans: for (var j = 0; j < stretchCur.length; ++j) {
-          var span = stretchCur[j];
-          for (var k = 0; k < oldCur.length; ++k)
-            if (oldCur[k].marker == span.marker) continue spans;
-          oldCur.push(span);
-        }
-      } else if (stretchCur) {
-        old[i] = stretchCur;
-      }
-    }
-    return old;
-  }
-
-  function removeReadOnlyRanges(doc, from, to) {
-    var markers = null;
-    doc.iter(from.line, to.line + 1, function(line) {
-      if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) {
-        var mark = line.markedSpans[i].marker;
-        if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))
-          (markers || (markers = [])).push(mark);
-      }
-    });
-    if (!markers) return null;
-    var parts = [{from: from, to: to}];
-    for (var i = 0; i < markers.length; ++i) {
-      var mk = markers[i], m = mk.find();
-      for (var j = 0; j < parts.length; ++j) {
-        var p = parts[j];
-        if (posLess(p.to, m.from) || posLess(m.to, p.from)) continue;
-        var newParts = [j, 1];
-        if (posLess(p.from, m.from) || !mk.inclusiveLeft && posEq(p.from, m.from))
-          newParts.push({from: p.from, to: m.from});
-        if (posLess(m.to, p.to) || !mk.inclusiveRight && posEq(p.to, m.to))
-          newParts.push({from: m.to, to: p.to});
-        parts.splice.apply(parts, newParts);
-        j += newParts.length - 1;
-      }
-    }
-    return parts;
-  }
-
-  function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0; }
-  function extraRight(marker) { return marker.inclusiveRight ? 1 : 0; }
-
-  function compareCollapsedMarkers(a, b) {
-    var lenDiff = a.lines.length - b.lines.length;
-    if (lenDiff != 0) return lenDiff;
-    var aPos = a.find(), bPos = b.find();
-    var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b);
-    if (fromCmp) return -fromCmp;
-    var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b);
-    if (toCmp) return toCmp;
-    return b.id - a.id;
-  }
-
-  function collapsedSpanAtSide(line, start) {
-    var sps = sawCollapsedSpans && line.markedSpans, found;
-    if (sps) for (var sp, i = 0; i < sps.length; ++i) {
-      sp = sps[i];
-      if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&
-          (!found || compareCollapsedMarkers(found, sp.marker) < 0))
-        found = sp.marker;
-    }
-    return found;
-  }
-  function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true); }
-  function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false); }
-
-  function conflictingCollapsedRange(doc, lineNo, from, to, marker) {
-    var line = getLine(doc, lineNo);
-    var sps = sawCollapsedSpans && line.markedSpans;
-    if (sps) for (var i = 0; i < sps.length; ++i) {
-      var sp = sps[i];
-      if (!sp.marker.collapsed) continue;
-      var found = sp.marker.find(true);
-      var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker);
-      var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker);
-      if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) continue;
-      if (fromCmp <= 0 && (cmp(found.to, from) || extraRight(sp.marker) - extraLeft(marker)) > 0 ||
-          fromCmp >= 0 && (cmp(found.from, to) || extraLeft(sp.marker) - extraRight(marker)) < 0)
-        return true;
-    }
-  }
-
-  function visualLine(doc, line) {
-    var merged;
-    while (merged = collapsedSpanAtStart(line))
-      line = getLine(doc, merged.find().from.line);
-    return line;
-  }
-
-  function lineIsHidden(doc, line) {
-    var sps = sawCollapsedSpans && line.markedSpans;
-    if (sps) for (var sp, i = 0; i < sps.length; ++i) {
-      sp = sps[i];
-      if (!sp.marker.collapsed) continue;
-      if (sp.from == null) return true;
-      if (sp.marker.replacedWith) continue;
-      if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))
-        return true;
-    }
-  }
-  function lineIsHiddenInner(doc, line, span) {
-    if (span.to == null) {
-      var end = span.marker.find().to, endLine = getLine(doc, end.line);
-      return lineIsHiddenInner(doc, endLine, getMarkedSpanFor(endLine.markedSpans, span.marker));
-    }
-    if (span.marker.inclusiveRight && span.to == line.text.length)
-      return true;
-    for (var sp, i = 0; i < line.markedSpans.length; ++i) {
-      sp = line.markedSpans[i];
-      if (sp.marker.collapsed && !sp.marker.replacedWith && sp.from == span.to &&
-          (sp.to == null || sp.to != span.from) &&
-          (sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&
-          lineIsHiddenInner(doc, line, sp)) return true;
-    }
-  }
-
-  function detachMarkedSpans(line) {
-    var spans = line.markedSpans;
-    if (!spans) return;
-    for (var i = 0; i < spans.length; ++i)
-      spans[i].marker.detachLine(line);
-    line.markedSpans = null;
-  }
-
-  function attachMarkedSpans(line, spans) {
-    if (!spans) return;
-    for (var i = 0; i < spans.length; ++i)
-      spans[i].marker.attachLine(line);
-    line.markedSpans = spans;
-  }
-
-  // LINE WIDGETS
-
-  var LineWidget = CodeMirror.LineWidget = function(cm, node, options) {
-    if (options) for (var opt in options) if (options.hasOwnProperty(opt))
-      this[opt] = options[opt];
-    this.cm = cm;
-    this.node = node;
-  };
-  eventMixin(LineWidget);
-  function widgetOperation(f) {
-    return function() {
-      var withOp = !this.cm.curOp;
-      if (withOp) startOperation(this.cm);
-      try {var result = f.apply(this, arguments);}
-      finally {if (withOp) endOperation(this.cm);}
-      return result;
-    };
-  }
-  LineWidget.prototype.clear = widgetOperation(function() {
-    var ws = this.line.widgets, no = lineNo(this.line);
-    if (no == null || !ws) return;
-    for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1);
-    if (!ws.length) this.line.widgets = null;
-    var aboveVisible = heightAtLine(this.cm, this.line) < this.cm.doc.scrollTop;
-    updateLineHeight(this.line, Math.max(0, this.line.height - widgetHeight(this)));
-    if (aboveVisible) addToScrollPos(this.cm, 0, -this.height);
-    regChange(this.cm, no, no + 1);
-  });
-  LineWidget.prototype.changed = widgetOperation(function() {
-    var oldH = this.height;
-    this.height = null;
-    var diff = widgetHeight(this) - oldH;
-    if (!diff) return;
-    updateLineHeight(this.line, this.line.height + diff);
-    var no = lineNo(this.line);
-    regChange(this.cm, no, no + 1);
-  });
-
-  function widgetHeight(widget) {
-    if (widget.height != null) return widget.height;
-    if (!widget.node.parentNode || widget.node.parentNode.nodeType != 1)
-      removeChildrenAndAdd(widget.cm.display.measure, elt("div", [widget.node], null, "position: relative"));
-    return widget.height = widget.node.offsetHeight;
-  }
-
-  function addLineWidget(cm, handle, node, options) {
-    var widget = new LineWidget(cm, node, options);
-    if (widget.noHScroll) cm.display.alignWidgets = true;
-    changeLine(cm, handle, function(line) {
-      var widgets = line.widgets || (line.widgets = []);
-      if (widget.insertAt == null) widgets.push(widget);
-      else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget);
-      widget.line = line;
-      if (!lineIsHidden(cm.doc, line) || widget.showIfHidden) {
-        var aboveVisible = heightAtLine(cm, line) < cm.doc.scrollTop;
-        updateLineHeight(line, line.height + widgetHeight(widget));
-        if (aboveVisible) addToScrollPos(cm, 0, widget.height);
-      }
-      return true;
-    });
-    return widget;
-  }
-
-  // LINE DATA STRUCTURE
-
-  // Line objects. These hold state related to a line, including
-  // highlighting info (the styles array).
-  var Line = CodeMirror.Line = function(text, markedSpans, estimateHeight) {
-    this.text = text;
-    attachMarkedSpans(this, markedSpans);
-    this.height = estimateHeight ? estimateHeight(this) : 1;
-  };
-  eventMixin(Line);
-  Line.prototype.lineNo = function() { return lineNo(this); };
-
-  function updateLine(line, text, markedSpans, estimateHeight) {
-    line.text = text;
-    if (line.stateAfter) line.stateAfter = null;
-    if (line.styles) line.styles = null;
-    if (line.order != null) line.order = null;
-    detachMarkedSpans(line);
-    attachMarkedSpans(line, markedSpans);
-    var estHeight = estimateHeight ? estimateHeight(line) : 1;
-    if (estHeight != line.height) updateLineHeight(line, estHeight);
-  }
-
-  function cleanUpLine(line) {
-    line.parent = null;
-    detachMarkedSpans(line);
-  }
-
-  // Run the given mode's parser over a line, update the styles
-  // array, which contains alternating fragments of text and CSS
-  // classes.
-  function runMode(cm, text, mode, state, f, forceToEnd) {
-    var flattenSpans = mode.flattenSpans;
-    if (flattenSpans == null) flattenSpans = cm.options.flattenSpans;
-    var curStart = 0, curStyle = null;
-    var stream = new StringStream(text, cm.options.tabSize), style;
-    if (text == "" && mode.blankLine) mode.blankLine(state);
-    while (!stream.eol()) {
-      if (stream.pos > cm.options.maxHighlightLength) {
-        flattenSpans = false;
-        if (forceToEnd) processLine(cm, text, state, stream.pos);
-        stream.pos = text.length;
-        style = null;
-      } else {
-        style = mode.token(stream, state);
-      }
-      if (!flattenSpans || curStyle != style) {
-        if (curStart < stream.start) f(stream.start, curStyle);
-        curStart = stream.start; curStyle = style;
-      }
-      stream.start = stream.pos;
-    }
-    while (curStart < stream.pos) {
-      // Webkit seems to refuse to render text nodes longer than 57444 characters
-      var pos = Math.min(stream.pos, curStart + 50000);
-      f(pos, curStyle);
-      curStart = pos;
-    }
-  }
-
-  function highlightLine(cm, line, state, forceToEnd) {
-    // A styles array always starts with a number identifying the
-    // mode/overlays that it is based on (for easy invalidation).
-    var st = [cm.state.modeGen];
-    // Compute the base array of styles
-    runMode(cm, line.text, cm.doc.mode, state, function(end, style) {
-      st.push(end, style);
-    }, forceToEnd);
-
-    // Run overlays, adjust style array.
-    for (var o = 0; o < cm.state.overlays.length; ++o) {
-      var overlay = cm.state.overlays[o], i = 1, at = 0;
-      runMode(cm, line.text, overlay.mode, true, function(end, style) {
-        var start = i;
-        // Ensure there's a token end at the current position, and that i points at it
-        while (at < end) {
-          var i_end = st[i];
-          if (i_end > end)
-            st.splice(i, 1, end, st[i+1], i_end);
-          i += 2;
-          at = Math.min(end, i_end);
-        }
-        if (!style) return;
-        if (overlay.opaque) {
-          st.splice(start, i - start, end, style);
-          i = start + 2;
-        } else {
-          for (; start < i; start += 2) {
-            var cur = st[start+1];
-            st[start+1] = cur ? cur + " " + style : style;
-          }
-        }
-      });
-    }
-
-    return st;
-  }
-
-  function getLineStyles(cm, line) {
-    if (!line.styles || line.styles[0] != cm.state.modeGen)
-      line.styles = highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line)));
-    return line.styles;
-  }
-
-  // Lightweight form of highlight -- proceed over this line and
-  // update state, but don't save a style array.
-  function processLine(cm, text, state, startAt) {
-    var mode = cm.doc.mode;
-    var stream = new StringStream(text, cm.options.tabSize);
-    stream.start = stream.pos = startAt || 0;
-    if (text == "" && mode.blankLine) mode.blankLine(state);
-    while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) {
-      mode.token(stream, state);
-      stream.start = stream.pos;
-    }
-  }
-
-  var styleToClassCache = {};
-  function interpretTokenStyle(style, builder) {
-    if (!style) return null;
-    for (;;) {
-      var lineClass = style.match(/(?:^|\s)line-(background-)?(\S+)/);
-      if (!lineClass) break;
-      style = style.slice(0, lineClass.index) + style.slice(lineClass.index + lineClass[0].length);
-      var prop = lineClass[1] ? "bgClass" : "textClass";
-      if (builder[prop] == null)
-        builder[prop] = lineClass[2];
-      else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(builder[prop]))
-        builder[prop] += " " + lineClass[2];
-    }
-    return styleToClassCache[style] ||
-      (styleToClassCache[style] = "cm-" + style.replace(/ +/g, " cm-"));
-  }
-
-  function buildLineContent(cm, realLine, measure, copyWidgets) {
-    var merged, line = realLine, empty = true;
-    while (merged = collapsedSpanAtStart(line))
-      line = getLine(cm.doc, merged.find().from.line);
-
-    var builder = {pre: elt("pre"), col: 0, pos: 0,
-                   measure: null, measuredSomething: false, cm: cm,
-                   copyWidgets: copyWidgets};
-
-    do {
-      if (line.text) empty = false;
-      builder.measure = line == realLine && measure;
-      builder.pos = 0;
-      builder.addToken = builder.measure ? buildTokenMeasure : buildToken;
-      if ((ie || webkit) && cm.getOption("lineWrapping"))
-        builder.addToken = buildTokenSplitSpaces(builder.addToken);
-      var next = insertLineContent(line, builder, getLineStyles(cm, line));
-      if (measure && line == realLine && !builder.measuredSomething) {
-        measure[0] = builder.pre.appendChild(zeroWidthElement(cm.display.measure));
-        builder.measuredSomething = true;
-      }
-      if (next) line = getLine(cm.doc, next.to.line);
-    } while (next);
-
-    if (measure && !builder.measuredSomething && !measure[0])
-      measure[0] = builder.pre.appendChild(empty ? elt("span", "\u00a0") : zeroWidthElement(cm.display.measure));
-    if (!builder.pre.firstChild && !lineIsHidden(cm.doc, realLine))
-      builder.pre.appendChild(document.createTextNode("\u00a0"));
-
-    var order;
-    // Work around problem with the reported dimensions of single-char
-    // direction spans on IE (issue #1129). See also the comment in
-    // cursorCoords.
-    if (measure && (ie || ie_gt10) && (order = getOrder(line))) {
-      var l = order.length - 1;
-      if (order[l].from == order[l].to) --l;
-      var last = order[l], prev = order[l - 1];
-      if (last.from + 1 == last.to && prev && last.level < prev.level) {
-        var span = measure[builder.pos - 1];
-        if (span) span.parentNode.insertBefore(span.measureRight = zeroWidthElement(cm.display.measure),
-                                               span.nextSibling);
-      }
-    }
-
-    var textClass = builder.textClass ? builder.textClass + " " + (realLine.textClass || "") : realLine.textClass;
-    if (textClass) builder.pre.className = textClass;
-
-    signal(cm, "renderLine", cm, realLine, builder.pre);
-    return builder;
-  }
-
-  function defaultSpecialCharPlaceholder(ch) {
-    var token = elt("span", "\u2022", "cm-invalidchar");
-    token.title = "\\u" + ch.charCodeAt(0).toString(16);
-    return token;
-  }
-
-  function buildToken(builder, text, style, startStyle, endStyle, title) {
-    if (!text) return;
-    var special = builder.cm.options.specialChars;
-    if (!special.test(text)) {
-      builder.col += text.length;
-      var content = document.createTextNode(text);
-    } else {
-      var content = document.createDocumentFragment(), pos = 0;
-      while (true) {
-        special.lastIndex = pos;
-        var m = special.exec(text);
-        var skipped = m ? m.index - pos : text.length - pos;
-        if (skipped) {
-          content.appendChild(document.createTextNode(text.slice(pos, pos + skipped)));
-          builder.col += skipped;
-        }
-        if (!m) break;
-        pos += skipped + 1;
-        if (m[0] == "\t") {
-          var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize;
-          content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab"));
-          builder.col += tabWidth;
-        } else {
-          var token = builder.cm.options.specialCharPlaceholder(m[0]);
-          content.appendChild(token);
-          builder.col += 1;
-        }
-      }
-    }
-    if (style || startStyle || endStyle || builder.measure) {
-      var fullStyle = style || "";
-      if (startStyle) fullStyle += startStyle;
-      if (endStyle) fullStyle += endStyle;
-      var token = elt("span", [content], fullStyle);
-      if (title) token.title = title;
-      return builder.pre.appendChild(token);
-    }
-    builder.pre.appendChild(content);
-  }
-
-  function buildTokenMeasure(builder, text, style, startStyle, endStyle) {
-    var wrapping = builder.cm.options.lineWrapping;
-    for (var i = 0; i < text.length; ++i) {
-      var ch = text.charAt(i), start = i == 0;
-      if (ch >= "\ud800" && ch < "\udbff" && i < text.length - 1) {
-        ch = text.slice(i, i + 2);
-        ++i;
-      } else if (i && wrapping && spanAffectsWrapping(text, i)) {
-        builder.pre.appendChild(elt("wbr"));
-      }
-      var old = builder.measure[builder.pos];
-      var span = builder.measure[builder.pos] =
-        buildToken(builder, ch, style,
-                   start && startStyle, i == text.length - 1 && endStyle);
-      if (old) span.leftSide = old.leftSide || old;
-      // In IE single-space nodes wrap differently than spaces
-      // embedded in larger text nodes, except when set to
-      // white-space: normal (issue #1268).
-      if (ie && wrapping && ch == " " && i && !/\s/.test(text.charAt(i - 1)) &&
-          i < text.length - 1 && !/\s/.test(text.charAt(i + 1)))
-        span.style.whiteSpace = "normal";
-      builder.pos += ch.length;
-    }
-    if (text.length) builder.measuredSomething = true;
-  }
-
-  function buildTokenSplitSpaces(inner) {
-    function split(old) {
-      var out = " ";
-      for (var i = 0; i < old.length - 2; ++i) out += i % 2 ? " " : "\u00a0";
-      out += " ";
-      return out;
-    }
-    return function(builder, text, style, startStyle, endStyle, title) {
-      return inner(builder, text.replace(/ {3,}/g, split), style, startStyle, endStyle, title);
-    };
-  }
-
-  function buildCollapsedSpan(builder, size, marker, ignoreWidget) {
-    var widget = !ignoreWidget && marker.replacedWith;
-    if (widget) {
-      if (builder.copyWidgets) widget = widget.cloneNode(true);
-      builder.pre.appendChild(widget);
-      if (builder.measure) {
-        if (size) {
-          builder.measure[builder.pos] = widget;
-        } else {
-          var elt = zeroWidthElement(builder.cm.display.measure);
-          if (marker.type == "bookmark" && !marker.insertLeft)
-            builder.measure[builder.pos] = builder.pre.appendChild(elt);
-          else if (builder.measure[builder.pos])
-            return;
-          else
-            builder.measure[builder.pos] = builder.pre.insertBefore(elt, widget);
-        }
-        builder.measuredSomething = true;
-      }
-    }
-    builder.pos += size;
-  }
-
-  // Outputs a number of spans to make up a line, taking highlighting
-  // and marked text into account.
-  function insertLineContent(line, builder, styles) {
-    var spans = line.markedSpans, allText = line.text, at = 0;
-    if (!spans) {
-      for (var i = 1; i < styles.length; i+=2)
-        builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i+1], builder));
-      return;
-    }
-
-    var len = allText.length, pos = 0, i = 1, text = "", style;
-    var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed;
-    for (;;) {
-      if (nextChange == pos) { // Update current marker set
-        spanStyle = spanEndStyle = spanStartStyle = title = "";
-        collapsed = null; nextChange = Infinity;
-        var foundBookmarks = [];
-        for (var j = 0; j < spans.length; ++j) {
-          var sp = spans[j], m = sp.marker;
-          if (sp.from <= pos && (sp.to == null || sp.to > pos)) {
-            if (sp.to != null && nextChange > sp.to) { nextChange = sp.to; spanEndStyle = ""; }
-            if (m.className) spanStyle += " " + m.className;
-            if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle;
-            if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle;
-            if (m.title && !title) title = m.title;
-            if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
-              collapsed = sp;
-          } else if (sp.from > pos && nextChange > sp.from) {
-            nextChange = sp.from;
-          }
-          if (m.type == "bookmark" && sp.from == pos && m.replacedWith) foundBookmarks.push(m);
-        }
-        if (collapsed && (collapsed.from || 0) == pos) {
-          buildCollapsedSpan(builder, (collapsed.to == null ? len : collapsed.to) - pos,
-                             collapsed.marker, collapsed.from == null);
-          if (collapsed.to == null) return collapsed.marker.find();
-        }
-        if (!collapsed && foundBookmarks.length) for (var j = 0; j < foundBookmarks.length; ++j)
-          buildCollapsedSpan(builder, 0, foundBookmarks[j]);
-      }
-      if (pos >= len) break;
-
-      var upto = Math.min(len, nextChange);
-      while (true) {
-        if (text) {
-          var end = pos + text.length;
-          if (!collapsed) {
-            var tokenText = end > upto ? text.slice(0, upto - pos) : text;
-            builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
-                             spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title);
-          }
-          if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}
-          pos = end;
-          spanStartStyle = "";
-        }
-        text = allText.slice(at, at = styles[i++]);
-        style = interpretTokenStyle(styles[i++], builder);
-      }
-    }
-  }
-
-  // DOCUMENT DATA STRUCTURE
-
-  function updateDoc(doc, change, markedSpans, selAfter, estimateHeight) {
-    function spansFor(n) {return markedSpans ? markedSpans[n] : null;}
-    function update(line, text, spans) {
-      updateLine(line, text, spans, estimateHeight);
-      signalLater(line, "change", line, change);
-    }
-
-    var from = change.from, to = change.to, text = change.text;
-    var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line);
-    var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line;
-
-    // First adjust the line structure
-    if (from.ch == 0 && to.ch == 0 && lastText == "" &&
-        (!doc.cm || doc.cm.options.wholeLineUpdateBefore)) {
-      // This is a whole-line replace. Treated specially to make
-      // sure line objects move the way they are supposed to.
-      for (var i = 0, e = text.length - 1, added = []; i < e; ++i)
-        added.push(new Line(text[i], spansFor(i), estimateHeight));
-      update(lastLine, lastLine.text, lastSpans);
-      if (nlines) doc.remove(from.line, nlines);
-      if (added.length) doc.insert(from.line, added);
-    } else if (firstLine == lastLine) {
-      if (text.length == 1) {
-        update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans);
-      } else {
-        for (var added = [], i = 1, e = text.length - 1; i < e; ++i)
-          added.push(new Line(text[i], spansFor(i), estimateHeight));
-        added.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight));
-        update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
-        doc.insert(from.line + 1, added);
-      }
-    } else if (text.length == 1) {
-      update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0));
-      doc.remove(from.line + 1, nlines);
-    } else {
-      update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
-      update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans);
-      for (var i = 1, e = text.length - 1, added = []; i < e; ++i)
-        added.push(new Line(text[i], spansFor(i), estimateHeight));
-      if (nlines > 1) doc.remove(from.line + 1, nlines - 1);
-      doc.insert(from.line + 1, added);
-    }
-
-    signalLater(doc, "change", doc, change);
-    setSelection(doc, selAfter.anchor, selAfter.head, null, true);
-  }
-
-  function LeafChunk(lines) {
-    this.lines = lines;
-    this.parent = null;
-    for (var i = 0, e = lines.length, height = 0; i < e; ++i) {
-      lines[i].parent = this;
-      height += lines[i].height;
-    }
-    this.height = height;
-  }
-
-  LeafChunk.prototype = {
-    chunkSize: function() { return this.lines.length; },
-    removeInner: function(at, n) {
-      for (var i = at, e = at + n; i < e; ++i) {
-        var line = this.lines[i];
-        this.height -= line.height;
-        cleanUpLine(line);
-        signalLater(line, "delete");
-      }
-      this.lines.splice(at, n);
-    },
-    collapse: function(lines) {
-      lines.splice.apply(lines, [lines.length, 0].concat(this.lines));
-    },
-    insertInner: function(at, lines, height) {
-      this.height += height;
-      this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
-      for (var i = 0, e = lines.length; i < e; ++i) lines[i].parent = this;
-    },
-    iterN: function(at, n, op) {
-      for (var e = at + n; at < e; ++at)
-        if (op(this.lines[at])) return true;
-    }
-  };
-
-  function BranchChunk(children) {
-    this.children = children;
-    var size = 0, height = 0;
-    for (var i = 0, e = children.length; i < e; ++i) {
-      var ch = children[i];
-      size += ch.chunkSize(); height += ch.height;
-      ch.parent = this;
-    }
-    this.size = size;
-    this.height = height;
-    this.parent = null;
-  }
-
-  BranchChunk.prototype = {
-    chunkSize: function() { return this.size; },
-    removeInner: function(at, n) {
-      this.size -= n;
-      for (var i = 0; i < this.children.length; ++i) {
-        var child = this.children[i], sz = child.chunkSize();
-        if (at < sz) {
-          var rm = Math.min(n, sz - at), oldHeight = child.height;
-          child.removeInner(at, rm);
-          this.height -= oldHeight - child.height;
-          if (sz == rm) { this.children.splice(i--, 1); child.parent = null; }
-          if ((n -= rm) == 0) break;
-          at = 0;
-        } else at -= sz;
-      }
-      if (this.size - n < 25) {
-        var lines = [];
-        this.collapse(lines);
-        this.children = [new LeafChunk(lines)];
-        this.children[0].parent = this;
-      }
-    },
-    collapse: function(lines) {
-      for (var i = 0, e = this.children.length; i < e; ++i) this.children[i].collapse(lines);
-    },
-    insertInner: function(at, lines, height) {
-      this.size += lines.length;
-      this.height += height;
-      for (var i = 0, e = this.children.length; i < e; ++i) {
-        var child = this.children[i], sz = child.chunkSize();
-        if (at <= sz) {
-          child.insertInner(at, lines, height);
-          if (child.lines && child.lines.length > 50) {
-            while (child.lines.length > 50) {
-              var spilled = child.lines.splice(child.lines.length - 25, 25);
-              var newleaf = new LeafChunk(spilled);
-              child.height -= newleaf.height;
-              this.children.splice(i + 1, 0, newleaf);
-              newleaf.parent = this;
-            }
-            this.maybeSpill();
-          }
-          break;
-        }
-        at -= sz;
-      }
-    },
-    maybeSpill: function() {
-      if (this.children.length <= 10) return;
-      var me = this;
-      do {
-        var spilled = me.children.splice(me.children.length - 5, 5);
-        var sibling = new BranchChunk(spilled);
-        if (!me.parent) { // Become the parent node
-          var copy = new BranchChunk(me.children);
-          copy.parent = me;
-          me.children = [copy, sibling];
-          me = copy;
-        } else {
-          me.size -= sibling.size;
-          me.height -= sibling.height;
-          var myIndex = indexOf(me.parent.children, me);
-          me.parent.children.splice(myIndex + 1, 0, sibling);
-        }
-        sibling.parent = me.parent;
-      } while (me.children.length > 10);
-      me.parent.maybeSpill();
-    },
-    iterN: function(at, n, op) {
-      for (var i = 0, e = this.children.length; i < e; ++i) {
-        var child = this.children[i], sz = child.chunkSize();
-        if (at < sz) {
-          var used = Math.min(n, sz - at);
-          if (child.iterN(at, used, op)) return true;
-          if ((n -= used) == 0) break;
-          at = 0;
-        } else at -= sz;
-      }
-    }
-  };
-
-  var nextDocId = 0;
-  var Doc = CodeMirror.Doc = function(text, mode, firstLine) {
-    if (!(this instanceof Doc)) return new Doc(text, mode, firstLine);
-    if (firstLine == null) firstLine = 0;
-
-    BranchChunk.call(this, [new LeafChunk([new Line("", null)])]);
-    this.first = firstLine;
-    this.scrollTop = this.scrollLeft = 0;
-    this.cantEdit = false;
-    this.history = makeHistory();
-    this.cleanGeneration = 1;
-    this.frontier = firstLine;
-    var start = Pos(firstLine, 0);
-    this.sel = {from: start, to: start, head: start, anchor: start, shift: false, extend: false, goalColumn: null};
-    this.id = ++nextDocId;
-    this.modeOption = mode;
-
-    if (typeof text == "string") text = splitLines(text);
-    updateDoc(this, {from: start, to: start, text: text}, null, {head: start, anchor: start});
-  };
-
-  Doc.prototype = createObj(BranchChunk.prototype, {
-    constructor: Doc,
-    iter: function(from, to, op) {
-      if (op) this.iterN(from - this.first, to - from, op);
-      else this.iterN(this.first, this.first + this.size, from);
-    },
-
-    insert: function(at, lines) {
-      var height = 0;
-      for (var i = 0, e = lines.length; i < e; ++i) height += lines[i].height;
-      this.insertInner(at - this.first, lines, height);
-    },
-    remove: function(at, n) { this.removeInner(at - this.first, n); },
-
-    getValue: function(lineSep) {
-      var lines = getLines(this, this.first, this.first + this.size);
-      if (lineSep === false) return lines;
-      return lines.join(lineSep || "\n");
-    },
-    setValue: function(code) {
-      var top = Pos(this.first, 0), last = this.first + this.size - 1;
-      makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length),
-                        text: splitLines(code), origin: "setValue"},
-                 {head: top, anchor: top}, true);
-    },
-    replaceRange: function(code, from, to, origin) {
-      from = clipPos(this, from);
-      to = to ? clipPos(this, to) : from;
-      replaceRange(this, code, from, to, origin);
-    },
-    getRange: function(from, to, lineSep) {
-      var lines = getBetween(this, clipPos(this, from), clipPos(this, to));
-      if (lineSep === false) return lines;
-      return lines.join(lineSep || "\n");
-    },
-
-    getLine: function(line) {var l = this.getLineHandle(line); return l && l.text;},
-    setLine: function(line, text) {
-      if (isLine(this, line))
-        replaceRange(this, text, Pos(line, 0), clipPos(this, Pos(line)));
-    },
-    removeLine: function(line) {
-      if (line) replaceRange(this, "", clipPos(this, Pos(line - 1)), clipPos(this, Pos(line)));
-      else replaceRange(this, "", Pos(0, 0), clipPos(this, Pos(1, 0)));
-    },
-
-    getLineHandle: function(line) {if (isLine(this, line)) return getLine(this, line);},
-    getLineNumber: function(line) {return lineNo(line);},
-
-    getLineHandleVisualStart: function(line) {
-      if (typeof line == "number") line = getLine(this, line);
-      return visualLine(this, line);
-    },
-
-    lineCount: function() {return this.size;},
-    firstLine: function() {return this.first;},
-    lastLine: function() {return this.first + this.size - 1;},
-
-    clipPos: function(pos) {return clipPos(this, pos);},
-
-    getCursor: function(start) {
-      var sel = this.sel, pos;
-      if (start == null || start == "head") pos = sel.head;
-      else if (start == "anchor") pos = sel.anchor;
-      else if (start == "end" || start === false) pos = sel.to;
-      else pos = sel.from;
-      return copyPos(pos);
-    },
-    somethingSelected: function() {return !posEq(this.sel.head, this.sel.anchor);},
-
-    setCursor: docOperation(function(line, ch, extend) {
-      var pos = clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line);
-      if (extend) extendSelection(this, pos);
-      else setSelection(this, pos, pos);
-    }),
-    setSelection: docOperation(function(anchor, head, bias) {
-      setSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), bias);
-    }),
-    extendSelection: docOperation(function(from, to, bias) {
-      extendSelection(this, clipPos(this, from), to && clipPos(this, to), bias);
-    }),
-
-    getSelection: function(lineSep) {return this.getRange(this.sel.from, this.sel.to, lineSep);},
-    replaceSelection: function(code, collapse, origin) {
-      makeChange(this, {from: this.sel.from, to: this.sel.to, text: splitLines(code), origin: origin}, collapse || "around");
-    },
-    undo: docOperation(function() {makeChangeFromHistory(this, "undo");}),
-    redo: docOperation(function() {makeChangeFromHistory(this, "redo");}),
-
-    setExtending: function(val) {this.sel.extend = val;},
-
-    historySize: function() {
-      var hist = this.history;
-      return {undo: hist.done.length, redo: hist.undone.length};
-    },
-    clearHistory: function() {this.history = makeHistory(this.history.maxGeneration);},
-
-    markClean: function() {
-      this.cleanGeneration = this.changeGeneration(true);
-    },
-    changeGeneration: function(forceSplit) {
-      if (forceSplit)
-        this.history.lastOp = this.history.lastOrigin = null;
-      return this.history.generation;
-    },
-    isClean: function (gen) {
-      return this.history.generation == (gen || this.cleanGeneration);
-    },
-
-    getHistory: function() {
-      return {done: copyHistoryArray(this.history.done),
-              undone: copyHistoryArray(this.history.undone)};
-    },
-    setHistory: function(histData) {
-      var hist = this.history = makeHistory(this.history.maxGeneration);
-      hist.done = histData.done.slice(0);
-      hist.undone = histData.undone.slice(0);
-    },
-
-    markText: function(from, to, options) {
-      return markText(this, clipPos(this, from), clipPos(this, to), options, "range");
-    },
-    setBookmark: function(pos, options) {
-      var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),
-                      insertLeft: options && options.insertLeft,
-                      clearWhenEmpty: false};
-      pos = clipPos(this, pos);
-      return markText(this, pos, pos, realOpts, "bookmark");
-    },
-    findMarksAt: function(pos) {
-      pos = clipPos(this, pos);
-      var markers = [], spans = getLine(this, pos.line).markedSpans;
-      if (spans) for (var i = 0; i < spans.length; ++i) {
-        var span = spans[i];
-        if ((span.from == null || span.from <= pos.ch) &&
-            (span.to == null || span.to >= pos.ch))
-          markers.push(span.marker.parent || span.marker);
-      }
-      return markers;
-    },
-    getAllMarks: function() {
-      var markers = [];
-      this.iter(function(line) {
-        var sps = line.markedSpans;
-        if (sps) for (var i = 0; i < sps.length; ++i)
-          if (sps[i].from != null) markers.push(sps[i].marker);
-      });
-      return markers;
-    },
-
-    posFromIndex: function(off) {
-      var ch, lineNo = this.first;
-      this.iter(function(line) {
-        var sz = line.text.length + 1;
-        if (sz > off) { ch = off; return true; }
-        off -= sz;
-        ++lineNo;
-      });
-      return clipPos(this, Pos(lineNo, ch));
-    },
-    indexFromPos: function (coords) {
-      coords = clipPos(this, coords);
-      var index = coords.ch;
-      if (coords.line < this.first || coords.ch < 0) return 0;
-      this.iter(this.first, coords.line, function (line) {
-        index += line.text.length + 1;
-      });
-      return index;
-    },
-
-    copy: function(copyHistory) {
-      var doc = new Doc(getLines(this, this.first, this.first + this.size), this.modeOption, this.first);
-      doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft;
-      doc.sel = {from: this.sel.from, to: this.sel.to, head: this.sel.head, anchor: this.sel.anchor,
-                 shift: this.sel.shift, extend: false, goalColumn: this.sel.goalColumn};
-      if (copyHistory) {
-        doc.history.undoDepth = this.history.undoDepth;
-        doc.setHistory(this.getHistory());
-      }
-      return doc;
-    },
-
-    linkedDoc: function(options) {
-      if (!options) options = {};
-      var from = this.first, to = this.first + this.size;
-      if (options.from != null && options.from > from) from = options.from;
-      if (options.to != null && options.to < to) to = options.to;
-      var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from);
-      if (options.sharedHist) copy.history = this.history;
-      (this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist});
-      copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}];
-      return copy;
-    },
-    unlinkDoc: function(other) {
-      if (other instanceof CodeMirror) other = other.doc;
-      if (this.linked) for (var i = 0; i < this.linked.length; ++i) {
-        var link = this.linked[i];
-        if (link.doc != other) continue;
-        this.linked.splice(i, 1);
-        other.unlinkDoc(this);
-        break;
-      }
-      // If the histories were shared, split them again
-      if (other.history == this.history) {
-        var splitIds = [other.id];
-        linkedDocs(other, function(doc) {splitIds.push(doc.id);}, true);
-        other.history = makeHistory();
-        other.history.done = copyHistoryArray(this.history.done, splitIds);
-        other.history.undone = copyHistoryArray(this.history.undone, splitIds);
-      }
-    },
-    iterLinkedDocs: function(f) {linkedDocs(this, f);},
-
-    getMode: function() {return this.mode;},
-    getEditor: function() {return this.cm;}
-  });
-
-  Doc.prototype.eachLine = Doc.prototype.iter;
-
-  // The Doc methods that should be available on CodeMirror instances
-  var dontDelegate = "iter insert remove copy getEditor".split(" ");
-  for (var prop in Doc.prototype) if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0)
-    CodeMirror.prototype[prop] = (function(method) {
-      return function() {return method.apply(this.doc, arguments);};
-    })(Doc.prototype[prop]);
-
-  eventMixin(Doc);
-
-  function linkedDocs(doc, f, sharedHistOnly) {
-    function propagate(doc, skip, sharedHist) {
-      if (doc.linked) for (var i = 0; i < doc.linked.length; ++i) {
-        var rel = doc.linked[i];
-        if (rel.doc == skip) continue;
-        var shared = sharedHist && rel.sharedHist;
-        if (sharedHistOnly && !shared) continue;
-        f(rel.doc, shared);
-        propagate(rel.doc, doc, shared);
-      }
-    }
-    propagate(doc, null, true);
-  }
-
-  function attachDoc(cm, doc) {
-    if (doc.cm) throw new Error("This document is already in use.");
-    cm.doc = doc;
-    doc.cm = cm;
-    estimateLineHeights(cm);
-    loadMode(cm);
-    if (!cm.options.lineWrapping) computeMaxLength(cm);
-    cm.options.mode = doc.modeOption;
-    regChange(cm);
-  }
-
-  // LINE UTILITIES
-
-  function getLine(chunk, n) {
-    n -= chunk.first;
-    while (!chunk.lines) {
-      for (var i = 0;; ++i) {
-        var child = chunk.children[i], sz = child.chunkSize();
-        if (n < sz) { chunk = child; break; }
-        n -= sz;
-      }
-    }
-    return chunk.lines[n];
-  }
-
-  function getBetween(doc, start, end) {
-    var out = [], n = start.line;
-    doc.iter(start.line, end.line + 1, function(line) {
-      var text = line.text;
-      if (n == end.line) text = text.slice(0, end.ch);
-      if (n == start.line) text = text.slice(start.ch);
-      out.push(text);
-      ++n;
-    });
-    return out;
-  }
-  function getLines(doc, from, to) {
-    var out = [];
-    doc.iter(from, to, function(line) { out.push(line.text); });
-    return out;
-  }
-
-  function updateLineHeight(line, height) {
-    var diff = height - line.height;
-    for (var n = line; n; n = n.parent) n.height += diff;
-  }
-
-  function lineNo(line) {
-    if (line.parent == null) return null;
-    var cur = line.parent, no = indexOf(cur.lines, line);
-    for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
-      for (var i = 0;; ++i) {
-        if (chunk.children[i] == cur) break;
-        no += chunk.children[i].chunkSize();
-      }
-    }
-    return no + cur.first;
-  }
-
-  function lineAtHeight(chunk, h) {
-    var n = chunk.first;
-    outer: do {
-      for (var i = 0, e = chunk.children.length; i < e; ++i) {
-        var child = chunk.children[i], ch = child.height;
-        if (h < ch) { chunk = child; continue outer; }
-        h -= ch;
-        n += child.chunkSize();
-      }
-      return n;
-    } while (!chunk.lines);
-    for (var i = 0, e = chunk.lines.length; i < e; ++i) {
-      var line = chunk.lines[i], lh = line.height;
-      if (h < lh) break;
-      h -= lh;
-    }
-    return n + i;
-  }
-
-  function heightAtLine(cm, lineObj) {
-    lineObj = visualLine(cm.doc, lineObj);
-
-    var h = 0, chunk = lineObj.parent;
-    for (var i = 0; i < chunk.lines.length; ++i) {
-      var line = chunk.lines[i];
-      if (line == lineObj) break;
-      else h += line.height;
-    }
-    for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {
-      for (var i = 0; i < p.children.length; ++i) {
-        var cur = p.children[i];
-        if (cur == chunk) break;
-        else h += cur.height;
-      }
-    }
-    return h;
-  }
-
-  function getOrder(line) {
-    var order = line.order;
-    if (order == null) order = line.order = bidiOrdering(line.text);
-    return order;
-  }
-
-  // HISTORY
-
-  function makeHistory(startGen) {
-    return {
-      // Arrays of history events. Doing something adds an event to
-      // done and clears undo. Undoing moves events from done to
-      // undone, redoing moves them in the other direction.
-      done: [], undone: [], undoDepth: Infinity,
-      // Used to track when changes can be merged into a single undo
-      // event
-      lastTime: 0, lastOp: null, lastOrigin: null,
-      // Used by the isClean() method
-      generation: startGen || 1, maxGeneration: startGen || 1
-    };
-  }
-
-  function attachLocalSpans(doc, change, from, to) {
-    var existing = change["spans_" + doc.id], n = 0;
-    doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function(line) {
-      if (line.markedSpans)
-        (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans;
-      ++n;
-    });
-  }
-
-  function historyChangeFromChange(doc, change) {
-    var from = { line: change.from.line, ch: change.from.ch };
-    var histChange = {from: from, to: changeEnd(change), text: getBetween(doc, change.from, change.to)};
-    attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);
-    linkedDocs(doc, function(doc) {attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);}, true);
-    return histChange;
-  }
-
-  function addToHistory(doc, change, selAfter, opId) {
-    var hist = doc.history;
-    hist.undone.length = 0;
-    var time = +new Date, cur = lst(hist.done);
-
-    if (cur &&
-        (hist.lastOp == opId ||
-         hist.lastOrigin == change.origin && change.origin &&
-         ((change.origin.charAt(0) == "+" && doc.cm && hist.lastTime > time - doc.cm.options.historyEventDelay) ||
-          change.origin.charAt(0) == "*"))) {
-      // Merge this change into the last event
-      var last = lst(cur.changes);
-      if (posEq(change.from, change.to) && posEq(change.from, last.to)) {
-        // Optimized case for simple insertion -- don't want to add
-        // new changesets for every character typed
-        last.to = changeEnd(change);
-      } else {
-        // Add new sub-event
-        cur.changes.push(historyChangeFromChange(doc, change));
-      }
-      cur.anchorAfter = selAfter.anchor; cur.headAfter = selAfter.head;
-    } else {
-      // Can not be merged, start a new event.
-      cur = {changes: [historyChangeFromChange(doc, change)],
-             generation: hist.generation,
-             anchorBefore: doc.sel.anchor, headBefore: doc.sel.head,
-             anchorAfter: selAfter.anchor, headAfter: selAfter.head};
-      hist.done.push(cur);
-      while (hist.done.length > hist.undoDepth)
-        hist.done.shift();
-    }
-    hist.generation = ++hist.maxGeneration;
-    hist.lastTime = time;
-    hist.lastOp = opId;
-    hist.lastOrigin = change.origin;
-  }
-
-  function removeClearedSpans(spans) {
-    if (!spans) return null;
-    for (var i = 0, out; i < spans.length; ++i) {
-      if (spans[i].marker.explicitlyCleared) { if (!out) out = spans.slice(0, i); }
-      else if (out) out.push(spans[i]);
-    }
-    return !out ? spans : out.length ? out : null;
-  }
-
-  function getOldSpans(doc, change) {
-    var found = change["spans_" + doc.id];
-    if (!found) return null;
-    for (var i = 0, nw = []; i < change.text.length; ++i)
-      nw.push(removeClearedSpans(found[i]));
-    return nw;
-  }
-
-  // Used both to provide a JSON-safe object in .getHistory, and, when
-  // detaching a document, to split the history in two
-  function copyHistoryArray(events, newGroup) {
-    for (var i = 0, copy = []; i < events.length; ++i) {
-      var event = events[i], changes = event.changes, newChanges = [];
-      copy.push({changes: newChanges, anchorBefore: event.anchorBefore, headBefore: event.headBefore,
-                 anchorAfter: event.anchorAfter, headAfter: event.headAfter});
-      for (var j = 0; j < changes.length; ++j) {
-        var change = changes[j], m;
-        newChanges.push({from: change.from, to: change.to, text: change.text});
-        if (newGroup) for (var prop in change) if (m = prop.match(/^spans_(\d+)$/)) {
-          if (indexOf(newGroup, Number(m[1])) > -1) {
-            lst(newChanges)[prop] = change[prop];
-            delete change[prop];
-          }
-        }
-      }
-    }
-    return copy;
-  }
-
-  // Rebasing/resetting history to deal with externally-sourced changes
-
-  function rebaseHistSel(pos, from, to, diff) {
-    if (to < pos.line) {
-      pos.line += diff;
-    } else if (from < pos.line) {
-      pos.line = from;
-      pos.ch = 0;
-    }
-  }
-
-  // Tries to rebase an array of history events given a change in the
-  // document. If the change touches the same lines as the event, the
-  // event, and everything 'behind' it, is discarded. If the change is
-  // before the event, the event's positions are updated. Uses a
-  // copy-on-write scheme for the positions, to avoid having to
-  // reallocate them all on every rebase, but also avoid problems with
-  // shared position objects being unsafely updated.
-  function rebaseHistArray(array, from, to, diff) {
-    for (var i = 0; i < array.length; ++i) {
-      var sub = array[i], ok = true;
-      for (var j = 0; j < sub.changes.length; ++j) {
-        var cur = sub.changes[j];
-        if (!sub.copied) { cur.from = copyPos(cur.from); cur.to = copyPos(cur.to); }
-        if (to < cur.from.line) {
-          cur.from.line += diff;
-          cur.to.line += diff;
-        } else if (from <= cur.to.line) {
-          ok = false;
-          break;
-        }
-      }
-      if (!sub.copied) {
-        sub.anchorBefore = copyPos(sub.anchorBefore); sub.headBefore = copyPos(sub.headBefore);
-        sub.anchorAfter = copyPos(sub.anchorAfter); sub.readAfter = copyPos(sub.headAfter);
-        sub.copied = true;
-      }
-      if (!ok) {
-        array.splice(0, i + 1);
-        i = 0;
-      } else {
-        rebaseHistSel(sub.anchorBefore); rebaseHistSel(sub.headBefore);
-        rebaseHistSel(sub.anchorAfter); rebaseHistSel(sub.headAfter);
-      }
-    }
-  }
-
-  function rebaseHist(hist, change) {
-    var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1;
-    rebaseHistArray(hist.done, from, to, diff);
-    rebaseHistArray(hist.undone, from, to, diff);
-  }
-
-  // EVENT OPERATORS
-
-  function stopMethod() {e_stop(this);}
-  // Ensure an event has a stop method.
-  function addStop(event) {
-    if (!event.stop) event.stop = stopMethod;
-    return event;
-  }
-
-  function e_preventDefault(e) {
-    if (e.preventDefault) e.preventDefault();
-    else e.returnValue = false;
-  }
-  function e_stopPropagation(e) {
-    if (e.stopPropagation) e.stopPropagation();
-    else e.cancelBubble = true;
-  }
-  function e_defaultPrevented(e) {
-    return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false;
-  }
-  function e_stop(e) {e_preventDefault(e); e_stopPropagation(e);}
-  CodeMirror.e_stop = e_stop;
-  CodeMirror.e_preventDefault = e_preventDefault;
-  CodeMirror.e_stopPropagation = e_stopPropagation;
-
-  function e_target(e) {return e.target || e.srcElement;}
-  function e_button(e) {
-    var b = e.which;
-    if (b == null) {
-      if (e.button & 1) b = 1;
-      else if (e.button & 2) b = 3;
-      else if (e.button & 4) b = 2;
-    }
-    if (mac && e.ctrlKey && b == 1) b = 3;
-    return b;
-  }
-
-  // EVENT HANDLING
-
-  function on(emitter, type, f) {
-    if (emitter.addEventListener)
-      emitter.addEventListener(type, f, false);
-    else if (emitter.attachEvent)
-      emitter.attachEvent("on" + type, f);
-    else {
-      var map = emitter._handlers || (emitter._handlers = {});
-      var arr = map[type] || (map[type] = []);
-      arr.push(f);
-    }
-  }
-
-  function off(emitter, type, f) {
-    if (emitter.removeEventListener)
-      emitter.removeEventListener(type, f, false);
-    else if (emitter.detachEvent)
-      emitter.detachEvent("on" + type, f);
-    else {
-      var arr = emitter._handlers && emitter._handlers[type];
-      if (!arr) return;
-      for (var i = 0; i < arr.length; ++i)
-        if (arr[i] == f) { arr.splice(i, 1); break; }
-    }
-  }
-
-  function signal(emitter, type /*, values...*/) {
-    var arr = emitter._handlers && emitter._handlers[type];
-    if (!arr) return;
-    var args = Array.prototype.slice.call(arguments, 2);
-    for (var i = 0; i < arr.length; ++i) arr[i].apply(null, args);
-  }
-
-  var delayedCallbacks, delayedCallbackDepth = 0;
-  function signalLater(emitter, type /*, values...*/) {
-    var arr = emitter._handlers && emitter._handlers[type];
-    if (!arr) return;
-    var args = Array.prototype.slice.call(arguments, 2);
-    if (!delayedCallbacks) {
-      ++delayedCallbackDepth;
-      delayedCallbacks = [];
-      setTimeout(fireDelayed, 0);
-    }
-    function bnd(f) {return function(){f.apply(null, args);};};
-    for (var i = 0; i < arr.length; ++i)
-      delayedCallbacks.push(bnd(arr[i]));
-  }
-
-  function signalDOMEvent(cm, e, override) {
-    signal(cm, override || e.type, cm, e);
-    return e_defaultPrevented(e) || e.codemirrorIgnore;
-  }
-
-  function fireDelayed() {
-    --delayedCallbackDepth;
-    var delayed = delayedCallbacks;
-    delayedCallbacks = null;
-    for (var i = 0; i < delayed.length; ++i) delayed[i]();
-  }
-
-  function hasHandler(emitter, type) {
-    var arr = emitter._handlers && emitter._handlers[type];
-    return arr && arr.length > 0;
-  }
-
-  CodeMirror.on = on; CodeMirror.off = off; CodeMirror.signal = signal;
-
-  function eventMixin(ctor) {
-    ctor.prototype.on = function(type, f) {on(this, type, f);};
-    ctor.prototype.off = function(type, f) {off(this, type, f);};
-  }
-
-  // MISC UTILITIES
-
-  // Number of pixels added to scroller and sizer to hide scrollbar
-  var scrollerCutOff = 30;
-
-  // Returned or thrown by various protocols to signal 'I'm not
-  // handling this'.
-  var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}};
-
-  function Delayed() {this.id = null;}
-  Delayed.prototype = {set: function(ms, f) {clearTimeout(this.id); this.id = setTimeout(f, ms);}};
-
-  // Counts the column offset in a string, taking tabs into account.
-  // Used mostly to find indentation.
-  function countColumn(string, end, tabSize, startIndex, startValue) {
-    if (end == null) {
-      end = string.search(/[^\s\u00a0]/);
-      if (end == -1) end = string.length;
-    }
-    for (var i = startIndex || 0, n = startValue || 0; i < end; ++i) {
-      if (string.charAt(i) == "\t") n += tabSize - (n % tabSize);
-      else ++n;
-    }
-    return n;
-  }
-  CodeMirror.countColumn = countColumn;
-
-  var spaceStrs = [""];
-  function spaceStr(n) {
-    while (spaceStrs.length <= n)
-      spaceStrs.push(lst(spaceStrs) + " ");
-    return spaceStrs[n];
-  }
-
-  function lst(arr) { return arr[arr.length-1]; }
-
-  function selectInput(node) {
-    if (ios) { // Mobile Safari apparently has a bug where select() is broken.
-      node.selectionStart = 0;
-      node.selectionEnd = node.value.length;
-    } else {
-      // Suppress mysterious IE10 errors
-      try { node.select(); }
-      catch(_e) {}
-    }
-  }
-
-  function indexOf(collection, elt) {
-    if (collection.indexOf) return collection.indexOf(elt);
-    for (var i = 0, e = collection.length; i < e; ++i)
-      if (collection[i] == elt) return i;
-    return -1;
-  }
-
-  function createObj(base, props) {
-    function Obj() {}
-    Obj.prototype = base;
-    var inst = new Obj();
-    if (props) copyObj(props, inst);
-    return inst;
-  }
-
-  function copyObj(obj, target) {
-    if (!target) target = {};
-    for (var prop in obj) if (obj.hasOwnProperty(prop)) target[prop] = obj[prop];
-    return target;
-  }
-
-  function emptyArray(size) {
-    for (var a = [], i = 0; i < size; ++i) a.push(undefined);
-    return a;
-  }
-
-  function bind(f) {
-    var args = Array.prototype.slice.call(arguments, 1);
-    return function(){return f.apply(null, args);};
-  }
-
-  var nonASCIISingleCaseWordChar = /[\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;
-  function isWordChar(ch) {
-    return /\w/.test(ch) || ch > "\x80" &&
-      (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch));
-  }
-
-  function isEmpty(obj) {
-    for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false;
-    return true;
-  }
-
-  var isExtendingChar = /[\u0300-\u036F\u0483-\u0487\u0488-\u0489\u0591-\u05BD\u05BF\u05C1-\u05C2\u05C4-\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7-\u06E8\u06EA-\u06ED\uA66F\u1DC0-\u1DFF\u20D0-\u20FF\uA670-\uA672\uA674-\uA67D\uA69F\udc00-\udfff\uFE20-\uFE2F]/;
-
-  // DOM UTILITIES
-
-  function elt(tag, content, className, style) {
-    var e = document.createElement(tag);
-    if (className) e.className = className;
-    if (style) e.style.cssText = style;
-    if (typeof content == "string") setTextContent(e, content);
-    else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]);
-    return e;
-  }
-
-  function removeChildren(e) {
-    for (var count = e.childNodes.length; count > 0; --count)
-      e.removeChild(e.firstChild);
-    return e;
-  }
-
-  function removeChildrenAndAdd(parent, e) {
-    return removeChildren(parent).appendChild(e);
-  }
-
-  function setTextContent(e, str) {
-    if (ie_lt9) {
-      e.innerHTML = "";
-      e.appendChild(document.createTextNode(str));
-    } else e.textContent = str;
-  }
-
-  function getRect(node) {
-    return node.getBoundingClientRect();
-  }
-  CodeMirror.replaceGetRect = function(f) { getRect = f; };
-
-  // FEATURE DETECTION
-
-  // Detect drag-and-drop
-  var dragAndDrop = function() {
-    // There is *some* kind of drag-and-drop support in IE6-8, but I
-    // couldn't get it to work yet.
-    if (ie_lt9) return false;
-    var div = elt('div');
-    return "draggable" in div || "dragDrop" in div;
-  }();
-
-  // For a reason I have yet to figure out, some browsers disallow
-  // word wrapping between certain characters *only* if a new inline
-  // element is started between them. This makes it hard to reliably
-  // measure the position of things, since that requires inserting an
-  // extra span. This terribly fragile set of tests matches the
-  // character combinations that suffer from this phenomenon on the
-  // various browsers.
-  function spanAffectsWrapping() { return false; }
-  if (gecko) // Only for "$'"
-    spanAffectsWrapping = function(str, i) {
-      return str.charCodeAt(i - 1) == 36 && str.charCodeAt(i) == 39;
-    };
-  else if (safari && !/Version\/([6-9]|\d\d)\b/.test(navigator.userAgent))
-    spanAffectsWrapping = function(str, i) {
-      return /\-[^ \-?]|\?[^ !\'\"\),.\-\/:;\?\]\}]/.test(str.slice(i - 1, i + 1));
-    };
-  else if (webkit && /Chrome\/(?:29|[3-9]\d|\d\d\d)\./.test(navigator.userAgent))
-    spanAffectsWrapping = function(str, i) {
-      var code = str.charCodeAt(i - 1);
-      return code >= 8208 && code <= 8212;
-    };
-  else if (webkit)
-    spanAffectsWrapping = function(str, i) {
-      if (i > 1 && str.charCodeAt(i - 1) == 45) {
-        if (/\w/.test(str.charAt(i - 2)) && /[^\-?\.]/.test(str.charAt(i))) return true;
-        if (i > 2 && /[\d\.,]/.test(str.charAt(i - 2)) && /[\d\.,]/.test(str.charAt(i))) return false;
-      }
-      return /[~!#%&*)=+}\]\\|\"\.>,:;][({[<]|-[^\-?\.\u2010-\u201f\u2026]|\?[\w~`@#$%\^&*(_=+{[|><]|\u2026[\w~`@#$%\^&*(_=+{[><]/.test(str.slice(i - 1, i + 1));
-    };
-
-  var knownScrollbarWidth;
-  function scrollbarWidth(measure) {
-    if (knownScrollbarWidth != null) return knownScrollbarWidth;
-    var test = elt("div", null, null, "width: 50px; height: 50px; overflow-x: scroll");
-    removeChildrenAndAdd(measure, test);
-    if (test.offsetWidth)
-      knownScrollbarWidth = test.offsetHeight - test.clientHeight;
-    return knownScrollbarWidth || 0;
-  }
-
-  var zwspSupported;
-  function zeroWidthElement(measure) {
-    if (zwspSupported == null) {
-      var test = elt("span", "\u200b");
-      removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")]));
-      if (measure.firstChild.offsetHeight != 0)
-        zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !ie_lt8;
-    }
-    if (zwspSupported) return elt("span", "\u200b");
-    else return elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px");
-  }
-
-  // See if "".split is the broken IE version, if so, provide an
-  // alternative way to split lines.
-  var splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) {
-    var pos = 0, result = [], l = string.length;
-    while (pos <= l) {
-      var nl = string.indexOf("\n", pos);
-      if (nl == -1) nl = string.length;
-      var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl);
-      var rt = line.indexOf("\r");
-      if (rt != -1) {
-        result.push(line.slice(0, rt));
-        pos += rt + 1;
-      } else {
-        result.push(line);
-        pos = nl + 1;
-      }
-    }
-    return result;
-  } : function(string){return string.split(/\r\n?|\n/);};
-  CodeMirror.splitLines = splitLines;
-
-  var hasSelection = window.getSelection ? function(te) {
-    try { return te.selectionStart != te.selectionEnd; }
-    catch(e) { return false; }
-  } : function(te) {
-    try {var range = te.ownerDocument.selection.createRange();}
-    catch(e) {}
-    if (!range || range.parentElement() != te) return false;
-    return range.compareEndPoints("StartToEnd", range) != 0;
-  };
-
-  var hasCopyEvent = (function() {
-    var e = elt("div");
-    if ("oncopy" in e) return true;
-    e.setAttribute("oncopy", "return;");
-    return typeof e.oncopy == 'function';
-  })();
-
-  // KEY NAMING
-
-  var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
-                  19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
-                  36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
-                  46: "Delete", 59: ";", 91: "Mod", 92: "Mod", 93: "Mod", 109: "-", 107: "=", 127: "Delete",
-                  186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
-                  221: "]", 222: "'", 63276: "PageUp", 63277: "PageDown", 63275: "End", 63273: "Home",
-                  63234: "Left", 63232: "Up", 63235: "Right", 63233: "Down", 63302: "Insert", 63272: "Delete"};
-  CodeMirror.keyNames = keyNames;
-  (function() {
-    // Number keys
-    for (var i = 0; i < 10; i++) keyNames[i + 48] = String(i);
-    // Alphabetic keys
-    for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i);
-    // Function keys
-    for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i;
-  })();
-
-  // BIDI HELPERS
-
-  function iterateBidiSections(order, from, to, f) {
-    if (!order) return f(from, to, "ltr");
-    var found = false;
-    for (var i = 0; i < order.length; ++i) {
-      var part = order[i];
-      if (part.from < to && part.to > from || from == to && part.to == from) {
-        f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr");
-        found = true;
-      }
-    }
-    if (!found) f(from, to, "ltr");
-  }
-
-  function bidiLeft(part) { return part.level % 2 ? part.to : part.from; }
-  function bidiRight(part) { return part.level % 2 ? part.from : part.to; }
-
-  function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0; }
-  function lineRight(line) {
-    var order = getOrder(line);
-    if (!order) return line.text.length;
-    return bidiRight(lst(order));
-  }
-
-  function lineStart(cm, lineN) {
-    var line = getLine(cm.doc, lineN);
-    var visual = visualLine(cm.doc, line);
-    if (visual != line) lineN = lineNo(visual);
-    var order = getOrder(visual);
-    var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual);
-    return Pos(lineN, ch);
-  }
-  function lineEnd(cm, lineN) {
-    var merged, line;
-    while (merged = collapsedSpanAtEnd(line = getLine(cm.doc, lineN)))
-      lineN = merged.find().to.line;
-    var order = getOrder(line);
-    var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line);
-    return Pos(lineN, ch);
-  }
-
-  function compareBidiLevel(order, a, b) {
-    var linedir = order[0].level;
-    if (a == linedir) return true;
-    if (b == linedir) return false;
-    return a < b;
-  }
-  var bidiOther;
-  function getBidiPartAt(order, pos) {
-    bidiOther = null;
-    for (var i = 0, found; i < order.length; ++i) {
-      var cur = order[i];
-      if (cur.from < pos && cur.to > pos) return i;
-      if ((cur.from == pos || cur.to == pos)) {
-        if (found == null) {
-          found = i;
-        } else if (compareBidiLevel(order, cur.level, order[found].level)) {
-          if (cur.from != cur.to) bidiOther = found;
-          return i;
-        } else {
-          if (cur.from != cur.to) bidiOther = i;
-          return found;
-        }
-      }
-    }
-    return found;
-  }
-
-  function moveInLine(line, pos, dir, byUnit) {
-    if (!byUnit) return pos + dir;
-    do pos += dir;
-    while (pos > 0 && isExtendingChar.test(line.text.charAt(pos)));
-    return pos;
-  }
-
-  // This is somewhat involved. It is needed in order to move
-  // 'visually' through bi-directional text -- i.e., pressing left
-  // should make the cursor go left, even when in RTL text. The
-  // tricky part is the 'jumps', where RTL and LTR text touch each
-  // other. This often requires the cursor offset to move more than
-  // one unit, in order to visually move one unit.
-  function moveVisually(line, start, dir, byUnit) {
-    var bidi = getOrder(line);
-    if (!bidi) return moveLogically(line, start, dir, byUnit);
-    var pos = getBidiPartAt(bidi, start), part = bidi[pos];
-    var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit);
-
-    for (;;) {
-      if (target > part.from && target < part.to) return target;
-      if (target == part.from || target == part.to) {
-        if (getBidiPartAt(bidi, target) == pos) return target;
-        part = bidi[pos += dir];
-        return (dir > 0) == part.level % 2 ? part.to : part.from;
-      } else {
-        part = bidi[pos += dir];
-        if (!part) return null;
-        if ((dir > 0) == part.level % 2)
-          target = moveInLine(line, part.to, -1, byUnit);
-        else
-          target = moveInLine(line, part.from, 1, byUnit);
-      }
-    }
-  }
-
-  function moveLogically(line, start, dir, byUnit) {
-    var target = start + dir;
-    if (byUnit) while (target > 0 && isExtendingChar.test(line.text.charAt(target))) target += dir;
-    return target < 0 || target > line.text.length ? null : target;
-  }
-
-  // Bidirectional ordering algorithm
-  // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm
-  // that this (partially) implements.
-
-  // One-char codes used for character types:
-  // L (L):   Left-to-Right
-  // R (R):   Right-to-Left
-  // r (AL):  Right-to-Left Arabic
-  // 1 (EN):  European Number
-  // + (ES):  European Number Separator
-  // % (ET):  European Number Terminator
-  // n (AN):  Arabic Number
-  // , (CS):  Common Number Separator
-  // m (NSM): Non-Spacing Mark
-  // b (BN):  Boundary Neutral
-  // s (B):   Paragraph Separator
-  // t (S):   Segment Separator
-  // w (WS):  Whitespace
-  // N (ON):  Other Neutrals
-
-  // Returns null if characters are ordered as they appear
-  // (left-to-right), or an array of sections ({from, to, level}
-  // objects) in the order in which they occur visually.
-  var bidiOrdering = (function() {
-    // Character types for codepoints 0 to 0xff
-    var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLL";
-    // Character types for codepoints 0x600 to 0x6ff
-    var arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmmrrrrrrrrrrrrrrrrrr";
-    function charType(code) {
-      if (code <= 0xff) return lowTypes.charAt(code);
-      else if (0x590 <= code && code <= 0x5f4) return "R";
-      else if (0x600 <= code && code <= 0x6ff) return arabicTypes.charAt(code - 0x600);
-      else if (0x700 <= code && code <= 0x8ac) return "r";
-      else return "L";
-    }
-
-    var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
-    var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;
-    // Browsers seem to always treat the boundaries of block elements as being L.
-    var outerType = "L";
-
-    return function(str) {
-      if (!bidiRE.test(str)) return false;
-      var len = str.length, types = [];
-      for (var i = 0, type; i < len; ++i)
-        types.push(type = charType(str.charCodeAt(i)));
-
-      // W1. Examine each non-spacing mark (NSM) in the level run, and
-      // change the type of the NSM to the type of the previous
-      // character. If the NSM is at the start of the level run, it will
-      // get the type of sor.
-      for (var i = 0, prev = outerType; i < len; ++i) {
-        var type = types[i];
-        if (type == "m") types[i] = prev;
-        else prev = type;
-      }
-
-      // W2. Search backwards from each instance of a European number
-      // until the first strong type (R, L, AL, or sor) is found. If an
-      // AL is found, change the type of the European number to Arabic
-      // number.
-      // W3. Change all ALs to R.
-      for (var i = 0, cur = outerType; i < len; ++i) {
-        var type = types[i];
-        if (type == "1" && cur == "r") types[i] = "n";
-        else if (isStrong.test(type)) { cur = type; if (type == "r") types[i] = "R"; }
-      }
-
-      // W4. A single European separator between two European numbers
-      // changes to a European number. A single common separator between
-      // two numbers of the same type changes to that type.
-      for (var i = 1, prev = types[0]; i < len - 1; ++i) {
-        var type = types[i];
-        if (type == "+" && prev == "1" && types[i+1] == "1") types[i] = "1";
-        else if (type == "," && prev == types[i+1] &&
-                 (prev == "1" || prev == "n")) types[i] = prev;
-        prev = type;
-      }
-
-      // W5. A sequence of European terminators adjacent to European
-      // numbers changes to all European numbers.
-      // W6. Otherwise, separators and terminators change to Other
-      // Neutral.
-      for (var i = 0; i < len; ++i) {
-        var type = types[i];
-        if (type == ",") types[i] = "N";
-        else if (type == "%") {
-          for (var end = i + 1; end < len && types[end] == "%"; ++end) {}
-          var replace = (i && types[i-1] == "!") || (end < len && types[end] == "1") ? "1" : "N";
-          for (var j = i; j < end; ++j) types[j] = replace;
-          i = end - 1;
-        }
-      }
-
-      // W7. Search backwards from each instance of a European number
-      // until the first strong type (R, L, or sor) is found. If an L is
-      // found, then change the type of the European number to L.
-      for (var i = 0, cur = outerType; i < len; ++i) {
-        var type = types[i];
-        if (cur == "L" && type == "1") types[i] = "L";
-        else if (isStrong.test(type)) cur = type;
-      }
-
-      // N1. A sequence of neutrals takes the direction of the
-      // surrounding strong text if the text on both sides has the same
-      // direction. European and Arabic numbers act as if they were R in
-      // terms of their influence on neutrals. Start-of-level-run (sor)
-      // and end-of-level-run (eor) are used at level run boundaries.
-      // N2. Any remaining neutrals take the embedding direction.
-      for (var i = 0; i < len; ++i) {
-        if (isNeutral.test(types[i])) {
-          for (var end = i + 1; end < len && isNeutral.test(types[end]); ++end) {}
-          var before = (i ? types[i-1] : outerType) == "L";
-          var after = (end < len ? types[end] : outerType) == "L";
-          var replace = before || after ? "L" : "R";
-          for (var j = i; j < end; ++j) types[j] = replace;
-          i = end - 1;
-        }
-      }
-
-      // Here we depart from the documented algorithm, in order to avoid
-      // building up an actual levels array. Since there are only three
-      // levels (0, 1, 2) in an implementation that doesn't take
-      // explicit embedding into account, we can build up the order on
-      // the fly, without following the level-based algorithm.
-      var order = [], m;
-      for (var i = 0; i < len;) {
-        if (countsAsLeft.test(types[i])) {
-          var start = i;
-          for (++i; i < len && countsAsLeft.test(types[i]); ++i) {}
-          order.push({from: start, to: i, level: 0});
-        } else {
-          var pos = i, at = order.length;
-          for (++i; i < len && types[i] != "L"; ++i) {}
-          for (var j = pos; j < i;) {
-            if (countsAsNum.test(types[j])) {
-              if (pos < j) order.splice(at, 0, {from: pos, to: j, level: 1});
-              var nstart = j;
-              for (++j; j < i && countsAsNum.test(types[j]); ++j) {}
-              order.splice(at, 0, {from: nstart, to: j, level: 2});
-              pos = j;
-            } else ++j;
-          }
-          if (pos < i) order.splice(at, 0, {from: pos, to: i, level: 1});
-        }
-      }
-      if (order[0].level == 1 && (m = str.match(/^\s+/))) {
-        order[0].from = m[0].length;
-        order.unshift({from: 0, to: m[0].length, level: 0});
-      }
-      if (lst(order).level == 1 && (m = str.match(/\s+$/))) {
-        lst(order).to -= m[0].length;
-        order.push({from: len - m[0].length, to: len, level: 0});
-      }
-      if (order[0].level != lst(order).level)
-        order.push({from: len, to: len, level: order[0].level});
-
-      return order;
-    };
-  })();
-
-  // THE END
-
-  CodeMirror.version = "3.20.1";
-
-  return CodeMirror;
-})();
diff --git a/docs/js/es5-sham.min.js b/docs/js/es5-sham.min.js
deleted file mode 100644
index 033c27a3fd8e..000000000000
--- a/docs/js/es5-sham.min.js
+++ /dev/null
@@ -1,2 +0,0 @@
-(function(definition){if(typeof define=="function"){define(definition)}else if(typeof YUI=="function"){YUI.add("es5-sham",definition)}else{definition()}})(function(){var call=Function.prototype.call;var prototypeOfObject=Object.prototype;var owns=call.bind(prototypeOfObject.hasOwnProperty);var defineGetter;var defineSetter;var lookupGetter;var lookupSetter;var supportsAccessors;if(supportsAccessors=owns(prototypeOfObject,"__defineGetter__")){defineGetter=call.bind(prototypeOfObject.__defineGetter__);defineSetter=call.bind(prototypeOfObject.__defineSetter__);lookupGetter=call.bind(prototypeOfObject.__lookupGetter__);lookupSetter=call.bind(prototypeOfObject.__lookupSetter__)}if(!Object.getPrototypeOf){Object.getPrototypeOf=function getPrototypeOf(object){return object.__proto__||(object.constructor?object.constructor.prototype:prototypeOfObject)}}function doesGetOwnPropertyDescriptorWork(object){try{object.sentinel=0;return Object.getOwnPropertyDescriptor(object,"sentinel").value===0}catch(exception){}}if(Object.defineProperty){var getOwnPropertyDescriptorWorksOnObject=doesGetOwnPropertyDescriptorWork({});var getOwnPropertyDescriptorWorksOnDom=typeof document=="undefined"||doesGetOwnPropertyDescriptorWork(document.createElement("div"));if(!getOwnPropertyDescriptorWorksOnDom||!getOwnPropertyDescriptorWorksOnObject){var getOwnPropertyDescriptorFallback=Object.getOwnPropertyDescriptor}}if(!Object.getOwnPropertyDescriptor||getOwnPropertyDescriptorFallback){var ERR_NON_OBJECT="Object.getOwnPropertyDescriptor called on a non-object: ";Object.getOwnPropertyDescriptor=function getOwnPropertyDescriptor(object,property){if(typeof object!="object"&&typeof object!="function"||object===null){throw new TypeError(ERR_NON_OBJECT+object)}if(getOwnPropertyDescriptorFallback){try{return getOwnPropertyDescriptorFallback.call(Object,object,property)}catch(exception){}}if(!owns(object,property)){return}var descriptor={enumerable:true,configurable:true};if(supportsAccessors){var prototype=object.__proto__;object.__proto__=prototypeOfObject;var getter=lookupGetter(object,property);var setter=lookupSetter(object,property);object.__proto__=prototype;if(getter||setter){if(getter){descriptor.get=getter}if(setter){descriptor.set=setter}return descriptor}}descriptor.value=object[property];descriptor.writable=true;return descriptor}}if(!Object.getOwnPropertyNames){Object.getOwnPropertyNames=function getOwnPropertyNames(object){return Object.keys(object)}}if(!Object.create){var createEmpty;var supportsProto=Object.prototype.__proto__===null;if(supportsProto||typeof document=="undefined"){createEmpty=function(){return{__proto__:null}}}else{createEmpty=function(){var iframe=document.createElement("iframe");var parent=document.body||document.documentElement;iframe.style.display="none";parent.appendChild(iframe);iframe.src="javascript:";var empty=iframe.contentWindow.Object.prototype;parent.removeChild(iframe);iframe=null;delete empty.constructor;delete empty.hasOwnProperty;delete empty.propertyIsEnumerable;delete empty.isPrototypeOf;delete empty.toLocaleString;delete empty.toString;delete empty.valueOf;empty.__proto__=null;function Empty(){}Empty.prototype=empty;createEmpty=function(){return new Empty};return new Empty}}Object.create=function create(prototype,properties){var object;function Type(){}if(prototype===null){object=createEmpty()}else{if(typeof prototype!=="object"&&typeof prototype!=="function"){throw new TypeError("Object prototype may only be an Object or null")}Type.prototype=prototype;object=new Type;object.__proto__=prototype}if(properties!==void 0){Object.defineProperties(object,properties)}return object}}function doesDefinePropertyWork(object){try{Object.defineProperty(object,"sentinel",{});return"sentinel"in object}catch(exception){}}if(Object.defineProperty){var definePropertyWorksOnObject=doesDefinePropertyWork({});var definePropertyWorksOnDom=typeof document=="undefined"||doesDefinePropertyWork(document.createElement("div"));if(!definePropertyWorksOnObject||!definePropertyWorksOnDom){var definePropertyFallback=Object.defineProperty,definePropertiesFallback=Object.defineProperties}}if(!Object.defineProperty||definePropertyFallback){var ERR_NON_OBJECT_DESCRIPTOR="Property description must be an object: ";var ERR_NON_OBJECT_TARGET="Object.defineProperty called on non-object: ";var ERR_ACCESSORS_NOT_SUPPORTED="getters & setters can not be defined "+"on this javascript engine";Object.defineProperty=function defineProperty(object,property,descriptor){if(typeof object!="object"&&typeof object!="function"||object===null){throw new TypeError(ERR_NON_OBJECT_TARGET+object)}if(typeof descriptor!="object"&&typeof descriptor!="function"||descriptor===null){throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR+descriptor)}if(definePropertyFallback){try{return definePropertyFallback.call(Object,object,property,descriptor)}catch(exception){}}if(owns(descriptor,"value")){if(supportsAccessors&&(lookupGetter(object,property)||lookupSetter(object,property))){var prototype=object.__proto__;object.__proto__=prototypeOfObject;delete object[property];object[property]=descriptor.value;object.__proto__=prototype}else{object[property]=descriptor.value}}else{if(!supportsAccessors){throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED)}if(owns(descriptor,"get")){defineGetter(object,property,descriptor.get)}if(owns(descriptor,"set")){defineSetter(object,property,descriptor.set)}}return object}}if(!Object.defineProperties||definePropertiesFallback){Object.defineProperties=function defineProperties(object,properties){if(definePropertiesFallback){try{return definePropertiesFallback.call(Object,object,properties)}catch(exception){}}for(var property in properties){if(owns(properties,property)&&property!="__proto__"){Object.defineProperty(object,property,properties[property])}}return object}}if(!Object.seal){Object.seal=function seal(object){return object}}if(!Object.freeze){Object.freeze=function freeze(object){return object}}try{Object.freeze(function(){})}catch(exception){Object.freeze=function freeze(freezeObject){return function freeze(object){if(typeof object=="function"){return object}else{return freezeObject(object)}}}(Object.freeze)}if(!Object.preventExtensions){Object.preventExtensions=function preventExtensions(object){return object}}if(!Object.isSealed){Object.isSealed=function isSealed(object){return false}}if(!Object.isFrozen){Object.isFrozen=function isFrozen(object){return false}}if(!Object.isExtensible){Object.isExtensible=function isExtensible(object){if(Object(object)!==object){throw new TypeError}var name="";while(owns(object,name)){name+="?"}object[name]=true;var returnValue=owns(object,name);delete object[name];return returnValue}}});
-//# sourceMappingURL=es5-sham.map
\ No newline at end of file
diff --git a/docs/js/es5-shim.min.js b/docs/js/es5-shim.min.js
deleted file mode 100644
index 50502e0548bd..000000000000
--- a/docs/js/es5-shim.min.js
+++ /dev/null
@@ -1,2 +0,0 @@
-(function(definition){if(typeof define=="function"){define(definition)}else if(typeof YUI=="function"){YUI.add("es5",definition)}else{definition()}})(function(){if(parseInt("08")!==8){parseInt=function(origParseInt){var hexRegex=/^0[xX]/;return function parseIntES5(str,radix){str=String(str).trim();if(!+radix){radix=hexRegex.test(str)?16:10}return origParseInt(str,radix)}}(parseInt)}function Empty(){}if(!Function.prototype.bind){Function.prototype.bind=function bind(that){var target=this;if(typeof target!="function"){throw new TypeError("Function.prototype.bind called on incompatible "+target)}var args=_Array_slice_.call(arguments,1);var binder=function(){if(this instanceof bound){var result=target.apply(this,args.concat(_Array_slice_.call(arguments)));if(Object(result)===result){return result}return this}else{return target.apply(that,args.concat(_Array_slice_.call(arguments)))}};var boundLength=Math.max(0,target.length-args.length);var boundArgs=[];for(var i=0;i<boundLength;i++){boundArgs.push("$"+i)}var bound=Function("binder","return function("+boundArgs.join(",")+"){return binder.apply(this,arguments)}")(binder);if(target.prototype){Empty.prototype=target.prototype;bound.prototype=new Empty;Empty.prototype=null}return bound}}var call=Function.prototype.call;var prototypeOfArray=Array.prototype;var prototypeOfObject=Object.prototype;var _Array_slice_=prototypeOfArray.slice;var _toString=call.bind(prototypeOfObject.toString);var owns=call.bind(prototypeOfObject.hasOwnProperty);var defineGetter;var defineSetter;var lookupGetter;var lookupSetter;var supportsAccessors;if(supportsAccessors=owns(prototypeOfObject,"__defineGetter__")){defineGetter=call.bind(prototypeOfObject.__defineGetter__);defineSetter=call.bind(prototypeOfObject.__defineSetter__);lookupGetter=call.bind(prototypeOfObject.__lookupGetter__);lookupSetter=call.bind(prototypeOfObject.__lookupSetter__)}if([1,2].splice(0).length!=2){var array_splice=Array.prototype.splice;var array_push=Array.prototype.push;var array_unshift=Array.prototype.unshift;if(function(){function makeArray(l){var a=[];while(l--){a.unshift(l)}return a}var array=[],lengthBefore;array.splice.bind(array,0,0).apply(null,makeArray(20));array.splice.bind(array,0,0).apply(null,makeArray(26));lengthBefore=array.length;array.splice(5,0,"XXX");if(lengthBefore+1==array.length){return true}}()){Array.prototype.splice=function(start,deleteCount){if(!arguments.length){return[]}else{return array_splice.apply(this,[start===void 0?0:start,deleteCount===void 0?this.length-start:deleteCount].concat(_Array_slice_.call(arguments,2)))}}}else{Array.prototype.splice=function(start,deleteCount){var result,args=_Array_slice_.call(arguments,2),addElementsCount=args.length;if(!arguments.length){return[]}if(start===void 0){start=0}if(deleteCount===void 0){deleteCount=this.length-start}if(addElementsCount>0){if(deleteCount<=0){if(start==this.length){array_push.apply(this,args);return[]}if(start==0){array_unshift.apply(this,args);return[]}}result=_Array_slice_.call(this,start,start+deleteCount);args.push.apply(args,_Array_slice_.call(this,start+deleteCount,this.length));args.unshift.apply(args,_Array_slice_.call(this,0,start));args.unshift(0,this.length);array_splice.apply(this,args);return result}return array_splice.call(this,start,deleteCount)}}}if([].unshift(0)!=1){var array_unshift=Array.prototype.unshift;Array.prototype.unshift=function(){array_unshift.apply(this,arguments);return this.length}}if(!Array.isArray){Array.isArray=function isArray(obj){return _toString(obj)=="[object Array]"}}var boxedString=Object("a"),splitString=boxedString[0]!="a"||!(0 in boxedString);var boxedForEach=true;if(Array.prototype.forEach){Array.prototype.forEach.call("foo",function(item,i,obj){if(typeof obj!=="object")boxedForEach=false})}if(!Array.prototype.forEach||!boxedForEach){Array.prototype.forEach=function forEach(fun){var object=toObject(this),self=splitString&&_toString(this)=="[object String]"?this.split(""):object,thisp=arguments[1],i=-1,length=self.length>>>0;if(_toString(fun)!="[object Function]"){throw new TypeError}while(++i<length){if(i in self){fun.call(thisp,self[i],i,object)}}}}if(!Array.prototype.map){Array.prototype.map=function map(fun){var object=toObject(this),self=splitString&&_toString(this)=="[object String]"?this.split(""):object,length=self.length>>>0,result=Array(length),thisp=arguments[1];if(_toString(fun)!="[object Function]"){throw new TypeError(fun+" is not a function")}for(var i=0;i<length;i++){if(i in self)result[i]=fun.call(thisp,self[i],i,object)}return result}}if(!Array.prototype.filter){Array.prototype.filter=function filter(fun){var object=toObject(this),self=splitString&&_toString(this)=="[object String]"?this.split(""):object,length=self.length>>>0,result=[],value,thisp=arguments[1];if(_toString(fun)!="[object Function]"){throw new TypeError(fun+" is not a function")}for(var i=0;i<length;i++){if(i in self){value=self[i];if(fun.call(thisp,value,i,object)){result.push(value)}}}return result}}if(!Array.prototype.every){Array.prototype.every=function every(fun){var object=toObject(this),self=splitString&&_toString(this)=="[object String]"?this.split(""):object,length=self.length>>>0,thisp=arguments[1];if(_toString(fun)!="[object Function]"){throw new TypeError(fun+" is not a function")}for(var i=0;i<length;i++){if(i in self&&!fun.call(thisp,self[i],i,object)){return false}}return true}}if(!Array.prototype.some){Array.prototype.some=function some(fun){var object=toObject(this),self=splitString&&_toString(this)=="[object String]"?this.split(""):object,length=self.length>>>0,thisp=arguments[1];if(_toString(fun)!="[object Function]"){throw new TypeError(fun+" is not a function")}for(var i=0;i<length;i++){if(i in self&&fun.call(thisp,self[i],i,object)){return true}}return false}}if(!Array.prototype.reduce){Array.prototype.reduce=function reduce(fun){var object=toObject(this),self=splitString&&_toString(this)=="[object String]"?this.split(""):object,length=self.length>>>0;if(_toString(fun)!="[object Function]"){throw new TypeError(fun+" is not a function")}if(!length&&arguments.length==1){throw new TypeError("reduce of empty array with no initial value")}var i=0;var result;if(arguments.length>=2){result=arguments[1]}else{do{if(i in self){result=self[i++];break}if(++i>=length){throw new TypeError("reduce of empty array with no initial value")}}while(true)}for(;i<length;i++){if(i in self){result=fun.call(void 0,result,self[i],i,object)}}return result}}if(!Array.prototype.reduceRight){Array.prototype.reduceRight=function reduceRight(fun){var object=toObject(this),self=splitString&&_toString(this)=="[object String]"?this.split(""):object,length=self.length>>>0;if(_toString(fun)!="[object Function]"){throw new TypeError(fun+" is not a function")}if(!length&&arguments.length==1){throw new TypeError("reduceRight of empty array with no initial value")}var result,i=length-1;if(arguments.length>=2){result=arguments[1]}else{do{if(i in self){result=self[i--];break}if(--i<0){throw new TypeError("reduceRight of empty array with no initial value")}}while(true)}if(i<0){return result}do{if(i in this){result=fun.call(void 0,result,self[i],i,object)}}while(i--);return result}}if(!Array.prototype.indexOf||[0,1].indexOf(1,2)!=-1){Array.prototype.indexOf=function indexOf(sought){var self=splitString&&_toString(this)=="[object String]"?this.split(""):toObject(this),length=self.length>>>0;if(!length){return-1}var i=0;if(arguments.length>1){i=toInteger(arguments[1])}i=i>=0?i:Math.max(0,length+i);for(;i<length;i++){if(i in self&&self[i]===sought){return i}}return-1}}if(!Array.prototype.lastIndexOf||[0,1].lastIndexOf(0,-3)!=-1){Array.prototype.lastIndexOf=function lastIndexOf(sought){var self=splitString&&_toString(this)=="[object String]"?this.split(""):toObject(this),length=self.length>>>0;if(!length){return-1}var i=length-1;if(arguments.length>1){i=Math.min(i,toInteger(arguments[1]))}i=i>=0?i:length-Math.abs(i);for(;i>=0;i--){if(i in self&&sought===self[i]){return i}}return-1}}if(!Object.keys){var hasDontEnumBug=true,dontEnums=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],dontEnumsLength=dontEnums.length;for(var key in{toString:null}){hasDontEnumBug=false}Object.keys=function keys(object){if(typeof object!="object"&&typeof object!="function"||object===null){throw new TypeError("Object.keys called on a non-object")}var keys=[];for(var name in object){if(owns(object,name)){keys.push(name)}}if(hasDontEnumBug){for(var i=0,ii=dontEnumsLength;i<ii;i++){var dontEnum=dontEnums[i];if(owns(object,dontEnum)){keys.push(dontEnum)}}}return keys}}var negativeDate=-621987552e5,negativeYearString="-000001";if(!Date.prototype.toISOString||new Date(negativeDate).toISOString().indexOf(negativeYearString)===-1){Date.prototype.toISOString=function toISOString(){var result,length,value,year,month;if(!isFinite(this)){throw new RangeError("Date.prototype.toISOString called on non-finite value.")}year=this.getUTCFullYear();month=this.getUTCMonth();year+=Math.floor(month/12);month=(month%12+12)%12;result=[month+1,this.getUTCDate(),this.getUTCHours(),this.getUTCMinutes(),this.getUTCSeconds()];year=(year<0?"-":year>9999?"+":"")+("00000"+Math.abs(year)).slice(0<=year&&year<=9999?-4:-6);length=result.length;while(length--){value=result[length];if(value<10){result[length]="0"+value}}return year+"-"+result.slice(0,2).join("-")+"T"+result.slice(2).join(":")+"."+("000"+this.getUTCMilliseconds()).slice(-3)+"Z"}}var dateToJSONIsSupported=false;try{dateToJSONIsSupported=Date.prototype.toJSON&&new Date(NaN).toJSON()===null&&new Date(negativeDate).toJSON().indexOf(negativeYearString)!==-1&&Date.prototype.toJSON.call({toISOString:function(){return true}})}catch(e){}if(!dateToJSONIsSupported){Date.prototype.toJSON=function toJSON(key){var o=Object(this),tv=toPrimitive(o),toISO;if(typeof tv==="number"&&!isFinite(tv)){return null}toISO=o.toISOString;if(typeof toISO!="function"){throw new TypeError("toISOString property is not callable")}return toISO.call(o)}}if(!Date.parse||"Date.parse is buggy"){Date=function(NativeDate){function Date(Y,M,D,h,m,s,ms){var length=arguments.length;if(this instanceof NativeDate){var date=length==1&&String(Y)===Y?new NativeDate(Date.parse(Y)):length>=7?new NativeDate(Y,M,D,h,m,s,ms):length>=6?new NativeDate(Y,M,D,h,m,s):length>=5?new NativeDate(Y,M,D,h,m):length>=4?new NativeDate(Y,M,D,h):length>=3?new NativeDate(Y,M,D):length>=2?new NativeDate(Y,M):length>=1?new NativeDate(Y):new NativeDate;date.constructor=Date;return date}return NativeDate.apply(this,arguments)}var isoDateExpression=new RegExp("^"+"(\\d{4}|[+-]\\d{6})"+"(?:-(\\d{2})"+"(?:-(\\d{2})"+"(?:"+"T(\\d{2})"+":(\\d{2})"+"(?:"+":(\\d{2})"+"(?:(\\.\\d{1,}))?"+")?"+"("+"Z|"+"(?:"+"([-+])"+"(\\d{2})"+":(\\d{2})"+")"+")?)?)?)?"+"$");var months=[0,31,59,90,120,151,181,212,243,273,304,334,365];function dayFromMonth(year,month){var t=month>1?1:0;return months[month]+Math.floor((year-1969+t)/4)-Math.floor((year-1901+t)/100)+Math.floor((year-1601+t)/400)+365*(year-1970)}function toUTC(t){return Number(new NativeDate(1970,0,1,0,0,0,t))}for(var key in NativeDate){Date[key]=NativeDate[key]}Date.now=NativeDate.now;Date.UTC=NativeDate.UTC;Date.prototype=NativeDate.prototype;Date.prototype.constructor=Date;Date.parse=function parse(string){var match=isoDateExpression.exec(string);if(match){var year=Number(match[1]),month=Number(match[2]||1)-1,day=Number(match[3]||1)-1,hour=Number(match[4]||0),minute=Number(match[5]||0),second=Number(match[6]||0),millisecond=Math.floor(Number(match[7]||0)*1e3),isLocalTime=Boolean(match[4]&&!match[8]),signOffset=match[9]==="-"?1:-1,hourOffset=Number(match[10]||0),minuteOffset=Number(match[11]||0),result;if(hour<(minute>0||second>0||millisecond>0?24:25)&&minute<60&&second<60&&millisecond<1e3&&month>-1&&month<12&&hourOffset<24&&minuteOffset<60&&day>-1&&day<dayFromMonth(year,month+1)-dayFromMonth(year,month)){result=((dayFromMonth(year,month)+day)*24+hour+hourOffset*signOffset)*60;result=((result+minute+minuteOffset*signOffset)*60+second)*1e3+millisecond;if(isLocalTime){result=toUTC(result)}if(-864e13<=result&&result<=864e13){return result}}return NaN}return NativeDate.parse.apply(this,arguments)};return Date}(Date)}if(!Date.now){Date.now=function now(){return(new Date).getTime()}}if(!Number.prototype.toFixed||8e-5.toFixed(3)!=="0.000"||.9.toFixed(0)==="0"||1.255.toFixed(2)!=="1.25"||0xde0b6b3a7640080.toFixed(0)!=="1000000000000000128"){(function(){var base,size,data,i;base=1e7;size=6;data=[0,0,0,0,0,0];function multiply(n,c){var i=-1;while(++i<size){c+=n*data[i];data[i]=c%base;c=Math.floor(c/base)}}function divide(n){var i=size,c=0;while(--i>=0){c+=data[i];data[i]=Math.floor(c/n);c=c%n*base}}function toString(){var i=size;var s="";while(--i>=0){if(s!==""||i===0||data[i]!==0){var t=String(data[i]);if(s===""){s=t}else{s+="0000000".slice(0,7-t.length)+t}}}return s}function pow(x,n,acc){return n===0?acc:n%2===1?pow(x,n-1,acc*x):pow(x*x,n/2,acc)}function log(x){var n=0;while(x>=4096){n+=12;x/=4096}while(x>=2){n+=1;x/=2}return n}Number.prototype.toFixed=function(fractionDigits){var f,x,s,m,e,z,j,k;f=Number(fractionDigits);f=f!==f?0:Math.floor(f);if(f<0||f>20){throw new RangeError("Number.toFixed called with invalid number of decimals")}x=Number(this);if(x!==x){return"NaN"}if(x<=-1e21||x>=1e21){return String(x)}s="";if(x<0){s="-";x=-x}m="0";if(x>1e-21){e=log(x*pow(2,69,1))-69;z=e<0?x*pow(2,-e,1):x/pow(2,e,1);z*=4503599627370496;e=52-e;if(e>0){multiply(0,z);j=f;while(j>=7){multiply(1e7,0);j-=7}multiply(pow(10,j,1),0);j=e-1;while(j>=23){divide(1<<23);j-=23}divide(1<<j);multiply(1,1);divide(2);m=toString()}else{multiply(0,z);multiply(1<<-e,0);m=toString()+"0.00000000000000000000".slice(2,2+f)}}if(f>0){k=m.length;if(k<=f){m=s+"0.0000000000000000000".slice(0,f-k+2)+m}else{m=s+m.slice(0,k-f)+"."+m.slice(k-f)}}else{m=s+m}return m}})()}var string_split=String.prototype.split;if("ab".split(/(?:ab)*/).length!==2||".".split(/(.?)(.?)/).length!==4||"tesst".split(/(s)*/)[1]==="t"||"".split(/.?/).length||".".split(/()()/).length>1){(function(){var compliantExecNpcg=/()??/.exec("")[1]===void 0;String.prototype.split=function(separator,limit){var string=this;if(separator===void 0&&limit===0)return[];if(Object.prototype.toString.call(separator)!=="[object RegExp]"){return string_split.apply(this,arguments)}var output=[],flags=(separator.ignoreCase?"i":"")+(separator.multiline?"m":"")+(separator.extended?"x":"")+(separator.sticky?"y":""),lastLastIndex=0,separator=new RegExp(separator.source,flags+"g"),separator2,match,lastIndex,lastLength;string+="";if(!compliantExecNpcg){separator2=new RegExp("^"+separator.source+"$(?!\\s)",flags)}limit=limit===void 0?-1>>>0:limit>>>0;while(match=separator.exec(string)){lastIndex=match.index+match[0].length;if(lastIndex>lastLastIndex){output.push(string.slice(lastLastIndex,match.index));if(!compliantExecNpcg&&match.length>1){match[0].replace(separator2,function(){for(var i=1;i<arguments.length-2;i++){if(arguments[i]===void 0){match[i]=void 0}}})}if(match.length>1&&match.index<string.length){Array.prototype.push.apply(output,match.slice(1))}lastLength=match[0].length;lastLastIndex=lastIndex;if(output.length>=limit){break}}if(separator.lastIndex===match.index){separator.lastIndex++}}if(lastLastIndex===string.length){if(lastLength||!separator.test("")){output.push("")}}else{output.push(string.slice(lastLastIndex))}return output.length>limit?output.slice(0,limit):output}})()}else if("0".split(void 0,0).length){String.prototype.split=function(separator,limit){if(separator===void 0&&limit===0)return[];return string_split.apply(this,arguments)}}if("".substr&&"0b".substr(-1)!=="b"){var string_substr=String.prototype.substr;String.prototype.substr=function(start,length){return string_substr.call(this,start<0?(start=this.length+start)<0?0:start:start,length)}}var ws="	\n\f\r \xa0\u1680\u180e\u2000\u2001\u2002\u2003"+"\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028"+"\u2029\ufeff";if(!String.prototype.trim||ws.trim()){ws="["+ws+"]";var trimBeginRegexp=new RegExp("^"+ws+ws+"*"),trimEndRegexp=new RegExp(ws+ws+"*$");String.prototype.trim=function trim(){if(this===void 0||this===null){throw new TypeError("can't convert "+this+" to object")}return String(this).replace(trimBeginRegexp,"").replace(trimEndRegexp,"")}}function toInteger(n){n=+n;if(n!==n){n=0}else if(n!==0&&n!==1/0&&n!==-(1/0)){n=(n>0||-1)*Math.floor(Math.abs(n))}return n}function isPrimitive(input){var type=typeof input;return input===null||type==="undefined"||type==="boolean"||type==="number"||type==="string"}function toPrimitive(input){var val,valueOf,toString;if(isPrimitive(input)){return input}valueOf=input.valueOf;if(typeof valueOf==="function"){val=valueOf.call(input);if(isPrimitive(val)){return val}}toString=input.toString;if(typeof toString==="function"){val=toString.call(input);if(isPrimitive(val)){return val}}throw new TypeError}var toObject=function(o){if(o==null){throw new TypeError("can't convert "+o+" to object")}return Object(o)}});
-//# sourceMappingURL=es5-shim.map
\ No newline at end of file
diff --git a/docs/js/html5shiv.min.js b/docs/js/html5shiv.min.js
deleted file mode 100644
index dcf351c867e1..000000000000
--- a/docs/js/html5shiv.min.js
+++ /dev/null
@@ -1,8 +0,0 @@
-/*
- HTML5 Shiv v3.6.2 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
-*/
-(function(l,f){function m(){var a=e.elements;return"string"==typeof a?a.split(" "):a}function i(a){var b=n[a[o]];b||(b={},h++,a[o]=h,n[h]=b);return b}function p(a,b,c){b||(b=f);if(g)return b.createElement(a);c||(c=i(b));b=c.cache[a]?c.cache[a].cloneNode():r.test(a)?(c.cache[a]=c.createElem(a)).cloneNode():c.createElem(a);return b.canHaveChildren&&!s.test(a)?c.frag.appendChild(b):b}function t(a,b){if(!b.cache)b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag();
-a.createElement=function(c){return!e.shivMethods?b.createElem(c):p(c,a,b)};a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+m().join().replace(/\w+/g,function(a){b.createElem(a);b.frag.createElement(a);return'c("'+a+'")'})+");return n}")(e,b.frag)}function q(a){a||(a=f);var b=i(a);if(e.shivCSS&&!j&&!b.hasCSS){var c,d=a;c=d.createElement("p");d=d.getElementsByTagName("head")[0]||d.documentElement;c.innerHTML="x<style>article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}</style>";
-c=d.insertBefore(c.lastChild,d.firstChild);b.hasCSS=!!c}g||t(a,b);return a}var k=l.html5||{},s=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,r=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,j,o="_html5shiv",h=0,n={},g;(function(){try{var a=f.createElement("a");a.innerHTML="<xyz></xyz>";j="hidden"in a;var b;if(!(b=1==a.childNodes.length)){f.createElement("a");var c=f.createDocumentFragment();b="undefined"==typeof c.cloneNode||
-"undefined"==typeof c.createDocumentFragment||"undefined"==typeof c.createElement}g=b}catch(d){g=j=!0}})();var e={elements:k.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup main mark meter nav output progress section summary time video",version:"3.6.2",shivCSS:!1!==k.shivCSS,supportsUnknownElements:g,shivMethods:!1!==k.shivMethods,type:"default",shivDocument:q,createElement:p,createDocumentFragment:function(a,b){a||(a=f);if(g)return a.createDocumentFragment();
-for(var b=b||i(a),c=b.frag.cloneNode(),d=0,e=m(),h=e.length;d<h;d++)c.createElement(e[d]);return c}};l.html5=e;q(f)})(this,document);
diff --git a/docs/js/javascript.js b/docs/js/javascript.js
deleted file mode 100644
index c734555047f4..000000000000
--- a/docs/js/javascript.js
+++ /dev/null
@@ -1,425 +0,0 @@
-// TODO actually recognize syntax of TypeScript constructs
-
-CodeMirror.defineMode("javascript", function(config, parserConfig) {
-  var indentUnit = config.indentUnit;
-  var jsonMode = parserConfig.json;
-  var isTS = parserConfig.typescript;
-
-  // Tokenizer
-
-  var keywords = function(){
-    function kw(type) {return {type: type, style: "keyword"};}
-    var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
-    var operator = kw("operator"), atom = {type: "atom", style: "atom"};
-    
-    var jsKeywords = {
-      "if": A, "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
-      "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C,
-      "var": kw("var"), "const": kw("var"), "let": kw("var"),
-      "function": kw("function"), "catch": kw("catch"),
-      "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
-      "in": operator, "typeof": operator, "instanceof": operator,
-      "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom
-    };
-
-    // Extend the 'normal' keywords with the TypeScript language extensions
-    if (isTS) {
-      var type = {type: "variable", style: "variable-3"};
-      var tsKeywords = {
-        // object-like things
-        "interface": kw("interface"),
-        "class": kw("class"),
-        "extends": kw("extends"),
-        "constructor": kw("constructor"),
-
-        // scope modifiers
-        "public": kw("public"),
-        "private": kw("private"),
-        "protected": kw("protected"),
-        "static": kw("static"),
-
-        "super": kw("super"),
-
-        // types
-        "string": type, "number": type, "bool": type, "any": type
-      };
-
-      for (var attr in tsKeywords) {
-        jsKeywords[attr] = tsKeywords[attr];
-      }
-    }
-
-    return jsKeywords;
-  }();
-
-  var isOperatorChar = /[+\-*&%=<>!?|]/;
-
-  function chain(stream, state, f) {
-    state.tokenize = f;
-    return f(stream, state);
-  }
-
-  function nextUntilUnescaped(stream, end) {
-    var escaped = false, next;
-    while ((next = stream.next()) != null) {
-      if (next == end && !escaped)
-        return false;
-      escaped = !escaped && next == "\\";
-    }
-    return escaped;
-  }
-
-  // Used as scratch variables to communicate multiple values without
-  // consing up tons of objects.
-  var type, content;
-  function ret(tp, style, cont) {
-    type = tp; content = cont;
-    return style;
-  }
-
-  function jsTokenBase(stream, state) {
-    var ch = stream.next();
-    if (ch == '"' || ch == "'")
-      return chain(stream, state, jsTokenString(ch));
-    else if (/[\[\]{}\(\),;\:\.]/.test(ch))
-      return ret(ch);
-    else if (ch == "0" && stream.eat(/x/i)) {
-      stream.eatWhile(/[\da-f]/i);
-      return ret("number", "number");
-    }      
-    else if (/\d/.test(ch) || ch == "-" && stream.eat(/\d/)) {
-      stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
-      return ret("number", "number");
-    }
-    else if (ch == "/") {
-      if (stream.eat("*")) {
-        return chain(stream, state, jsTokenComment);
-      }
-      else if (stream.eat("/")) {
-        stream.skipToEnd();
-        return ret("comment", "comment");
-      }
-      else if (state.lastType == "operator" || state.lastType == "keyword c" ||
-               /^[\[{}\(,;:]$/.test(state.lastType)) {
-        nextUntilUnescaped(stream, "/");
-        stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla
-        return ret("regexp", "string-2");
-      }
-      else {
-        stream.eatWhile(isOperatorChar);
-        return ret("operator", null, stream.current());
-      }
-    }
-    else if (ch == "#") {
-      stream.skipToEnd();
-      return ret("error", "error");
-    }
-    else if (isOperatorChar.test(ch)) {
-      stream.eatWhile(isOperatorChar);
-      return ret("operator", null, stream.current());
-    }
-    else {
-      stream.eatWhile(/[\w\$_]/);
-      var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
-      return (known && state.lastType != ".") ? ret(known.type, known.style, word) :
-                     ret("variable", "variable", word);
-    }
-  }
-
-  function jsTokenString(quote) {
-    return function(stream, state) {
-      if (!nextUntilUnescaped(stream, quote))
-        state.tokenize = jsTokenBase;
-      return ret("string", "string");
-    };
-  }
-
-  function jsTokenComment(stream, state) {
-    var maybeEnd = false, ch;
-    while (ch = stream.next()) {
-      if (ch == "/" && maybeEnd) {
-        state.tokenize = jsTokenBase;
-        break;
-      }
-      maybeEnd = (ch == "*");
-    }
-    return ret("comment", "comment");
-  }
-
-  // Parser
-
-  var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true};
-
-  function JSLexical(indented, column, type, align, prev, info) {
-    this.indented = indented;
-    this.column = column;
-    this.type = type;
-    this.prev = prev;
-    this.info = info;
-    if (align != null) this.align = align;
-  }
-
-  function inScope(state, varname) {
-    for (var v = state.localVars; v; v = v.next)
-      if (v.name == varname) return true;
-  }
-
-  function parseJS(state, style, type, content, stream) {
-    var cc = state.cc;
-    // Communicate our context to the combinators.
-    // (Less wasteful than consing up a hundred closures on every call.)
-    cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc;
-  
-    if (!state.lexical.hasOwnProperty("align"))
-      state.lexical.align = true;
-
-    while(true) {
-      var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
-      if (combinator(type, content)) {
-        while(cc.length && cc[cc.length - 1].lex)
-          cc.pop()();
-        if (cx.marked) return cx.marked;
-        if (type == "variable" && inScope(state, content)) return "variable-2";
-        return style;
-      }
-    }
-  }
-
-  // Combinator utils
-
-  var cx = {state: null, column: null, marked: null, cc: null};
-  function pass() {
-    for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
-  }
-  function cont() {
-    pass.apply(null, arguments);
-    return true;
-  }
-  function register(varname) {
-    function inList(list) {
-      for (var v = list; v; v = v.next)
-        if (v.name == varname) return true;
-      return false;
-    }
-    var state = cx.state;
-    if (state.context) {
-      cx.marked = "def";
-      if (inList(state.localVars)) return;
-      state.localVars = {name: varname, next: state.localVars};
-    } else {
-      if (inList(state.globalVars)) return;
-      state.globalVars = {name: varname, next: state.globalVars};
-    }
-  }
-
-  // Combinators
-
-  var defaultVars = {name: "this", next: {name: "arguments"}};
-  function pushcontext() {
-    cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
-    cx.state.localVars = defaultVars;
-  }
-  function popcontext() {
-    cx.state.localVars = cx.state.context.vars;
-    cx.state.context = cx.state.context.prev;
-  }
-  function pushlex(type, info) {
-    var result = function() {
-      var state = cx.state;
-      state.lexical = new JSLexical(state.indented, cx.stream.column(), type, null, state.lexical, info);
-    };
-    result.lex = true;
-    return result;
-  }
-  function poplex() {
-    var state = cx.state;
-    if (state.lexical.prev) {
-      if (state.lexical.type == ")")
-        state.indented = state.lexical.indented;
-      state.lexical = state.lexical.prev;
-    }
-  }
-  poplex.lex = true;
-
-  function expect(wanted) {
-    return function(type) {
-      if (type == wanted) return cont();
-      else if (wanted == ";") return pass();
-      else return cont(arguments.callee);
-    };
-  }
-
-  function statement(type) {
-    if (type == "var") return cont(pushlex("vardef"), vardef1, expect(";"), poplex);
-    if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex);
-    if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
-    if (type == "{") return cont(pushlex("}"), block, poplex);
-    if (type == ";") return cont();
-    if (type == "function") return cont(functiondef);
-    if (type == "for") return cont(pushlex("form"), expect("("), pushlex(")"), forspec1, expect(")"),
-                                      poplex, statement, poplex);
-    if (type == "variable") return cont(pushlex("stat"), maybelabel);
-    if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
-                                         block, poplex, poplex);
-    if (type == "case") return cont(expression, expect(":"));
-    if (type == "default") return cont(expect(":"));
-    if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
-                                        statement, poplex, popcontext);
-    return pass(pushlex("stat"), expression, expect(";"), poplex);
-  }
-  function expression(type) {
-    if (atomicTypes.hasOwnProperty(type)) return cont(maybeoperator);
-    if (type == "function") return cont(functiondef);
-    if (type == "keyword c") return cont(maybeexpression);
-    if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeoperator);
-    if (type == "operator") return cont(expression);
-    if (type == "[") return cont(pushlex("]"), commasep(expression, "]"), poplex, maybeoperator);
-    if (type == "{") return cont(pushlex("}"), commasep(objprop, "}"), poplex, maybeoperator);
-    return cont();
-  }
-  function maybeexpression(type) {
-    if (type.match(/[;\}\)\],]/)) return pass();
-    return pass(expression);
-  }
-    
-  function maybeoperator(type, value) {
-    if (type == "operator") {
-      if (/\+\+|--/.test(value)) return cont(maybeoperator);
-      if (value == "?") return cont(expression, expect(":"), expression);
-      return cont(expression);
-    }
-    if (type == ";") return;
-    if (type == "(") return cont(pushlex(")"), commasep(expression, ")"), poplex, maybeoperator);
-    if (type == ".") return cont(property, maybeoperator);
-    if (type == "[") return cont(pushlex("]"), expression, expect("]"), poplex, maybeoperator);
-  }
-  function maybelabel(type) {
-    if (type == ":") return cont(poplex, statement);
-    return pass(maybeoperator, expect(";"), poplex);
-  }
-  function property(type) {
-    if (type == "variable") {cx.marked = "property"; return cont();}
-  }
-  function objprop(type) {
-    if (type == "variable") cx.marked = "property";
-    if (atomicTypes.hasOwnProperty(type)) return cont(expect(":"), expression);
-  }
-  function commasep(what, end) {
-    function proceed(type) {
-      if (type == ",") return cont(what, proceed);
-      if (type == end) return cont();
-      return cont(expect(end));
-    }
-    return function(type) {
-      if (type == end) return cont();
-      else return pass(what, proceed);
-    };
-  }
-  function block(type) {
-    if (type == "}") return cont();
-    return pass(statement, block);
-  }
-  function maybetype(type) {
-    if (type == ":") return cont(typedef);
-    return pass();
-  }
-  function typedef(type) {
-    if (type == "variable"){cx.marked = "variable-3"; return cont();}
-    return pass();
-  }
-  function vardef1(type, value) {
-    if (type == "variable") {
-      register(value);
-      return isTS ? cont(maybetype, vardef2) : cont(vardef2);
-    }
-    return pass();
-  }
-  function vardef2(type, value) {
-    if (value == "=") return cont(expression, vardef2);
-    if (type == ",") return cont(vardef1);
-  }
-  function forspec1(type) {
-    if (type == "var") return cont(vardef1, expect(";"), forspec2);
-    if (type == ";") return cont(forspec2);
-    if (type == "variable") return cont(formaybein);
-    return cont(forspec2);
-  }
-  function formaybein(_type, value) {
-    if (value == "in") return cont(expression);
-    return cont(maybeoperator, forspec2);
-  }
-  function forspec2(type, value) {
-    if (type == ";") return cont(forspec3);
-    if (value == "in") return cont(expression);
-    return cont(expression, expect(";"), forspec3);
-  }
-  function forspec3(type) {
-    if (type != ")") cont(expression);
-  }
-  function functiondef(type, value) {
-    if (type == "variable") {register(value); return cont(functiondef);}
-    if (type == "(") return cont(pushlex(")"), pushcontext, commasep(funarg, ")"), poplex, statement, popcontext);
-  }
-  function funarg(type, value) {
-    if (type == "variable") {register(value); return isTS ? cont(maybetype) : cont();}
-  }
-
-  // Interface
-
-  return {
-    startState: function(basecolumn) {
-      return {
-        tokenize: jsTokenBase,
-        lastType: null,
-        cc: [],
-        lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
-        localVars: parserConfig.localVars,
-        globalVars: parserConfig.globalVars,
-        context: parserConfig.localVars && {vars: parserConfig.localVars},
-        indented: 0
-      };
-    },
-
-    token: function(stream, state) {
-      if (stream.sol()) {
-        if (!state.lexical.hasOwnProperty("align"))
-          state.lexical.align = false;
-        state.indented = stream.indentation();
-      }
-      if (stream.eatSpace()) return null;
-      var style = state.tokenize(stream, state);
-      if (type == "comment") return style;
-      state.lastType = type;
-      return parseJS(state, style, type, content, stream);
-    },
-
-    indent: function(state, textAfter) {
-      if (state.tokenize == jsTokenComment) return CodeMirror.Pass;
-      if (state.tokenize != jsTokenBase) return 0;
-      var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;
-      if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev;
-      var type = lexical.type, closing = firstChar == type;
-      if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? 4 : 0);
-      else if (type == "form" && firstChar == "{") return lexical.indented;
-      else if (type == "form") return lexical.indented + indentUnit;
-      else if (type == "stat")
-        return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? indentUnit : 0);
-      else if (lexical.info == "switch" && !closing)
-        return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
-      else if (lexical.align) return lexical.column + (closing ? 0 : 1);
-      else return lexical.indented + (closing ? 0 : indentUnit);
-    },
-
-    electricChars: ":{}",
-
-    jsonMode: jsonMode
-  };
-});
-
-CodeMirror.defineMIME("text/javascript", "javascript");
-CodeMirror.defineMIME("text/ecmascript", "javascript");
-CodeMirror.defineMIME("application/javascript", "javascript");
-CodeMirror.defineMIME("application/ecmascript", "javascript");
-CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
-CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
-CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });
diff --git a/docs/js/marked.min.js b/docs/js/marked.min.js
deleted file mode 100644
index 45adb9e491f7..000000000000
--- a/docs/js/marked.min.js
+++ /dev/null
@@ -1,6 +0,0 @@
-/**
- * marked - a markdown parser
- * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
- * https://github.com/chjj/marked
- */
-(function(){var block={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:noop,hr:/^( *[-*_]){3,} *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,nptable:noop,lheading:/^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,blockquote:/^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,list:/^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:/^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/,def:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,table:noop,paragraph:/^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,text:/^[^\n]+/};block.bullet=/(?:[*+-]|\d+\.)/;block.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;block.item=replace(block.item,"gm")(/bull/g,block.bullet)();block.list=replace(block.list)(/bull/g,block.bullet)("hr","\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))")("def","\\n+(?="+block.def.source+")")();block.blockquote=replace(block.blockquote)("def",block.def)();block._tag="(?!(?:"+"a|em|strong|small|s|cite|q|dfn|abbr|data|time|code"+"|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo"+"|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b";block.html=replace(block.html)("comment",/<!--[\s\S]*?-->/)("closed",/<(tag)[\s\S]+?<\/\1>/)("closing",/<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)(/tag/g,block._tag)();block.paragraph=replace(block.paragraph)("hr",block.hr)("heading",block.heading)("lheading",block.lheading)("blockquote",block.blockquote)("tag","<"+block._tag)("def",block.def)();block.normal=merge({},block);block.gfm=merge({},block.normal,{fences:/^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,paragraph:/^/});block.gfm.paragraph=replace(block.paragraph)("(?!","(?!"+block.gfm.fences.source.replace("\\1","\\2")+"|"+block.list.source.replace("\\1","\\3")+"|")();block.tables=merge({},block.gfm,{nptable:/^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,table:/^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/});function Lexer(options){this.tokens=[];this.tokens.links={};this.options=options||marked.defaults;this.rules=block.normal;if(this.options.gfm){if(this.options.tables){this.rules=block.tables}else{this.rules=block.gfm}}}Lexer.rules=block;Lexer.lex=function(src,options){var lexer=new Lexer(options);return lexer.lex(src)};Lexer.prototype.lex=function(src){src=src.replace(/\r\n|\r/g,"\n").replace(/\t/g,"    ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n");return this.token(src,true)};Lexer.prototype.token=function(src,top,bq){var src=src.replace(/^ +$/gm,""),next,loose,cap,bull,b,item,space,i,l;while(src){if(cap=this.rules.newline.exec(src)){src=src.substring(cap[0].length);if(cap[0].length>1){this.tokens.push({type:"space"})}}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);cap=cap[0].replace(/^ {4}/gm,"");this.tokens.push({type:"code",text:!this.options.pedantic?cap.replace(/\n+$/,""):cap});continue}if(cap=this.rules.fences.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"code",lang:cap[2],text:cap[3]});continue}if(cap=this.rules.heading.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"heading",depth:cap[1].length,text:cap[2]});continue}if(top&&(cap=this.rules.nptable.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/\n$/,"").split("\n")};for(i=0;i<item.align.length;i++){if(/^ *-+: *$/.test(item.align[i])){item.align[i]="right"}else if(/^ *:-+: *$/.test(item.align[i])){item.align[i]="center"}else if(/^ *:-+ *$/.test(item.align[i])){item.align[i]="left"}else{item.align[i]=null}}for(i=0;i<item.cells.length;i++){item.cells[i]=item.cells[i].split(/ *\| */)}this.tokens.push(item);continue}if(cap=this.rules.lheading.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"heading",depth:cap[2]==="="?1:2,text:cap[1]});continue}if(cap=this.rules.hr.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"hr"});continue}if(cap=this.rules.blockquote.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"blockquote_start"});cap=cap[0].replace(/^ *> ?/gm,"");this.token(cap,top,true);this.tokens.push({type:"blockquote_end"});continue}if(cap=this.rules.list.exec(src)){src=src.substring(cap[0].length);bull=cap[2];this.tokens.push({type:"list_start",ordered:bull.length>1});cap=cap[0].match(this.rules.item);next=false;l=cap.length;i=0;for(;i<l;i++){item=cap[i];space=item.length;item=item.replace(/^ *([*+-]|\d+\.) +/,"");if(~item.indexOf("\n ")){space-=item.length;item=!this.options.pedantic?item.replace(new RegExp("^ {1,"+space+"}","gm"),""):item.replace(/^ {1,4}/gm,"")}if(this.options.smartLists&&i!==l-1){b=block.bullet.exec(cap[i+1])[0];if(bull!==b&&!(bull.length>1&&b.length>1)){src=cap.slice(i+1).join("\n")+src;i=l-1}}loose=next||/\n\n(?!\s*$)/.test(item);if(i!==l-1){next=item.charAt(item.length-1)==="\n";if(!loose)loose=next}this.tokens.push({type:loose?"loose_item_start":"list_item_start"});this.token(item,false,bq);this.tokens.push({type:"list_item_end"})}this.tokens.push({type:"list_end"});continue}if(cap=this.rules.html.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:this.options.sanitize?"paragraph":"html",pre:cap[1]==="pre"||cap[1]==="script"||cap[1]==="style",text:cap[0]});continue}if(!bq&&top&&(cap=this.rules.def.exec(src))){src=src.substring(cap[0].length);this.tokens.links[cap[1].toLowerCase()]={href:cap[2],title:cap[3]};continue}if(top&&(cap=this.rules.table.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/(?: *\| *)?\n$/,"").split("\n")};for(i=0;i<item.align.length;i++){if(/^ *-+: *$/.test(item.align[i])){item.align[i]="right"}else if(/^ *:-+: *$/.test(item.align[i])){item.align[i]="center"}else if(/^ *:-+ *$/.test(item.align[i])){item.align[i]="left"}else{item.align[i]=null}}for(i=0;i<item.cells.length;i++){item.cells[i]=item.cells[i].replace(/^ *\| *| *\| *$/g,"").split(/ *\| */)}this.tokens.push(item);continue}if(top&&(cap=this.rules.paragraph.exec(src))){src=src.substring(cap[0].length);this.tokens.push({type:"paragraph",text:cap[1].charAt(cap[1].length-1)==="\n"?cap[1].slice(0,-1):cap[1]});continue}if(cap=this.rules.text.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"text",text:cap[0]});continue}if(src){throw new Error("Infinite loop on byte: "+src.charCodeAt(0))}}return this.tokens};var inline={escape:/^\\([\\`*{}\[\]()#+\-.!_>])/,autolink:/^<([^ >]+(@|:\/)[^ >]+)>/,url:noop,tag:/^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,link:/^!?\[(inside)\]\(href\)/,reflink:/^!?\[(inside)\]\s*\[([^\]]*)\]/,nolink:/^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,strong:/^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,em:/^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,code:/^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:noop,text:/^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/};inline._inside=/(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;inline._href=/\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;inline.link=replace(inline.link)("inside",inline._inside)("href",inline._href)();inline.reflink=replace(inline.reflink)("inside",inline._inside)();inline.normal=merge({},inline);inline.pedantic=merge({},inline.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/});inline.gfm=merge({},inline.normal,{escape:replace(inline.escape)("])","~|])")(),url:/^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,del:/^~~(?=\S)([\s\S]*?\S)~~/,text:replace(inline.text)("]|","~]|")("|","|https?://|")()});inline.breaks=merge({},inline.gfm,{br:replace(inline.br)("{2,}","*")(),text:replace(inline.gfm.text)("{2,}","*")()});function InlineLexer(links,options){this.options=options||marked.defaults;this.links=links;this.rules=inline.normal;this.renderer=this.options.renderer||new Renderer;this.renderer.options=this.options;if(!this.links){throw new Error("Tokens array requires a `links` property.")}if(this.options.gfm){if(this.options.breaks){this.rules=inline.breaks}else{this.rules=inline.gfm}}else if(this.options.pedantic){this.rules=inline.pedantic}}InlineLexer.rules=inline;InlineLexer.output=function(src,links,options){var inline=new InlineLexer(links,options);return inline.output(src)};InlineLexer.prototype.output=function(src){var out="",link,text,href,cap;while(src){if(cap=this.rules.escape.exec(src)){src=src.substring(cap[0].length);out+=cap[1];continue}if(cap=this.rules.autolink.exec(src)){src=src.substring(cap[0].length);if(cap[2]==="@"){text=cap[1].charAt(6)===":"?this.mangle(cap[1].substring(7)):this.mangle(cap[1]);href=this.mangle("mailto:")+text}else{text=escape(cap[1]);href=text}out+=this.renderer.link(href,null,text);continue}if(!this.inLink&&(cap=this.rules.url.exec(src))){src=src.substring(cap[0].length);text=escape(cap[1]);href=text;out+=this.renderer.link(href,null,text);continue}if(cap=this.rules.tag.exec(src)){if(!this.inLink&&/^<a /i.test(cap[0])){this.inLink=true}else if(this.inLink&&/^<\/a>/i.test(cap[0])){this.inLink=false}src=src.substring(cap[0].length);out+=this.options.sanitize?escape(cap[0]):cap[0];continue}if(cap=this.rules.link.exec(src)){src=src.substring(cap[0].length);this.inLink=true;out+=this.outputLink(cap,{href:cap[2],title:cap[3]});this.inLink=false;continue}if((cap=this.rules.reflink.exec(src))||(cap=this.rules.nolink.exec(src))){src=src.substring(cap[0].length);link=(cap[2]||cap[1]).replace(/\s+/g," ");link=this.links[link.toLowerCase()];if(!link||!link.href){out+=cap[0].charAt(0);src=cap[0].substring(1)+src;continue}this.inLink=true;out+=this.outputLink(cap,link);this.inLink=false;continue}if(cap=this.rules.strong.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.strong(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.em.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.em(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.codespan(escape(cap[2],true));continue}if(cap=this.rules.br.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.br();continue}if(cap=this.rules.del.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.del(this.output(cap[1]));continue}if(cap=this.rules.text.exec(src)){src=src.substring(cap[0].length);out+=escape(this.smartypants(cap[0]));continue}if(src){throw new Error("Infinite loop on byte: "+src.charCodeAt(0))}}return out};InlineLexer.prototype.outputLink=function(cap,link){var href=escape(link.href),title=link.title?escape(link.title):null;return cap[0].charAt(0)!=="!"?this.renderer.link(href,title,this.output(cap[1])):this.renderer.image(href,title,escape(cap[1]))};InlineLexer.prototype.smartypants=function(text){if(!this.options.smartypants)return text;return text.replace(/--/g,"—").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…")};InlineLexer.prototype.mangle=function(text){var out="",l=text.length,i=0,ch;for(;i<l;i++){ch=text.charCodeAt(i);if(Math.random()>.5){ch="x"+ch.toString(16)}out+="&#"+ch+";"}return out};function Renderer(options){this.options=options||{}}Renderer.prototype.code=function(code,lang,escaped){if(this.options.highlight){var out=this.options.highlight(code,lang);if(out!=null&&out!==code){escaped=true;code=out}}if(!lang){return"<pre><code>"+(escaped?code:escape(code,true))+"\n</code></pre>"}return'<pre><code class="'+this.options.langPrefix+escape(lang,true)+'">'+(escaped?code:escape(code,true))+"\n</code></pre>\n"};Renderer.prototype.blockquote=function(quote){return"<blockquote>\n"+quote+"</blockquote>\n"};Renderer.prototype.html=function(html){return html};Renderer.prototype.heading=function(text,level,raw){return"<h"+level+' id="'+this.options.headerPrefix+raw.toLowerCase().replace(/[^\w]+/g,"-")+'">'+text+"</h"+level+">\n"};Renderer.prototype.hr=function(){return this.options.xhtml?"<hr/>\n":"<hr>\n"};Renderer.prototype.list=function(body,ordered){var type=ordered?"ol":"ul";return"<"+type+">\n"+body+"</"+type+">\n"};Renderer.prototype.listitem=function(text){return"<li>"+text+"</li>\n"};Renderer.prototype.paragraph=function(text){return"<p>"+text+"</p>\n"};Renderer.prototype.table=function(header,body){return"<table>\n"+"<thead>\n"+header+"</thead>\n"+"<tbody>\n"+body+"</tbody>\n"+"</table>\n"};Renderer.prototype.tablerow=function(content){return"<tr>\n"+content+"</tr>\n"};Renderer.prototype.tablecell=function(content,flags){var type=flags.header?"th":"td";var tag=flags.align?"<"+type+' style="text-align:'+flags.align+'">':"<"+type+">";return tag+content+"</"+type+">\n"};Renderer.prototype.strong=function(text){return"<strong>"+text+"</strong>"};Renderer.prototype.em=function(text){return"<em>"+text+"</em>"};Renderer.prototype.codespan=function(text){return"<code>"+text+"</code>"};Renderer.prototype.br=function(){return this.options.xhtml?"<br/>":"<br>"};Renderer.prototype.del=function(text){return"<del>"+text+"</del>"};Renderer.prototype.link=function(href,title,text){if(this.options.sanitize){try{var prot=decodeURIComponent(unescape(href)).replace(/[^\w:]/g,"").toLowerCase()}catch(e){return""}if(prot.indexOf("javascript:")===0){return""}}var out='<a href="'+href+'"';if(title){out+=' title="'+title+'"'}out+=">"+text+"</a>";return out};Renderer.prototype.image=function(href,title,text){var out='<img src="'+href+'" alt="'+text+'"';if(title){out+=' title="'+title+'"'}out+=this.options.xhtml?"/>":">";return out};function Parser(options){this.tokens=[];this.token=null;this.options=options||marked.defaults;this.options.renderer=this.options.renderer||new Renderer;this.renderer=this.options.renderer;this.renderer.options=this.options}Parser.parse=function(src,options,renderer){var parser=new Parser(options,renderer);return parser.parse(src)};Parser.prototype.parse=function(src){this.inline=new InlineLexer(src.links,this.options,this.renderer);this.tokens=src.reverse();var out="";while(this.next()){out+=this.tok()}return out};Parser.prototype.next=function(){return this.token=this.tokens.pop()};Parser.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0};Parser.prototype.parseText=function(){var body=this.token.text;while(this.peek().type==="text"){body+="\n"+this.next().text}return this.inline.output(body)};Parser.prototype.tok=function(){switch(this.token.type){case"space":{return""}case"hr":{return this.renderer.hr()}case"heading":{return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,this.token.text)}case"code":{return this.renderer.code(this.token.text,this.token.lang,this.token.escaped)}case"table":{var header="",body="",i,row,cell,flags,j;cell="";for(i=0;i<this.token.header.length;i++){flags={header:true,align:this.token.align[i]};cell+=this.renderer.tablecell(this.inline.output(this.token.header[i]),{header:true,align:this.token.align[i]})}header+=this.renderer.tablerow(cell);for(i=0;i<this.token.cells.length;i++){row=this.token.cells[i];cell="";for(j=0;j<row.length;j++){cell+=this.renderer.tablecell(this.inline.output(row[j]),{header:false,align:this.token.align[j]})}body+=this.renderer.tablerow(cell)}return this.renderer.table(header,body)}case"blockquote_start":{var body="";while(this.next().type!=="blockquote_end"){body+=this.tok()}return this.renderer.blockquote(body)}case"list_start":{var body="",ordered=this.token.ordered;while(this.next().type!=="list_end"){body+=this.tok()}return this.renderer.list(body,ordered)}case"list_item_start":{var body="";while(this.next().type!=="list_item_end"){body+=this.token.type==="text"?this.parseText():this.tok()}return this.renderer.listitem(body)}case"loose_item_start":{var body="";while(this.next().type!=="list_item_end"){body+=this.tok()}return this.renderer.listitem(body)}case"html":{var html=!this.token.pre&&!this.options.pedantic?this.inline.output(this.token.text):this.token.text;return this.renderer.html(html)}case"paragraph":{return this.renderer.paragraph(this.inline.output(this.token.text))}case"text":{return this.renderer.paragraph(this.parseText())}}};function escape(html,encode){return html.replace(!encode?/&(?!#?\w+;)/g:/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}function unescape(html){return html.replace(/&([#\w]+);/g,function(_,n){n=n.toLowerCase();if(n==="colon")return":";if(n.charAt(0)==="#"){return n.charAt(1)==="x"?String.fromCharCode(parseInt(n.substring(2),16)):String.fromCharCode(+n.substring(1))}return""})}function replace(regex,opt){regex=regex.source;opt=opt||"";return function self(name,val){if(!name)return new RegExp(regex,opt);val=val.source||val;val=val.replace(/(^|[^\[])\^/g,"$1");regex=regex.replace(name,val);return self}}function noop(){}noop.exec=noop;function merge(obj){var i=1,target,key;for(;i<arguments.length;i++){target=arguments[i];for(key in target){if(Object.prototype.hasOwnProperty.call(target,key)){obj[key]=target[key]}}}return obj}function marked(src,opt,callback){if(callback||typeof opt==="function"){if(!callback){callback=opt;opt=null}opt=merge({},marked.defaults,opt||{});var highlight=opt.highlight,tokens,pending,i=0;try{tokens=Lexer.lex(src,opt)}catch(e){return callback(e)}pending=tokens.length;var done=function(){var out,err;try{out=Parser.parse(tokens,opt)}catch(e){err=e}opt.highlight=highlight;return err?callback(err):callback(null,out)};if(!highlight||highlight.length<3){return done()}delete opt.highlight;if(!pending)return done();for(;i<tokens.length;i++){(function(token){if(token.type!=="code"){return--pending||done()}return highlight(token.text,token.lang,function(err,code){if(code==null||code===token.text){return--pending||done()}token.text=code;token.escaped=true;--pending||done()})})(tokens[i])}return}try{if(opt)opt=merge({},marked.defaults,opt);return Parser.parse(Lexer.lex(src,opt),opt)}catch(e){e.message+="\nPlease report this to https://github.com/chjj/marked.";if((opt||marked.defaults).silent){return"<p>An error occured:</p><pre>"+escape(e.message+"",true)+"</pre>"}throw e}}marked.options=marked.setOptions=function(opt){merge(marked.defaults,opt);return marked};marked.defaults={gfm:true,tables:true,breaks:false,pedantic:false,sanitize:false,smartLists:false,silent:false,highlight:null,langPrefix:"lang-",smartypants:false,headerPrefix:"",renderer:new Renderer,xhtml:false};marked.Parser=Parser;marked.parser=Parser.parse;marked.Renderer=Renderer;marked.Lexer=Lexer;marked.lexer=Lexer.lex;marked.InlineLexer=InlineLexer;marked.inlineLexer=InlineLexer.output;marked.parse=marked;if(typeof exports==="object"){module.exports=marked}else if(typeof define==="function"&&define.amd){define(function(){return marked})}else{this.marked=marked}}).call(function(){return this||(typeof window!=="undefined"?window:global)}());
\ No newline at end of file
diff --git a/docs/js/react-dom.js b/docs/js/react-dom.js
deleted file mode 100644
index 117e1393c649..000000000000
--- a/docs/js/react-dom.js
+++ /dev/null
@@ -1,42 +0,0 @@
-/**
- * ReactDOM v0.14.7
- *
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- */
-// Based off https://github.com/ForbesLindesay/umd/blob/master/template.js
-;(function(f) {
-  // CommonJS
-  if (typeof exports === "object" && typeof module !== "undefined") {
-    module.exports = f(require('react'));
-
-  // RequireJS
-  } else if (typeof define === "function" && define.amd) {
-    define(['react'], f);
-
-  // <script>
-  } else {
-    var g;
-    if (typeof window !== "undefined") {
-      g = window;
-    } else if (typeof global !== "undefined") {
-      g = global;
-    } else if (typeof self !== "undefined") {
-      g = self;
-    } else {
-      // works providing we're not in "use strict";
-      // needed for Java 8 Nashorn
-      // see https://github.com/facebook/react/issues/3037
-      g = this;
-    }
-    g.ReactDOM = f(g.React);
-  }
-
-})(function(React) {
-  return React.__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
-});
diff --git a/docs/js/react.js b/docs/js/react.js
deleted file mode 100644
index b8c9f6755335..000000000000
--- a/docs/js/react.js
+++ /dev/null
@@ -1,18808 +0,0 @@
- /**
-  * React v0.14.7
-  */
-(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.React = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule React
- */
-
-'use strict';
-
-var ReactDOM = _dereq_(35);
-var ReactDOMServer = _dereq_(45);
-var ReactIsomorphic = _dereq_(63);
-
-var assign = _dereq_(23);
-var deprecated = _dereq_(106);
-
-// `version` will be added here by ReactIsomorphic.
-var React = {};
-
-assign(React, ReactIsomorphic);
-
-assign(React, {
-  // ReactDOM
-  findDOMNode: deprecated('findDOMNode', 'ReactDOM', 'react-dom', ReactDOM, ReactDOM.findDOMNode),
-  render: deprecated('render', 'ReactDOM', 'react-dom', ReactDOM, ReactDOM.render),
-  unmountComponentAtNode: deprecated('unmountComponentAtNode', 'ReactDOM', 'react-dom', ReactDOM, ReactDOM.unmountComponentAtNode),
-
-  // ReactDOMServer
-  renderToString: deprecated('renderToString', 'ReactDOMServer', 'react-dom/server', ReactDOMServer, ReactDOMServer.renderToString),
-  renderToStaticMarkup: deprecated('renderToStaticMarkup', 'ReactDOMServer', 'react-dom/server', ReactDOMServer, ReactDOMServer.renderToStaticMarkup)
-});
-
-React.__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = ReactDOM;
-React.__SECRET_DOM_SERVER_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = ReactDOMServer;
-
-module.exports = React;
-},{"106":106,"23":23,"35":35,"45":45,"63":63}],2:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule AutoFocusUtils
- * @typechecks static-only
- */
-
-'use strict';
-
-var ReactMount = _dereq_(65);
-
-var findDOMNode = _dereq_(108);
-var focusNode = _dereq_(138);
-
-var Mixin = {
-  componentDidMount: function () {
-    if (this.props.autoFocus) {
-      focusNode(findDOMNode(this));
-    }
-  }
-};
-
-var AutoFocusUtils = {
-  Mixin: Mixin,
-
-  focusDOMComponent: function () {
-    focusNode(ReactMount.getNode(this._rootNodeID));
-  }
-};
-
-module.exports = AutoFocusUtils;
-},{"108":108,"138":138,"65":65}],3:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015 Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule BeforeInputEventPlugin
- * @typechecks static-only
- */
-
-'use strict';
-
-var EventConstants = _dereq_(15);
-var EventPropagators = _dereq_(19);
-var ExecutionEnvironment = _dereq_(130);
-var FallbackCompositionState = _dereq_(20);
-var SyntheticCompositionEvent = _dereq_(90);
-var SyntheticInputEvent = _dereq_(94);
-
-var keyOf = _dereq_(148);
-
-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);
-
-var topLevelTypes = EventConstants.topLevelTypes;
-
-// Events and their corresponding property names.
-var eventTypes = {
-  beforeInput: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onBeforeInput: null }),
-      captured: keyOf({ onBeforeInputCapture: null })
-    },
-    dependencies: [topLevelTypes.topCompositionEnd, topLevelTypes.topKeyPress, topLevelTypes.topTextInput, topLevelTypes.topPaste]
-  },
-  compositionEnd: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onCompositionEnd: null }),
-      captured: keyOf({ onCompositionEndCapture: null })
-    },
-    dependencies: [topLevelTypes.topBlur, topLevelTypes.topCompositionEnd, topLevelTypes.topKeyDown, topLevelTypes.topKeyPress, topLevelTypes.topKeyUp, topLevelTypes.topMouseDown]
-  },
-  compositionStart: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onCompositionStart: null }),
-      captured: keyOf({ onCompositionStartCapture: null })
-    },
-    dependencies: [topLevelTypes.topBlur, topLevelTypes.topCompositionStart, topLevelTypes.topKeyDown, topLevelTypes.topKeyPress, topLevelTypes.topKeyUp, topLevelTypes.topMouseDown]
-  },
-  compositionUpdate: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onCompositionUpdate: null }),
-      captured: keyOf({ onCompositionUpdateCapture: null })
-    },
-    dependencies: [topLevelTypes.topBlur, topLevelTypes.topCompositionUpdate, topLevelTypes.topKeyDown, topLevelTypes.topKeyPress, topLevelTypes.topKeyUp, topLevelTypes.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 topLevelTypes.topCompositionStart:
-      return eventTypes.compositionStart;
-    case topLevelTypes.topCompositionEnd:
-      return eventTypes.compositionEnd;
-    case topLevelTypes.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 === topLevelTypes.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 topLevelTypes.topKeyUp:
-      // Command keys insert or clear IME input.
-      return END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1;
-    case topLevelTypes.topKeyDown:
-      // Expect IME keyCode on each keydown. If we get any other
-      // code we must have exited earlier.
-      return nativeEvent.keyCode !== START_KEYCODE;
-    case topLevelTypes.topKeyPress:
-    case topLevelTypes.topMouseDown:
-    case topLevelTypes.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;
-
-/**
- * @param {string} topLevelType Record from `EventConstants`.
- * @param {DOMEventTarget} topLevelTarget The listening component root node.
- * @param {string} topLevelTargetID ID of `topLevelTarget`.
- * @param {object} nativeEvent Native browser event.
- * @return {?object} A SyntheticCompositionEvent.
- */
-function extractCompositionEvent(topLevelType, topLevelTarget, topLevelTargetID, 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(topLevelTarget);
-    } else if (eventType === eventTypes.compositionEnd) {
-      if (currentComposition) {
-        fallbackData = currentComposition.getData();
-      }
-    }
-  }
-
-  var event = SyntheticCompositionEvent.getPooled(eventType, topLevelTargetID, 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 topLevelTypes.topCompositionEnd:
-      return getDataFromCustomEvent(nativeEvent);
-    case topLevelTypes.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 topLevelTypes.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 (currentComposition) {
-    if (topLevelType === topLevelTypes.topCompositionEnd || isFallbackCompositionEnd(topLevelType, nativeEvent)) {
-      var chars = currentComposition.getData();
-      FallbackCompositionState.release(currentComposition);
-      currentComposition = null;
-      return chars;
-    }
-    return null;
-  }
-
-  switch (topLevelType) {
-    case topLevelTypes.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 topLevelTypes.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 topLevelTypes.topCompositionEnd:
-      return useFallbackCompositionData ? null : nativeEvent.data;
-    default:
-      return null;
-  }
-}
-
-/**
- * Extract a SyntheticInputEvent for `beforeInput`, based on either native
- * `textInput` or fallback behavior.
- *
- * @param {string} topLevelType Record from `EventConstants`.
- * @param {DOMEventTarget} topLevelTarget The listening component root node.
- * @param {string} topLevelTargetID ID of `topLevelTarget`.
- * @param {object} nativeEvent Native browser event.
- * @return {?object} A SyntheticInputEvent.
- */
-function extractBeforeInputEvent(topLevelType, topLevelTarget, topLevelTargetID, 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, topLevelTargetID, 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,
-
-  /**
-   * @param {string} topLevelType Record from `EventConstants`.
-   * @param {DOMEventTarget} topLevelTarget The listening component root node.
-   * @param {string} topLevelTargetID ID of `topLevelTarget`.
-   * @param {object} nativeEvent Native browser event.
-   * @return {*} An accumulation of synthetic events.
-   * @see {EventPluginHub.extractEvents}
-   */
-  extractEvents: function (topLevelType, topLevelTarget, topLevelTargetID, nativeEvent, nativeEventTarget) {
-    return [extractCompositionEvent(topLevelType, topLevelTarget, topLevelTargetID, nativeEvent, nativeEventTarget), extractBeforeInputEvent(topLevelType, topLevelTarget, topLevelTargetID, nativeEvent, nativeEventTarget)];
-  }
-};
-
-module.exports = BeforeInputEventPlugin;
-},{"130":130,"148":148,"15":15,"19":19,"20":20,"90":90,"94":94}],4:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule CSSProperty
- */
-
-'use strict';
-
-/**
- * CSS properties which accept numbers but are not in units of "px".
- */
-var isUnitlessNumber = {
-  animationIterationCount: true,
-  boxFlex: true,
-  boxFlexGroup: true,
-  boxOrdinalGroup: true,
-  columnCount: true,
-  flex: true,
-  flexGrow: true,
-  flexPositive: true,
-  flexShrink: true,
-  flexNegative: true,
-  flexOrder: 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,
-  stopOpacity: true,
-  strokeDashoffset: 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;
-},{}],5:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule CSSPropertyOperations
- * @typechecks static-only
- */
-
-'use strict';
-
-var CSSProperty = _dereq_(4);
-var ExecutionEnvironment = _dereq_(130);
-var ReactPerf = _dereq_(71);
-
-var camelizeStyleName = _dereq_(132);
-var dangerousStyleValue = _dereq_(105);
-var hyphenateStyleName = _dereq_(143);
-var memoizeStringOnly = _dereq_(150);
-var warning = _dereq_(155);
-
-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 ("development" !== 'production') {
-  // '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 warnHyphenatedStyleName = function (name) {
-    if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) {
-      return;
-    }
-
-    warnedStyleNames[name] = true;
-    "development" !== 'production' ? warning(false, 'Unsupported style property %s. Did you mean %s?', name, camelizeStyleName(name)) : undefined;
-  };
-
-  var warnBadVendoredStyleName = function (name) {
-    if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) {
-      return;
-    }
-
-    warnedStyleNames[name] = true;
-    "development" !== 'production' ? warning(false, 'Unsupported vendor-prefixed style property %s. Did you mean %s?', name, name.charAt(0).toUpperCase() + name.slice(1)) : undefined;
-  };
-
-  var warnStyleValueWithSemicolon = function (name, value) {
-    if (warnedStyleValues.hasOwnProperty(value) && warnedStyleValues[value]) {
-      return;
-    }
-
-    warnedStyleValues[value] = true;
-    "development" !== 'production' ? warning(false, 'Style property values shouldn\'t contain a semicolon. ' + 'Try "%s: %s" instead.', name, value.replace(badStyleValueWithSemicolonPattern, '')) : undefined;
-  };
-
-  /**
-   * @param {string} name
-   * @param {*} value
-   */
-  var warnValidStyle = function (name, value) {
-    if (name.indexOf('-') > -1) {
-      warnHyphenatedStyleName(name);
-    } else if (badVendoredStyleNamePattern.test(name)) {
-      warnBadVendoredStyleName(name);
-    } else if (badStyleValueWithSemicolonPattern.test(value)) {
-      warnStyleValueWithSemicolon(name, value);
-    }
-  };
-}
-
-/**
- * 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
-   * @return {?string}
-   */
-  createMarkupForStyles: function (styles) {
-    var serialized = '';
-    for (var styleName in styles) {
-      if (!styles.hasOwnProperty(styleName)) {
-        continue;
-      }
-      var styleValue = styles[styleName];
-      if ("development" !== 'production') {
-        warnValidStyle(styleName, styleValue);
-      }
-      if (styleValue != null) {
-        serialized += processStyleName(styleName) + ':';
-        serialized += dangerousStyleValue(styleName, styleValue) + ';';
-      }
-    }
-    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
-   */
-  setValueForStyles: function (node, styles) {
-    var style = node.style;
-    for (var styleName in styles) {
-      if (!styles.hasOwnProperty(styleName)) {
-        continue;
-      }
-      if ("development" !== 'production') {
-        warnValidStyle(styleName, styles[styleName]);
-      }
-      var styleValue = dangerousStyleValue(styleName, styles[styleName]);
-      if (styleName === 'float') {
-        styleName = styleFloatAccessor;
-      }
-      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] = '';
-        }
-      }
-    }
-  }
-
-};
-
-ReactPerf.measureMethods(CSSPropertyOperations, 'CSSPropertyOperations', {
-  setValueForStyles: 'setValueForStyles'
-});
-
-module.exports = CSSPropertyOperations;
-},{"105":105,"130":130,"132":132,"143":143,"150":150,"155":155,"4":4,"71":71}],6:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule CallbackQueue
- */
-
-'use strict';
-
-var PooledClass = _dereq_(24);
-
-var assign = _dereq_(23);
-var invariant = _dereq_(144);
-
-/**
- * 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
- */
-function CallbackQueue() {
-  this._callbacks = null;
-  this._contexts = null;
-}
-
-assign(CallbackQueue.prototype, {
-
-  /**
-   * 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
-   */
-  enqueue: function (callback, context) {
-    this._callbacks = this._callbacks || [];
-    this._contexts = this._contexts || [];
-    this._callbacks.push(callback);
-    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
-   */
-  notifyAll: function () {
-    var callbacks = this._callbacks;
-    var contexts = this._contexts;
-    if (callbacks) {
-      !(callbacks.length === contexts.length) ? "development" !== 'production' ? invariant(false, 'Mismatched list of contexts in callback queue') : invariant(false) : undefined;
-      this._callbacks = null;
-      this._contexts = null;
-      for (var i = 0; i < callbacks.length; i++) {
-        callbacks[i].call(contexts[i]);
-      }
-      callbacks.length = 0;
-      contexts.length = 0;
-    }
-  },
-
-  /**
-   * Resets the internal queue.
-   *
-   * @internal
-   */
-  reset: function () {
-    this._callbacks = null;
-    this._contexts = null;
-  },
-
-  /**
-   * `PooledClass` looks for this.
-   */
-  destructor: function () {
-    this.reset();
-  }
-
-});
-
-PooledClass.addPoolingTo(CallbackQueue);
-
-module.exports = CallbackQueue;
-},{"144":144,"23":23,"24":24}],7:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ChangeEventPlugin
- */
-
-'use strict';
-
-var EventConstants = _dereq_(15);
-var EventPluginHub = _dereq_(16);
-var EventPropagators = _dereq_(19);
-var ExecutionEnvironment = _dereq_(130);
-var ReactUpdates = _dereq_(83);
-var SyntheticEvent = _dereq_(92);
-
-var getEventTarget = _dereq_(114);
-var isEventSupported = _dereq_(119);
-var isTextInputElement = _dereq_(120);
-var keyOf = _dereq_(148);
-
-var topLevelTypes = EventConstants.topLevelTypes;
-
-var eventTypes = {
-  change: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onChange: null }),
-      captured: keyOf({ onChangeCapture: null })
-    },
-    dependencies: [topLevelTypes.topBlur, topLevelTypes.topChange, topLevelTypes.topClick, topLevelTypes.topFocus, topLevelTypes.topInput, topLevelTypes.topKeyDown, topLevelTypes.topKeyUp, topLevelTypes.topSelectionChange]
-  }
-};
-
-/**
- * For IE shims
- */
-var activeElement = null;
-var activeElementID = null;
-var activeElementValue = null;
-var activeElementValueProp = 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') && (!('documentMode' in document) || document.documentMode > 8);
-}
-
-function manualDispatchChangeEvent(nativeEvent) {
-  var event = SyntheticEvent.getPooled(eventTypes.change, activeElementID, nativeEvent, getEventTarget(nativeEvent));
-  EventPropagators.accumulateTwoPhaseDispatches(event);
-
-  // 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, targetID) {
-  activeElement = target;
-  activeElementID = targetID;
-  activeElement.attachEvent('onchange', manualDispatchChangeEvent);
-}
-
-function stopWatchingForChangeEventIE8() {
-  if (!activeElement) {
-    return;
-  }
-  activeElement.detachEvent('onchange', manualDispatchChangeEvent);
-  activeElement = null;
-  activeElementID = null;
-}
-
-function getTargetIDForChangeEvent(topLevelType, topLevelTarget, topLevelTargetID) {
-  if (topLevelType === topLevelTypes.topChange) {
-    return topLevelTargetID;
-  }
-}
-function handleEventsForChangeEventIE8(topLevelType, topLevelTarget, topLevelTargetID) {
-  if (topLevelType === topLevelTypes.topFocus) {
-    // stopWatching() should be a noop here but we call it just in case we
-    // missed a blur event somehow.
-    stopWatchingForChangeEventIE8();
-    startWatchingForChangeEventIE8(topLevelTarget, topLevelTargetID);
-  } else if (topLevelType === topLevelTypes.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') && (!('documentMode' in document) || document.documentMode > 9);
-}
-
-/**
- * (For old IE.) Replacement getter/setter for the `value` property that gets
- * set on the active element.
- */
-var newValueProp = {
-  get: function () {
-    return activeElementValueProp.get.call(this);
-  },
-  set: function (val) {
-    // Cast to a string so we can do equality checks.
-    activeElementValue = '' + val;
-    activeElementValueProp.set.call(this, val);
-  }
-};
-
-/**
- * (For old IE.) 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, targetID) {
-  activeElement = target;
-  activeElementID = targetID;
-  activeElementValue = target.value;
-  activeElementValueProp = Object.getOwnPropertyDescriptor(target.constructor.prototype, 'value');
-
-  // Not guarded in a canDefineProperty check: IE8 supports defineProperty only
-  // on DOM elements
-  Object.defineProperty(activeElement, 'value', newValueProp);
-  activeElement.attachEvent('onpropertychange', handlePropertyChange);
-}
-
-/**
- * (For old IE.) Removes the event listeners from the currently-tracked element,
- * if any exists.
- */
-function stopWatchingForValueChange() {
-  if (!activeElement) {
-    return;
-  }
-
-  // delete restores the original property definition
-  delete activeElement.value;
-  activeElement.detachEvent('onpropertychange', handlePropertyChange);
-
-  activeElement = null;
-  activeElementID = null;
-  activeElementValue = null;
-  activeElementValueProp = null;
-}
-
-/**
- * (For old IE.) 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;
-  }
-  var value = nativeEvent.srcElement.value;
-  if (value === activeElementValue) {
-    return;
-  }
-  activeElementValue = value;
-
-  manualDispatchChangeEvent(nativeEvent);
-}
-
-/**
- * If a `change` event should be fired, returns the target's ID.
- */
-function getTargetIDForInputEvent(topLevelType, topLevelTarget, topLevelTargetID) {
-  if (topLevelType === topLevelTypes.topInput) {
-    // In modern browsers (i.e., not IE8 or IE9), the input event is exactly
-    // what we want so fall through here and trigger an abstract event
-    return topLevelTargetID;
-  }
-}
-
-// For IE8 and IE9.
-function handleEventsForInputEventIE(topLevelType, topLevelTarget, topLevelTargetID) {
-  if (topLevelType === topLevelTypes.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(topLevelTarget, topLevelTargetID);
-  } else if (topLevelType === topLevelTypes.topBlur) {
-    stopWatchingForValueChange();
-  }
-}
-
-// For IE8 and IE9.
-function getTargetIDForInputEventIE(topLevelType, topLevelTarget, topLevelTargetID) {
-  if (topLevelType === topLevelTypes.topSelectionChange || topLevelType === topLevelTypes.topKeyUp || topLevelType === topLevelTypes.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.
-    if (activeElement && activeElement.value !== activeElementValue) {
-      activeElementValue = activeElement.value;
-      return activeElementID;
-    }
-  }
-}
-
-/**
- * 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.
-  return elem.nodeName && elem.nodeName.toLowerCase() === 'input' && (elem.type === 'checkbox' || elem.type === 'radio');
-}
-
-function getTargetIDForClickEvent(topLevelType, topLevelTarget, topLevelTargetID) {
-  if (topLevelType === topLevelTypes.topClick) {
-    return topLevelTargetID;
-  }
-}
-
-/**
- * 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,
-
-  /**
-   * @param {string} topLevelType Record from `EventConstants`.
-   * @param {DOMEventTarget} topLevelTarget The listening component root node.
-   * @param {string} topLevelTargetID ID of `topLevelTarget`.
-   * @param {object} nativeEvent Native browser event.
-   * @return {*} An accumulation of synthetic events.
-   * @see {EventPluginHub.extractEvents}
-   */
-  extractEvents: function (topLevelType, topLevelTarget, topLevelTargetID, nativeEvent, nativeEventTarget) {
-
-    var getTargetIDFunc, handleEventFunc;
-    if (shouldUseChangeEvent(topLevelTarget)) {
-      if (doesChangeEventBubble) {
-        getTargetIDFunc = getTargetIDForChangeEvent;
-      } else {
-        handleEventFunc = handleEventsForChangeEventIE8;
-      }
-    } else if (isTextInputElement(topLevelTarget)) {
-      if (isInputEventSupported) {
-        getTargetIDFunc = getTargetIDForInputEvent;
-      } else {
-        getTargetIDFunc = getTargetIDForInputEventIE;
-        handleEventFunc = handleEventsForInputEventIE;
-      }
-    } else if (shouldUseClickEvent(topLevelTarget)) {
-      getTargetIDFunc = getTargetIDForClickEvent;
-    }
-
-    if (getTargetIDFunc) {
-      var targetID = getTargetIDFunc(topLevelType, topLevelTarget, topLevelTargetID);
-      if (targetID) {
-        var event = SyntheticEvent.getPooled(eventTypes.change, targetID, nativeEvent, nativeEventTarget);
-        event.type = 'change';
-        EventPropagators.accumulateTwoPhaseDispatches(event);
-        return event;
-      }
-    }
-
-    if (handleEventFunc) {
-      handleEventFunc(topLevelType, topLevelTarget, topLevelTargetID);
-    }
-  }
-
-};
-
-module.exports = ChangeEventPlugin;
-},{"114":114,"119":119,"120":120,"130":130,"148":148,"15":15,"16":16,"19":19,"83":83,"92":92}],8:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ClientReactRootIndex
- * @typechecks
- */
-
-'use strict';
-
-var nextReactRootIndex = 0;
-
-var ClientReactRootIndex = {
-  createReactRootIndex: function () {
-    return nextReactRootIndex++;
-  }
-};
-
-module.exports = ClientReactRootIndex;
-},{}],9:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule DOMChildrenOperations
- * @typechecks static-only
- */
-
-'use strict';
-
-var Danger = _dereq_(12);
-var ReactMultiChildUpdateTypes = _dereq_(67);
-var ReactPerf = _dereq_(71);
-
-var setInnerHTML = _dereq_(124);
-var setTextContent = _dereq_(125);
-var invariant = _dereq_(144);
-
-/**
- * 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
- */
-function insertChildAt(parentNode, childNode, index) {
-  // By exploiting arrays returning `undefined` for an undefined index, we can
-  // rely exclusively on `insertBefore(node, null)` instead of also using
-  // `appendChild(node)`. However, using `undefined` is not allowed by all
-  // browsers so we must replace it with `null`.
-
-  // fix render order error in safari
-  // IE8 will throw error when index out of list size.
-  var beforeChild = index >= parentNode.childNodes.length ? null : parentNode.childNodes.item(index);
-
-  parentNode.insertBefore(childNode, beforeChild);
-}
-
-/**
- * Operations for updating with DOM children.
- */
-var DOMChildrenOperations = {
-
-  dangerouslyReplaceNodeWithMarkup: Danger.dangerouslyReplaceNodeWithMarkup,
-
-  updateTextContent: setTextContent,
-
-  /**
-   * 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.
-   * @param {array<string>} markupList List of markup strings.
-   * @internal
-   */
-  processUpdates: function (updates, markupList) {
-    var update;
-    // Mapping from parent IDs to initial child orderings.
-    var initialChildren = null;
-    // List of children that will be moved or removed.
-    var updatedChildren = null;
-
-    for (var i = 0; i < updates.length; i++) {
-      update = updates[i];
-      if (update.type === ReactMultiChildUpdateTypes.MOVE_EXISTING || update.type === ReactMultiChildUpdateTypes.REMOVE_NODE) {
-        var updatedIndex = update.fromIndex;
-        var updatedChild = update.parentNode.childNodes[updatedIndex];
-        var parentID = update.parentID;
-
-        !updatedChild ? "development" !== 'production' ? invariant(false, 'processUpdates(): Unable to find child %s of element. This ' + 'probably means the DOM was unexpectedly mutated (e.g., by the ' + 'browser), usually due to forgetting a <tbody> when using tables, ' + 'nesting tags like <form>, <p>, or <a>, or using non-SVG elements ' + 'in an <svg> parent. Try inspecting the child nodes of the element ' + 'with React ID `%s`.', updatedIndex, parentID) : invariant(false) : undefined;
-
-        initialChildren = initialChildren || {};
-        initialChildren[parentID] = initialChildren[parentID] || [];
-        initialChildren[parentID][updatedIndex] = updatedChild;
-
-        updatedChildren = updatedChildren || [];
-        updatedChildren.push(updatedChild);
-      }
-    }
-
-    var renderedMarkup;
-    // markupList is either a list of markup or just a list of elements
-    if (markupList.length && typeof markupList[0] === 'string') {
-      renderedMarkup = Danger.dangerouslyRenderMarkup(markupList);
-    } else {
-      renderedMarkup = markupList;
-    }
-
-    // Remove updated children first so that `toIndex` is consistent.
-    if (updatedChildren) {
-      for (var j = 0; j < updatedChildren.length; j++) {
-        updatedChildren[j].parentNode.removeChild(updatedChildren[j]);
-      }
-    }
-
-    for (var k = 0; k < updates.length; k++) {
-      update = updates[k];
-      switch (update.type) {
-        case ReactMultiChildUpdateTypes.INSERT_MARKUP:
-          insertChildAt(update.parentNode, renderedMarkup[update.markupIndex], update.toIndex);
-          break;
-        case ReactMultiChildUpdateTypes.MOVE_EXISTING:
-          insertChildAt(update.parentNode, initialChildren[update.parentID][update.fromIndex], update.toIndex);
-          break;
-        case ReactMultiChildUpdateTypes.SET_MARKUP:
-          setInnerHTML(update.parentNode, update.content);
-          break;
-        case ReactMultiChildUpdateTypes.TEXT_CONTENT:
-          setTextContent(update.parentNode, update.content);
-          break;
-        case ReactMultiChildUpdateTypes.REMOVE_NODE:
-          // Already removed by the for-loop above.
-          break;
-      }
-    }
-  }
-
-};
-
-ReactPerf.measureMethods(DOMChildrenOperations, 'DOMChildrenOperations', {
-  updateTextContent: 'updateTextContent'
-});
-
-module.exports = DOMChildrenOperations;
-},{"12":12,"124":124,"125":125,"144":144,"67":67,"71":71}],10:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule DOMProperty
- * @typechecks static-only
- */
-
-'use strict';
-
-var invariant = _dereq_(144);
-
-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_ATTRIBUTE: 0x1,
-  MUST_USE_PROPERTY: 0x2,
-  HAS_SIDE_EFFECTS: 0x4,
-  HAS_BOOLEAN_VALUE: 0x8,
-  HAS_NUMERIC_VALUE: 0x10,
-  HAS_POSITIVE_NUMERIC_VALUE: 0x20 | 0x10,
-  HAS_OVERLOADED_BOOLEAN_VALUE: 0x40,
-
-  /**
-   * 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) ? "development" !== 'production' ? 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) : invariant(false) : undefined;
-
-      var lowerCased = propName.toLowerCase();
-      var propConfig = Properties[propName];
-
-      var propertyInfo = {
-        attributeName: lowerCased,
-        attributeNamespace: null,
-        propertyName: propName,
-        mutationMethod: null,
-
-        mustUseAttribute: checkMask(propConfig, Injection.MUST_USE_ATTRIBUTE),
-        mustUseProperty: checkMask(propConfig, Injection.MUST_USE_PROPERTY),
-        hasSideEffects: checkMask(propConfig, Injection.HAS_SIDE_EFFECTS),
-        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.mustUseAttribute || !propertyInfo.mustUseProperty) ? "development" !== 'production' ? invariant(false, 'DOMProperty: Cannot require using both attribute and property: %s', propName) : invariant(false) : undefined;
-      !(propertyInfo.mustUseProperty || !propertyInfo.hasSideEffects) ? "development" !== 'production' ? invariant(false, 'DOMProperty: Properties that have side effects must use property: %s', propName) : invariant(false) : undefined;
-      !(propertyInfo.hasBooleanValue + propertyInfo.hasNumericValue + propertyInfo.hasOverloadedBooleanValue <= 1) ? "development" !== 'production' ? invariant(false, 'DOMProperty: Value can be one of boolean, overloaded boolean, or ' + 'numeric value, but not a combination: %s', propName) : invariant(false) : undefined;
-
-      if ("development" !== 'production') {
-        DOMProperty.getPossibleStandardName[lowerCased] = propName;
-      }
-
-      if (DOMAttributeNames.hasOwnProperty(propName)) {
-        var attributeName = DOMAttributeNames[propName];
-        propertyInfo.attributeName = attributeName;
-        if ("development" !== 'production') {
-          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;
-    }
-  }
-};
-var defaultValueCache = {};
-
-/**
- * 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',
-
-  /**
-   * 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.
-   * mustUseAttribute:
-   *   Whether the property must be accessed and mutated using `*Attribute()`.
-   *   (This includes anything that fails `<propName> in <element>`.)
-   * mustUseProperty:
-   *   Whether the property must be accessed and mutated as an object property.
-   * hasSideEffects:
-   *   Whether or not setting a value causes side effects such as triggering
-   *   resources to be loaded or text selection changes. If true, we read from
-   *   the DOM before updating to ensure that the value is only set if it has
-   *   changed.
-   * 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__.
-   * @type {Object}
-   */
-  getPossibleStandardName: "development" !== 'production' ? {} : 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;
-  },
-
-  /**
-   * Returns the default property value for a DOM property (i.e., not an
-   * attribute). Most default values are '' or false, but not all. Worse yet,
-   * some (in particular, `type`) vary depending on the type of element.
-   *
-   * TODO: Is it better to grab all the possible properties when creating an
-   * element to avoid having to create the same element twice?
-   */
-  getDefaultValueForProperty: function (nodeName, prop) {
-    var nodeDefaults = defaultValueCache[nodeName];
-    var testElement;
-    if (!nodeDefaults) {
-      defaultValueCache[nodeName] = nodeDefaults = {};
-    }
-    if (!(prop in nodeDefaults)) {
-      testElement = document.createElement(nodeName);
-      nodeDefaults[prop] = testElement[prop];
-    }
-    return nodeDefaults[prop];
-  },
-
-  injection: DOMPropertyInjection
-};
-
-module.exports = DOMProperty;
-},{"144":144}],11:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule DOMPropertyOperations
- * @typechecks static-only
- */
-
-'use strict';
-
-var DOMProperty = _dereq_(10);
-var ReactPerf = _dereq_(71);
-
-var quoteAttributeValueForBrowser = _dereq_(122);
-var warning = _dereq_(155);
-
-// Simplified subset
-var VALID_ATTRIBUTE_NAME_REGEX = /^[a-zA-Z_][\w\.\-]*$/;
-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;
-  "development" !== 'production' ? warning(false, 'Invalid attribute name: `%s`', attributeName) : undefined;
-  return false;
-}
-
-function shouldIgnoreValue(propertyInfo, value) {
-  return value == null || propertyInfo.hasBooleanValue && !value || propertyInfo.hasNumericValue && isNaN(value) || propertyInfo.hasPositiveNumericValue && value < 1 || propertyInfo.hasOverloadedBooleanValue && value === false;
-}
-
-if ("development" !== 'production') {
-  var reactProps = {
-    children: true,
-    dangerouslySetInnerHTML: true,
-    key: true,
-    ref: true
-  };
-  var warnedProperties = {};
-
-  var warnUnknownProperty = function (name) {
-    if (reactProps.hasOwnProperty(name) && reactProps[name] || warnedProperties.hasOwnProperty(name) && warnedProperties[name]) {
-      return;
-    }
-
-    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;
-
-    // For now, only warn when we have a suggested correction. This prevents
-    // logging too much when using transferPropsTo.
-    "development" !== 'production' ? warning(standardName == null, 'Unknown DOM property %s. Did you mean %s?', name, standardName) : undefined;
-  };
-}
-
-/**
- * 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);
-  },
-
-  /**
-   * 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);
-    } else if ("development" !== 'production') {
-      warnUnknownProperty(name);
-    }
-    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);
-      } else if (propertyInfo.mustUseAttribute) {
-        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 {
-        var propName = propertyInfo.propertyName;
-        // Must explicitly cast values for HAS_SIDE_EFFECTS-properties to the
-        // property type before comparing; only `value` does and is string.
-        if (!propertyInfo.hasSideEffects || '' + node[propName] !== '' + value) {
-          // Contrary to `setAttribute`, object properties are properly
-          // `toString`ed by IE8/9.
-          node[propName] = value;
-        }
-      }
-    } else if (DOMProperty.isCustomAttribute(name)) {
-      DOMPropertyOperations.setValueForAttribute(node, name, value);
-    } else if ("development" !== 'production') {
-      warnUnknownProperty(name);
-    }
-  },
-
-  setValueForAttribute: function (node, name, value) {
-    if (!isAttributeNameSafe(name)) {
-      return;
-    }
-    if (value == null) {
-      node.removeAttribute(name);
-    } else {
-      node.setAttribute(name, '' + value);
-    }
-  },
-
-  /**
-   * 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.mustUseAttribute) {
-        node.removeAttribute(propertyInfo.attributeName);
-      } else {
-        var propName = propertyInfo.propertyName;
-        var defaultValue = DOMProperty.getDefaultValueForProperty(node.nodeName, propName);
-        if (!propertyInfo.hasSideEffects || '' + node[propName] !== defaultValue) {
-          node[propName] = defaultValue;
-        }
-      }
-    } else if (DOMProperty.isCustomAttribute(name)) {
-      node.removeAttribute(name);
-    } else if ("development" !== 'production') {
-      warnUnknownProperty(name);
-    }
-  }
-
-};
-
-ReactPerf.measureMethods(DOMPropertyOperations, 'DOMPropertyOperations', {
-  setValueForProperty: 'setValueForProperty',
-  setValueForAttribute: 'setValueForAttribute',
-  deleteValueForProperty: 'deleteValueForProperty'
-});
-
-module.exports = DOMPropertyOperations;
-},{"10":10,"122":122,"155":155,"71":71}],12:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule Danger
- * @typechecks static-only
- */
-
-'use strict';
-
-var ExecutionEnvironment = _dereq_(130);
-
-var createNodesFromMarkup = _dereq_(135);
-var emptyFunction = _dereq_(136);
-var getMarkupWrap = _dereq_(140);
-var invariant = _dereq_(144);
-
-var OPEN_TAG_NAME_EXP = /^(<[^ \/>]+)/;
-var RESULT_INDEX_ATTR = 'data-danger-index';
-
-/**
- * Extracts the `nodeName` from a string of markup.
- *
- * NOTE: Extracting the `nodeName` does not require a regular expression match
- * because we make assumptions about React-generated markup (i.e. there are no
- * spaces surrounding the opening tag and there is at least one attribute).
- *
- * @param {string} markup String of markup.
- * @return {string} Node name of the supplied markup.
- * @see http://jsperf.com/extract-nodename
- */
-function getNodeName(markup) {
-  return markup.substring(1, markup.indexOf(' '));
-}
-
-var Danger = {
-
-  /**
-   * Renders markup into an array of nodes. The markup is expected to render
-   * into a list of root nodes. Also, the length of `resultList` and
-   * `markupList` should be the same.
-   *
-   * @param {array<string>} markupList List of markup strings to render.
-   * @return {array<DOMElement>} List of rendered nodes.
-   * @internal
-   */
-  dangerouslyRenderMarkup: function (markupList) {
-    !ExecutionEnvironment.canUseDOM ? "development" !== 'production' ? invariant(false, 'dangerouslyRenderMarkup(...): 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.') : invariant(false) : undefined;
-    var nodeName;
-    var markupByNodeName = {};
-    // Group markup by `nodeName` if a wrap is necessary, else by '*'.
-    for (var i = 0; i < markupList.length; i++) {
-      !markupList[i] ? "development" !== 'production' ? invariant(false, 'dangerouslyRenderMarkup(...): Missing markup.') : invariant(false) : undefined;
-      nodeName = getNodeName(markupList[i]);
-      nodeName = getMarkupWrap(nodeName) ? nodeName : '*';
-      markupByNodeName[nodeName] = markupByNodeName[nodeName] || [];
-      markupByNodeName[nodeName][i] = markupList[i];
-    }
-    var resultList = [];
-    var resultListAssignmentCount = 0;
-    for (nodeName in markupByNodeName) {
-      if (!markupByNodeName.hasOwnProperty(nodeName)) {
-        continue;
-      }
-      var markupListByNodeName = markupByNodeName[nodeName];
-
-      // This for-in loop skips the holes of the sparse array. The order of
-      // iteration should follow the order of assignment, which happens to match
-      // numerical index order, but we don't rely on that.
-      var resultIndex;
-      for (resultIndex in markupListByNodeName) {
-        if (markupListByNodeName.hasOwnProperty(resultIndex)) {
-          var markup = markupListByNodeName[resultIndex];
-
-          // Push the requested markup with an additional RESULT_INDEX_ATTR
-          // attribute.  If the markup does not start with a < character, it
-          // will be discarded below (with an appropriate console.error).
-          markupListByNodeName[resultIndex] = markup.replace(OPEN_TAG_NAME_EXP,
-          // This index will be parsed back out below.
-          '$1 ' + RESULT_INDEX_ATTR + '="' + resultIndex + '" ');
-        }
-      }
-
-      // Render each group of markup with similar wrapping `nodeName`.
-      var renderNodes = createNodesFromMarkup(markupListByNodeName.join(''), emptyFunction // Do nothing special with <script> tags.
-      );
-
-      for (var j = 0; j < renderNodes.length; ++j) {
-        var renderNode = renderNodes[j];
-        if (renderNode.hasAttribute && renderNode.hasAttribute(RESULT_INDEX_ATTR)) {
-
-          resultIndex = +renderNode.getAttribute(RESULT_INDEX_ATTR);
-          renderNode.removeAttribute(RESULT_INDEX_ATTR);
-
-          !!resultList.hasOwnProperty(resultIndex) ? "development" !== 'production' ? invariant(false, 'Danger: Assigning to an already-occupied result index.') : invariant(false) : undefined;
-
-          resultList[resultIndex] = renderNode;
-
-          // This should match resultList.length and markupList.length when
-          // we're done.
-          resultListAssignmentCount += 1;
-        } else if ("development" !== 'production') {
-          console.error('Danger: Discarding unexpected node:', renderNode);
-        }
-      }
-    }
-
-    // Although resultList was populated out of order, it should now be a dense
-    // array.
-    !(resultListAssignmentCount === resultList.length) ? "development" !== 'production' ? invariant(false, 'Danger: Did not assign to every index of resultList.') : invariant(false) : undefined;
-
-    !(resultList.length === markupList.length) ? "development" !== 'production' ? invariant(false, 'Danger: Expected markup to render %s nodes, but rendered %s.', markupList.length, resultList.length) : invariant(false) : undefined;
-
-    return resultList;
-  },
-
-  /**
-   * 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 ? "development" !== 'production' ? 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.') : invariant(false) : undefined;
-    !markup ? "development" !== 'production' ? invariant(false, 'dangerouslyReplaceNodeWithMarkup(...): Missing markup.') : invariant(false) : undefined;
-    !(oldChild.tagName.toLowerCase() !== 'html') ? "development" !== 'production' ? 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().') : invariant(false) : undefined;
-
-    var newChild;
-    if (typeof markup === 'string') {
-      newChild = createNodesFromMarkup(markup, emptyFunction)[0];
-    } else {
-      newChild = markup;
-    }
-    oldChild.parentNode.replaceChild(newChild, oldChild);
-  }
-
-};
-
-module.exports = Danger;
-},{"130":130,"135":135,"136":136,"140":140,"144":144}],13:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule DefaultEventPluginOrder
- */
-
-'use strict';
-
-var keyOf = _dereq_(148);
-
-/**
- * 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 = [keyOf({ ResponderEventPlugin: null }), keyOf({ SimpleEventPlugin: null }), keyOf({ TapEventPlugin: null }), keyOf({ EnterLeaveEventPlugin: null }), keyOf({ ChangeEventPlugin: null }), keyOf({ SelectEventPlugin: null }), keyOf({ BeforeInputEventPlugin: null })];
-
-module.exports = DefaultEventPluginOrder;
-},{"148":148}],14:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule EnterLeaveEventPlugin
- * @typechecks static-only
- */
-
-'use strict';
-
-var EventConstants = _dereq_(15);
-var EventPropagators = _dereq_(19);
-var SyntheticMouseEvent = _dereq_(96);
-
-var ReactMount = _dereq_(65);
-var keyOf = _dereq_(148);
-
-var topLevelTypes = EventConstants.topLevelTypes;
-var getFirstReactDOM = ReactMount.getFirstReactDOM;
-
-var eventTypes = {
-  mouseEnter: {
-    registrationName: keyOf({ onMouseEnter: null }),
-    dependencies: [topLevelTypes.topMouseOut, topLevelTypes.topMouseOver]
-  },
-  mouseLeave: {
-    registrationName: keyOf({ onMouseLeave: null }),
-    dependencies: [topLevelTypes.topMouseOut, topLevelTypes.topMouseOver]
-  }
-};
-
-var extractedEvents = [null, null];
-
-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.
-   *
-   * @param {string} topLevelType Record from `EventConstants`.
-   * @param {DOMEventTarget} topLevelTarget The listening component root node.
-   * @param {string} topLevelTargetID ID of `topLevelTarget`.
-   * @param {object} nativeEvent Native browser event.
-   * @return {*} An accumulation of synthetic events.
-   * @see {EventPluginHub.extractEvents}
-   */
-  extractEvents: function (topLevelType, topLevelTarget, topLevelTargetID, nativeEvent, nativeEventTarget) {
-    if (topLevelType === topLevelTypes.topMouseOver && (nativeEvent.relatedTarget || nativeEvent.fromElement)) {
-      return null;
-    }
-    if (topLevelType !== topLevelTypes.topMouseOut && topLevelType !== topLevelTypes.topMouseOver) {
-      // Must not be a mouse in or mouse out - ignoring.
-      return null;
-    }
-
-    var win;
-    if (topLevelTarget.window === topLevelTarget) {
-      // `topLevelTarget` is probably a window object.
-      win = topLevelTarget;
-    } else {
-      // TODO: Figure out why `ownerDocument` is sometimes undefined in IE8.
-      var doc = topLevelTarget.ownerDocument;
-      if (doc) {
-        win = doc.defaultView || doc.parentWindow;
-      } else {
-        win = window;
-      }
-    }
-
-    var from;
-    var to;
-    var fromID = '';
-    var toID = '';
-    if (topLevelType === topLevelTypes.topMouseOut) {
-      from = topLevelTarget;
-      fromID = topLevelTargetID;
-      to = getFirstReactDOM(nativeEvent.relatedTarget || nativeEvent.toElement);
-      if (to) {
-        toID = ReactMount.getID(to);
-      } else {
-        to = win;
-      }
-      to = to || win;
-    } else {
-      from = win;
-      to = topLevelTarget;
-      toID = topLevelTargetID;
-    }
-
-    if (from === to) {
-      // Nothing pertains to our managed components.
-      return null;
-    }
-
-    var leave = SyntheticMouseEvent.getPooled(eventTypes.mouseLeave, fromID, nativeEvent, nativeEventTarget);
-    leave.type = 'mouseleave';
-    leave.target = from;
-    leave.relatedTarget = to;
-
-    var enter = SyntheticMouseEvent.getPooled(eventTypes.mouseEnter, toID, nativeEvent, nativeEventTarget);
-    enter.type = 'mouseenter';
-    enter.target = to;
-    enter.relatedTarget = from;
-
-    EventPropagators.accumulateEnterLeaveDispatches(leave, enter, fromID, toID);
-
-    extractedEvents[0] = leave;
-    extractedEvents[1] = enter;
-
-    return extractedEvents;
-  }
-
-};
-
-module.exports = EnterLeaveEventPlugin;
-},{"148":148,"15":15,"19":19,"65":65,"96":96}],15:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule EventConstants
- */
-
-'use strict';
-
-var keyMirror = _dereq_(147);
-
-var PropagationPhases = keyMirror({ bubbled: null, captured: null });
-
-/**
- * Types of raw signals from the browser caught at the top level.
- */
-var topLevelTypes = keyMirror({
-  topAbort: null,
-  topBlur: null,
-  topCanPlay: null,
-  topCanPlayThrough: null,
-  topChange: null,
-  topClick: null,
-  topCompositionEnd: null,
-  topCompositionStart: null,
-  topCompositionUpdate: null,
-  topContextMenu: null,
-  topCopy: null,
-  topCut: null,
-  topDoubleClick: null,
-  topDrag: null,
-  topDragEnd: null,
-  topDragEnter: null,
-  topDragExit: null,
-  topDragLeave: null,
-  topDragOver: null,
-  topDragStart: null,
-  topDrop: null,
-  topDurationChange: null,
-  topEmptied: null,
-  topEncrypted: null,
-  topEnded: null,
-  topError: null,
-  topFocus: null,
-  topInput: null,
-  topKeyDown: null,
-  topKeyPress: null,
-  topKeyUp: null,
-  topLoad: null,
-  topLoadedData: null,
-  topLoadedMetadata: null,
-  topLoadStart: null,
-  topMouseDown: null,
-  topMouseMove: null,
-  topMouseOut: null,
-  topMouseOver: null,
-  topMouseUp: null,
-  topPaste: null,
-  topPause: null,
-  topPlay: null,
-  topPlaying: null,
-  topProgress: null,
-  topRateChange: null,
-  topReset: null,
-  topScroll: null,
-  topSeeked: null,
-  topSeeking: null,
-  topSelectionChange: null,
-  topStalled: null,
-  topSubmit: null,
-  topSuspend: null,
-  topTextInput: null,
-  topTimeUpdate: null,
-  topTouchCancel: null,
-  topTouchEnd: null,
-  topTouchMove: null,
-  topTouchStart: null,
-  topVolumeChange: null,
-  topWaiting: null,
-  topWheel: null
-});
-
-var EventConstants = {
-  topLevelTypes: topLevelTypes,
-  PropagationPhases: PropagationPhases
-};
-
-module.exports = EventConstants;
-},{"147":147}],16:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule EventPluginHub
- */
-
-'use strict';
-
-var EventPluginRegistry = _dereq_(17);
-var EventPluginUtils = _dereq_(18);
-var ReactErrorUtils = _dereq_(56);
-
-var accumulateInto = _dereq_(102);
-var forEachAccumulated = _dereq_(110);
-var invariant = _dereq_(144);
-var warning = _dereq_(155);
-
-/**
- * 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);
-};
-
-/**
- * - `InstanceHandle`: [required] Module that performs logical traversals of DOM
- *   hierarchy given ids of the logical DOM elements involved.
- */
-var InstanceHandle = null;
-
-function validateInstanceHandle() {
-  var valid = InstanceHandle && InstanceHandle.traverseTwoPhase && InstanceHandle.traverseEnterLeave;
-  "development" !== 'production' ? warning(valid, 'InstanceHandle not injected before use!') : undefined;
-}
-
-/**
- * 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 {object} InjectedMount
-     * @public
-     */
-    injectMount: EventPluginUtils.injection.injectMount,
-
-    /**
-     * @param {object} InjectedInstanceHandle
-     * @public
-     */
-    injectInstanceHandle: function (InjectedInstanceHandle) {
-      InstanceHandle = InjectedInstanceHandle;
-      if ("development" !== 'production') {
-        validateInstanceHandle();
-      }
-    },
-
-    getInstanceHandle: function () {
-      if ("development" !== 'production') {
-        validateInstanceHandle();
-      }
-      return InstanceHandle;
-    },
-
-    /**
-     * @param {array} InjectedEventPluginOrder
-     * @public
-     */
-    injectEventPluginOrder: EventPluginRegistry.injectEventPluginOrder,
-
-    /**
-     * @param {object} injectedNamesToPlugins Map from names to plugin modules.
-     */
-    injectEventPluginsByName: EventPluginRegistry.injectEventPluginsByName
-
-  },
-
-  eventNameDispatchConfigs: EventPluginRegistry.eventNameDispatchConfigs,
-
-  registrationNameModules: EventPluginRegistry.registrationNameModules,
-
-  /**
-   * Stores `listener` at `listenerBank[registrationName][id]`. Is idempotent.
-   *
-   * @param {string} id ID of the DOM element.
-   * @param {string} registrationName Name of listener (e.g. `onClick`).
-   * @param {?function} listener The callback to store.
-   */
-  putListener: function (id, registrationName, listener) {
-    !(typeof listener === 'function') ? "development" !== 'production' ? invariant(false, 'Expected %s listener to be a function, instead got type %s', registrationName, typeof listener) : invariant(false) : undefined;
-
-    var bankForRegistrationName = listenerBank[registrationName] || (listenerBank[registrationName] = {});
-    bankForRegistrationName[id] = listener;
-
-    var PluginModule = EventPluginRegistry.registrationNameModules[registrationName];
-    if (PluginModule && PluginModule.didPutListener) {
-      PluginModule.didPutListener(id, registrationName, listener);
-    }
-  },
-
-  /**
-   * @param {string} id ID of the DOM element.
-   * @param {string} registrationName Name of listener (e.g. `onClick`).
-   * @return {?function} The stored callback.
-   */
-  getListener: function (id, registrationName) {
-    var bankForRegistrationName = listenerBank[registrationName];
-    return bankForRegistrationName && bankForRegistrationName[id];
-  },
-
-  /**
-   * Deletes a listener from the registration bank.
-   *
-   * @param {string} id ID of the DOM element.
-   * @param {string} registrationName Name of listener (e.g. `onClick`).
-   */
-  deleteListener: function (id, registrationName) {
-    var PluginModule = EventPluginRegistry.registrationNameModules[registrationName];
-    if (PluginModule && PluginModule.willDeleteListener) {
-      PluginModule.willDeleteListener(id, registrationName);
-    }
-
-    var bankForRegistrationName = listenerBank[registrationName];
-    // TODO: This should never be null -- when is it?
-    if (bankForRegistrationName) {
-      delete bankForRegistrationName[id];
-    }
-  },
-
-  /**
-   * Deletes all listeners for the DOM element with the supplied ID.
-   *
-   * @param {string} id ID of the DOM element.
-   */
-  deleteAllListeners: function (id) {
-    for (var registrationName in listenerBank) {
-      if (!listenerBank[registrationName][id]) {
-        continue;
-      }
-
-      var PluginModule = EventPluginRegistry.registrationNameModules[registrationName];
-      if (PluginModule && PluginModule.willDeleteListener) {
-        PluginModule.willDeleteListener(id, registrationName);
-      }
-
-      delete listenerBank[registrationName][id];
-    }
-  },
-
-  /**
-   * Allows registered plugins an opportunity to extract events from top-level
-   * native browser events.
-   *
-   * @param {string} topLevelType Record from `EventConstants`.
-   * @param {DOMEventTarget} topLevelTarget The listening component root node.
-   * @param {string} topLevelTargetID ID of `topLevelTarget`.
-   * @param {object} nativeEvent Native browser event.
-   * @return {*} An accumulation of synthetic events.
-   * @internal
-   */
-  extractEvents: function (topLevelType, topLevelTarget, topLevelTargetID, 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, topLevelTarget, topLevelTargetID, 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 ? "development" !== 'production' ? invariant(false, 'processEventQueue(): Additional events were enqueued while processing ' + 'an event queue. Support for this has not yet been implemented.') : invariant(false) : undefined;
-    // 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;
-},{"102":102,"110":110,"144":144,"155":155,"17":17,"18":18,"56":56}],17:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule EventPluginRegistry
- * @typechecks static-only
- */
-
-'use strict';
-
-var invariant = _dereq_(144);
-
-/**
- * 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) ? "development" !== 'production' ? invariant(false, 'EventPluginRegistry: Cannot inject event plugins that do not exist in ' + 'the plugin ordering, `%s`.', pluginName) : invariant(false) : undefined;
-    if (EventPluginRegistry.plugins[pluginIndex]) {
-      continue;
-    }
-    !PluginModule.extractEvents ? "development" !== 'production' ? invariant(false, 'EventPluginRegistry: Event plugins must implement an `extractEvents` ' + 'method, but `%s` does not.', pluginName) : invariant(false) : undefined;
-    EventPluginRegistry.plugins[pluginIndex] = PluginModule;
-    var publishedEvents = PluginModule.eventTypes;
-    for (var eventName in publishedEvents) {
-      !publishEventForPlugin(publishedEvents[eventName], PluginModule, eventName) ? "development" !== 'production' ? invariant(false, 'EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.', eventName, pluginName) : invariant(false) : undefined;
-    }
-  }
-}
-
-/**
- * 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) ? "development" !== 'production' ? invariant(false, 'EventPluginHub: More than one plugin attempted to publish the same ' + 'event name, `%s`.', eventName) : invariant(false) : undefined;
-  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] ? "development" !== 'production' ? invariant(false, 'EventPluginHub: More than one plugin attempted to publish the same ' + 'registration name, `%s`.', registrationName) : invariant(false) : undefined;
-  EventPluginRegistry.registrationNameModules[registrationName] = PluginModule;
-  EventPluginRegistry.registrationNameDependencies[registrationName] = PluginModule.eventTypes[eventName].dependencies;
-}
-
-/**
- * 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: {},
-
-  /**
-   * 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 ? "development" !== 'production' ? invariant(false, 'EventPluginRegistry: Cannot inject event plugin ordering more than ' + 'once. You are likely trying to load more than one copy of React.') : invariant(false) : undefined;
-    // 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] ? "development" !== 'production' ? invariant(false, 'EventPluginRegistry: Cannot inject two different event plugins ' + 'using the same name, `%s`.', pluginName) : invariant(false) : undefined;
-        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;
-    }
-    for (var phase in dispatchConfig.phasedRegistrationNames) {
-      if (!dispatchConfig.phasedRegistrationNames.hasOwnProperty(phase)) {
-        continue;
-      }
-      var PluginModule = EventPluginRegistry.registrationNameModules[dispatchConfig.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];
-      }
-    }
-  }
-
-};
-
-module.exports = EventPluginRegistry;
-},{"144":144}],18:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule EventPluginUtils
- */
-
-'use strict';
-
-var EventConstants = _dereq_(15);
-var ReactErrorUtils = _dereq_(56);
-
-var invariant = _dereq_(144);
-var warning = _dereq_(155);
-
-/**
- * Injected dependencies:
- */
-
-/**
- * - `Mount`: [required] Module that can convert between React dom IDs and
- *   actual node references.
- */
-var injection = {
-  Mount: null,
-  injectMount: function (InjectedMount) {
-    injection.Mount = InjectedMount;
-    if ("development" !== 'production') {
-      "development" !== 'production' ? warning(InjectedMount && InjectedMount.getNode && InjectedMount.getID, 'EventPluginUtils.injection.injectMount(...): Injected Mount ' + 'module is missing getNode or getID.') : undefined;
-    }
-  }
-};
-
-var topLevelTypes = EventConstants.topLevelTypes;
-
-function isEndish(topLevelType) {
-  return topLevelType === topLevelTypes.topMouseUp || topLevelType === topLevelTypes.topTouchEnd || topLevelType === topLevelTypes.topTouchCancel;
-}
-
-function isMoveish(topLevelType) {
-  return topLevelType === topLevelTypes.topMouseMove || topLevelType === topLevelTypes.topTouchMove;
-}
-function isStartish(topLevelType) {
-  return topLevelType === topLevelTypes.topMouseDown || topLevelType === topLevelTypes.topTouchStart;
-}
-
-var validateEventDispatches;
-if ("development" !== 'production') {
-  validateEventDispatches = function (event) {
-    var dispatchListeners = event._dispatchListeners;
-    var dispatchIDs = event._dispatchIDs;
-
-    var listenersIsArr = Array.isArray(dispatchListeners);
-    var idsIsArr = Array.isArray(dispatchIDs);
-    var IDsLen = idsIsArr ? dispatchIDs.length : dispatchIDs ? 1 : 0;
-    var listenersLen = listenersIsArr ? dispatchListeners.length : dispatchListeners ? 1 : 0;
-
-    "development" !== 'production' ? warning(idsIsArr === listenersIsArr && IDsLen === listenersLen, 'EventPluginUtils: Invalid `event`.') : undefined;
-  };
-}
-
-/**
- * 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 {string} domID DOM id to pass to the callback.
- */
-function executeDispatch(event, simulated, listener, domID) {
-  var type = event.type || 'unknown-event';
-  event.currentTarget = injection.Mount.getNode(domID);
-  if (simulated) {
-    ReactErrorUtils.invokeGuardedCallbackWithCatch(type, listener, event, domID);
-  } else {
-    ReactErrorUtils.invokeGuardedCallback(type, listener, event, domID);
-  }
-  event.currentTarget = null;
-}
-
-/**
- * Standard/simple iteration through an event's collected dispatches.
- */
-function executeDispatchesInOrder(event, simulated) {
-  var dispatchListeners = event._dispatchListeners;
-  var dispatchIDs = event._dispatchIDs;
-  if ("development" !== 'production') {
-    validateEventDispatches(event);
-  }
-  if (Array.isArray(dispatchListeners)) {
-    for (var i = 0; i < dispatchListeners.length; i++) {
-      if (event.isPropagationStopped()) {
-        break;
-      }
-      // Listeners and IDs are two parallel arrays that are always in sync.
-      executeDispatch(event, simulated, dispatchListeners[i], dispatchIDs[i]);
-    }
-  } else if (dispatchListeners) {
-    executeDispatch(event, simulated, dispatchListeners, dispatchIDs);
-  }
-  event._dispatchListeners = null;
-  event._dispatchIDs = 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 dispatchIDs = event._dispatchIDs;
-  if ("development" !== 'production') {
-    validateEventDispatches(event);
-  }
-  if (Array.isArray(dispatchListeners)) {
-    for (var i = 0; i < dispatchListeners.length; i++) {
-      if (event.isPropagationStopped()) {
-        break;
-      }
-      // Listeners and IDs are two parallel arrays that are always in sync.
-      if (dispatchListeners[i](event, dispatchIDs[i])) {
-        return dispatchIDs[i];
-      }
-    }
-  } else if (dispatchListeners) {
-    if (dispatchListeners(event, dispatchIDs)) {
-      return dispatchIDs;
-    }
-  }
-  return null;
-}
-
-/**
- * @see executeDispatchesInOrderStopAtTrueImpl
- */
-function executeDispatchesInOrderStopAtTrue(event) {
-  var ret = executeDispatchesInOrderStopAtTrueImpl(event);
-  event._dispatchIDs = 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 ("development" !== 'production') {
-    validateEventDispatches(event);
-  }
-  var dispatchListener = event._dispatchListeners;
-  var dispatchID = event._dispatchIDs;
-  !!Array.isArray(dispatchListener) ? "development" !== 'production' ? invariant(false, 'executeDirectDispatch(...): Invalid `event`.') : invariant(false) : undefined;
-  var res = dispatchListener ? dispatchListener(event, dispatchID) : null;
-  event._dispatchListeners = null;
-  event._dispatchIDs = 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,
-
-  getNode: function (id) {
-    return injection.Mount.getNode(id);
-  },
-  getID: function (node) {
-    return injection.Mount.getID(node);
-  },
-
-  injection: injection
-};
-
-module.exports = EventPluginUtils;
-},{"144":144,"15":15,"155":155,"56":56}],19:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule EventPropagators
- */
-
-'use strict';
-
-var EventConstants = _dereq_(15);
-var EventPluginHub = _dereq_(16);
-
-var warning = _dereq_(155);
-
-var accumulateInto = _dereq_(102);
-var forEachAccumulated = _dereq_(110);
-
-var PropagationPhases = EventConstants.PropagationPhases;
-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(id, event, propagationPhase) {
-  var registrationName = event.dispatchConfig.phasedRegistrationNames[propagationPhase];
-  return getListener(id, 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(domID, upwards, event) {
-  if ("development" !== 'production') {
-    "development" !== 'production' ? warning(domID, 'Dispatching id must not be null') : undefined;
-  }
-  var phase = upwards ? PropagationPhases.bubbled : PropagationPhases.captured;
-  var listener = listenerAtPhase(domID, event, phase);
-  if (listener) {
-    event._dispatchListeners = accumulateInto(event._dispatchListeners, listener);
-    event._dispatchIDs = accumulateInto(event._dispatchIDs, domID);
-  }
-}
-
-/**
- * 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) {
-    EventPluginHub.injection.getInstanceHandle().traverseTwoPhase(event.dispatchMarker, accumulateDirectionalDispatches, event);
-  }
-}
-
-/**
- * Same as `accumulateTwoPhaseDispatchesSingle`, but skips over the targetID.
- */
-function accumulateTwoPhaseDispatchesSingleSkipTarget(event) {
-  if (event && event.dispatchConfig.phasedRegistrationNames) {
-    EventPluginHub.injection.getInstanceHandle().traverseTwoPhaseSkipTarget(event.dispatchMarker, 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(id, ignoredDirection, event) {
-  if (event && event.dispatchConfig.registrationName) {
-    var registrationName = event.dispatchConfig.registrationName;
-    var listener = getListener(id, registrationName);
-    if (listener) {
-      event._dispatchListeners = accumulateInto(event._dispatchListeners, listener);
-      event._dispatchIDs = accumulateInto(event._dispatchIDs, id);
-    }
-  }
-}
-
-/**
- * Accumulates dispatches on an `SyntheticEvent`, but only for the
- * `dispatchMarker`.
- * @param {SyntheticEvent} event
- */
-function accumulateDirectDispatchesSingle(event) {
-  if (event && event.dispatchConfig.registrationName) {
-    accumulateDispatches(event.dispatchMarker, null, event);
-  }
-}
-
-function accumulateTwoPhaseDispatches(events) {
-  forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle);
-}
-
-function accumulateTwoPhaseDispatchesSkipTarget(events) {
-  forEachAccumulated(events, accumulateTwoPhaseDispatchesSingleSkipTarget);
-}
-
-function accumulateEnterLeaveDispatches(leave, enter, fromID, toID) {
-  EventPluginHub.injection.getInstanceHandle().traverseEnterLeave(fromID, toID, 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;
-},{"102":102,"110":110,"15":15,"155":155,"16":16}],20:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule FallbackCompositionState
- * @typechecks static-only
- */
-
-'use strict';
-
-var PooledClass = _dereq_(24);
-
-var assign = _dereq_(23);
-var getTextContentAccessor = _dereq_(117);
-
-/**
- * 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;
-},{"117":117,"23":23,"24":24}],21:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule HTMLDOMPropertyConfig
- */
-
-'use strict';
-
-var DOMProperty = _dereq_(10);
-var ExecutionEnvironment = _dereq_(130);
-
-var MUST_USE_ATTRIBUTE = DOMProperty.injection.MUST_USE_ATTRIBUTE;
-var MUST_USE_PROPERTY = DOMProperty.injection.MUST_USE_PROPERTY;
-var HAS_BOOLEAN_VALUE = DOMProperty.injection.HAS_BOOLEAN_VALUE;
-var HAS_SIDE_EFFECTS = DOMProperty.injection.HAS_SIDE_EFFECTS;
-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 hasSVG;
-if (ExecutionEnvironment.canUseDOM) {
-  var implementation = document.implementation;
-  hasSVG = implementation && implementation.hasFeature && implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#BasicStructure', '1.1');
-}
-
-var HTMLDOMPropertyConfig = {
-  isCustomAttribute: RegExp.prototype.test.bind(/^(data|aria)-[a-z_][a-z\d_.\-]*$/),
-  Properties: {
-    /**
-     * Standard Properties
-     */
-    accept: null,
-    acceptCharset: null,
-    accessKey: null,
-    action: null,
-    allowFullScreen: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
-    allowTransparency: MUST_USE_ATTRIBUTE,
-    alt: null,
-    async: HAS_BOOLEAN_VALUE,
-    autoComplete: null,
-    // autoFocus is polyfilled/normalized by AutoFocusUtils
-    // autoFocus: HAS_BOOLEAN_VALUE,
-    autoPlay: HAS_BOOLEAN_VALUE,
-    capture: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
-    cellPadding: null,
-    cellSpacing: null,
-    charSet: MUST_USE_ATTRIBUTE,
-    challenge: MUST_USE_ATTRIBUTE,
-    checked: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
-    classID: MUST_USE_ATTRIBUTE,
-    // To set className on SVG elements, it's necessary to use .setAttribute;
-    // this works on HTML elements too in all browsers except IE8. Conveniently,
-    // IE8 doesn't support SVG and so we can simply use the attribute in
-    // browsers that support SVG and the property in browsers that don't,
-    // regardless of whether the element is HTML or SVG.
-    className: hasSVG ? MUST_USE_ATTRIBUTE : MUST_USE_PROPERTY,
-    cols: MUST_USE_ATTRIBUTE | HAS_POSITIVE_NUMERIC_VALUE,
-    colSpan: null,
-    content: null,
-    contentEditable: null,
-    contextMenu: MUST_USE_ATTRIBUTE,
-    controls: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
-    coords: null,
-    crossOrigin: null,
-    data: null, // For `<object />` acts as `src`.
-    dateTime: MUST_USE_ATTRIBUTE,
-    'default': HAS_BOOLEAN_VALUE,
-    defer: HAS_BOOLEAN_VALUE,
-    dir: null,
-    disabled: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
-    download: HAS_OVERLOADED_BOOLEAN_VALUE,
-    draggable: null,
-    encType: null,
-    form: MUST_USE_ATTRIBUTE,
-    formAction: MUST_USE_ATTRIBUTE,
-    formEncType: MUST_USE_ATTRIBUTE,
-    formMethod: MUST_USE_ATTRIBUTE,
-    formNoValidate: HAS_BOOLEAN_VALUE,
-    formTarget: MUST_USE_ATTRIBUTE,
-    frameBorder: MUST_USE_ATTRIBUTE,
-    headers: null,
-    height: MUST_USE_ATTRIBUTE,
-    hidden: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
-    high: null,
-    href: null,
-    hrefLang: null,
-    htmlFor: null,
-    httpEquiv: null,
-    icon: null,
-    id: MUST_USE_PROPERTY,
-    inputMode: MUST_USE_ATTRIBUTE,
-    integrity: null,
-    is: MUST_USE_ATTRIBUTE,
-    keyParams: MUST_USE_ATTRIBUTE,
-    keyType: MUST_USE_ATTRIBUTE,
-    kind: null,
-    label: null,
-    lang: null,
-    list: MUST_USE_ATTRIBUTE,
-    loop: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
-    low: null,
-    manifest: MUST_USE_ATTRIBUTE,
-    marginHeight: null,
-    marginWidth: null,
-    max: null,
-    maxLength: MUST_USE_ATTRIBUTE,
-    media: MUST_USE_ATTRIBUTE,
-    mediaGroup: null,
-    method: null,
-    min: null,
-    minLength: MUST_USE_ATTRIBUTE,
-    multiple: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
-    muted: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
-    name: null,
-    nonce: MUST_USE_ATTRIBUTE,
-    noValidate: HAS_BOOLEAN_VALUE,
-    open: HAS_BOOLEAN_VALUE,
-    optimum: null,
-    pattern: null,
-    placeholder: null,
-    poster: null,
-    preload: null,
-    radioGroup: null,
-    readOnly: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
-    rel: null,
-    required: HAS_BOOLEAN_VALUE,
-    reversed: HAS_BOOLEAN_VALUE,
-    role: MUST_USE_ATTRIBUTE,
-    rows: MUST_USE_ATTRIBUTE | HAS_POSITIVE_NUMERIC_VALUE,
-    rowSpan: null,
-    sandbox: null,
-    scope: null,
-    scoped: HAS_BOOLEAN_VALUE,
-    scrolling: null,
-    seamless: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
-    selected: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
-    shape: null,
-    size: MUST_USE_ATTRIBUTE | HAS_POSITIVE_NUMERIC_VALUE,
-    sizes: MUST_USE_ATTRIBUTE,
-    span: HAS_POSITIVE_NUMERIC_VALUE,
-    spellCheck: null,
-    src: null,
-    srcDoc: MUST_USE_PROPERTY,
-    srcLang: null,
-    srcSet: MUST_USE_ATTRIBUTE,
-    start: HAS_NUMERIC_VALUE,
-    step: null,
-    style: null,
-    summary: null,
-    tabIndex: null,
-    target: null,
-    title: null,
-    type: null,
-    useMap: null,
-    value: MUST_USE_PROPERTY | HAS_SIDE_EFFECTS,
-    width: MUST_USE_ATTRIBUTE,
-    wmode: MUST_USE_ATTRIBUTE,
-    wrap: null,
-
-    /**
-     * RDFa Properties
-     */
-    about: MUST_USE_ATTRIBUTE,
-    datatype: MUST_USE_ATTRIBUTE,
-    inlist: MUST_USE_ATTRIBUTE,
-    prefix: MUST_USE_ATTRIBUTE,
-    // property is also supported for OpenGraph in meta tags.
-    property: MUST_USE_ATTRIBUTE,
-    resource: MUST_USE_ATTRIBUTE,
-    'typeof': MUST_USE_ATTRIBUTE,
-    vocab: MUST_USE_ATTRIBUTE,
-
-    /**
-     * Non-standard Properties
-     */
-    // autoCapitalize and autoCorrect are supported in Mobile Safari for
-    // keyboard hints.
-    autoCapitalize: MUST_USE_ATTRIBUTE,
-    autoCorrect: MUST_USE_ATTRIBUTE,
-    // autoSave allows WebKit/Blink to persist values of input fields on page reloads
-    autoSave: null,
-    // color is for Safari mask-icon link
-    color: null,
-    // itemProp, itemScope, itemType are for
-    // Microdata support. See http://schema.org/docs/gs.html
-    itemProp: MUST_USE_ATTRIBUTE,
-    itemScope: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
-    itemType: MUST_USE_ATTRIBUTE,
-    // itemID and itemRef are for Microdata support as well but
-    // only specified in the the WHATWG spec document. See
-    // https://html.spec.whatwg.org/multipage/microdata.html#microdata-dom-api
-    itemID: MUST_USE_ATTRIBUTE,
-    itemRef: MUST_USE_ATTRIBUTE,
-    // results show looking glass icon and recent searches on input
-    // search fields in WebKit/Blink
-    results: null,
-    // IE-only attribute that specifies security restrictions on an iframe
-    // as an alternative to the sandbox attribute on IE<10
-    security: MUST_USE_ATTRIBUTE,
-    // IE-only attribute that controls focus behavior
-    unselectable: MUST_USE_ATTRIBUTE
-  },
-  DOMAttributeNames: {
-    acceptCharset: 'accept-charset',
-    className: 'class',
-    htmlFor: 'for',
-    httpEquiv: 'http-equiv'
-  },
-  DOMPropertyNames: {
-    autoComplete: 'autocomplete',
-    autoFocus: 'autofocus',
-    autoPlay: 'autoplay',
-    autoSave: 'autosave',
-    // `encoding` is equivalent to `enctype`, IE8 lacks an `enctype` setter.
-    // http://www.w3.org/TR/html5/forms.html#dom-fs-encoding
-    encType: 'encoding',
-    hrefLang: 'hreflang',
-    radioGroup: 'radiogroup',
-    spellCheck: 'spellcheck',
-    srcDoc: 'srcdoc',
-    srcSet: 'srcset'
-  }
-};
-
-module.exports = HTMLDOMPropertyConfig;
-},{"10":10,"130":130}],22:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule LinkedValueUtils
- * @typechecks static-only
- */
-
-'use strict';
-
-var ReactPropTypes = _dereq_(74);
-var ReactPropTypeLocations = _dereq_(73);
-
-var invariant = _dereq_(144);
-var warning = _dereq_(155);
-
-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) ? "development" !== 'production' ? 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.') : invariant(false) : undefined;
-}
-function _assertValueLink(inputProps) {
-  _assertSingleLink(inputProps);
-  !(inputProps.value == null && inputProps.onChange == null) ? "development" !== 'production' ? 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.') : invariant(false) : undefined;
-}
-
-function _assertCheckedLink(inputProps) {
-  _assertSingleLink(inputProps);
-  !(inputProps.checked == null && inputProps.onChange == null) ? "development" !== 'production' ? 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') : invariant(false) : undefined;
-}
-
-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: ReactPropTypes.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, ReactPropTypeLocations.prop);
-      }
-      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);
-        "development" !== 'production' ? warning(false, 'Failed form propType: %s%s', error.message, addendum) : undefined;
-      }
-    }
-  },
-
-  /**
-   * @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;
-},{"144":144,"155":155,"73":73,"74":74}],23:[function(_dereq_,module,exports){
-/**
- * Copyright 2014-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule Object.assign
- */
-
-// https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.assign
-
-'use strict';
-
-function assign(target, sources) {
-  if (target == null) {
-    throw new TypeError('Object.assign target cannot be null or undefined');
-  }
-
-  var to = Object(target);
-  var hasOwnProperty = Object.prototype.hasOwnProperty;
-
-  for (var nextIndex = 1; nextIndex < arguments.length; nextIndex++) {
-    var nextSource = arguments[nextIndex];
-    if (nextSource == null) {
-      continue;
-    }
-
-    var from = Object(nextSource);
-
-    // We don't currently support accessors nor proxies. Therefore this
-    // copy cannot throw. If we ever supported this then we must handle
-    // exceptions and side-effects. We don't support symbols so they won't
-    // be transferred.
-
-    for (var key in from) {
-      if (hasOwnProperty.call(from, key)) {
-        to[key] = from[key];
-      }
-    }
-  }
-
-  return to;
-}
-
-module.exports = assign;
-},{}],24:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule PooledClass
- */
-
-'use strict';
-
-var invariant = _dereq_(144);
-
-/**
- * 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 fiveArgumentPooler = function (a1, a2, a3, a4, a5) {
-  var Klass = this;
-  if (Klass.instancePool.length) {
-    var instance = Klass.instancePool.pop();
-    Klass.call(instance, a1, a2, a3, a4, a5);
-    return instance;
-  } else {
-    return new Klass(a1, a2, a3, a4, a5);
-  }
-};
-
-var standardReleaser = function (instance) {
-  var Klass = this;
-  !(instance instanceof Klass) ? "development" !== 'production' ? invariant(false, 'Trying to release an instance into a pool of a different type.') : invariant(false) : undefined;
-  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 (optional).
- *
- * @param {Function} CopyConstructor Constructor that can be used to reset.
- * @param {Function} pooler Customizable pooler.
- */
-var addPoolingTo = function (CopyConstructor, pooler) {
-  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,
-  fiveArgumentPooler: fiveArgumentPooler
-};
-
-module.exports = PooledClass;
-},{"144":144}],25:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactBrowserComponentMixin
- */
-
-'use strict';
-
-var ReactInstanceMap = _dereq_(62);
-
-var findDOMNode = _dereq_(108);
-var warning = _dereq_(155);
-
-var didWarnKey = '_getDOMNodeDidWarn';
-
-var ReactBrowserComponentMixin = {
-  /**
-   * Returns the DOM node rendered by this component.
-   *
-   * @return {DOMElement} The root node of this component.
-   * @final
-   * @protected
-   */
-  getDOMNode: function () {
-    "development" !== 'production' ? warning(this.constructor[didWarnKey], '%s.getDOMNode(...) is deprecated. Please use ' + 'ReactDOM.findDOMNode(instance) instead.', ReactInstanceMap.get(this).getName() || this.tagName || 'Unknown') : undefined;
-    this.constructor[didWarnKey] = true;
-    return findDOMNode(this);
-  }
-};
-
-module.exports = ReactBrowserComponentMixin;
-},{"108":108,"155":155,"62":62}],26:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactBrowserEventEmitter
- * @typechecks static-only
- */
-
-'use strict';
-
-var EventConstants = _dereq_(15);
-var EventPluginHub = _dereq_(16);
-var EventPluginRegistry = _dereq_(17);
-var ReactEventEmitterMixin = _dereq_(57);
-var ReactPerf = _dereq_(71);
-var ViewportMetrics = _dereq_(101);
-
-var assign = _dereq_(23);
-var isEventSupported = _dereq_(119);
-
-/**
- * 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 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',
-  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',
-  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:
- *
- *   ReactBrowserEventEmitter.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];
-
-    var topLevelTypes = EventConstants.topLevelTypes;
-    for (var i = 0; i < dependencies.length; i++) {
-      var dependency = dependencies[i];
-      if (!(isListening.hasOwnProperty(dependency) && isListening[dependency])) {
-        if (dependency === topLevelTypes.topWheel) {
-          if (isEventSupported('wheel')) {
-            ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(topLevelTypes.topWheel, 'wheel', mountAt);
-          } else if (isEventSupported('mousewheel')) {
-            ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(topLevelTypes.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(topLevelTypes.topWheel, 'DOMMouseScroll', mountAt);
-          }
-        } else if (dependency === topLevelTypes.topScroll) {
-
-          if (isEventSupported('scroll', true)) {
-            ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(topLevelTypes.topScroll, 'scroll', mountAt);
-          } else {
-            ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(topLevelTypes.topScroll, 'scroll', ReactBrowserEventEmitter.ReactEventListener.WINDOW_HANDLE);
-          }
-        } else if (dependency === topLevelTypes.topFocus || dependency === topLevelTypes.topBlur) {
-
-          if (isEventSupported('focus', true)) {
-            ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(topLevelTypes.topFocus, 'focus', mountAt);
-            ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(topLevelTypes.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(topLevelTypes.topFocus, 'focusin', mountAt);
-            ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(topLevelTypes.topBlur, 'focusout', mountAt);
-          }
-
-          // to make sure blur and focus event listeners are only attached once
-          isListening[topLevelTypes.topBlur] = true;
-          isListening[topLevelTypes.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);
-  },
-
-  /**
-   * Listens to window scroll and resize events. We cache scroll values so that
-   * application code can access them without triggering reflows.
-   *
-   * NOTE: Scroll events do not bubble.
-   *
-   * @see http://www.quirksmode.org/dom/events/scroll.html
-   */
-  ensureScrollValueMonitoring: function () {
-    if (!isMonitoringScrollValue) {
-      var refresh = ViewportMetrics.refreshScrollValues;
-      ReactBrowserEventEmitter.ReactEventListener.monitorScrollValue(refresh);
-      isMonitoringScrollValue = true;
-    }
-  },
-
-  eventNameDispatchConfigs: EventPluginHub.eventNameDispatchConfigs,
-
-  registrationNameModules: EventPluginHub.registrationNameModules,
-
-  putListener: EventPluginHub.putListener,
-
-  getListener: EventPluginHub.getListener,
-
-  deleteListener: EventPluginHub.deleteListener,
-
-  deleteAllListeners: EventPluginHub.deleteAllListeners
-
-});
-
-ReactPerf.measureMethods(ReactBrowserEventEmitter, 'ReactBrowserEventEmitter', {
-  putListener: 'putListener',
-  deleteListener: 'deleteListener'
-});
-
-module.exports = ReactBrowserEventEmitter;
-},{"101":101,"119":119,"15":15,"16":16,"17":17,"23":23,"57":57,"71":71}],27:[function(_dereq_,module,exports){
-/**
- * Copyright 2014-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactChildReconciler
- * @typechecks static-only
- */
-
-'use strict';
-
-var ReactReconciler = _dereq_(76);
-
-var instantiateReactComponent = _dereq_(118);
-var shouldUpdateReactComponent = _dereq_(126);
-var traverseAllChildren = _dereq_(127);
-var warning = _dereq_(155);
-
-function instantiateChild(childInstances, child, name) {
-  // We found a component instance.
-  var keyUnique = childInstances[name] === undefined;
-  if ("development" !== 'production') {
-    "development" !== 'production' ? warning(keyUnique, '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.', name) : undefined;
-  }
-  if (child != null && keyUnique) {
-    childInstances[name] = instantiateReactComponent(child, null);
-  }
-}
-
-/**
- * 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) {
-    if (nestedChildNodes == null) {
-      return null;
-    }
-    var childInstances = {};
-    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, transaction, context) {
-    // 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 null;
-    }
-    var name;
-    for (name in nextChildren) {
-      if (!nextChildren.hasOwnProperty(name)) {
-        continue;
-      }
-      var 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) {
-          ReactReconciler.unmountComponent(prevChild, name);
-        }
-        // The child must be instantiated before it's mounted.
-        var nextChildInstance = instantiateReactComponent(nextElement, null);
-        nextChildren[name] = nextChildInstance;
-      }
-    }
-    // Unmount children that are no longer present.
-    for (name in prevChildren) {
-      if (prevChildren.hasOwnProperty(name) && !(nextChildren && nextChildren.hasOwnProperty(name))) {
-        ReactReconciler.unmountComponent(prevChildren[name]);
-      }
-    }
-    return nextChildren;
-  },
-
-  /**
-   * 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) {
-    for (var name in renderedChildren) {
-      if (renderedChildren.hasOwnProperty(name)) {
-        var renderedChild = renderedChildren[name];
-        ReactReconciler.unmountComponent(renderedChild);
-      }
-    }
-  }
-
-};
-
-module.exports = ReactChildReconciler;
-},{"118":118,"126":126,"127":127,"155":155,"76":76}],28:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactChildren
- */
-
-'use strict';
-
-var PooledClass = _dereq_(24);
-var ReactElement = _dereq_(52);
-
-var emptyFunction = _dereq_(136);
-var traverseAllChildren = _dereq_(127);
-
-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;
-  var context = bookKeeping.context;
-
-  func.call(context, child, bookKeeping.count++);
-}
-
-/**
- * Iterates through children that are typically specified as `props.children`.
- *
- * 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;
-  var keyPrefix = bookKeeping.keyPrefix;
-  var func = bookKeeping.func;
-  var 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 !== child ? 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`.
- *
- * 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`.
- *
- * @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.
- */
-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;
-},{"127":127,"136":136,"24":24,"52":52}],29:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactClass
- */
-
-'use strict';
-
-var ReactComponent = _dereq_(30);
-var ReactElement = _dereq_(52);
-var ReactPropTypeLocations = _dereq_(73);
-var ReactPropTypeLocationNames = _dereq_(72);
-var ReactNoopUpdateQueue = _dereq_(69);
-
-var assign = _dereq_(23);
-var emptyObject = _dereq_(137);
-var invariant = _dereq_(144);
-var keyMirror = _dereq_(147);
-var keyOf = _dereq_(148);
-var warning = _dereq_(155);
-
-var MIXINS_KEY = keyOf({ mixins: null });
-
-/**
- * Policies that describe methods in `ReactClassInterface`.
- */
-var SpecPolicy = keyMirror({
-  /**
-   * These methods may be defined only once by the class specification or mixin.
-   */
-  DEFINE_ONCE: null,
-  /**
-   * These methods may be defined by both the class specification and mixins.
-   * Subsequent definitions will be chained. These methods must return void.
-   */
-  DEFINE_MANY: null,
-  /**
-   * These methods are overriding the base class.
-   */
-  OVERRIDE_BASE: null,
-  /**
-   * These methods are similar to DEFINE_MANY, except we assume they return
-   * objects. We try to merge the keys of the return values of all the mixed in
-   * functions. If there is a key conflict we throw.
-   */
-  DEFINE_MANY_MERGED: null
-});
-
-var injectedMixins = [];
-
-var warnedSetProps = false;
-function warnSetProps() {
-  if (!warnedSetProps) {
-    warnedSetProps = true;
-    "development" !== 'production' ? warning(false, 'setProps(...) and replaceProps(...) are deprecated. ' + 'Instead, call render again at the top level.') : undefined;
-  }
-}
-
-/**
- * Composite components are higher-level components that compose other composite
- * or native 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: SpecPolicy.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: SpecPolicy.DEFINE_MANY,
-
-  /**
-   * Definition of prop types for this component.
-   *
-   * @type {object}
-   * @optional
-   */
-  propTypes: SpecPolicy.DEFINE_MANY,
-
-  /**
-   * Definition of context types for this component.
-   *
-   * @type {object}
-   * @optional
-   */
-  contextTypes: SpecPolicy.DEFINE_MANY,
-
-  /**
-   * Definition of context types this component sets for its children.
-   *
-   * @type {object}
-   * @optional
-   */
-  childContextTypes: SpecPolicy.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: SpecPolicy.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: SpecPolicy.DEFINE_MANY_MERGED,
-
-  /**
-   * @return {object}
-   * @optional
-   */
-  getChildContext: SpecPolicy.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}
-   * @nosideeffects
-   * @required
-   */
-  render: SpecPolicy.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: SpecPolicy.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: SpecPolicy.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: SpecPolicy.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: SpecPolicy.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: SpecPolicy.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: SpecPolicy.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: SpecPolicy.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: SpecPolicy.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 ("development" !== 'production') {
-      validateTypeDef(Constructor, childContextTypes, ReactPropTypeLocations.childContext);
-    }
-    Constructor.childContextTypes = assign({}, Constructor.childContextTypes, childContextTypes);
-  },
-  contextTypes: function (Constructor, contextTypes) {
-    if ("development" !== 'production') {
-      validateTypeDef(Constructor, contextTypes, ReactPropTypeLocations.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 ("development" !== 'production') {
-      validateTypeDef(Constructor, propTypes, ReactPropTypeLocations.prop);
-    }
-    Constructor.propTypes = assign({}, Constructor.propTypes, propTypes);
-  },
-  statics: function (Constructor, statics) {
-    mixStaticSpecIntoComponent(Constructor, statics);
-  },
-  autobind: function () {} };
-
-// noop
-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 not in __DEV__
-      "development" !== 'production' ? 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) : undefined;
-    }
-  }
-}
-
-function validateMethodOverride(proto, name) {
-  var specPolicy = ReactClassInterface.hasOwnProperty(name) ? ReactClassInterface[name] : null;
-
-  // Disallow overriding of base class methods unless explicitly allowed.
-  if (ReactClassMixin.hasOwnProperty(name)) {
-    !(specPolicy === SpecPolicy.OVERRIDE_BASE) ? "development" !== 'production' ? invariant(false, 'ReactClassInterface: You are attempting to override ' + '`%s` from your class specification. Ensure that your method names ' + 'do not overlap with React methods.', name) : invariant(false) : undefined;
-  }
-
-  // Disallow defining methods more than once unless explicitly allowed.
-  if (proto.hasOwnProperty(name)) {
-    !(specPolicy === SpecPolicy.DEFINE_MANY || specPolicy === SpecPolicy.DEFINE_MANY_MERGED) ? "development" !== 'production' ? invariant(false, 'ReactClassInterface: You are attempting to define ' + '`%s` on your component more than once. This conflict may be due ' + 'to a mixin.', name) : invariant(false) : undefined;
-  }
-}
-
-/**
- * Mixin helper which handles policy validation and reserved
- * specification keys when building React classses.
- */
-function mixSpecIntoComponent(Constructor, spec) {
-  if (!spec) {
-    return;
-  }
-
-  !(typeof spec !== 'function') ? "development" !== 'production' ? invariant(false, 'ReactClass: You\'re attempting to ' + 'use a component class as a mixin. Instead, just use a regular object.') : invariant(false) : undefined;
-  !!ReactElement.isValidElement(spec) ? "development" !== 'production' ? invariant(false, 'ReactClass: You\'re attempting to ' + 'use a component as a mixin. Instead, just use a regular object.') : invariant(false) : undefined;
-
-  var proto = Constructor.prototype;
-
-  // 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];
-    validateMethodOverride(proto, 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 isAlreadyDefined = proto.hasOwnProperty(name);
-      var isFunction = typeof property === 'function';
-      var shouldAutoBind = isFunction && !isReactClassMethod && !isAlreadyDefined && spec.autobind !== false;
-
-      if (shouldAutoBind) {
-        if (!proto.__reactAutoBindMap) {
-          proto.__reactAutoBindMap = {};
-        }
-        proto.__reactAutoBindMap[name] = property;
-        proto[name] = property;
-      } else {
-        if (isAlreadyDefined) {
-          var specPolicy = ReactClassInterface[name];
-
-          // These cases should already be caught by validateMethodOverride.
-          !(isReactClassMethod && (specPolicy === SpecPolicy.DEFINE_MANY_MERGED || specPolicy === SpecPolicy.DEFINE_MANY)) ? "development" !== 'production' ? invariant(false, 'ReactClass: Unexpected spec policy %s for key %s ' + 'when mixing in component specs.', specPolicy, name) : invariant(false) : undefined;
-
-          // For methods which are defined more than once, call the existing
-          // methods before calling the new property, merging if appropriate.
-          if (specPolicy === SpecPolicy.DEFINE_MANY_MERGED) {
-            proto[name] = createMergedResultFunction(proto[name], property);
-          } else if (specPolicy === SpecPolicy.DEFINE_MANY) {
-            proto[name] = createChainedFunction(proto[name], property);
-          }
-        } else {
-          proto[name] = property;
-          if ("development" !== 'production') {
-            // 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);
-    !!isReserved ? "development" !== 'production' ? invariant(false, '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) : invariant(false) : undefined;
-
-    var isInherited = (name in Constructor);
-    !!isInherited ? "development" !== 'production' ? invariant(false, 'ReactClass: You are attempting to define ' + '`%s` on your component more than once. This conflict may be ' + 'due to a mixin.', name) : invariant(false) : undefined;
-    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) {
-  !(one && two && typeof one === 'object' && typeof two === 'object') ? "development" !== 'production' ? invariant(false, 'mergeIntoWithNoDuplicateKeys(): Cannot merge non-objects.') : invariant(false) : undefined;
-
-  for (var key in two) {
-    if (two.hasOwnProperty(key)) {
-      !(one[key] === undefined) ? "development" !== 'production' ? invariant(false, '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) : invariant(false) : undefined;
-      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 ("development" !== 'production') {
-    boundMethod.__reactBoundContext = component;
-    boundMethod.__reactBoundMethod = method;
-    boundMethod.__reactBoundArguments = null;
-    var componentName = component.constructor.displayName;
-    var _bind = boundMethod.bind;
-    /* eslint-disable block-scoped-var, no-undef */
-    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) {
-        "development" !== 'production' ? warning(false, 'bind(): React component methods may only be bound to the ' + 'component instance. See %s', componentName) : undefined;
-      } else if (!args.length) {
-        "development" !== 'production' ? 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) : undefined;
-        return boundMethod;
-      }
-      var reboundMethod = _bind.apply(boundMethod, arguments);
-      reboundMethod.__reactBoundContext = component;
-      reboundMethod.__reactBoundMethod = method;
-      reboundMethod.__reactBoundArguments = args;
-      return reboundMethod;
-      /* eslint-enable */
-    };
-  }
-  return boundMethod;
-}
-
-/**
- * Binds all auto-bound methods in a component.
- *
- * @param {object} component Component whose method is going to be bound.
- */
-function bindAutoBindMethods(component) {
-  for (var autoBindKey in component.__reactAutoBindMap) {
-    if (component.__reactAutoBindMap.hasOwnProperty(autoBindKey)) {
-      var method = component.__reactAutoBindMap[autoBindKey];
-      component[autoBindKey] = bindAutoBindMethod(component, method);
-    }
-  }
-}
-
-/**
- * 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);
-    if (callback) {
-      this.updater.enqueueCallback(this, callback);
-    }
-  },
-
-  /**
-   * Checks whether or not this composite component is mounted.
-   * @return {boolean} True if mounted, false otherwise.
-   * @protected
-   * @final
-   */
-  isMounted: function () {
-    return this.updater.isMounted(this);
-  },
-
-  /**
-   * Sets a subset of the props.
-   *
-   * @param {object} partialProps Subset of the next props.
-   * @param {?function} callback Called after props are updated.
-   * @final
-   * @public
-   * @deprecated
-   */
-  setProps: function (partialProps, callback) {
-    if ("development" !== 'production') {
-      warnSetProps();
-    }
-    this.updater.enqueueSetProps(this, partialProps);
-    if (callback) {
-      this.updater.enqueueCallback(this, callback);
-    }
-  },
-
-  /**
-   * Replace all the props.
-   *
-   * @param {object} newProps Subset of the next props.
-   * @param {?function} callback Called after props are updated.
-   * @final
-   * @public
-   * @deprecated
-   */
-  replaceProps: function (newProps, callback) {
-    if ("development" !== 'production') {
-      warnSetProps();
-    }
-    this.updater.enqueueReplaceProps(this, newProps);
-    if (callback) {
-      this.updater.enqueueCallback(this, callback);
-    }
-  }
-};
-
-var ReactClassComponent = function () {};
-assign(ReactClassComponent.prototype, ReactComponent.prototype, ReactClassMixin);
-
-/**
- * Module for creating composite components.
- *
- * @class ReactClass
- */
-var ReactClass = {
-
-  /**
-   * Creates a composite component class given a class specification.
-   *
-   * @param {object} spec Class specification (which must define `render`).
-   * @return {function} Component constructor function.
-   * @public
-   */
-  createClass: function (spec) {
-    var Constructor = function (props, context, updater) {
-      // This constructor is overridden by mocks. The argument is used
-      // by mocks to assert on what gets mounted.
-
-      if ("development" !== 'production') {
-        "development" !== 'production' ? warning(this instanceof Constructor, 'Something is calling a React component directly. Use a factory or ' + 'JSX instead. See: https://fb.me/react-legacyfactory') : undefined;
-      }
-
-      // Wire up auto-binding
-      if (this.__reactAutoBindMap) {
-        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 ("development" !== 'production') {
-        // We allow auto-mocks to proceed as if they're returning null.
-        if (typeof initialState === 'undefined' && this.getInitialState._isMockFunction) {
-          // This is probably bad practice. Consider warning here and
-          // deprecating this convenience.
-          initialState = null;
-        }
-      }
-      !(typeof initialState === 'object' && !Array.isArray(initialState)) ? "development" !== 'production' ? invariant(false, '%s.getInitialState(): must return an object or null', Constructor.displayName || 'ReactCompositeComponent') : invariant(false) : undefined;
-
-      this.state = initialState;
-    };
-    Constructor.prototype = new ReactClassComponent();
-    Constructor.prototype.constructor = Constructor;
-
-    injectedMixins.forEach(mixSpecIntoComponent.bind(null, Constructor));
-
-    mixSpecIntoComponent(Constructor, spec);
-
-    // Initialize the defaultProps property after all mixins have been merged.
-    if (Constructor.getDefaultProps) {
-      Constructor.defaultProps = Constructor.getDefaultProps();
-    }
-
-    if ("development" !== 'production') {
-      // 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 = {};
-      }
-    }
-
-    !Constructor.prototype.render ? "development" !== 'production' ? invariant(false, 'createClass(...): Class specification must implement a `render` method.') : invariant(false) : undefined;
-
-    if ("development" !== 'production') {
-      "development" !== 'production' ? 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') : undefined;
-      "development" !== 'production' ? warning(!Constructor.prototype.componentWillRecieveProps, '%s has a method called ' + 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?', spec.displayName || 'A component') : undefined;
-    }
-
-    // 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;
-  },
-
-  injection: {
-    injectMixin: function (mixin) {
-      injectedMixins.push(mixin);
-    }
-  }
-
-};
-
-module.exports = ReactClass;
-},{"137":137,"144":144,"147":147,"148":148,"155":155,"23":23,"30":30,"52":52,"69":69,"72":72,"73":73}],30:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactComponent
- */
-
-'use strict';
-
-var ReactNoopUpdateQueue = _dereq_(69);
-
-var canDefineProperty = _dereq_(104);
-var emptyObject = _dereq_(137);
-var invariant = _dereq_(144);
-var warning = _dereq_(155);
-
-/**
- * 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) ? "development" !== 'production' ? invariant(false, 'setState(...): takes an object of state variables to update or a ' + 'function which returns an object of state variables.') : invariant(false) : undefined;
-  if ("development" !== 'production') {
-    "development" !== 'production' ? warning(partialState != null, 'setState(...): You passed an undefined or null state object; ' + 'instead, use forceUpdate().') : undefined;
-  }
-  this.updater.enqueueSetState(this, partialState);
-  if (callback) {
-    this.updater.enqueueCallback(this, 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 {?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);
-  }
-};
-
-/**
- * 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 ("development" !== 'production') {
-  var deprecatedAPIs = {
-    getDOMNode: ['getDOMNode', 'Use ReactDOM.findDOMNode(component) instead.'],
-    isMounted: ['isMounted', 'Instead, make sure to clean up subscriptions and pending requests in ' + 'componentWillUnmount to prevent memory leaks.'],
-    replaceProps: ['replaceProps', 'Instead, call render again at the top level.'],
-    replaceState: ['replaceState', 'Refactor your code to use setState instead (see ' + 'https://github.com/facebook/react/issues/3236).'],
-    setProps: ['setProps', 'Instead, call render again at the top level.']
-  };
-  var defineDeprecationWarning = function (methodName, info) {
-    if (canDefineProperty) {
-      Object.defineProperty(ReactComponent.prototype, methodName, {
-        get: function () {
-          "development" !== 'production' ? warning(false, '%s(...) is deprecated in plain JavaScript React classes. %s', info[0], info[1]) : undefined;
-          return undefined;
-        }
-      });
-    }
-  };
-  for (var fnName in deprecatedAPIs) {
-    if (deprecatedAPIs.hasOwnProperty(fnName)) {
-      defineDeprecationWarning(fnName, deprecatedAPIs[fnName]);
-    }
-  }
-}
-
-module.exports = ReactComponent;
-},{"104":104,"137":137,"144":144,"155":155,"69":69}],31:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactComponentBrowserEnvironment
- */
-
-'use strict';
-
-var ReactDOMIDOperations = _dereq_(40);
-var ReactMount = _dereq_(65);
-
-/**
- * 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,
-
-  replaceNodeWithMarkupByID: ReactDOMIDOperations.dangerouslyReplaceNodeWithMarkupByID,
-
-  /**
-   * If a particular environment requires that some resources be cleaned up,
-   * specify this in the injected Mixin. In the DOM, we would likely want to
-   * purge any cached node ID lookups.
-   *
-   * @private
-   */
-  unmountIDFromEnvironment: function (rootNodeID) {
-    ReactMount.purgeID(rootNodeID);
-  }
-
-};
-
-module.exports = ReactComponentBrowserEnvironment;
-},{"40":40,"65":65}],32:[function(_dereq_,module,exports){
-/**
- * Copyright 2014-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactComponentEnvironment
- */
-
-'use strict';
-
-var invariant = _dereq_(144);
-
-var injected = false;
-
-var ReactComponentEnvironment = {
-
-  /**
-   * Optionally injectable environment dependent cleanup hook. (server vs.
-   * browser etc). Example: A browser system caches DOM nodes based on component
-   * ID and must remove that cache entry when this instance is unmounted.
-   */
-  unmountIDFromEnvironment: null,
-
-  /**
-   * Optionally injectable hook for swapping out mount images in the middle of
-   * the tree.
-   */
-  replaceNodeWithMarkupByID: null,
-
-  /**
-   * Optionally injectable hook for processing a queue of child updates. Will
-   * later move into MultiChildComponents.
-   */
-  processChildrenUpdates: null,
-
-  injection: {
-    injectEnvironment: function (environment) {
-      !!injected ? "development" !== 'production' ? invariant(false, 'ReactCompositeComponent: injectEnvironment() can only be called once.') : invariant(false) : undefined;
-      ReactComponentEnvironment.unmountIDFromEnvironment = environment.unmountIDFromEnvironment;
-      ReactComponentEnvironment.replaceNodeWithMarkupByID = environment.replaceNodeWithMarkupByID;
-      ReactComponentEnvironment.processChildrenUpdates = environment.processChildrenUpdates;
-      injected = true;
-    }
-  }
-
-};
-
-module.exports = ReactComponentEnvironment;
-},{"144":144}],33:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactCompositeComponent
- */
-
-'use strict';
-
-var ReactComponentEnvironment = _dereq_(32);
-var ReactCurrentOwner = _dereq_(34);
-var ReactElement = _dereq_(52);
-var ReactInstanceMap = _dereq_(62);
-var ReactPerf = _dereq_(71);
-var ReactPropTypeLocations = _dereq_(73);
-var ReactPropTypeLocationNames = _dereq_(72);
-var ReactReconciler = _dereq_(76);
-var ReactUpdateQueue = _dereq_(82);
-
-var assign = _dereq_(23);
-var emptyObject = _dereq_(137);
-var invariant = _dereq_(144);
-var shouldUpdateReactComponent = _dereq_(126);
-var warning = _dereq_(155);
-
-function getDeclarationErrorAddendum(component) {
-  var owner = component._currentElement._owner || null;
-  if (owner) {
-    var name = owner.getName();
-    if (name) {
-      return ' Check the render method of `' + name + '`.';
-    }
-  }
-  return '';
-}
-
-function StatelessComponent(Component) {}
-StatelessComponent.prototype.render = function () {
-  var Component = ReactInstanceMap.get(this)._currentElement.type;
-  return Component(this.props, this.context, this.updater);
-};
-
-/**
- * ------------------ 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 ReactCompositeComponentMixin = {
-
-  /**
-   * Base constructor for all composite component.
-   *
-   * @param {ReactElement} element
-   * @final
-   * @internal
-   */
-  construct: function (element) {
-    this._currentElement = element;
-    this._rootNodeID = null;
-    this._instance = null;
-
-    // See ReactUpdateQueue
-    this._pendingElement = null;
-    this._pendingStateQueue = null;
-    this._pendingReplaceState = false;
-    this._pendingForceUpdate = false;
-
-    this._renderedComponent = null;
-
-    this._context = null;
-    this._mountOrder = 0;
-    this._topLevelWrapper = null;
-
-    // See ReactUpdates and ReactUpdateQueue.
-    this._pendingCallbacks = null;
-  },
-
-  /**
-   * Initializes the component, renders markup, and registers event listeners.
-   *
-   * @param {string} rootID DOM ID of the root node.
-   * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
-   * @return {?string} Rendered markup to be inserted into the DOM.
-   * @final
-   * @internal
-   */
-  mountComponent: function (rootID, transaction, context) {
-    this._context = context;
-    this._mountOrder = nextMountID++;
-    this._rootNodeID = rootID;
-
-    var publicProps = this._processProps(this._currentElement.props);
-    var publicContext = this._processContext(context);
-
-    var Component = this._currentElement.type;
-
-    // Initialize the public class
-    var inst;
-    var renderedElement;
-
-    // This is a way to detect if Component is a stateless arrow function
-    // component, which is not newable. It might not be 100% reliable but is
-    // something we can do until we start detecting that Component extends
-    // React.Component. We already assume that typeof Component === 'function'.
-    var canInstantiate = ('prototype' in Component);
-
-    if (canInstantiate) {
-      if ("development" !== 'production') {
-        ReactCurrentOwner.current = this;
-        try {
-          inst = new Component(publicProps, publicContext, ReactUpdateQueue);
-        } finally {
-          ReactCurrentOwner.current = null;
-        }
-      } else {
-        inst = new Component(publicProps, publicContext, ReactUpdateQueue);
-      }
-    }
-
-    if (!canInstantiate || inst === null || inst === false || ReactElement.isValidElement(inst)) {
-      renderedElement = inst;
-      inst = new StatelessComponent(Component);
-    }
-
-    if ("development" !== 'production') {
-      // This will throw later in _renderValidatedComponent, but add an early
-      // warning now to help debugging
-      if (inst.render == null) {
-        "development" !== 'production' ? warning(false, '%s(...): No `render` method found on the returned component ' + 'instance: you may have forgotten to define `render`, returned ' + 'null/false from a stateless component, or tried to render an ' + 'element whose type is a function that isn\'t a React component.', Component.displayName || Component.name || 'Component') : undefined;
-      } else {
-        // We support ES6 inheriting from React.Component, the module pattern,
-        // and stateless components, but not ES6 classes that don't extend
-        "development" !== 'production' ? warning(Component.prototype && Component.prototype.isReactComponent || !canInstantiate || !(inst instanceof Component), '%s(...): React component classes must extend React.Component.', Component.displayName || Component.name || 'Component') : undefined;
-      }
-    }
-
-    // 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 = ReactUpdateQueue;
-
-    this._instance = inst;
-
-    // Store a reference from the instance back to the internal representation
-    ReactInstanceMap.set(inst, this);
-
-    if ("development" !== 'production') {
-      // 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.
-      "development" !== 'production' ? warning(!inst.getInitialState || inst.getInitialState.isReactClassApproved, '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') : undefined;
-      "development" !== 'production' ? 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') : undefined;
-      "development" !== 'production' ? warning(!inst.propTypes, 'propTypes was defined as an instance property on %s. Use a static ' + 'property to define propTypes instead.', this.getName() || 'a component') : undefined;
-      "development" !== 'production' ? warning(!inst.contextTypes, 'contextTypes was defined as an instance property on %s. Use a ' + 'static property to define contextTypes instead.', this.getName() || 'a component') : undefined;
-      "development" !== 'production' ? 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') : undefined;
-      "development" !== 'production' ? 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') : undefined;
-      "development" !== 'production' ? warning(typeof inst.componentWillRecieveProps !== 'function', '%s has a method called ' + 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?', this.getName() || 'A component') : undefined;
-    }
-
-    var initialState = inst.state;
-    if (initialState === undefined) {
-      inst.state = initialState = null;
-    }
-    !(typeof initialState === 'object' && !Array.isArray(initialState)) ? "development" !== 'production' ? invariant(false, '%s.state: must be set to an object or null', this.getName() || 'ReactCompositeComponent') : invariant(false) : undefined;
-
-    this._pendingStateQueue = null;
-    this._pendingReplaceState = false;
-    this._pendingForceUpdate = false;
-
-    if (inst.componentWillMount) {
-      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();
-    }
-
-    this._renderedComponent = this._instantiateReactComponent(renderedElement);
-
-    var markup = ReactReconciler.mountComponent(this._renderedComponent, rootID, transaction, this._processChildContext(context));
-    if (inst.componentDidMount) {
-      transaction.getReactMountReady().enqueue(inst.componentDidMount, inst);
-    }
-
-    return markup;
-  },
-
-  /**
-   * Releases any resources allocated by `mountComponent`.
-   *
-   * @final
-   * @internal
-   */
-  unmountComponent: function () {
-    var inst = this._instance;
-
-    if (inst.componentWillUnmount) {
-      inst.componentWillUnmount();
-    }
-
-    ReactReconciler.unmountComponent(this._renderedComponent);
-    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 = null;
-    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 maskedContext = null;
-    var Component = this._currentElement.type;
-    var contextTypes = Component.contextTypes;
-    if (!contextTypes) {
-      return emptyObject;
-    }
-    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 ("development" !== 'production') {
-      var Component = this._currentElement.type;
-      if (Component.contextTypes) {
-        this._checkPropTypes(Component.contextTypes, maskedContext, ReactPropTypeLocations.context);
-      }
-    }
-    return maskedContext;
-  },
-
-  /**
-   * @param {object} currentContext
-   * @return {object}
-   * @private
-   */
-  _processChildContext: function (currentContext) {
-    var Component = this._currentElement.type;
-    var inst = this._instance;
-    var childContext = inst.getChildContext && inst.getChildContext();
-    if (childContext) {
-      !(typeof Component.childContextTypes === 'object') ? "development" !== 'production' ? invariant(false, '%s.getChildContext(): childContextTypes must be defined in order to ' + 'use getChildContext().', this.getName() || 'ReactCompositeComponent') : invariant(false) : undefined;
-      if ("development" !== 'production') {
-        this._checkPropTypes(Component.childContextTypes, childContext, ReactPropTypeLocations.childContext);
-      }
-      for (var name in childContext) {
-        !(name in Component.childContextTypes) ? "development" !== 'production' ? invariant(false, '%s.getChildContext(): key "%s" is not defined in childContextTypes.', this.getName() || 'ReactCompositeComponent', name) : invariant(false) : undefined;
-      }
-      return assign({}, currentContext, childContext);
-    }
-    return currentContext;
-  },
-
-  /**
-   * Processes props by setting default values for unspecified props and
-   * asserting that the props are valid. Does not mutate its argument; returns
-   * a new props object with defaults merged in.
-   *
-   * @param {object} newProps
-   * @return {object}
-   * @private
-   */
-  _processProps: function (newProps) {
-    if ("development" !== 'production') {
-      var Component = this._currentElement.type;
-      if (Component.propTypes) {
-        this._checkPropTypes(Component.propTypes, newProps, ReactPropTypeLocations.prop);
-      }
-    }
-    return newProps;
-  },
-
-  /**
-   * Assert that the props are valid
-   *
-   * @param {object} propTypes Map of prop name to a ReactPropType
-   * @param {object} props
-   * @param {string} location e.g. "prop", "context", "child context"
-   * @private
-   */
-  _checkPropTypes: function (propTypes, props, location) {
-    // TODO: Stop validating prop types here and only use the element
-    // validation.
-    var componentName = this.getName();
-    for (var propName in propTypes) {
-      if (propTypes.hasOwnProperty(propName)) {
-        var error;
-        try {
-          // This is intentionally an invariant that gets caught. It's the same
-          // behavior as without this statement except with a better message.
-          !(typeof propTypes[propName] === 'function') ? "development" !== 'production' ? invariant(false, '%s: %s type `%s` is invalid; it must be a function, usually ' + 'from React.PropTypes.', componentName || 'React class', ReactPropTypeLocationNames[location], propName) : invariant(false) : undefined;
-          error = propTypes[propName](props, propName, componentName, location);
-        } catch (ex) {
-          error = ex;
-        }
-        if (error instanceof Error) {
-          // We may want to extend this logic for similar errors in
-          // top-level render calls, so I'm abstracting it away into
-          // a function to minimize refactoring in the future
-          var addendum = getDeclarationErrorAddendum(this);
-
-          if (location === ReactPropTypeLocations.prop) {
-            // Preface gives us something to blacklist in warning module
-            "development" !== 'production' ? warning(false, 'Failed Composite propType: %s%s', error.message, addendum) : undefined;
-          } else {
-            "development" !== 'production' ? warning(false, 'Failed Context Types: %s%s', error.message, addendum) : undefined;
-          }
-        }
-      }
-    }
-  },
-
-  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 || this._currentElement, transaction, this._context);
-    }
-
-    if (this._pendingStateQueue !== null || this._pendingForceUpdate) {
-      this.updateComponent(transaction, this._currentElement, this._currentElement, this._context, this._context);
-    }
-  },
-
-  /**
-   * 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;
-
-    var nextContext = this._context === nextUnmaskedContext ? inst.context : this._processContext(nextUnmaskedContext);
-    var nextProps;
-
-    // Distinguish between a props update versus a simple state update
-    if (prevParentElement === nextParentElement) {
-      // Skip checking prop types again -- we don't read inst.props to avoid
-      // warning for DOM component props in this upgrade
-      nextProps = nextParentElement.props;
-    } else {
-      nextProps = this._processProps(nextParentElement.props);
-      // 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 (inst.componentWillReceiveProps) {
-        inst.componentWillReceiveProps(nextProps, nextContext);
-      }
-    }
-
-    var nextState = this._processPendingState(nextProps, nextContext);
-
-    var shouldUpdate = this._pendingForceUpdate || !inst.shouldComponentUpdate || inst.shouldComponentUpdate(nextProps, nextState, nextContext);
-
-    if ("development" !== 'production') {
-      "development" !== 'production' ? warning(typeof shouldUpdate !== 'undefined', '%s.shouldComponentUpdate(): Returned undefined instead of a ' + 'boolean value. Make sure to return true or false.', this.getName() || 'ReactCompositeComponent') : undefined;
-    }
-
-    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 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) {
-      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) {
-      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();
-    if (shouldUpdateReactComponent(prevRenderedElement, nextRenderedElement)) {
-      ReactReconciler.receiveComponent(prevComponentInstance, nextRenderedElement, transaction, this._processChildContext(context));
-    } else {
-      // These two IDs are actually the same! But nothing should rely on that.
-      var thisID = this._rootNodeID;
-      var prevComponentID = prevComponentInstance._rootNodeID;
-      ReactReconciler.unmountComponent(prevComponentInstance);
-
-      this._renderedComponent = this._instantiateReactComponent(nextRenderedElement);
-      var nextMarkup = ReactReconciler.mountComponent(this._renderedComponent, thisID, transaction, this._processChildContext(context));
-      this._replaceNodeWithMarkupByID(prevComponentID, nextMarkup);
-    }
-  },
-
-  /**
-   * @protected
-   */
-  _replaceNodeWithMarkupByID: function (prevComponentID, nextMarkup) {
-    ReactComponentEnvironment.replaceNodeWithMarkupByID(prevComponentID, nextMarkup);
-  },
-
-  /**
-   * @protected
-   */
-  _renderValidatedComponentWithoutOwnerOrContext: function () {
-    var inst = this._instance;
-    var renderedComponent = inst.render();
-    if ("development" !== 'production') {
-      // We allow auto-mocks to proceed as if they're returning null.
-      if (typeof renderedComponent === 'undefined' && inst.render._isMockFunction) {
-        // This is probably bad practice. Consider warning here and
-        // deprecating this convenience.
-        renderedComponent = null;
-      }
-    }
-
-    return renderedComponent;
-  },
-
-  /**
-   * @private
-   */
-  _renderValidatedComponent: function () {
-    var renderedComponent;
-    ReactCurrentOwner.current = this;
-    try {
-      renderedComponent = this._renderValidatedComponentWithoutOwnerOrContext();
-    } finally {
-      ReactCurrentOwner.current = null;
-    }
-    !(
-    // TODO: An `isValidNode` function would probably be more appropriate
-    renderedComponent === null || renderedComponent === false || ReactElement.isValidElement(renderedComponent)) ? "development" !== 'production' ? invariant(false, '%s.render(): A valid ReactComponent must be returned. You may have ' + 'returned undefined, an array or some other invalid object.', this.getName() || 'ReactCompositeComponent') : invariant(false) : undefined;
-    return renderedComponent;
-  },
-
-  /**
-   * 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) ? "development" !== 'production' ? invariant(false, 'Stateless function components cannot have refs.') : invariant(false) : undefined;
-    var publicComponentInstance = component.getPublicInstance();
-    if ("development" !== 'production') {
-      var componentName = component && component.getName ? component.getName() : 'a component';
-      "development" !== 'production' ? warning(publicComponentInstance != null, '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()) : undefined;
-    }
-    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 (inst instanceof StatelessComponent) {
-      return null;
-    }
-    return inst;
-  },
-
-  // Stub
-  _instantiateReactComponent: null
-
-};
-
-ReactPerf.measureMethods(ReactCompositeComponentMixin, 'ReactCompositeComponent', {
-  mountComponent: 'mountComponent',
-  updateComponent: 'updateComponent',
-  _renderValidatedComponent: '_renderValidatedComponent'
-});
-
-var ReactCompositeComponent = {
-
-  Mixin: ReactCompositeComponentMixin
-
-};
-
-module.exports = ReactCompositeComponent;
-},{"126":126,"137":137,"144":144,"155":155,"23":23,"32":32,"34":34,"52":52,"62":62,"71":71,"72":72,"73":73,"76":76,"82":82}],34:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactCurrentOwner
- */
-
-'use strict';
-
-/**
- * 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;
-},{}],35:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDOM
- */
-
-/* globals __REACT_DEVTOOLS_GLOBAL_HOOK__*/
-
-'use strict';
-
-var ReactCurrentOwner = _dereq_(34);
-var ReactDOMTextComponent = _dereq_(46);
-var ReactDefaultInjection = _dereq_(49);
-var ReactInstanceHandles = _dereq_(61);
-var ReactMount = _dereq_(65);
-var ReactPerf = _dereq_(71);
-var ReactReconciler = _dereq_(76);
-var ReactUpdates = _dereq_(83);
-var ReactVersion = _dereq_(84);
-
-var findDOMNode = _dereq_(108);
-var renderSubtreeIntoContainer = _dereq_(123);
-var warning = _dereq_(155);
-
-ReactDefaultInjection.inject();
-
-var render = ReactPerf.measure('React', 'render', ReactMount.render);
-
-var React = {
-  findDOMNode: findDOMNode,
-  render: render,
-  unmountComponentAtNode: ReactMount.unmountComponentAtNode,
-  version: ReactVersion,
-
-  /* eslint-disable camelcase */
-  unstable_batchedUpdates: ReactUpdates.batchedUpdates,
-  unstable_renderSubtreeIntoContainer: renderSubtreeIntoContainer
-};
-
-// Inject the runtime into a devtools global hook regardless of browser.
-// Allows for debugging when the hook is injected on the page.
-/* eslint-enable camelcase */
-if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' && typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.inject === 'function') {
-  __REACT_DEVTOOLS_GLOBAL_HOOK__.inject({
-    CurrentOwner: ReactCurrentOwner,
-    InstanceHandles: ReactInstanceHandles,
-    Mount: ReactMount,
-    Reconciler: ReactReconciler,
-    TextComponent: ReactDOMTextComponent
-  });
-}
-
-if ("development" !== 'production') {
-  var ExecutionEnvironment = _dereq_(130);
-  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) {
-        console.debug('Download the React DevTools for a better development experience: ' + 'https://fb.me/react-devtools');
-      }
-    }
-
-    // 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;
-
-    "development" !== 'production' ? 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" />') : undefined;
-
-    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.split, String.prototype.trim,
-
-    // shams
-    Object.create, Object.freeze];
-
-    for (var i = 0; i < expectedFeatures.length; i++) {
-      if (!expectedFeatures[i]) {
-        console.error('One or more ES5 shim/shams expected by React are not available: ' + 'https://fb.me/react-warning-polyfills');
-        break;
-      }
-    }
-  }
-}
-
-module.exports = React;
-},{"108":108,"123":123,"130":130,"155":155,"34":34,"46":46,"49":49,"61":61,"65":65,"71":71,"76":76,"83":83,"84":84}],36:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDOMButton
- */
-
-'use strict';
-
-var mouseListenerNames = {
-  onClick: true,
-  onDoubleClick: true,
-  onMouseDown: true,
-  onMouseMove: true,
-  onMouseUp: true,
-
-  onClickCapture: true,
-  onDoubleClickCapture: true,
-  onMouseDownCapture: true,
-  onMouseMoveCapture: true,
-  onMouseUpCapture: true
-};
-
-/**
- * Implements a <button> native component that does not receive mouse events
- * when `disabled` is set.
- */
-var ReactDOMButton = {
-  getNativeProps: function (inst, props, context) {
-    if (!props.disabled) {
-      return props;
-    }
-
-    // Copy the props, except the mouse listeners
-    var nativeProps = {};
-    for (var key in props) {
-      if (props.hasOwnProperty(key) && !mouseListenerNames[key]) {
-        nativeProps[key] = props[key];
-      }
-    }
-
-    return nativeProps;
-  }
-};
-
-module.exports = ReactDOMButton;
-},{}],37:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDOMComponent
- * @typechecks static-only
- */
-
-/* global hasOwnProperty:true */
-
-'use strict';
-
-var AutoFocusUtils = _dereq_(2);
-var CSSPropertyOperations = _dereq_(5);
-var DOMProperty = _dereq_(10);
-var DOMPropertyOperations = _dereq_(11);
-var EventConstants = _dereq_(15);
-var ReactBrowserEventEmitter = _dereq_(26);
-var ReactComponentBrowserEnvironment = _dereq_(31);
-var ReactDOMButton = _dereq_(36);
-var ReactDOMInput = _dereq_(41);
-var ReactDOMOption = _dereq_(42);
-var ReactDOMSelect = _dereq_(43);
-var ReactDOMTextarea = _dereq_(47);
-var ReactMount = _dereq_(65);
-var ReactMultiChild = _dereq_(66);
-var ReactPerf = _dereq_(71);
-var ReactUpdateQueue = _dereq_(82);
-
-var assign = _dereq_(23);
-var canDefineProperty = _dereq_(104);
-var escapeTextContentForBrowser = _dereq_(107);
-var invariant = _dereq_(144);
-var isEventSupported = _dereq_(119);
-var keyOf = _dereq_(148);
-var setInnerHTML = _dereq_(124);
-var setTextContent = _dereq_(125);
-var shallowEqual = _dereq_(153);
-var validateDOMNesting = _dereq_(128);
-var warning = _dereq_(155);
-
-var deleteListener = ReactBrowserEventEmitter.deleteListener;
-var listenTo = ReactBrowserEventEmitter.listenTo;
-var registrationNameModules = ReactBrowserEventEmitter.registrationNameModules;
-
-// For quickly matching children type, to test if can be treated as content.
-var CONTENT_TYPES = { 'string': true, 'number': true };
-
-var CHILDREN = keyOf({ children: null });
-var STYLE = keyOf({ style: null });
-var HTML = keyOf({ __html: null });
-
-var ELEMENT_NODE_TYPE = 1;
-
-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 '';
-}
-
-var legacyPropsDescriptor;
-if ("development" !== 'production') {
-  legacyPropsDescriptor = {
-    props: {
-      enumerable: false,
-      get: function () {
-        var component = this._reactInternalComponent;
-        "development" !== 'production' ? warning(false, 'ReactDOMComponent: Do not access .props of a DOM node; instead, ' + 'recreate the props as `render` did originally or read the DOM ' + 'properties/attributes directly from this node (e.g., ' + 'this.refs.box.className).%s', getDeclarationErrorAddendum(component)) : undefined;
-        return component._currentElement.props;
-      }
-    }
-  };
-}
-
-function legacyGetDOMNode() {
-  if ("development" !== 'production') {
-    var component = this._reactInternalComponent;
-    "development" !== 'production' ? warning(false, 'ReactDOMComponent: Do not access .getDOMNode() of a DOM node; ' + 'instead, use the node directly.%s', getDeclarationErrorAddendum(component)) : undefined;
-  }
-  return this;
-}
-
-function legacyIsMounted() {
-  var component = this._reactInternalComponent;
-  if ("development" !== 'production') {
-    "development" !== 'production' ? warning(false, 'ReactDOMComponent: Do not access .isMounted() of a DOM node.%s', getDeclarationErrorAddendum(component)) : undefined;
-  }
-  return !!component;
-}
-
-function legacySetStateEtc() {
-  if ("development" !== 'production') {
-    var component = this._reactInternalComponent;
-    "development" !== 'production' ? warning(false, 'ReactDOMComponent: Do not access .setState(), .replaceState(), or ' + '.forceUpdate() of a DOM node. This is a no-op.%s', getDeclarationErrorAddendum(component)) : undefined;
-  }
-}
-
-function legacySetProps(partialProps, callback) {
-  var component = this._reactInternalComponent;
-  if ("development" !== 'production') {
-    "development" !== 'production' ? warning(false, 'ReactDOMComponent: Do not access .setProps() of a DOM node. ' + 'Instead, call ReactDOM.render again at the top level.%s', getDeclarationErrorAddendum(component)) : undefined;
-  }
-  if (!component) {
-    return;
-  }
-  ReactUpdateQueue.enqueueSetPropsInternal(component, partialProps);
-  if (callback) {
-    ReactUpdateQueue.enqueueCallbackInternal(component, callback);
-  }
-}
-
-function legacyReplaceProps(partialProps, callback) {
-  var component = this._reactInternalComponent;
-  if ("development" !== 'production') {
-    "development" !== 'production' ? warning(false, 'ReactDOMComponent: Do not access .replaceProps() of a DOM node. ' + 'Instead, call ReactDOM.render again at the top level.%s', getDeclarationErrorAddendum(component)) : undefined;
-  }
-  if (!component) {
-    return;
-  }
-  ReactUpdateQueue.enqueueReplacePropsInternal(component, partialProps);
-  if (callback) {
-    ReactUpdateQueue.enqueueCallbackInternal(component, callback);
-  }
-}
-
-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 becauses 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;
-
-  "development" !== '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)) : undefined;
-}
-
-/**
- * @param {object} component
- * @param {?object} props
- */
-function assertValidProps(component, props) {
-  if (!props) {
-    return;
-  }
-  // Note the use of `==` which checks for null or undefined.
-  if ("development" !== 'production') {
-    if (voidElementTags[component._tag]) {
-      "development" !== 'production' ? warning(props.children == null && props.dangerouslySetInnerHTML == null, '%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() + '.' : '') : undefined;
-    }
-  }
-  if (props.dangerouslySetInnerHTML != null) {
-    !(props.children == null) ? "development" !== 'production' ? invariant(false, 'Can only set one of `children` or `props.dangerouslySetInnerHTML`.') : invariant(false) : undefined;
-    !(typeof props.dangerouslySetInnerHTML === 'object' && HTML in props.dangerouslySetInnerHTML) ? "development" !== '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) : undefined;
-  }
-  if ("development" !== 'production') {
-    "development" !== 'production' ? warning(props.innerHTML == null, 'Directly setting property `innerHTML` is not permitted. ' + 'For more information, lookup documentation on `dangerouslySetInnerHTML`.') : undefined;
-    "development" !== 'production' ? warning(!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.') : undefined;
-  }
-  !(props.style == null || typeof props.style === 'object') ? "development" !== '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) : undefined;
-}
-
-function enqueuePutListener(id, registrationName, listener, transaction) {
-  if ("development" !== 'production') {
-    // IE8 has no API for event capturing and the `onScroll` event doesn't
-    // bubble.
-    "development" !== 'production' ? warning(registrationName !== 'onScroll' || isEventSupported('scroll', true), 'This browser doesn\'t support the `onScroll` event') : undefined;
-  }
-  var container = ReactMount.findReactContainerForID(id);
-  if (container) {
-    var doc = container.nodeType === ELEMENT_NODE_TYPE ? container.ownerDocument : container;
-    listenTo(registrationName, doc);
-  }
-  transaction.getReactMountReady().enqueue(putListener, {
-    id: id,
-    registrationName: registrationName,
-    listener: listener
-  });
-}
-
-function putListener() {
-  var listenerToPut = this;
-  ReactBrowserEventEmitter.putListener(listenerToPut.id, listenerToPut.registrationName, listenerToPut.listener);
-}
-
-// 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 ? "development" !== 'production' ? invariant(false, 'Must be mounted to trap events') : invariant(false) : undefined;
-  var node = ReactMount.getNode(inst._rootNodeID);
-  !node ? "development" !== 'production' ? invariant(false, 'trapBubbledEvent(...): Requires node to be rendered.') : invariant(false) : undefined;
-
-  switch (inst._tag) {
-    case 'iframe':
-      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;
-  }
-}
-
-function mountReadyInputWrapper() {
-  ReactDOMInput.mountReadyWrapper(this);
-}
-
-function postUpdateSelectWrapper() {
-  ReactDOMSelect.postUpdateWrapper(this);
-}
-
-// For HTML, certain tags should omit their close tag. We keep a whitelist for
-// those special cased 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) ? "development" !== 'production' ? invariant(false, 'Invalid tag: %s', tag) : invariant(false) : undefined;
-    validatedTagCache[tag] = true;
-  }
-}
-
-function processChildContextDev(context, inst) {
-  // Pass down our tag name to child components for validation purposes
-  context = assign({}, context);
-  var info = context[validateDOMNesting.ancestorInfoContextKey];
-  context[validateDOMNesting.ancestorInfoContextKey] = validateDOMNesting.updatedAncestorInfo(info, inst._tag, inst);
-  return context;
-}
-
-function isCustomComponent(tagName, props) {
-  return tagName.indexOf('-') >= 0 || props.is != null;
-}
-
-/**
- * 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(tag) {
-  validateDangerousTag(tag);
-  this._tag = tag.toLowerCase();
-  this._renderedChildren = null;
-  this._previousStyle = null;
-  this._previousStyleCopy = null;
-  this._rootNodeID = null;
-  this._wrapperState = null;
-  this._topLevelWrapper = null;
-  this._nodeWithLegacyProperties = null;
-  if ("development" !== 'production') {
-    this._unprocessedContextDev = null;
-    this._processedContextDev = null;
-  }
-}
-
-ReactDOMComponent.displayName = 'ReactDOMComponent';
-
-ReactDOMComponent.Mixin = {
-
-  construct: function (element) {
-    this._currentElement = element;
-  },
-
-  /**
-   * Generates root tag markup then recurses. This method has side effects and
-   * is not idempotent.
-   *
-   * @internal
-   * @param {string} rootID The root DOM ID for this node.
-   * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
-   * @param {object} context
-   * @return {string} The computed markup.
-   */
-  mountComponent: function (rootID, transaction, context) {
-    this._rootNodeID = rootID;
-
-    var props = this._currentElement.props;
-
-    switch (this._tag) {
-      case 'iframe':
-      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, context);
-        break;
-      case 'input':
-        ReactDOMInput.mountWrapper(this, props, context);
-        props = ReactDOMInput.getNativeProps(this, props, context);
-        break;
-      case 'option':
-        ReactDOMOption.mountWrapper(this, props, context);
-        props = ReactDOMOption.getNativeProps(this, props, context);
-        break;
-      case 'select':
-        ReactDOMSelect.mountWrapper(this, props, context);
-        props = ReactDOMSelect.getNativeProps(this, props, context);
-        context = ReactDOMSelect.processChildContext(this, props, context);
-        break;
-      case 'textarea':
-        ReactDOMTextarea.mountWrapper(this, props, context);
-        props = ReactDOMTextarea.getNativeProps(this, props, context);
-        break;
-    }
-
-    assertValidProps(this, props);
-    if ("development" !== 'production') {
-      if (context[validateDOMNesting.ancestorInfoContextKey]) {
-        validateDOMNesting(this._tag, this, context[validateDOMNesting.ancestorInfoContextKey]);
-      }
-    }
-
-    if ("development" !== 'production') {
-      this._unprocessedContextDev = context;
-      this._processedContextDev = processChildContextDev(context, this);
-      context = this._processedContextDev;
-    }
-
-    var mountImage;
-    if (transaction.useCreateElement) {
-      var ownerDocument = context[ReactMount.ownerDocumentContextKey];
-      var el = ownerDocument.createElement(this._currentElement.type);
-      DOMPropertyOperations.setAttributeForID(el, this._rootNodeID);
-      // Populate node cache
-      ReactMount.getID(el);
-      this._updateDOMProperties({}, props, transaction, el);
-      this._createInitialChildren(transaction, props, context, el);
-      mountImage = el;
-    } 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(mountReadyInputWrapper, this);
-      // falls through
-      case 'button':
-      case 'select':
-      case 'textarea':
-        if (props.autoFocus) {
-          transaction.getReactMountReady().enqueue(AutoFocusUtils.focusDOMComponent, 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._rootNodeID, propKey, propValue, transaction);
-        }
-      } else {
-        if (propKey === STYLE) {
-          if (propValue) {
-            if ("development" !== 'production') {
-              // See `_updateDOMProperties`. style block
-              this._previousStyle = propValue;
-            }
-            propValue = this._previousStyleCopy = assign({}, props.style);
-          }
-          propValue = CSSPropertyOperations.createMarkupForStyles(propValue);
-        }
-        var markup = null;
-        if (this._tag != null && isCustomComponent(this._tag, props)) {
-          if (propKey !== CHILDREN) {
-            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;
-    }
-
-    var markupForID = DOMPropertyOperations.createMarkupForID(this._rootNodeID);
-    return ret + ' ' + markupForID;
-  },
-
-  /**
-   * 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);
-      } 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, el) {
-    // Intentional use of != to avoid catching zero/false.
-    var innerHTML = props.dangerouslySetInnerHTML;
-    if (innerHTML != null) {
-      if (innerHTML.__html != null) {
-        setInnerHTML(el, 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
-        setTextContent(el, contentToUse);
-      } else if (childrenToUse != null) {
-        var mountImages = this.mountChildren(childrenToUse, transaction, context);
-        for (var i = 0; i < mountImages.length; i++) {
-          el.appendChild(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;
-    }
-
-    if ("development" !== 'production') {
-      // If the context is reference-equal to the old one, pass down the same
-      // processed object so the update bailout in ReactReconciler behaves
-      // correctly (and identically in dev and prod). See #5005.
-      if (this._unprocessedContextDev !== context) {
-        this._unprocessedContextDev = context;
-        this._processedContextDev = processChildContextDev(context, this);
-      }
-      context = this._processedContextDev;
-    }
-
-    assertValidProps(this, nextProps);
-    this._updateDOMProperties(lastProps, nextProps, transaction, null);
-    this._updateDOMChildren(lastProps, nextProps, transaction, context);
-
-    if (!canDefineProperty && this._nodeWithLegacyProperties) {
-      this._nodeWithLegacyProperties.props = nextProps;
-    }
-
-    if (this._tag === 'select') {
-      // <select> value update needs to occur after <option> children
-      // reconciliation
-      transaction.getReactMountReady().enqueue(postUpdateSelectWrapper, this);
-    }
-  },
-
-  /**
-   * 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 {ReactReconcileTransaction} transaction
-   * @param {?DOMElement} node
-   */
-  _updateDOMProperties: function (lastProps, nextProps, transaction, node) {
-    var propKey;
-    var styleName;
-    var styleUpdates;
-    for (propKey in lastProps) {
-      if (nextProps.hasOwnProperty(propKey) || !lastProps.hasOwnProperty(propKey)) {
-        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._rootNodeID, propKey);
-        }
-      } else if (DOMProperty.properties[propKey] || DOMProperty.isCustomAttribute(propKey)) {
-        if (!node) {
-          node = ReactMount.getNode(this._rootNodeID);
-        }
-        DOMPropertyOperations.deleteValueForProperty(node, propKey);
-      }
-    }
-    for (propKey in nextProps) {
-      var nextProp = nextProps[propKey];
-      var lastProp = propKey === STYLE ? this._previousStyleCopy : lastProps[propKey];
-      if (!nextProps.hasOwnProperty(propKey) || nextProp === lastProp) {
-        continue;
-      }
-      if (propKey === STYLE) {
-        if (nextProp) {
-          if ("development" !== 'production') {
-            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._rootNodeID, propKey, nextProp, transaction);
-        } else if (lastProp) {
-          deleteListener(this._rootNodeID, propKey);
-        }
-      } else if (isCustomComponent(this._tag, nextProps)) {
-        if (!node) {
-          node = ReactMount.getNode(this._rootNodeID);
-        }
-        if (propKey === CHILDREN) {
-          nextProp = null;
-        }
-        DOMPropertyOperations.setValueForAttribute(node, propKey, nextProp);
-      } else if (DOMProperty.properties[propKey] || DOMProperty.isCustomAttribute(propKey)) {
-        if (!node) {
-          node = ReactMount.getNode(this._rootNodeID);
-        }
-        // If we're updating to null or undefined, we should remove the property
-        // from the DOM node instead of inadvertantly 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) {
-      if (!node) {
-        node = ReactMount.getNode(this._rootNodeID);
-      }
-      CSSPropertyOperations.setValueForStyles(node, styleUpdates);
-    }
-  },
-
-  /**
-   * 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 (nextContent != null) {
-      if (lastContent !== nextContent) {
-        this.updateTextContent('' + nextContent);
-      }
-    } else if (nextHtml != null) {
-      if (lastHtml !== nextHtml) {
-        this.updateMarkup('' + nextHtml);
-      }
-    } else if (nextChildren != null) {
-      this.updateChildren(nextChildren, transaction, context);
-    }
-  },
-
-  /**
-   * Destroys all event registrations for this instance. Does not remove from
-   * the DOM. That must be done by the parent.
-   *
-   * @internal
-   */
-  unmountComponent: function () {
-    switch (this._tag) {
-      case 'iframe':
-      case 'img':
-      case 'form':
-      case 'video':
-      case 'audio':
-        var listeners = this._wrapperState.listeners;
-        if (listeners) {
-          for (var i = 0; i < listeners.length; i++) {
-            listeners[i].remove();
-          }
-        }
-        break;
-      case 'input':
-        ReactDOMInput.unmountWrapper(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.
-         */
-        !false ? "development" !== 'production' ? 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) : invariant(false) : undefined;
-        break;
-    }
-
-    this.unmountChildren();
-    ReactBrowserEventEmitter.deleteAllListeners(this._rootNodeID);
-    ReactComponentBrowserEnvironment.unmountIDFromEnvironment(this._rootNodeID);
-    this._rootNodeID = null;
-    this._wrapperState = null;
-    if (this._nodeWithLegacyProperties) {
-      var node = this._nodeWithLegacyProperties;
-      node._reactInternalComponent = null;
-      this._nodeWithLegacyProperties = null;
-    }
-  },
-
-  getPublicInstance: function () {
-    if (!this._nodeWithLegacyProperties) {
-      var node = ReactMount.getNode(this._rootNodeID);
-
-      node._reactInternalComponent = this;
-      node.getDOMNode = legacyGetDOMNode;
-      node.isMounted = legacyIsMounted;
-      node.setState = legacySetStateEtc;
-      node.replaceState = legacySetStateEtc;
-      node.forceUpdate = legacySetStateEtc;
-      node.setProps = legacySetProps;
-      node.replaceProps = legacyReplaceProps;
-
-      if ("development" !== 'production') {
-        if (canDefineProperty) {
-          Object.defineProperties(node, legacyPropsDescriptor);
-        } else {
-          // updateComponent will update this property on subsequent renders
-          node.props = this._currentElement.props;
-        }
-      } else {
-        // updateComponent will update this property on subsequent renders
-        node.props = this._currentElement.props;
-      }
-
-      this._nodeWithLegacyProperties = node;
-    }
-    return this._nodeWithLegacyProperties;
-  }
-
-};
-
-ReactPerf.measureMethods(ReactDOMComponent, 'ReactDOMComponent', {
-  mountComponent: 'mountComponent',
-  updateComponent: 'updateComponent'
-});
-
-assign(ReactDOMComponent.prototype, ReactDOMComponent.Mixin, ReactMultiChild.Mixin);
-
-module.exports = ReactDOMComponent;
-},{"10":10,"104":104,"107":107,"11":11,"119":119,"124":124,"125":125,"128":128,"144":144,"148":148,"15":15,"153":153,"155":155,"2":2,"23":23,"26":26,"31":31,"36":36,"41":41,"42":42,"43":43,"47":47,"5":5,"65":65,"66":66,"71":71,"82":82}],38:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDOMFactories
- * @typechecks static-only
- */
-
-'use strict';
-
-var ReactElement = _dereq_(52);
-var ReactElementValidator = _dereq_(53);
-
-var mapObject = _dereq_(149);
-
-/**
- * Create a factory that creates HTML tag elements.
- *
- * @param {string} tag Tag name (e.g. `div`).
- * @private
- */
-function createDOMFactory(tag) {
-  if ("development" !== 'production') {
-    return ReactElementValidator.createFactory(tag);
-  }
-  return ReactElement.createFactory(tag);
-}
-
-/**
- * Creates a mapping from supported HTML tags to `ReactDOMComponent` classes.
- * This is also accessible via `React.DOM`.
- *
- * @public
- */
-var ReactDOMFactories = mapObject({
-  a: 'a',
-  abbr: 'abbr',
-  address: 'address',
-  area: 'area',
-  article: 'article',
-  aside: 'aside',
-  audio: 'audio',
-  b: 'b',
-  base: 'base',
-  bdi: 'bdi',
-  bdo: 'bdo',
-  big: 'big',
-  blockquote: 'blockquote',
-  body: 'body',
-  br: 'br',
-  button: 'button',
-  canvas: 'canvas',
-  caption: 'caption',
-  cite: 'cite',
-  code: 'code',
-  col: 'col',
-  colgroup: 'colgroup',
-  data: 'data',
-  datalist: 'datalist',
-  dd: 'dd',
-  del: 'del',
-  details: 'details',
-  dfn: 'dfn',
-  dialog: 'dialog',
-  div: 'div',
-  dl: 'dl',
-  dt: 'dt',
-  em: 'em',
-  embed: 'embed',
-  fieldset: 'fieldset',
-  figcaption: 'figcaption',
-  figure: 'figure',
-  footer: 'footer',
-  form: 'form',
-  h1: 'h1',
-  h2: 'h2',
-  h3: 'h3',
-  h4: 'h4',
-  h5: 'h5',
-  h6: 'h6',
-  head: 'head',
-  header: 'header',
-  hgroup: 'hgroup',
-  hr: 'hr',
-  html: 'html',
-  i: 'i',
-  iframe: 'iframe',
-  img: 'img',
-  input: 'input',
-  ins: 'ins',
-  kbd: 'kbd',
-  keygen: 'keygen',
-  label: 'label',
-  legend: 'legend',
-  li: 'li',
-  link: 'link',
-  main: 'main',
-  map: 'map',
-  mark: 'mark',
-  menu: 'menu',
-  menuitem: 'menuitem',
-  meta: 'meta',
-  meter: 'meter',
-  nav: 'nav',
-  noscript: 'noscript',
-  object: 'object',
-  ol: 'ol',
-  optgroup: 'optgroup',
-  option: 'option',
-  output: 'output',
-  p: 'p',
-  param: 'param',
-  picture: 'picture',
-  pre: 'pre',
-  progress: 'progress',
-  q: 'q',
-  rp: 'rp',
-  rt: 'rt',
-  ruby: 'ruby',
-  s: 's',
-  samp: 'samp',
-  script: 'script',
-  section: 'section',
-  select: 'select',
-  small: 'small',
-  source: 'source',
-  span: 'span',
-  strong: 'strong',
-  style: 'style',
-  sub: 'sub',
-  summary: 'summary',
-  sup: 'sup',
-  table: 'table',
-  tbody: 'tbody',
-  td: 'td',
-  textarea: 'textarea',
-  tfoot: 'tfoot',
-  th: 'th',
-  thead: 'thead',
-  time: 'time',
-  title: 'title',
-  tr: 'tr',
-  track: 'track',
-  u: 'u',
-  ul: 'ul',
-  'var': 'var',
-  video: 'video',
-  wbr: 'wbr',
-
-  // SVG
-  circle: 'circle',
-  clipPath: 'clipPath',
-  defs: 'defs',
-  ellipse: 'ellipse',
-  g: 'g',
-  image: 'image',
-  line: 'line',
-  linearGradient: 'linearGradient',
-  mask: 'mask',
-  path: 'path',
-  pattern: 'pattern',
-  polygon: 'polygon',
-  polyline: 'polyline',
-  radialGradient: 'radialGradient',
-  rect: 'rect',
-  stop: 'stop',
-  svg: 'svg',
-  text: 'text',
-  tspan: 'tspan'
-
-}, createDOMFactory);
-
-module.exports = ReactDOMFactories;
-},{"149":149,"52":52,"53":53}],39:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDOMFeatureFlags
- */
-
-'use strict';
-
-var ReactDOMFeatureFlags = {
-  useCreateElement: false
-};
-
-module.exports = ReactDOMFeatureFlags;
-},{}],40:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDOMIDOperations
- * @typechecks static-only
- */
-
-'use strict';
-
-var DOMChildrenOperations = _dereq_(9);
-var DOMPropertyOperations = _dereq_(11);
-var ReactMount = _dereq_(65);
-var ReactPerf = _dereq_(71);
-
-var invariant = _dereq_(144);
-
-/**
- * Errors for properties that should not be updated with `updatePropertyByID()`.
- *
- * @type {object}
- * @private
- */
-var INVALID_PROPERTY_ERRORS = {
-  dangerouslySetInnerHTML: '`dangerouslySetInnerHTML` must be set using `updateInnerHTMLByID()`.',
-  style: '`style` must be set using `updateStylesByID()`.'
-};
-
-/**
- * Operations used to process updates to DOM nodes.
- */
-var ReactDOMIDOperations = {
-
-  /**
-   * Updates a DOM node with new property values. This should only be used to
-   * update DOM properties in `DOMProperty`.
-   *
-   * @param {string} id ID of the node to update.
-   * @param {string} name A valid property name, see `DOMProperty`.
-   * @param {*} value New value of the property.
-   * @internal
-   */
-  updatePropertyByID: function (id, name, value) {
-    var node = ReactMount.getNode(id);
-    !!INVALID_PROPERTY_ERRORS.hasOwnProperty(name) ? "development" !== 'production' ? invariant(false, 'updatePropertyByID(...): %s', INVALID_PROPERTY_ERRORS[name]) : invariant(false) : undefined;
-
-    // If we're updating to null or undefined, we should remove the property
-    // from the DOM node instead of inadvertantly setting to a string. This
-    // brings us in line with the same behavior we have on initial render.
-    if (value != null) {
-      DOMPropertyOperations.setValueForProperty(node, name, value);
-    } else {
-      DOMPropertyOperations.deleteValueForProperty(node, name);
-    }
-  },
-
-  /**
-   * Replaces a DOM node that exists in the document with markup.
-   *
-   * @param {string} id ID of child to be replaced.
-   * @param {string} markup Dangerous markup to inject in place of child.
-   * @internal
-   * @see {Danger.dangerouslyReplaceNodeWithMarkup}
-   */
-  dangerouslyReplaceNodeWithMarkupByID: function (id, markup) {
-    var node = ReactMount.getNode(id);
-    DOMChildrenOperations.dangerouslyReplaceNodeWithMarkup(node, markup);
-  },
-
-  /**
-   * Updates a component's children by processing a series of updates.
-   *
-   * @param {array<object>} updates List of update configurations.
-   * @param {array<string>} markup List of markup strings.
-   * @internal
-   */
-  dangerouslyProcessChildrenUpdates: function (updates, markup) {
-    for (var i = 0; i < updates.length; i++) {
-      updates[i].parentNode = ReactMount.getNode(updates[i].parentID);
-    }
-    DOMChildrenOperations.processUpdates(updates, markup);
-  }
-};
-
-ReactPerf.measureMethods(ReactDOMIDOperations, 'ReactDOMIDOperations', {
-  dangerouslyReplaceNodeWithMarkupByID: 'dangerouslyReplaceNodeWithMarkupByID',
-  dangerouslyProcessChildrenUpdates: 'dangerouslyProcessChildrenUpdates'
-});
-
-module.exports = ReactDOMIDOperations;
-},{"11":11,"144":144,"65":65,"71":71,"9":9}],41:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDOMInput
- */
-
-'use strict';
-
-var ReactDOMIDOperations = _dereq_(40);
-var LinkedValueUtils = _dereq_(22);
-var ReactMount = _dereq_(65);
-var ReactUpdates = _dereq_(83);
-
-var assign = _dereq_(23);
-var invariant = _dereq_(144);
-
-var instancesByReactID = {};
-
-function forceUpdateIfMounted() {
-  if (this._rootNodeID) {
-    // DOM component is still mounted; update
-    ReactDOMInput.updateWrapper(this);
-  }
-}
-
-/**
- * Implements an <input> native 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 = {
-  getNativeProps: function (inst, props, context) {
-    var value = LinkedValueUtils.getValue(props);
-    var checked = LinkedValueUtils.getChecked(props);
-
-    var nativeProps = assign({}, props, {
-      defaultChecked: undefined,
-      defaultValue: undefined,
-      value: value != null ? value : inst._wrapperState.initialValue,
-      checked: checked != null ? checked : inst._wrapperState.initialChecked,
-      onChange: inst._wrapperState.onChange
-    });
-
-    return nativeProps;
-  },
-
-  mountWrapper: function (inst, props) {
-    if ("development" !== 'production') {
-      LinkedValueUtils.checkPropTypes('input', props, inst._currentElement._owner);
-    }
-
-    var defaultValue = props.defaultValue;
-    inst._wrapperState = {
-      initialChecked: props.defaultChecked || false,
-      initialValue: defaultValue != null ? defaultValue : null,
-      onChange: _handleChange.bind(inst)
-    };
-  },
-
-  mountReadyWrapper: function (inst) {
-    // Can't be in mountWrapper or else server rendering leaks.
-    instancesByReactID[inst._rootNodeID] = inst;
-  },
-
-  unmountWrapper: function (inst) {
-    delete instancesByReactID[inst._rootNodeID];
-  },
-
-  updateWrapper: function (inst) {
-    var props = inst._currentElement.props;
-
-    // TODO: Shouldn't this be getChecked(props)?
-    var checked = props.checked;
-    if (checked != null) {
-      ReactDOMIDOperations.updatePropertyByID(inst._rootNodeID, 'checked', checked || false);
-    }
-
-    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.
-      ReactDOMIDOperations.updatePropertyByID(inst._rootNodeID, 'value', '' + value);
-    }
-  }
-};
-
-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 = ReactMount.getNode(this._rootNodeID);
-    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 with non-React.
-      var otherID = ReactMount.getID(otherNode);
-      !otherID ? "development" !== 'production' ? invariant(false, 'ReactDOMInput: Mixing React and non-React radio inputs with the ' + 'same `name` is not supported.') : invariant(false) : undefined;
-      var otherInstance = instancesByReactID[otherID];
-      !otherInstance ? "development" !== 'production' ? invariant(false, 'ReactDOMInput: Unknown radio button ID %s.', otherID) : invariant(false) : undefined;
-      // 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;
-},{"144":144,"22":22,"23":23,"40":40,"65":65,"83":83}],42:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDOMOption
- */
-
-'use strict';
-
-var ReactChildren = _dereq_(28);
-var ReactDOMSelect = _dereq_(43);
-
-var assign = _dereq_(23);
-var warning = _dereq_(155);
-
-var valueContextKey = ReactDOMSelect.valueContextKey;
-
-/**
- * Implements an <option> native component that warns when `selected` is set.
- */
-var ReactDOMOption = {
-  mountWrapper: function (inst, props, context) {
-    // TODO (yungsters): Remove support for `selected` in <option>.
-    if ("development" !== 'production') {
-      "development" !== 'production' ? warning(props.selected == null, 'Use the `defaultValue` or `value` props on <select> instead of ' + 'setting `selected` on <option>.') : undefined;
-    }
-
-    // Look up whether this option is 'selected' via context
-    var selectValue = context[valueContextKey];
-
-    // If context key 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) {
-      selected = false;
-      if (Array.isArray(selectValue)) {
-        // multiple
-        for (var i = 0; i < selectValue.length; i++) {
-          if ('' + selectValue[i] === '' + props.value) {
-            selected = true;
-            break;
-          }
-        }
-      } else {
-        selected = '' + selectValue === '' + props.value;
-      }
-    }
-
-    inst._wrapperState = { selected: selected };
-  },
-
-  getNativeProps: function (inst, props, context) {
-    var nativeProps = 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) {
-      nativeProps.selected = inst._wrapperState.selected;
-    }
-
-    var content = '';
-
-    // Flatten children and warn if they aren't strings or numbers;
-    // invalid types are ignored.
-    ReactChildren.forEach(props.children, function (child) {
-      if (child == null) {
-        return;
-      }
-      if (typeof child === 'string' || typeof child === 'number') {
-        content += child;
-      } else {
-        "development" !== 'production' ? warning(false, 'Only strings and numbers are supported as <option> children.') : undefined;
-      }
-    });
-
-    if (content) {
-      nativeProps.children = content;
-    }
-
-    return nativeProps;
-  }
-
-};
-
-module.exports = ReactDOMOption;
-},{"155":155,"23":23,"28":28,"43":43}],43:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDOMSelect
- */
-
-'use strict';
-
-var LinkedValueUtils = _dereq_(22);
-var ReactMount = _dereq_(65);
-var ReactUpdates = _dereq_(83);
-
-var assign = _dereq_(23);
-var warning = _dereq_(155);
-
-var valueContextKey = '__ReactDOMSelect_value$' + Math.random().toString(36).slice(2);
-
-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);
-
-  for (var i = 0; i < valuePropNames.length; i++) {
-    var propName = valuePropNames[i];
-    if (props[propName] == null) {
-      continue;
-    }
-    if (props.multiple) {
-      "development" !== 'production' ? warning(Array.isArray(props[propName]), 'The `%s` prop supplied to <select> must be an array if ' + '`multiple` is true.%s', propName, getDeclarationErrorAddendum(owner)) : undefined;
-    } else {
-      "development" !== 'production' ? warning(!Array.isArray(props[propName]), 'The `%s` prop supplied to <select> must be a scalar ' + 'value if `multiple` is false.%s', propName, getDeclarationErrorAddendum(owner)) : undefined;
-    }
-  }
-}
-
-/**
- * @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 = ReactMount.getNode(inst._rootNodeID).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> native 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 = {
-  valueContextKey: valueContextKey,
-
-  getNativeProps: function (inst, props, context) {
-    return assign({}, props, {
-      onChange: inst._wrapperState.onChange,
-      value: undefined
-    });
-  },
-
-  mountWrapper: function (inst, props) {
-    if ("development" !== 'production') {
-      checkSelectPropTypes(inst, props);
-    }
-
-    var value = LinkedValueUtils.getValue(props);
-    inst._wrapperState = {
-      pendingUpdate: false,
-      initialValue: value != null ? value : props.defaultValue,
-      onChange: _handleChange.bind(inst),
-      wasMultiple: Boolean(props.multiple)
-    };
-  },
-
-  processChildContext: function (inst, props, context) {
-    // Pass down initial value so initial generated markup has correct
-    // `selected` attributes
-    var childContext = assign({}, context);
-    childContext[valueContextKey] = inst._wrapperState.initialValue;
-    return childContext;
-  },
-
-  postUpdateWrapper: function (inst) {
-    var props = inst._currentElement.props;
-
-    // After the initial mount, we control selected-ness manually so don't pass
-    // the context 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);
-
-  this._wrapperState.pendingUpdate = true;
-  ReactUpdates.asap(updateOptionsIfPendingUpdateAndMounted, this);
-  return returnValue;
-}
-
-module.exports = ReactDOMSelect;
-},{"155":155,"22":22,"23":23,"65":65,"83":83}],44:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDOMSelection
- */
-
-'use strict';
-
-var ExecutionEnvironment = _dereq_(130);
-
-var getNodeForCharacterOffset = _dereq_(116);
-var getTextContentAccessor = _dereq_(117);
-
-/**
- * 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 (typeof 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 programatically 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 = typeof 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;
-},{"116":116,"117":117,"130":130}],45:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDOMServer
- */
-
-'use strict';
-
-var ReactDefaultInjection = _dereq_(49);
-var ReactServerRendering = _dereq_(80);
-var ReactVersion = _dereq_(84);
-
-ReactDefaultInjection.inject();
-
-var ReactDOMServer = {
-  renderToString: ReactServerRendering.renderToString,
-  renderToStaticMarkup: ReactServerRendering.renderToStaticMarkup,
-  version: ReactVersion
-};
-
-module.exports = ReactDOMServer;
-},{"49":49,"80":80,"84":84}],46:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDOMTextComponent
- * @typechecks static-only
- */
-
-'use strict';
-
-var DOMChildrenOperations = _dereq_(9);
-var DOMPropertyOperations = _dereq_(11);
-var ReactComponentBrowserEnvironment = _dereq_(31);
-var ReactMount = _dereq_(65);
-
-var assign = _dereq_(23);
-var escapeTextContentForBrowser = _dereq_(107);
-var setTextContent = _dereq_(125);
-var validateDOMNesting = _dereq_(128);
-
-/**
- * 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 in elements 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 (props) {
-  // This constructor and its argument is currently used by mocks.
-};
-
-assign(ReactDOMTextComponent.prototype, {
-
-  /**
-   * @param {ReactText} text
-   * @internal
-   */
-  construct: function (text) {
-    // TODO: This is really a ReactText (ReactNode), not a ReactElement
-    this._currentElement = text;
-    this._stringText = '' + text;
-
-    // Properties
-    this._rootNodeID = null;
-    this._mountIndex = 0;
-  },
-
-  /**
-   * Creates the markup for this text node. This node is not intended to have
-   * any features besides containing text content.
-   *
-   * @param {string} rootID DOM ID of the root node.
-   * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
-   * @return {string} Markup for this text node.
-   * @internal
-   */
-  mountComponent: function (rootID, transaction, context) {
-    if ("development" !== 'production') {
-      if (context[validateDOMNesting.ancestorInfoContextKey]) {
-        validateDOMNesting('span', null, context[validateDOMNesting.ancestorInfoContextKey]);
-      }
-    }
-
-    this._rootNodeID = rootID;
-    if (transaction.useCreateElement) {
-      var ownerDocument = context[ReactMount.ownerDocumentContextKey];
-      var el = ownerDocument.createElement('span');
-      DOMPropertyOperations.setAttributeForID(el, rootID);
-      // Populate node cache
-      ReactMount.getID(el);
-      setTextContent(el, this._stringText);
-      return el;
-    } else {
-      var escapedText = escapeTextContentForBrowser(this._stringText);
-
-      if (transaction.renderToStaticMarkup) {
-        // Normally we'd wrap this in a `span` 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 '<span ' + DOMPropertyOperations.createMarkupForID(rootID) + '>' + escapedText + '</span>';
-    }
-  },
-
-  /**
-   * 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 node = ReactMount.getNode(this._rootNodeID);
-        DOMChildrenOperations.updateTextContent(node, nextStringText);
-      }
-    }
-  },
-
-  unmountComponent: function () {
-    ReactComponentBrowserEnvironment.unmountIDFromEnvironment(this._rootNodeID);
-  }
-
-});
-
-module.exports = ReactDOMTextComponent;
-},{"107":107,"11":11,"125":125,"128":128,"23":23,"31":31,"65":65,"9":9}],47:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDOMTextarea
- */
-
-'use strict';
-
-var LinkedValueUtils = _dereq_(22);
-var ReactDOMIDOperations = _dereq_(40);
-var ReactUpdates = _dereq_(83);
-
-var assign = _dereq_(23);
-var invariant = _dereq_(144);
-var warning = _dereq_(155);
-
-function forceUpdateIfMounted() {
-  if (this._rootNodeID) {
-    // DOM component is still mounted; update
-    ReactDOMTextarea.updateWrapper(this);
-  }
-}
-
-/**
- * Implements a <textarea> native 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 = {
-  getNativeProps: function (inst, props, context) {
-    !(props.dangerouslySetInnerHTML == null) ? "development" !== 'production' ? invariant(false, '`dangerouslySetInnerHTML` does not make sense on <textarea>.') : invariant(false) : undefined;
-
-    // Always set children to the same thing. In IE9, the selection range will
-    // get reset if `textContent` is mutated.
-    var nativeProps = assign({}, props, {
-      defaultValue: undefined,
-      value: undefined,
-      children: inst._wrapperState.initialValue,
-      onChange: inst._wrapperState.onChange
-    });
-
-    return nativeProps;
-  },
-
-  mountWrapper: function (inst, props) {
-    if ("development" !== 'production') {
-      LinkedValueUtils.checkPropTypes('textarea', props, inst._currentElement._owner);
-    }
-
-    var defaultValue = props.defaultValue;
-    // TODO (yungsters): Remove support for children content in <textarea>.
-    var children = props.children;
-    if (children != null) {
-      if ("development" !== 'production') {
-        "development" !== 'production' ? warning(false, 'Use the `defaultValue` or `value` props instead of setting ' + 'children on <textarea>.') : undefined;
-      }
-      !(defaultValue == null) ? "development" !== 'production' ? invariant(false, 'If you supply `defaultValue` on a <textarea>, do not pass children.') : invariant(false) : undefined;
-      if (Array.isArray(children)) {
-        !(children.length <= 1) ? "development" !== 'production' ? invariant(false, '<textarea> can only have at most one child.') : invariant(false) : undefined;
-        children = children[0];
-      }
-
-      defaultValue = '' + children;
-    }
-    if (defaultValue == null) {
-      defaultValue = '';
-    }
-    var value = LinkedValueUtils.getValue(props);
-
-    inst._wrapperState = {
-      // We save the initial value so that `ReactDOMComponent` doesn't update
-      // `textContent` (unnecessary since we update value).
-      // The initial value can be a boolean or object so that's why it's
-      // forced to be a string.
-      initialValue: '' + (value != null ? value : defaultValue),
-      onChange: _handleChange.bind(inst)
-    };
-  },
-
-  updateWrapper: function (inst) {
-    var props = inst._currentElement.props;
-    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.
-      ReactDOMIDOperations.updatePropertyByID(inst._rootNodeID, 'value', '' + value);
-    }
-  }
-};
-
-function _handleChange(event) {
-  var props = this._currentElement.props;
-  var returnValue = LinkedValueUtils.executeOnChange(props, event);
-  ReactUpdates.asap(forceUpdateIfMounted, this);
-  return returnValue;
-}
-
-module.exports = ReactDOMTextarea;
-},{"144":144,"155":155,"22":22,"23":23,"40":40,"83":83}],48:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDefaultBatchingStrategy
- */
-
-'use strict';
-
-var ReactUpdates = _dereq_(83);
-var Transaction = _dereq_(100);
-
-var assign = _dereq_(23);
-var emptyFunction = _dereq_(136);
-
-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.Mixin, {
-  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) {
-      callback(a, b, c, d, e);
-    } else {
-      transaction.perform(callback, null, a, b, c, d, e);
-    }
-  }
-};
-
-module.exports = ReactDefaultBatchingStrategy;
-},{"100":100,"136":136,"23":23,"83":83}],49:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDefaultInjection
- */
-
-'use strict';
-
-var BeforeInputEventPlugin = _dereq_(3);
-var ChangeEventPlugin = _dereq_(7);
-var ClientReactRootIndex = _dereq_(8);
-var DefaultEventPluginOrder = _dereq_(13);
-var EnterLeaveEventPlugin = _dereq_(14);
-var ExecutionEnvironment = _dereq_(130);
-var HTMLDOMPropertyConfig = _dereq_(21);
-var ReactBrowserComponentMixin = _dereq_(25);
-var ReactComponentBrowserEnvironment = _dereq_(31);
-var ReactDefaultBatchingStrategy = _dereq_(48);
-var ReactDOMComponent = _dereq_(37);
-var ReactDOMTextComponent = _dereq_(46);
-var ReactEventListener = _dereq_(58);
-var ReactInjection = _dereq_(59);
-var ReactInstanceHandles = _dereq_(61);
-var ReactMount = _dereq_(65);
-var ReactReconcileTransaction = _dereq_(75);
-var SelectEventPlugin = _dereq_(86);
-var ServerReactRootIndex = _dereq_(87);
-var SimpleEventPlugin = _dereq_(88);
-var SVGDOMPropertyConfig = _dereq_(85);
-
-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.EventPluginHub.injectInstanceHandle(ReactInstanceHandles);
-  ReactInjection.EventPluginHub.injectMount(ReactMount);
-
-  /**
-   * 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.NativeComponent.injectGenericComponentClass(ReactDOMComponent);
-
-  ReactInjection.NativeComponent.injectTextComponentClass(ReactDOMTextComponent);
-
-  ReactInjection.Class.injectMixin(ReactBrowserComponentMixin);
-
-  ReactInjection.DOMProperty.injectDOMPropertyConfig(HTMLDOMPropertyConfig);
-  ReactInjection.DOMProperty.injectDOMPropertyConfig(SVGDOMPropertyConfig);
-
-  ReactInjection.EmptyComponent.injectEmptyComponent('noscript');
-
-  ReactInjection.Updates.injectReconcileTransaction(ReactReconcileTransaction);
-  ReactInjection.Updates.injectBatchingStrategy(ReactDefaultBatchingStrategy);
-
-  ReactInjection.RootIndex.injectCreateReactRootIndex(ExecutionEnvironment.canUseDOM ? ClientReactRootIndex.createReactRootIndex : ServerReactRootIndex.createReactRootIndex);
-
-  ReactInjection.Component.injectEnvironment(ReactComponentBrowserEnvironment);
-
-  if ("development" !== 'production') {
-    var url = ExecutionEnvironment.canUseDOM && window.location.href || '';
-    if (/[?&]react_perf\b/.test(url)) {
-      var ReactDefaultPerf = _dereq_(50);
-      ReactDefaultPerf.start();
-    }
-  }
-}
-
-module.exports = {
-  inject: inject
-};
-},{"13":13,"130":130,"14":14,"21":21,"25":25,"3":3,"31":31,"37":37,"46":46,"48":48,"50":50,"58":58,"59":59,"61":61,"65":65,"7":7,"75":75,"8":8,"85":85,"86":86,"87":87,"88":88}],50:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDefaultPerf
- * @typechecks static-only
- */
-
-'use strict';
-
-var DOMProperty = _dereq_(10);
-var ReactDefaultPerfAnalysis = _dereq_(51);
-var ReactMount = _dereq_(65);
-var ReactPerf = _dereq_(71);
-
-var performanceNow = _dereq_(152);
-
-function roundFloat(val) {
-  return Math.floor(val * 100) / 100;
-}
-
-function addValue(obj, key, val) {
-  obj[key] = (obj[key] || 0) + val;
-}
-
-var ReactDefaultPerf = {
-  _allMeasurements: [], // last item in the list is the current one
-  _mountStack: [0],
-  _injected: false,
-
-  start: function () {
-    if (!ReactDefaultPerf._injected) {
-      ReactPerf.injection.injectMeasure(ReactDefaultPerf.measure);
-    }
-
-    ReactDefaultPerf._allMeasurements.length = 0;
-    ReactPerf.enableMeasure = true;
-  },
-
-  stop: function () {
-    ReactPerf.enableMeasure = false;
-  },
-
-  getLastMeasurements: function () {
-    return ReactDefaultPerf._allMeasurements;
-  },
-
-  printExclusive: function (measurements) {
-    measurements = measurements || ReactDefaultPerf._allMeasurements;
-    var summary = ReactDefaultPerfAnalysis.getExclusiveSummary(measurements);
-    console.table(summary.map(function (item) {
-      return {
-        'Component class name': item.componentName,
-        'Total inclusive time (ms)': roundFloat(item.inclusive),
-        'Exclusive mount time (ms)': roundFloat(item.exclusive),
-        'Exclusive render time (ms)': roundFloat(item.render),
-        'Mount time per instance (ms)': roundFloat(item.exclusive / item.count),
-        'Render time per instance (ms)': roundFloat(item.render / item.count),
-        'Instances': item.count
-      };
-    }));
-    // TODO: ReactDefaultPerfAnalysis.getTotalTime() does not return the correct
-    // number.
-  },
-
-  printInclusive: function (measurements) {
-    measurements = measurements || ReactDefaultPerf._allMeasurements;
-    var summary = ReactDefaultPerfAnalysis.getInclusiveSummary(measurements);
-    console.table(summary.map(function (item) {
-      return {
-        'Owner > component': item.componentName,
-        'Inclusive time (ms)': roundFloat(item.time),
-        'Instances': item.count
-      };
-    }));
-    console.log('Total time:', ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms');
-  },
-
-  getMeasurementsSummaryMap: function (measurements) {
-    var summary = ReactDefaultPerfAnalysis.getInclusiveSummary(measurements, true);
-    return summary.map(function (item) {
-      return {
-        'Owner > component': item.componentName,
-        'Wasted time (ms)': item.time,
-        'Instances': item.count
-      };
-    });
-  },
-
-  printWasted: function (measurements) {
-    measurements = measurements || ReactDefaultPerf._allMeasurements;
-    console.table(ReactDefaultPerf.getMeasurementsSummaryMap(measurements));
-    console.log('Total time:', ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms');
-  },
-
-  printDOM: function (measurements) {
-    measurements = measurements || ReactDefaultPerf._allMeasurements;
-    var summary = ReactDefaultPerfAnalysis.getDOMSummary(measurements);
-    console.table(summary.map(function (item) {
-      var result = {};
-      result[DOMProperty.ID_ATTRIBUTE_NAME] = item.id;
-      result.type = item.type;
-      result.args = JSON.stringify(item.args);
-      return result;
-    }));
-    console.log('Total time:', ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms');
-  },
-
-  _recordWrite: function (id, fnName, totalTime, args) {
-    // TODO: totalTime isn't that useful since it doesn't count paints/reflows
-    var writes = ReactDefaultPerf._allMeasurements[ReactDefaultPerf._allMeasurements.length - 1].writes;
-    writes[id] = writes[id] || [];
-    writes[id].push({
-      type: fnName,
-      time: totalTime,
-      args: args
-    });
-  },
-
-  measure: function (moduleName, fnName, func) {
-    return function () {
-      for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
-        args[_key] = arguments[_key];
-      }
-
-      var totalTime;
-      var rv;
-      var start;
-
-      if (fnName === '_renderNewRootComponent' || fnName === 'flushBatchedUpdates') {
-        // A "measurement" is a set of metrics recorded for each flush. We want
-        // to group the metrics for a given flush together so we can look at the
-        // components that rendered and the DOM operations that actually
-        // happened to determine the amount of "wasted work" performed.
-        ReactDefaultPerf._allMeasurements.push({
-          exclusive: {},
-          inclusive: {},
-          render: {},
-          counts: {},
-          writes: {},
-          displayNames: {},
-          totalTime: 0,
-          created: {}
-        });
-        start = performanceNow();
-        rv = func.apply(this, args);
-        ReactDefaultPerf._allMeasurements[ReactDefaultPerf._allMeasurements.length - 1].totalTime = performanceNow() - start;
-        return rv;
-      } else if (fnName === '_mountImageIntoNode' || moduleName === 'ReactBrowserEventEmitter' || moduleName === 'ReactDOMIDOperations' || moduleName === 'CSSPropertyOperations' || moduleName === 'DOMChildrenOperations' || moduleName === 'DOMPropertyOperations') {
-        start = performanceNow();
-        rv = func.apply(this, args);
-        totalTime = performanceNow() - start;
-
-        if (fnName === '_mountImageIntoNode') {
-          var mountID = ReactMount.getID(args[1]);
-          ReactDefaultPerf._recordWrite(mountID, fnName, totalTime, args[0]);
-        } else if (fnName === 'dangerouslyProcessChildrenUpdates') {
-          // special format
-          args[0].forEach(function (update) {
-            var writeArgs = {};
-            if (update.fromIndex !== null) {
-              writeArgs.fromIndex = update.fromIndex;
-            }
-            if (update.toIndex !== null) {
-              writeArgs.toIndex = update.toIndex;
-            }
-            if (update.textContent !== null) {
-              writeArgs.textContent = update.textContent;
-            }
-            if (update.markupIndex !== null) {
-              writeArgs.markup = args[1][update.markupIndex];
-            }
-            ReactDefaultPerf._recordWrite(update.parentID, update.type, totalTime, writeArgs);
-          });
-        } else {
-          // basic format
-          var id = args[0];
-          if (typeof id === 'object') {
-            id = ReactMount.getID(args[0]);
-          }
-          ReactDefaultPerf._recordWrite(id, fnName, totalTime, Array.prototype.slice.call(args, 1));
-        }
-        return rv;
-      } else if (moduleName === 'ReactCompositeComponent' && (fnName === 'mountComponent' || fnName === 'updateComponent' || // TODO: receiveComponent()?
-      fnName === '_renderValidatedComponent')) {
-
-        if (this._currentElement.type === ReactMount.TopLevelWrapper) {
-          return func.apply(this, args);
-        }
-
-        var rootNodeID = fnName === 'mountComponent' ? args[0] : this._rootNodeID;
-        var isRender = fnName === '_renderValidatedComponent';
-        var isMount = fnName === 'mountComponent';
-
-        var mountStack = ReactDefaultPerf._mountStack;
-        var entry = ReactDefaultPerf._allMeasurements[ReactDefaultPerf._allMeasurements.length - 1];
-
-        if (isRender) {
-          addValue(entry.counts, rootNodeID, 1);
-        } else if (isMount) {
-          entry.created[rootNodeID] = true;
-          mountStack.push(0);
-        }
-
-        start = performanceNow();
-        rv = func.apply(this, args);
-        totalTime = performanceNow() - start;
-
-        if (isRender) {
-          addValue(entry.render, rootNodeID, totalTime);
-        } else if (isMount) {
-          var subMountTime = mountStack.pop();
-          mountStack[mountStack.length - 1] += totalTime;
-          addValue(entry.exclusive, rootNodeID, totalTime - subMountTime);
-          addValue(entry.inclusive, rootNodeID, totalTime);
-        } else {
-          addValue(entry.inclusive, rootNodeID, totalTime);
-        }
-
-        entry.displayNames[rootNodeID] = {
-          current: this.getName(),
-          owner: this._currentElement._owner ? this._currentElement._owner.getName() : '<root>'
-        };
-
-        return rv;
-      } else {
-        return func.apply(this, args);
-      }
-    };
-  }
-};
-
-module.exports = ReactDefaultPerf;
-},{"10":10,"152":152,"51":51,"65":65,"71":71}],51:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactDefaultPerfAnalysis
- */
-
-'use strict';
-
-var assign = _dereq_(23);
-
-// Don't try to save users less than 1.2ms (a number I made up)
-var DONT_CARE_THRESHOLD = 1.2;
-var DOM_OPERATION_TYPES = {
-  '_mountImageIntoNode': 'set innerHTML',
-  INSERT_MARKUP: 'set innerHTML',
-  MOVE_EXISTING: 'move',
-  REMOVE_NODE: 'remove',
-  SET_MARKUP: 'set innerHTML',
-  TEXT_CONTENT: 'set textContent',
-  'setValueForProperty': 'update attribute',
-  'setValueForAttribute': 'update attribute',
-  'deleteValueForProperty': 'remove attribute',
-  'setValueForStyles': 'update styles',
-  'replaceNodeWithMarkup': 'replace',
-  'updateTextContent': 'set textContent'
-};
-
-function getTotalTime(measurements) {
-  // TODO: return number of DOM ops? could be misleading.
-  // TODO: measure dropped frames after reconcile?
-  // TODO: log total time of each reconcile and the top-level component
-  // class that triggered it.
-  var totalTime = 0;
-  for (var i = 0; i < measurements.length; i++) {
-    var measurement = measurements[i];
-    totalTime += measurement.totalTime;
-  }
-  return totalTime;
-}
-
-function getDOMSummary(measurements) {
-  var items = [];
-  measurements.forEach(function (measurement) {
-    Object.keys(measurement.writes).forEach(function (id) {
-      measurement.writes[id].forEach(function (write) {
-        items.push({
-          id: id,
-          type: DOM_OPERATION_TYPES[write.type] || write.type,
-          args: write.args
-        });
-      });
-    });
-  });
-  return items;
-}
-
-function getExclusiveSummary(measurements) {
-  var candidates = {};
-  var displayName;
-
-  for (var i = 0; i < measurements.length; i++) {
-    var measurement = measurements[i];
-    var allIDs = assign({}, measurement.exclusive, measurement.inclusive);
-
-    for (var id in allIDs) {
-      displayName = measurement.displayNames[id].current;
-
-      candidates[displayName] = candidates[displayName] || {
-        componentName: displayName,
-        inclusive: 0,
-        exclusive: 0,
-        render: 0,
-        count: 0
-      };
-      if (measurement.render[id]) {
-        candidates[displayName].render += measurement.render[id];
-      }
-      if (measurement.exclusive[id]) {
-        candidates[displayName].exclusive += measurement.exclusive[id];
-      }
-      if (measurement.inclusive[id]) {
-        candidates[displayName].inclusive += measurement.inclusive[id];
-      }
-      if (measurement.counts[id]) {
-        candidates[displayName].count += measurement.counts[id];
-      }
-    }
-  }
-
-  // Now make a sorted array with the results.
-  var arr = [];
-  for (displayName in candidates) {
-    if (candidates[displayName].exclusive >= DONT_CARE_THRESHOLD) {
-      arr.push(candidates[displayName]);
-    }
-  }
-
-  arr.sort(function (a, b) {
-    return b.exclusive - a.exclusive;
-  });
-
-  return arr;
-}
-
-function getInclusiveSummary(measurements, onlyClean) {
-  var candidates = {};
-  var inclusiveKey;
-
-  for (var i = 0; i < measurements.length; i++) {
-    var measurement = measurements[i];
-    var allIDs = assign({}, measurement.exclusive, measurement.inclusive);
-    var cleanComponents;
-
-    if (onlyClean) {
-      cleanComponents = getUnchangedComponents(measurement);
-    }
-
-    for (var id in allIDs) {
-      if (onlyClean && !cleanComponents[id]) {
-        continue;
-      }
-
-      var displayName = measurement.displayNames[id];
-
-      // Inclusive time is not useful for many components without knowing where
-      // they are instantiated. So we aggregate inclusive time with both the
-      // owner and current displayName as the key.
-      inclusiveKey = displayName.owner + ' > ' + displayName.current;
-
-      candidates[inclusiveKey] = candidates[inclusiveKey] || {
-        componentName: inclusiveKey,
-        time: 0,
-        count: 0
-      };
-
-      if (measurement.inclusive[id]) {
-        candidates[inclusiveKey].time += measurement.inclusive[id];
-      }
-      if (measurement.counts[id]) {
-        candidates[inclusiveKey].count += measurement.counts[id];
-      }
-    }
-  }
-
-  // Now make a sorted array with the results.
-  var arr = [];
-  for (inclusiveKey in candidates) {
-    if (candidates[inclusiveKey].time >= DONT_CARE_THRESHOLD) {
-      arr.push(candidates[inclusiveKey]);
-    }
-  }
-
-  arr.sort(function (a, b) {
-    return b.time - a.time;
-  });
-
-  return arr;
-}
-
-function getUnchangedComponents(measurement) {
-  // For a given reconcile, look at which components did not actually
-  // render anything to the DOM and return a mapping of their ID to
-  // the amount of time it took to render the entire subtree.
-  var cleanComponents = {};
-  var dirtyLeafIDs = Object.keys(measurement.writes);
-  var allIDs = assign({}, measurement.exclusive, measurement.inclusive);
-
-  for (var id in allIDs) {
-    var isDirty = false;
-    // For each component that rendered, see if a component that triggered
-    // a DOM op is in its subtree.
-    for (var i = 0; i < dirtyLeafIDs.length; i++) {
-      if (dirtyLeafIDs[i].indexOf(id) === 0) {
-        isDirty = true;
-        break;
-      }
-    }
-    // check if component newly created
-    if (measurement.created[id]) {
-      isDirty = true;
-    }
-    if (!isDirty && measurement.counts[id] > 0) {
-      cleanComponents[id] = true;
-    }
-  }
-  return cleanComponents;
-}
-
-var ReactDefaultPerfAnalysis = {
-  getExclusiveSummary: getExclusiveSummary,
-  getInclusiveSummary: getInclusiveSummary,
-  getDOMSummary: getDOMSummary,
-  getTotalTime: getTotalTime
-};
-
-module.exports = ReactDefaultPerfAnalysis;
-},{"23":23}],52:[function(_dereq_,module,exports){
-/**
- * Copyright 2014-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactElement
- */
-
-'use strict';
-
-var ReactCurrentOwner = _dereq_(34);
-
-var assign = _dereq_(23);
-var canDefineProperty = _dereq_(104);
-
-// 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;
-
-var RESERVED_PROPS = {
-  key: true,
-  ref: true,
-  __self: true,
-  __source: true
-};
-
-/**
- * Base constructor for all React elements. This is only used to make this
- * work with a dynamic instanceof check. Nothing should live on this prototype.
- *
- * @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 ("development" !== 'production') {
-    // 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;
-    }
-    Object.freeze(element.props);
-    Object.freeze(element);
-  }
-
-  return element;
-};
-
-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) {
-    ref = config.ref === undefined ? null : config.ref;
-    key = config.key === undefined ? null : '' + 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 (config.hasOwnProperty(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];
-    }
-    props.children = childArray;
-  }
-
-  // Resolve default props
-  if (type && type.defaultProps) {
-    var defaultProps = type.defaultProps;
-    for (propName in defaultProps) {
-      if (typeof props[propName] === 'undefined') {
-        props[propName] = defaultProps[propName];
-      }
-    }
-  }
-
-  return ReactElement(type, key, ref, self, source, ReactCurrentOwner.current, props);
-};
-
-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;
-};
-
-ReactElement.cloneAndReplaceProps = function (oldElement, newProps) {
-  var newElement = ReactElement(oldElement.type, oldElement.key, oldElement.ref, oldElement._self, oldElement._source, oldElement._owner, newProps);
-
-  if ("development" !== 'production') {
-    // If the key on the original is valid, then the clone is valid
-    newElement._store.validated = oldElement._store.validated;
-  }
-
-  return newElement;
-};
-
-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 (config.ref !== undefined) {
-      // Silently steal the ref from the parent.
-      ref = config.ref;
-      owner = ReactCurrentOwner.current;
-    }
-    if (config.key !== undefined) {
-      key = '' + config.key;
-    }
-    // Remaining properties override existing props
-    for (propName in config) {
-      if (config.hasOwnProperty(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];
-    }
-    props.children = childArray;
-  }
-
-  return ReactElement(element.type, key, ref, self, source, owner, props);
-};
-
-/**
- * @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;
-},{"104":104,"23":23,"34":34}],53:[function(_dereq_,module,exports){
-/**
- * Copyright 2014-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactElementValidator
- */
-
-/**
- * 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.
- */
-
-'use strict';
-
-var ReactElement = _dereq_(52);
-var ReactPropTypeLocations = _dereq_(73);
-var ReactPropTypeLocationNames = _dereq_(72);
-var ReactCurrentOwner = _dereq_(34);
-
-var canDefineProperty = _dereq_(104);
-var getIteratorFn = _dereq_(115);
-var invariant = _dereq_(144);
-var warning = _dereq_(155);
-
-function getDeclarationErrorAddendum() {
-  if (ReactCurrentOwner.current) {
-    var name = ReactCurrentOwner.current.getName();
-    if (name) {
-      return ' Check the render method of `' + name + '`.';
-    }
-  }
-  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 = {};
-
-var loggedTypeFailures = {};
-
-/**
- * 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.
- *
- * @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 addenda = getAddendaForKeyUse('uniqueKey', element, parentType);
-  if (addenda === null) {
-    // we already showed the warning
-    return;
-  }
-  "development" !== 'production' ? warning(false, 'Each child in an array or iterator should have a unique "key" prop.' + '%s%s%s', addenda.parentOrOwner || '', addenda.childOwner || '', addenda.url || '') : undefined;
-}
-
-/**
- * Shared warning and monitoring code for the key warnings.
- *
- * @internal
- * @param {string} messageType A key used for de-duping warnings.
- * @param {ReactElement} element Component that requires a key.
- * @param {*} parentType element's parent's type.
- * @returns {?object} A set of addenda to use in the warning message, or null
- * if the warning has already been shown before (and shouldn't be shown again).
- */
-function getAddendaForKeyUse(messageType, element, parentType) {
-  var addendum = getDeclarationErrorAddendum();
-  if (!addendum) {
-    var parentName = typeof parentType === 'string' ? parentType : parentType.displayName || parentType.name;
-    if (parentName) {
-      addendum = ' Check the top-level render call using <' + parentName + '>.';
-    }
-  }
-
-  var memoizer = ownerHasKeyUseWarning[messageType] || (ownerHasKeyUseWarning[messageType] = {});
-  if (memoizer[addendum]) {
-    return null;
-  }
-  memoizer[addendum] = true;
-
-  var addenda = {
-    parentOrOwner: addendum,
-    url: ' See https://fb.me/react-warning-keys for more information.',
-    childOwner: null
-  };
-
-  // 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.
-  if (element && element._owner && element._owner !== ReactCurrentOwner.current) {
-    // Give the component that originally created this child.
-    addenda.childOwner = ' It was passed a child from ' + element._owner.getName() + '.';
-  }
-
-  return addenda;
-}
-
-/**
- * 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);
-          }
-        }
-      }
-    }
-  }
-}
-
-/**
- * Assert that the props are valid
- *
- * @param {string} componentName Name of the component for error messages.
- * @param {object} propTypes Map of prop name to a ReactPropType
- * @param {object} props
- * @param {string} location e.g. "prop", "context", "child context"
- * @private
- */
-function checkPropTypes(componentName, propTypes, props, location) {
-  for (var propName in propTypes) {
-    if (propTypes.hasOwnProperty(propName)) {
-      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 propTypes[propName] === 'function') ? "development" !== 'production' ? invariant(false, '%s: %s type `%s` is invalid; it must be a function, usually from ' + 'React.PropTypes.', componentName || 'React class', ReactPropTypeLocationNames[location], propName) : invariant(false) : undefined;
-        error = propTypes[propName](props, propName, componentName, location);
-      } catch (ex) {
-        error = ex;
-      }
-      "development" !== 'production' ? 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], propName, typeof error) : undefined;
-      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();
-        "development" !== 'production' ? warning(false, 'Failed propType: %s%s', error.message, addendum) : undefined;
-      }
-    }
-  }
-}
-
-/**
- * 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) {
-    checkPropTypes(name, componentClass.propTypes, element.props, ReactPropTypeLocations.prop);
-  }
-  if (typeof componentClass.getDefaultProps === 'function') {
-    "development" !== 'production' ? warning(componentClass.getDefaultProps.isReactClassApproved, 'getDefaultProps is only used on classic React.createClass ' + 'definitions. Use a static property named `defaultProps` instead.') : undefined;
-  }
-}
-
-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.
-    "development" !== 'production' ? warning(validType, 'React.createElement: type should not be null, undefined, boolean, or ' + 'number. It should be a string (for DOM elements) or a ReactClass ' + '(for composite components).%s', getDeclarationErrorAddendum()) : undefined;
-
-    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 ("development" !== 'production') {
-      if (canDefineProperty) {
-        Object.defineProperty(validatedFactory, 'type', {
-          enumerable: false,
-          get: function () {
-            "development" !== 'production' ? warning(false, 'Factory.type is deprecated. Access the class directly ' + 'before passing it to createFactory.') : undefined;
-            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;
-},{"104":104,"115":115,"144":144,"155":155,"34":34,"52":52,"72":72,"73":73}],54:[function(_dereq_,module,exports){
-/**
- * Copyright 2014-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactEmptyComponent
- */
-
-'use strict';
-
-var ReactElement = _dereq_(52);
-var ReactEmptyComponentRegistry = _dereq_(55);
-var ReactReconciler = _dereq_(76);
-
-var assign = _dereq_(23);
-
-var placeholderElement;
-
-var ReactEmptyComponentInjection = {
-  injectEmptyComponent: function (component) {
-    placeholderElement = ReactElement.createElement(component);
-  }
-};
-
-var ReactEmptyComponent = function (instantiate) {
-  this._currentElement = null;
-  this._rootNodeID = null;
-  this._renderedComponent = instantiate(placeholderElement);
-};
-assign(ReactEmptyComponent.prototype, {
-  construct: function (element) {},
-  mountComponent: function (rootID, transaction, context) {
-    ReactEmptyComponentRegistry.registerNullComponentID(rootID);
-    this._rootNodeID = rootID;
-    return ReactReconciler.mountComponent(this._renderedComponent, rootID, transaction, context);
-  },
-  receiveComponent: function () {},
-  unmountComponent: function (rootID, transaction, context) {
-    ReactReconciler.unmountComponent(this._renderedComponent);
-    ReactEmptyComponentRegistry.deregisterNullComponentID(this._rootNodeID);
-    this._rootNodeID = null;
-    this._renderedComponent = null;
-  }
-});
-
-ReactEmptyComponent.injection = ReactEmptyComponentInjection;
-
-module.exports = ReactEmptyComponent;
-},{"23":23,"52":52,"55":55,"76":76}],55:[function(_dereq_,module,exports){
-/**
- * Copyright 2014-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactEmptyComponentRegistry
- */
-
-'use strict';
-
-// This registry keeps track of the React IDs of the components that rendered to
-// `null` (in reality a placeholder such as `noscript`)
-var nullComponentIDsRegistry = {};
-
-/**
- * @param {string} id Component's `_rootNodeID`.
- * @return {boolean} True if the component is rendered to null.
- */
-function isNullComponentID(id) {
-  return !!nullComponentIDsRegistry[id];
-}
-
-/**
- * Mark the component as having rendered to null.
- * @param {string} id Component's `_rootNodeID`.
- */
-function registerNullComponentID(id) {
-  nullComponentIDsRegistry[id] = true;
-}
-
-/**
- * Unmark the component as having rendered to null: it renders to something now.
- * @param {string} id Component's `_rootNodeID`.
- */
-function deregisterNullComponentID(id) {
-  delete nullComponentIDsRegistry[id];
-}
-
-var ReactEmptyComponentRegistry = {
-  isNullComponentID: isNullComponentID,
-  registerNullComponentID: registerNullComponentID,
-  deregisterNullComponentID: deregisterNullComponentID
-};
-
-module.exports = ReactEmptyComponentRegistry;
-},{}],56:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactErrorUtils
- * @typechecks
- */
-
-'use strict';
-
-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, b) {
-  try {
-    return func(a, b);
-  } catch (x) {
-    if (caughtError === null) {
-      caughtError = x;
-    }
-    return undefined;
-  }
-}
-
-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 ("development" !== 'production') {
-  /**
-   * 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, b) {
-      var boundFunc = func.bind(null, a, b);
-      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;
-},{}],57:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactEventEmitterMixin
- */
-
-'use strict';
-
-var EventPluginHub = _dereq_(16);
-
-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.
-   *
-   * @param {string} topLevelType Record from `EventConstants`.
-   * @param {object} topLevelTarget The listening component root node.
-   * @param {string} topLevelTargetID ID of `topLevelTarget`.
-   * @param {object} nativeEvent Native environment event.
-   */
-  handleTopLevel: function (topLevelType, topLevelTarget, topLevelTargetID, nativeEvent, nativeEventTarget) {
-    var events = EventPluginHub.extractEvents(topLevelType, topLevelTarget, topLevelTargetID, nativeEvent, nativeEventTarget);
-    runEventQueueInBatch(events);
-  }
-};
-
-module.exports = ReactEventEmitterMixin;
-},{"16":16}],58:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactEventListener
- * @typechecks static-only
- */
-
-'use strict';
-
-var EventListener = _dereq_(129);
-var ExecutionEnvironment = _dereq_(130);
-var PooledClass = _dereq_(24);
-var ReactInstanceHandles = _dereq_(61);
-var ReactMount = _dereq_(65);
-var ReactUpdates = _dereq_(83);
-
-var assign = _dereq_(23);
-var getEventTarget = _dereq_(114);
-var getUnboundedScrollPosition = _dereq_(141);
-
-var DOCUMENT_FRAGMENT_NODE_TYPE = 11;
-
-/**
- * Finds the parent React component of `node`.
- *
- * @param {*} node
- * @return {?DOMEventTarget} Parent container, or `null` if the specified node
- *                           is not nested.
- */
-function findParent(node) {
-  // 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.
-  var nodeID = ReactMount.getID(node);
-  var rootID = ReactInstanceHandles.getReactRootIDFromNodeID(nodeID);
-  var container = ReactMount.findReactContainerForID(rootID);
-  var parent = ReactMount.getFirstReactDOM(container);
-  return parent;
-}
-
-// 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) {
-  // TODO: Re-enable event.path handling
-  //
-  // if (bookKeeping.nativeEvent.path && bookKeeping.nativeEvent.path.length > 1) {
-  //   // New browsers have a path attribute on native events
-  //   handleTopLevelWithPath(bookKeeping);
-  // } else {
-  //   // Legacy browsers don't have a path attribute on native events
-  //   handleTopLevelWithoutPath(bookKeeping);
-  // }
-
-  void handleTopLevelWithPath; // temporarily unused
-  handleTopLevelWithoutPath(bookKeeping);
-}
-
-// Legacy browsers don't have a path attribute on native events
-function handleTopLevelWithoutPath(bookKeeping) {
-  var topLevelTarget = ReactMount.getFirstReactDOM(getEventTarget(bookKeeping.nativeEvent)) || window;
-
-  // 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 = topLevelTarget;
-  while (ancestor) {
-    bookKeeping.ancestors.push(ancestor);
-    ancestor = findParent(ancestor);
-  }
-
-  for (var i = 0; i < bookKeeping.ancestors.length; i++) {
-    topLevelTarget = bookKeeping.ancestors[i];
-    var topLevelTargetID = ReactMount.getID(topLevelTarget) || '';
-    ReactEventListener._handleTopLevel(bookKeeping.topLevelType, topLevelTarget, topLevelTargetID, bookKeeping.nativeEvent, getEventTarget(bookKeeping.nativeEvent));
-  }
-}
-
-// New browsers have a path attribute on native events
-function handleTopLevelWithPath(bookKeeping) {
-  var path = bookKeeping.nativeEvent.path;
-  var currentNativeTarget = path[0];
-  var eventsFired = 0;
-  for (var i = 0; i < path.length; i++) {
-    var currentPathElement = path[i];
-    if (currentPathElement.nodeType === DOCUMENT_FRAGMENT_NODE_TYPE) {
-      currentNativeTarget = path[i + 1];
-    }
-    // TODO: slow
-    var reactParent = ReactMount.getFirstReactDOM(currentPathElement);
-    if (reactParent === currentPathElement) {
-      var currentPathElementID = ReactMount.getID(currentPathElement);
-      var newRootID = ReactInstanceHandles.getReactRootIDFromNodeID(currentPathElementID);
-      bookKeeping.ancestors.push(currentPathElement);
-
-      var topLevelTargetID = ReactMount.getID(currentPathElement) || '';
-      eventsFired++;
-      ReactEventListener._handleTopLevel(bookKeeping.topLevelType, currentPathElement, topLevelTargetID, bookKeeping.nativeEvent, currentNativeTarget);
-
-      // Jump to the root of this React render tree
-      while (currentPathElementID !== newRootID) {
-        i++;
-        currentPathElement = path[i];
-        currentPathElementID = ReactMount.getID(currentPathElement);
-      }
-    }
-  }
-  if (eventsFired === 0) {
-    ReactEventListener._handleTopLevel(bookKeeping.topLevelType, window, '', 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} handle 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, handle) {
-    var element = handle;
-    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} handle 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, handle) {
-    var element = handle;
-    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;
-},{"114":114,"129":129,"130":130,"141":141,"23":23,"24":24,"61":61,"65":65,"83":83}],59:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactInjection
- */
-
-'use strict';
-
-var DOMProperty = _dereq_(10);
-var EventPluginHub = _dereq_(16);
-var ReactComponentEnvironment = _dereq_(32);
-var ReactClass = _dereq_(29);
-var ReactEmptyComponent = _dereq_(54);
-var ReactBrowserEventEmitter = _dereq_(26);
-var ReactNativeComponent = _dereq_(68);
-var ReactPerf = _dereq_(71);
-var ReactRootIndex = _dereq_(78);
-var ReactUpdates = _dereq_(83);
-
-var ReactInjection = {
-  Component: ReactComponentEnvironment.injection,
-  Class: ReactClass.injection,
-  DOMProperty: DOMProperty.injection,
-  EmptyComponent: ReactEmptyComponent.injection,
-  EventPluginHub: EventPluginHub.injection,
-  EventEmitter: ReactBrowserEventEmitter.injection,
-  NativeComponent: ReactNativeComponent.injection,
-  Perf: ReactPerf.injection,
-  RootIndex: ReactRootIndex.injection,
-  Updates: ReactUpdates.injection
-};
-
-module.exports = ReactInjection;
-},{"10":10,"16":16,"26":26,"29":29,"32":32,"54":54,"68":68,"71":71,"78":78,"83":83}],60:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactInputSelection
- */
-
-'use strict';
-
-var ReactDOMSelection = _dereq_(44);
-
-var containsNode = _dereq_(133);
-var focusNode = _dereq_(138);
-var getActiveElement = _dereq_(139);
-
-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 (typeof 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;
-},{"133":133,"138":138,"139":139,"44":44}],61:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactInstanceHandles
- * @typechecks static-only
- */
-
-'use strict';
-
-var ReactRootIndex = _dereq_(78);
-
-var invariant = _dereq_(144);
-
-var SEPARATOR = '.';
-var SEPARATOR_LENGTH = SEPARATOR.length;
-
-/**
- * Maximum depth of traversals before we consider the possibility of a bad ID.
- */
-var MAX_TREE_DEPTH = 10000;
-
-/**
- * Creates a DOM ID prefix to use when mounting React components.
- *
- * @param {number} index A unique integer
- * @return {string} React root ID.
- * @internal
- */
-function getReactRootIDString(index) {
-  return SEPARATOR + index.toString(36);
-}
-
-/**
- * Checks if a character in the supplied ID is a separator or the end.
- *
- * @param {string} id A React DOM ID.
- * @param {number} index Index of the character to check.
- * @return {boolean} True if the character is a separator or end of the ID.
- * @private
- */
-function isBoundary(id, index) {
-  return id.charAt(index) === SEPARATOR || index === id.length;
-}
-
-/**
- * Checks if the supplied string is a valid React DOM ID.
- *
- * @param {string} id A React DOM ID, maybe.
- * @return {boolean} True if the string is a valid React DOM ID.
- * @private
- */
-function isValidID(id) {
-  return id === '' || id.charAt(0) === SEPARATOR && id.charAt(id.length - 1) !== SEPARATOR;
-}
-
-/**
- * Checks if the first ID is an ancestor of or equal to the second ID.
- *
- * @param {string} ancestorID
- * @param {string} descendantID
- * @return {boolean} True if `ancestorID` is an ancestor of `descendantID`.
- * @internal
- */
-function isAncestorIDOf(ancestorID, descendantID) {
-  return descendantID.indexOf(ancestorID) === 0 && isBoundary(descendantID, ancestorID.length);
-}
-
-/**
- * Gets the parent ID of the supplied React DOM ID, `id`.
- *
- * @param {string} id ID of a component.
- * @return {string} ID of the parent, or an empty string.
- * @private
- */
-function getParentID(id) {
-  return id ? id.substr(0, id.lastIndexOf(SEPARATOR)) : '';
-}
-
-/**
- * Gets the next DOM ID on the tree path from the supplied `ancestorID` to the
- * supplied `destinationID`. If they are equal, the ID is returned.
- *
- * @param {string} ancestorID ID of an ancestor node of `destinationID`.
- * @param {string} destinationID ID of the destination node.
- * @return {string} Next ID on the path from `ancestorID` to `destinationID`.
- * @private
- */
-function getNextDescendantID(ancestorID, destinationID) {
-  !(isValidID(ancestorID) && isValidID(destinationID)) ? "development" !== 'production' ? invariant(false, 'getNextDescendantID(%s, %s): Received an invalid React DOM ID.', ancestorID, destinationID) : invariant(false) : undefined;
-  !isAncestorIDOf(ancestorID, destinationID) ? "development" !== 'production' ? invariant(false, 'getNextDescendantID(...): React has made an invalid assumption about ' + 'the DOM hierarchy. Expected `%s` to be an ancestor of `%s`.', ancestorID, destinationID) : invariant(false) : undefined;
-  if (ancestorID === destinationID) {
-    return ancestorID;
-  }
-  // Skip over the ancestor and the immediate separator. Traverse until we hit
-  // another separator or we reach the end of `destinationID`.
-  var start = ancestorID.length + SEPARATOR_LENGTH;
-  var i;
-  for (i = start; i < destinationID.length; i++) {
-    if (isBoundary(destinationID, i)) {
-      break;
-    }
-  }
-  return destinationID.substr(0, i);
-}
-
-/**
- * Gets the nearest common ancestor ID of two IDs.
- *
- * Using this ID scheme, the nearest common ancestor ID is the longest common
- * prefix of the two IDs that immediately preceded a "marker" in both strings.
- *
- * @param {string} oneID
- * @param {string} twoID
- * @return {string} Nearest common ancestor ID, or the empty string if none.
- * @private
- */
-function getFirstCommonAncestorID(oneID, twoID) {
-  var minLength = Math.min(oneID.length, twoID.length);
-  if (minLength === 0) {
-    return '';
-  }
-  var lastCommonMarkerIndex = 0;
-  // Use `<=` to traverse until the "EOL" of the shorter string.
-  for (var i = 0; i <= minLength; i++) {
-    if (isBoundary(oneID, i) && isBoundary(twoID, i)) {
-      lastCommonMarkerIndex = i;
-    } else if (oneID.charAt(i) !== twoID.charAt(i)) {
-      break;
-    }
-  }
-  var longestCommonID = oneID.substr(0, lastCommonMarkerIndex);
-  !isValidID(longestCommonID) ? "development" !== 'production' ? invariant(false, 'getFirstCommonAncestorID(%s, %s): Expected a valid React DOM ID: %s', oneID, twoID, longestCommonID) : invariant(false) : undefined;
-  return longestCommonID;
-}
-
-/**
- * Traverses the parent path between two IDs (either up or down). The IDs must
- * not be the same, and there must exist a parent path between them. If the
- * callback returns `false`, traversal is stopped.
- *
- * @param {?string} start ID at which to start traversal.
- * @param {?string} stop ID at which to end traversal.
- * @param {function} cb Callback to invoke each ID with.
- * @param {*} arg Argument to invoke the callback with.
- * @param {?boolean} skipFirst Whether or not to skip the first node.
- * @param {?boolean} skipLast Whether or not to skip the last node.
- * @private
- */
-function traverseParentPath(start, stop, cb, arg, skipFirst, skipLast) {
-  start = start || '';
-  stop = stop || '';
-  !(start !== stop) ? "development" !== 'production' ? invariant(false, 'traverseParentPath(...): Cannot traverse from and to the same ID, `%s`.', start) : invariant(false) : undefined;
-  var traverseUp = isAncestorIDOf(stop, start);
-  !(traverseUp || isAncestorIDOf(start, stop)) ? "development" !== 'production' ? invariant(false, 'traverseParentPath(%s, %s, ...): Cannot traverse from two IDs that do ' + 'not have a parent path.', start, stop) : invariant(false) : undefined;
-  // Traverse from `start` to `stop` one depth at a time.
-  var depth = 0;
-  var traverse = traverseUp ? getParentID : getNextDescendantID;
-  for (var id = start;; /* until break */id = traverse(id, stop)) {
-    var ret;
-    if ((!skipFirst || id !== start) && (!skipLast || id !== stop)) {
-      ret = cb(id, traverseUp, arg);
-    }
-    if (ret === false || id === stop) {
-      // Only break //after// visiting `stop`.
-      break;
-    }
-    !(depth++ < MAX_TREE_DEPTH) ? "development" !== 'production' ? invariant(false, 'traverseParentPath(%s, %s, ...): Detected an infinite loop while ' + 'traversing the React DOM ID tree. This may be due to malformed IDs: %s', start, stop, id) : invariant(false) : undefined;
-  }
-}
-
-/**
- * Manages the IDs assigned to DOM representations of React components. This
- * uses a specific scheme in order to traverse the DOM efficiently (e.g. in
- * order to simulate events).
- *
- * @internal
- */
-var ReactInstanceHandles = {
-
-  /**
-   * Constructs a React root ID
-   * @return {string} A React root ID.
-   */
-  createReactRootID: function () {
-    return getReactRootIDString(ReactRootIndex.createReactRootIndex());
-  },
-
-  /**
-   * Constructs a React ID by joining a root ID with a name.
-   *
-   * @param {string} rootID Root ID of a parent component.
-   * @param {string} name A component's name (as flattened children).
-   * @return {string} A React ID.
-   * @internal
-   */
-  createReactID: function (rootID, name) {
-    return rootID + name;
-  },
-
-  /**
-   * Gets the DOM ID of the React component that is the root of the tree that
-   * contains the React component with the supplied DOM ID.
-   *
-   * @param {string} id DOM ID of a React component.
-   * @return {?string} DOM ID of the React component that is the root.
-   * @internal
-   */
-  getReactRootIDFromNodeID: function (id) {
-    if (id && id.charAt(0) === SEPARATOR && id.length > 1) {
-      var index = id.indexOf(SEPARATOR, 1);
-      return index > -1 ? id.substr(0, index) : id;
-    }
-    return null;
-  },
-
-  /**
-   * Traverses the ID hierarchy and invokes the supplied `cb` on any IDs that
-   * should would receive a `mouseEnter` or `mouseLeave` event.
-   *
-   * NOTE: Does not invoke the callback on the nearest common ancestor because
-   * nothing "entered" or "left" that element.
-   *
-   * @param {string} leaveID ID being left.
-   * @param {string} enterID ID being entered.
-   * @param {function} cb Callback to invoke on each entered/left ID.
-   * @param {*} upArg Argument to invoke the callback with on left IDs.
-   * @param {*} downArg Argument to invoke the callback with on entered IDs.
-   * @internal
-   */
-  traverseEnterLeave: function (leaveID, enterID, cb, upArg, downArg) {
-    var ancestorID = getFirstCommonAncestorID(leaveID, enterID);
-    if (ancestorID !== leaveID) {
-      traverseParentPath(leaveID, ancestorID, cb, upArg, false, true);
-    }
-    if (ancestorID !== enterID) {
-      traverseParentPath(ancestorID, enterID, cb, downArg, true, false);
-    }
-  },
-
-  /**
-   * Simulates the traversal of a two-phase, capture/bubble event dispatch.
-   *
-   * NOTE: This traversal happens on IDs without touching the DOM.
-   *
-   * @param {string} targetID ID of the target node.
-   * @param {function} cb Callback to invoke.
-   * @param {*} arg Argument to invoke the callback with.
-   * @internal
-   */
-  traverseTwoPhase: function (targetID, cb, arg) {
-    if (targetID) {
-      traverseParentPath('', targetID, cb, arg, true, false);
-      traverseParentPath(targetID, '', cb, arg, false, true);
-    }
-  },
-
-  /**
-   * Same as `traverseTwoPhase` but skips the `targetID`.
-   */
-  traverseTwoPhaseSkipTarget: function (targetID, cb, arg) {
-    if (targetID) {
-      traverseParentPath('', targetID, cb, arg, true, true);
-      traverseParentPath(targetID, '', cb, arg, true, true);
-    }
-  },
-
-  /**
-   * Traverse a node ID, calling the supplied `cb` for each ancestor ID. For
-   * example, passing `.0.$row-0.1` would result in `cb` getting called
-   * with `.0`, `.0.$row-0`, and `.0.$row-0.1`.
-   *
-   * NOTE: This traversal happens on IDs without touching the DOM.
-   *
-   * @param {string} targetID ID of the target node.
-   * @param {function} cb Callback to invoke.
-   * @param {*} arg Argument to invoke the callback with.
-   * @internal
-   */
-  traverseAncestors: function (targetID, cb, arg) {
-    traverseParentPath('', targetID, cb, arg, true, false);
-  },
-
-  getFirstCommonAncestorID: getFirstCommonAncestorID,
-
-  /**
-   * Exposed for unit testing.
-   * @private
-   */
-  _getNextDescendantID: getNextDescendantID,
-
-  isAncestorIDOf: isAncestorIDOf,
-
-  SEPARATOR: SEPARATOR
-
-};
-
-module.exports = ReactInstanceHandles;
-},{"144":144,"78":78}],62:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactInstanceMap
- */
-
-'use strict';
-
-/**
- * `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;
-},{}],63:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactIsomorphic
- */
-
-'use strict';
-
-var ReactChildren = _dereq_(28);
-var ReactComponent = _dereq_(30);
-var ReactClass = _dereq_(29);
-var ReactDOMFactories = _dereq_(38);
-var ReactElement = _dereq_(52);
-var ReactElementValidator = _dereq_(53);
-var ReactPropTypes = _dereq_(74);
-var ReactVersion = _dereq_(84);
-
-var assign = _dereq_(23);
-var onlyChild = _dereq_(121);
-
-var createElement = ReactElement.createElement;
-var createFactory = ReactElement.createFactory;
-var cloneElement = ReactElement.cloneElement;
-
-if ("development" !== 'production') {
-  createElement = ReactElementValidator.createElement;
-  createFactory = ReactElementValidator.createFactory;
-  cloneElement = ReactElementValidator.cloneElement;
-}
-
-var React = {
-
-  // Modern
-
-  Children: {
-    map: ReactChildren.map,
-    forEach: ReactChildren.forEach,
-    count: ReactChildren.count,
-    toArray: ReactChildren.toArray,
-    only: onlyChild
-  },
-
-  Component: ReactComponent,
-
-  createElement: createElement,
-  cloneElement: cloneElement,
-  isValidElement: ReactElement.isValidElement,
-
-  // Classic
-
-  PropTypes: ReactPropTypes,
-  createClass: ReactClass.createClass,
-  createFactory: createFactory,
-  createMixin: function (mixin) {
-    // Currently a noop. Will be used to validate and trace mixins.
-    return mixin;
-  },
-
-  // This looks DOM specific but these are actually isomorphic helpers
-  // since they are just generating DOM strings.
-  DOM: ReactDOMFactories,
-
-  version: ReactVersion,
-
-  // Hook for JSX spread, don't use this for anything else.
-  __spread: assign
-};
-
-module.exports = React;
-},{"121":121,"23":23,"28":28,"29":29,"30":30,"38":38,"52":52,"53":53,"74":74,"84":84}],64:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactMarkupChecksum
- */
-
-'use strict';
-
-var adler32 = _dereq_(103);
-
-var TAG_END = /\/?>/;
-
-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 and self-closing tags)
-    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;
-},{"103":103}],65:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactMount
- */
-
-'use strict';
-
-var DOMProperty = _dereq_(10);
-var ReactBrowserEventEmitter = _dereq_(26);
-var ReactCurrentOwner = _dereq_(34);
-var ReactDOMFeatureFlags = _dereq_(39);
-var ReactElement = _dereq_(52);
-var ReactEmptyComponentRegistry = _dereq_(55);
-var ReactInstanceHandles = _dereq_(61);
-var ReactInstanceMap = _dereq_(62);
-var ReactMarkupChecksum = _dereq_(64);
-var ReactPerf = _dereq_(71);
-var ReactReconciler = _dereq_(76);
-var ReactUpdateQueue = _dereq_(82);
-var ReactUpdates = _dereq_(83);
-
-var assign = _dereq_(23);
-var emptyObject = _dereq_(137);
-var containsNode = _dereq_(133);
-var instantiateReactComponent = _dereq_(118);
-var invariant = _dereq_(144);
-var setInnerHTML = _dereq_(124);
-var shouldUpdateReactComponent = _dereq_(126);
-var validateDOMNesting = _dereq_(128);
-var warning = _dereq_(155);
-
-var ATTR_NAME = DOMProperty.ID_ATTRIBUTE_NAME;
-var nodeCache = {};
-
-var ELEMENT_NODE_TYPE = 1;
-var DOC_NODE_TYPE = 9;
-var DOCUMENT_FRAGMENT_NODE_TYPE = 11;
-
-var ownerDocumentContextKey = '__ReactMount_ownerDocument$' + Math.random().toString(36).slice(2);
-
-/** Mapping from reactRootID to React component instance. */
-var instancesByReactRootID = {};
-
-/** Mapping from reactRootID to `container` nodes. */
-var containersByReactRootID = {};
-
-if ("development" !== 'production') {
-  /** __DEV__-only mapping from reactRootID to root elements. */
-  var rootElementsByReactRootID = {};
-}
-
-// Used to store breadth-first search state in findComponentRoot.
-var findComponentRootReusableArray = [];
-
-/**
- * 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;
-  }
-}
-
-/**
- * @param {DOMElement} container DOM element that may contain a React component.
- * @return {?string} A "reactRoot" ID, if a React component is rendered.
- */
-function getReactRootID(container) {
-  var rootElement = getReactRootElementInContainer(container);
-  return rootElement && ReactMount.getID(rootElement);
-}
-
-/**
- * Accessing node[ATTR_NAME] or calling getAttribute(ATTR_NAME) on a form
- * element can return its control whose name or ID equals ATTR_NAME. All
- * DOM nodes support `getAttributeNode` but this can also get called on
- * other objects so just return '' if we're given something other than a
- * DOM node (such as window).
- *
- * @param {?DOMElement|DOMWindow|DOMDocument|DOMTextNode} node DOM node.
- * @return {string} ID of the supplied `domNode`.
- */
-function getID(node) {
-  var id = internalGetID(node);
-  if (id) {
-    if (nodeCache.hasOwnProperty(id)) {
-      var cached = nodeCache[id];
-      if (cached !== node) {
-        !!isValid(cached, id) ? "development" !== 'production' ? invariant(false, 'ReactMount: Two valid but unequal nodes with the same `%s`: %s', ATTR_NAME, id) : invariant(false) : undefined;
-
-        nodeCache[id] = node;
-      }
-    } else {
-      nodeCache[id] = node;
-    }
-  }
-
-  return id;
-}
-
-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 && node.getAttribute && node.getAttribute(ATTR_NAME) || '';
-}
-
-/**
- * Sets the React-specific ID of the given node.
- *
- * @param {DOMElement} node The DOM node whose ID will be set.
- * @param {string} id The value of the ID attribute.
- */
-function setID(node, id) {
-  var oldID = internalGetID(node);
-  if (oldID !== id) {
-    delete nodeCache[oldID];
-  }
-  node.setAttribute(ATTR_NAME, id);
-  nodeCache[id] = node;
-}
-
-/**
- * Finds the node with the supplied React-generated DOM ID.
- *
- * @param {string} id A React-generated DOM ID.
- * @return {DOMElement} DOM node with the suppled `id`.
- * @internal
- */
-function getNode(id) {
-  if (!nodeCache.hasOwnProperty(id) || !isValid(nodeCache[id], id)) {
-    nodeCache[id] = ReactMount.findReactNodeByID(id);
-  }
-  return nodeCache[id];
-}
-
-/**
- * Finds the node with the supplied public React instance.
- *
- * @param {*} instance A public React instance.
- * @return {?DOMElement} DOM node with the suppled `id`.
- * @internal
- */
-function getNodeFromInstance(instance) {
-  var id = ReactInstanceMap.get(instance)._rootNodeID;
-  if (ReactEmptyComponentRegistry.isNullComponentID(id)) {
-    return null;
-  }
-  if (!nodeCache.hasOwnProperty(id) || !isValid(nodeCache[id], id)) {
-    nodeCache[id] = ReactMount.findReactNodeByID(id);
-  }
-  return nodeCache[id];
-}
-
-/**
- * A node is "valid" if it is contained by a currently mounted container.
- *
- * This means that the node does not have to be contained by a document in
- * order to be considered valid.
- *
- * @param {?DOMElement} node The candidate DOM node.
- * @param {string} id The expected ID of the node.
- * @return {boolean} Whether the node is contained by a mounted container.
- */
-function isValid(node, id) {
-  if (node) {
-    !(internalGetID(node) === id) ? "development" !== 'production' ? invariant(false, 'ReactMount: Unexpected modification of `%s`', ATTR_NAME) : invariant(false) : undefined;
-
-    var container = ReactMount.findReactContainerForID(id);
-    if (container && containsNode(container, node)) {
-      return true;
-    }
-  }
-
-  return false;
-}
-
-/**
- * Causes the cache to forget about one React-specific ID.
- *
- * @param {string} id The ID to forget.
- */
-function purgeID(id) {
-  delete nodeCache[id];
-}
-
-var deepestNodeSoFar = null;
-function findDeepestCachedAncestorImpl(ancestorID) {
-  var ancestor = nodeCache[ancestorID];
-  if (ancestor && isValid(ancestor, ancestorID)) {
-    deepestNodeSoFar = ancestor;
-  } else {
-    // This node isn't populated in the cache, so presumably none of its
-    // descendants are. Break out of the loop.
-    return false;
-  }
-}
-
-/**
- * Return the deepest cached node whose ID is a prefix of `targetID`.
- */
-function findDeepestCachedAncestor(targetID) {
-  deepestNodeSoFar = null;
-  ReactInstanceHandles.traverseAncestors(targetID, findDeepestCachedAncestorImpl);
-
-  var foundNode = deepestNodeSoFar;
-  deepestNodeSoFar = null;
-  return foundNode;
-}
-
-/**
- * Mounts this component and inserts it into the DOM.
- *
- * @param {ReactComponent} componentInstance The instance to mount.
- * @param {string} rootID DOM ID of the root node.
- * @param {DOMElement} container DOM element to mount into.
- * @param {ReactReconcileTransaction} transaction
- * @param {boolean} shouldReuseMarkup If true, do not insert markup
- */
-function mountComponentIntoNode(componentInstance, rootID, container, transaction, shouldReuseMarkup, context) {
-  if (ReactDOMFeatureFlags.useCreateElement) {
-    context = assign({}, context);
-    if (container.nodeType === DOC_NODE_TYPE) {
-      context[ownerDocumentContextKey] = container;
-    } else {
-      context[ownerDocumentContextKey] = container.ownerDocument;
-    }
-  }
-  if ("development" !== 'production') {
-    if (context === emptyObject) {
-      context = {};
-    }
-    var tag = container.nodeName.toLowerCase();
-    context[validateDOMNesting.ancestorInfoContextKey] = validateDOMNesting.updatedAncestorInfo(null, tag, null);
-  }
-  var markup = ReactReconciler.mountComponent(componentInstance, rootID, transaction, context);
-  componentInstance._renderedComponent._topLevelWrapper = componentInstance;
-  ReactMount._mountImageIntoNode(markup, container, shouldReuseMarkup, transaction);
-}
-
-/**
- * Batched mount.
- *
- * @param {ReactComponent} componentInstance The instance to mount.
- * @param {string} rootID DOM ID of the root node.
- * @param {DOMElement} container DOM element to mount into.
- * @param {boolean} shouldReuseMarkup If true, do not insert markup
- */
-function batchedMountComponentIntoNode(componentInstance, rootID, container, shouldReuseMarkup, context) {
-  var transaction = ReactUpdates.ReactReconcileTransaction.getPooled(
-  /* forceHTML */shouldReuseMarkup);
-  transaction.perform(mountComponentIntoNode, null, componentInstance, rootID, 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) {
-  ReactReconciler.unmountComponent(instance);
-
-  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(node) {
-  var reactRootID = getReactRootID(node);
-  return reactRootID ? reactRootID !== ReactInstanceHandles.getReactRootIDFromNodeID(reactRootID) : false;
-}
-
-/**
- * Returns the first (deepest) ancestor of a node which is rendered by this copy
- * of React.
- */
-function findFirstReactDOMImpl(node) {
-  // This node might be from another React instance, so we make sure not to
-  // examine the node cache here
-  for (; node && node.parentNode !== node; node = node.parentNode) {
-    if (node.nodeType !== 1) {
-      // Not a DOMElement, therefore not a React component
-      continue;
-    }
-    var nodeID = internalGetID(node);
-    if (!nodeID) {
-      continue;
-    }
-    var reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(nodeID);
-
-    // If containersByReactRootID contains the container we find by crawling up
-    // the tree, we know that this instance of React rendered the node.
-    // nb. isValid's strategy (with containsNode) does not work because render
-    // trees may be nested and we don't want a false positive in that case.
-    var current = node;
-    var lastID;
-    do {
-      lastID = internalGetID(current);
-      current = current.parentNode;
-      if (current == null) {
-        // The passed-in node has been detached from the container it was
-        // originally rendered into.
-        return null;
-      }
-    } while (lastID !== reactRootID);
-
-    if (current === containersByReactRootID[reactRootID]) {
-      return node;
-    }
-  }
-  return 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 TopLevelWrapper = function () {};
-TopLevelWrapper.prototype.isReactComponent = {};
-if ("development" !== 'production') {
-  TopLevelWrapper.displayName = 'TopLevelWrapper';
-}
-TopLevelWrapper.prototype.render = function () {
-  // this.props is actually a ReactElement
-  return this.props;
-};
-
-/**
- * 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,
-
-  /** Exposed for debugging purposes **/
-  _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, container, callback) {
-    ReactMount.scrollMonitor(container, function () {
-      ReactUpdateQueue.enqueueElementInternal(prevComponent, nextElement);
-      if (callback) {
-        ReactUpdateQueue.enqueueCallbackInternal(prevComponent, callback);
-      }
-    });
-
-    if ("development" !== 'production') {
-      // Record the root element in case it later gets transplanted.
-      rootElementsByReactRootID[getReactRootID(container)] = getReactRootElementInContainer(container);
-    }
-
-    return prevComponent;
-  },
-
-  /**
-   * Register a component into the instance map and starts scroll value
-   * monitoring
-   * @param {ReactComponent} nextComponent component instance to render
-   * @param {DOMElement} container container to render into
-   * @return {string} reactRoot ID prefix
-   */
-  _registerComponent: function (nextComponent, container) {
-    !(container && (container.nodeType === ELEMENT_NODE_TYPE || container.nodeType === DOC_NODE_TYPE || container.nodeType === DOCUMENT_FRAGMENT_NODE_TYPE)) ? "development" !== 'production' ? invariant(false, '_registerComponent(...): Target container is not a DOM element.') : invariant(false) : undefined;
-
-    ReactBrowserEventEmitter.ensureScrollValueMonitoring();
-
-    var reactRootID = ReactMount.registerContainer(container);
-    instancesByReactRootID[reactRootID] = nextComponent;
-    return reactRootID;
-  },
-
-  /**
-   * Render a new component into the DOM.
-   * @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.
-    "development" !== 'production' ? 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') : undefined;
-
-    var componentInstance = instantiateReactComponent(nextElement, null);
-    var reactRootID = ReactMount._registerComponent(componentInstance, container);
-
-    // 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, reactRootID, container, shouldReuseMarkup, context);
-
-    if ("development" !== 'production') {
-      // Record the root element in case it later gets transplanted.
-      rootElementsByReactRootID[reactRootID] = getReactRootElementInContainer(container);
-    }
-
-    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 && parentComponent._reactInternalInstance != null) ? "development" !== 'production' ? invariant(false, 'parentComponent must be a valid React Component') : invariant(false) : undefined;
-    return ReactMount._renderSubtreeIntoContainer(parentComponent, nextElement, container, callback);
-  },
-
-  _renderSubtreeIntoContainer: function (parentComponent, nextElement, container, callback) {
-    !ReactElement.isValidElement(nextElement) ? "development" !== 'production' ? invariant(false, 'ReactDOM.render(): Invalid component element.%s', typeof nextElement === 'string' ? ' Instead of passing an element string, make sure to instantiate ' + 'it by passing it to React.createElement.' : typeof nextElement === 'function' ? ' Instead of passing a component class, make sure to instantiate ' + 'it by passing it to React.createElement.' :
-    // Check if it quacks like an element
-    nextElement != null && nextElement.props !== undefined ? ' This may be caused by unintentionally loading two independent ' + 'copies of React.' : '') : invariant(false) : undefined;
-
-    "development" !== 'production' ? 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.') : undefined;
-
-    var nextWrappedElement = new ReactElement(TopLevelWrapper, null, null, null, null, null, nextElement);
-
-    var prevComponent = instancesByReactRootID[getReactRootID(container)];
-
-    if (prevComponent) {
-      var prevWrappedElement = prevComponent._currentElement;
-      var prevElement = prevWrappedElement.props;
-      if (shouldUpdateReactComponent(prevElement, nextElement)) {
-        var publicInst = prevComponent._renderedComponent.getPublicInstance();
-        var updatedCallback = callback && function () {
-          callback.call(publicInst);
-        };
-        ReactMount._updateRootComponent(prevComponent, nextWrappedElement, container, updatedCallback);
-        return publicInst;
-      } else {
-        ReactMount.unmountComponentAtNode(container);
-      }
-    }
-
-    var reactRootElement = getReactRootElementInContainer(container);
-    var containerHasReactMarkup = reactRootElement && !!internalGetID(reactRootElement);
-    var containerHasNonRootReactChild = hasNonRootReactChild(container);
-
-    if ("development" !== 'production') {
-      "development" !== 'production' ? 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.') : undefined;
-
-      if (!containerHasReactMarkup || reactRootElement.nextSibling) {
-        var rootElementSibling = reactRootElement;
-        while (rootElementSibling) {
-          if (internalGetID(rootElementSibling)) {
-            "development" !== 'production' ? 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.') : undefined;
-            break;
-          }
-          rootElementSibling = rootElementSibling.nextSibling;
-        }
-      }
-    }
-
-    var shouldReuseMarkup = containerHasReactMarkup && !prevComponent && !containerHasNonRootReactChild;
-    var component = ReactMount._renderNewRootComponent(nextWrappedElement, container, shouldReuseMarkup, parentComponent != null ? parentComponent._reactInternalInstance._processChildContext(parentComponent._reactInternalInstance._context) : emptyObject)._renderedComponent.getPublicInstance();
-    if (callback) {
-      callback.call(component);
-    }
-    return component;
-  },
-
-  /**
-   * 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 {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);
-  },
-
-  /**
-   * Registers a container node into which React components will be rendered.
-   * This also creates the "reactRoot" ID that will be assigned to the element
-   * rendered within.
-   *
-   * @param {DOMElement} container DOM element to register as a container.
-   * @return {string} The "reactRoot" ID of elements rendered within.
-   */
-  registerContainer: function (container) {
-    var reactRootID = getReactRootID(container);
-    if (reactRootID) {
-      // If one exists, make sure it is a valid "reactRoot" ID.
-      reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(reactRootID);
-    }
-    if (!reactRootID) {
-      // No valid "reactRoot" ID found, create one.
-      reactRootID = ReactInstanceHandles.createReactRootID();
-    }
-    containersByReactRootID[reactRootID] = container;
-    return reactRootID;
-  },
-
-  /**
-   * Unmounts and destroys the React component rendered in the `container`.
-   *
-   * @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.)
-    "development" !== 'production' ? 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') : undefined;
-
-    !(container && (container.nodeType === ELEMENT_NODE_TYPE || container.nodeType === DOC_NODE_TYPE || container.nodeType === DOCUMENT_FRAGMENT_NODE_TYPE)) ? "development" !== 'production' ? invariant(false, 'unmountComponentAtNode(...): Target container is not a DOM element.') : invariant(false) : undefined;
-
-    var reactRootID = getReactRootID(container);
-    var component = instancesByReactRootID[reactRootID];
-    if (!component) {
-      // 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 containerID = internalGetID(container);
-      var isContainerReactRoot = containerID && containerID === ReactInstanceHandles.getReactRootIDFromNodeID(containerID);
-
-      if ("development" !== 'production') {
-        "development" !== 'production' ? 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.') : undefined;
-      }
-
-      return false;
-    }
-    ReactUpdates.batchedUpdates(unmountComponentFromNode, component, container);
-    delete instancesByReactRootID[reactRootID];
-    delete containersByReactRootID[reactRootID];
-    if ("development" !== 'production') {
-      delete rootElementsByReactRootID[reactRootID];
-    }
-    return true;
-  },
-
-  /**
-   * Finds the container DOM element that contains React component to which the
-   * supplied DOM `id` belongs.
-   *
-   * @param {string} id The ID of an element rendered by a React component.
-   * @return {?DOMElement} DOM element that contains the `id`.
-   */
-  findReactContainerForID: function (id) {
-    var reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(id);
-    var container = containersByReactRootID[reactRootID];
-
-    if ("development" !== 'production') {
-      var rootElement = rootElementsByReactRootID[reactRootID];
-      if (rootElement && rootElement.parentNode !== container) {
-        "development" !== 'production' ? warning(
-        // Call internalGetID here because getID calls isValid which calls
-        // findReactContainerForID (this function).
-        internalGetID(rootElement) === reactRootID, 'ReactMount: Root element ID differed from reactRootID.') : undefined;
-        var containerChild = container.firstChild;
-        if (containerChild && reactRootID === internalGetID(containerChild)) {
-          // If the container has a new child with the same ID as the old
-          // root element, then rootElementsByReactRootID[reactRootID] is
-          // just stale and needs to be updated. The case that deserves a
-          // warning is when the container is empty.
-          rootElementsByReactRootID[reactRootID] = containerChild;
-        } else {
-          "development" !== 'production' ? warning(false, 'ReactMount: Root element has been removed from its original ' + 'container. New container: %s', rootElement.parentNode) : undefined;
-        }
-      }
-    }
-
-    return container;
-  },
-
-  /**
-   * Finds an element rendered by React with the supplied ID.
-   *
-   * @param {string} id ID of a DOM node in the React component.
-   * @return {DOMElement} Root DOM node of the React component.
-   */
-  findReactNodeByID: function (id) {
-    var reactRoot = ReactMount.findReactContainerForID(id);
-    return ReactMount.findComponentRoot(reactRoot, id);
-  },
-
-  /**
-   * Traverses up the ancestors of the supplied node to find a node that is a
-   * DOM representation of a React component rendered by this copy of React.
-   *
-   * @param {*} node
-   * @return {?DOMEventTarget}
-   * @internal
-   */
-  getFirstReactDOM: function (node) {
-    return findFirstReactDOMImpl(node);
-  },
-
-  /**
-   * Finds a node with the supplied `targetID` inside of the supplied
-   * `ancestorNode`.  Exploits the ID naming scheme to perform the search
-   * quickly.
-   *
-   * @param {DOMEventTarget} ancestorNode Search from this root.
-   * @pararm {string} targetID ID of the DOM representation of the component.
-   * @return {DOMEventTarget} DOM node with the supplied `targetID`.
-   * @internal
-   */
-  findComponentRoot: function (ancestorNode, targetID) {
-    var firstChildren = findComponentRootReusableArray;
-    var childIndex = 0;
-
-    var deepestAncestor = findDeepestCachedAncestor(targetID) || ancestorNode;
-
-    if ("development" !== 'production') {
-      // This will throw on the next line; give an early warning
-      "development" !== 'production' ? warning(deepestAncestor != null, 'React can\'t find the root component node for data-reactid value ' + '`%s`. If you\'re seeing this message, it probably means that ' + 'you\'ve loaded two copies of React on the page. At this time, only ' + 'a single copy of React can be loaded at a time.', targetID) : undefined;
-    }
-
-    firstChildren[0] = deepestAncestor.firstChild;
-    firstChildren.length = 1;
-
-    while (childIndex < firstChildren.length) {
-      var child = firstChildren[childIndex++];
-      var targetChild;
-
-      while (child) {
-        var childID = ReactMount.getID(child);
-        if (childID) {
-          // Even if we find the node we're looking for, we finish looping
-          // through its siblings to ensure they're cached so that we don't have
-          // to revisit this node again. Otherwise, we make n^2 calls to getID
-          // when visiting the many children of a single node in order.
-
-          if (targetID === childID) {
-            targetChild = child;
-          } else if (ReactInstanceHandles.isAncestorIDOf(childID, targetID)) {
-            // If we find a child whose ID is an ancestor of the given ID,
-            // then we can be sure that we only want to search the subtree
-            // rooted at this child, so we can throw out the rest of the
-            // search state.
-            firstChildren.length = childIndex = 0;
-            firstChildren.push(child.firstChild);
-          }
-        } else {
-          // If this child had no ID, then there's a chance that it was
-          // injected automatically by the browser, as when a `<table>`
-          // element sprouts an extra `<tbody>` child as a side effect of
-          // `.innerHTML` parsing. Optimistically continue down this
-          // branch, but not before examining the other siblings.
-          firstChildren.push(child.firstChild);
-        }
-
-        child = child.nextSibling;
-      }
-
-      if (targetChild) {
-        // Emptying firstChildren/findComponentRootReusableArray is
-        // not necessary for correctness, but it helps the GC reclaim
-        // any nodes that were left at the end of the search.
-        firstChildren.length = 0;
-
-        return targetChild;
-      }
-    }
-
-    firstChildren.length = 0;
-
-    !false ? "development" !== 'production' ? invariant(false, 'findComponentRoot(..., %s): Unable to find element. This probably ' + 'means the DOM was unexpectedly mutated (e.g., by the browser), ' + 'usually due to forgetting a <tbody> when using tables, nesting tags ' + 'like <form>, <p>, or <a>, or using non-SVG elements in an <svg> ' + 'parent. ' + 'Try inspecting the child nodes of the element with React ID `%s`.', targetID, ReactMount.getID(ancestorNode)) : invariant(false) : undefined;
-  },
-
-  _mountImageIntoNode: function (markup, container, shouldReuseMarkup, transaction) {
-    !(container && (container.nodeType === ELEMENT_NODE_TYPE || container.nodeType === DOC_NODE_TYPE || container.nodeType === DOCUMENT_FRAGMENT_NODE_TYPE)) ? "development" !== 'production' ? invariant(false, 'mountComponentIntoNode(...): Target container is not valid.') : invariant(false) : undefined;
-
-    if (shouldReuseMarkup) {
-      var rootElement = getReactRootElementInContainer(container);
-      if (ReactMarkupChecksum.canReuseMarkup(markup, 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 ("development" !== 'production') {
-          // 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) ? "development" !== 'production' ? 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) : invariant(false) : undefined;
-
-        if ("development" !== 'production') {
-          "development" !== 'production' ? 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) : undefined;
-        }
-      }
-    }
-
-    !(container.nodeType !== DOC_NODE_TYPE) ? "development" !== 'production' ? 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.') : invariant(false) : undefined;
-
-    if (transaction.useCreateElement) {
-      while (container.lastChild) {
-        container.removeChild(container.lastChild);
-      }
-      container.appendChild(markup);
-    } else {
-      setInnerHTML(container, markup);
-    }
-  },
-
-  ownerDocumentContextKey: ownerDocumentContextKey,
-
-  /**
-   * React ID utilities.
-   */
-
-  getReactRootID: getReactRootID,
-
-  getID: getID,
-
-  setID: setID,
-
-  getNode: getNode,
-
-  getNodeFromInstance: getNodeFromInstance,
-
-  isValid: isValid,
-
-  purgeID: purgeID
-};
-
-ReactPerf.measureMethods(ReactMount, 'ReactMount', {
-  _renderNewRootComponent: '_renderNewRootComponent',
-  _mountImageIntoNode: '_mountImageIntoNode'
-});
-
-module.exports = ReactMount;
-},{"10":10,"118":118,"124":124,"126":126,"128":128,"133":133,"137":137,"144":144,"155":155,"23":23,"26":26,"34":34,"39":39,"52":52,"55":55,"61":61,"62":62,"64":64,"71":71,"76":76,"82":82,"83":83}],66:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactMultiChild
- * @typechecks static-only
- */
-
-'use strict';
-
-var ReactComponentEnvironment = _dereq_(32);
-var ReactMultiChildUpdateTypes = _dereq_(67);
-
-var ReactCurrentOwner = _dereq_(34);
-var ReactReconciler = _dereq_(76);
-var ReactChildReconciler = _dereq_(27);
-
-var flattenChildren = _dereq_(109);
-
-/**
- * Updating children of a component may trigger recursive updates. The depth is
- * used to batch recursive updates to render markup more efficiently.
- *
- * @type {number}
- * @private
- */
-var updateDepth = 0;
-
-/**
- * Queue of update configuration objects.
- *
- * Each object has a `type` property that is in `ReactMultiChildUpdateTypes`.
- *
- * @type {array<object>}
- * @private
- */
-var updateQueue = [];
-
-/**
- * Queue of markup to be rendered.
- *
- * @type {array<string>}
- * @private
- */
-var markupQueue = [];
-
-/**
- * Enqueues markup to be rendered and inserted at a supplied index.
- *
- * @param {string} parentID ID of the parent component.
- * @param {string} markup Markup that renders into an element.
- * @param {number} toIndex Destination index.
- * @private
- */
-function enqueueInsertMarkup(parentID, markup, toIndex) {
-  // NOTE: Null values reduce hidden classes.
-  updateQueue.push({
-    parentID: parentID,
-    parentNode: null,
-    type: ReactMultiChildUpdateTypes.INSERT_MARKUP,
-    markupIndex: markupQueue.push(markup) - 1,
-    content: null,
-    fromIndex: null,
-    toIndex: toIndex
-  });
-}
-
-/**
- * Enqueues moving an existing element to another index.
- *
- * @param {string} parentID ID of the parent component.
- * @param {number} fromIndex Source index of the existing element.
- * @param {number} toIndex Destination index of the element.
- * @private
- */
-function enqueueMove(parentID, fromIndex, toIndex) {
-  // NOTE: Null values reduce hidden classes.
-  updateQueue.push({
-    parentID: parentID,
-    parentNode: null,
-    type: ReactMultiChildUpdateTypes.MOVE_EXISTING,
-    markupIndex: null,
-    content: null,
-    fromIndex: fromIndex,
-    toIndex: toIndex
-  });
-}
-
-/**
- * Enqueues removing an element at an index.
- *
- * @param {string} parentID ID of the parent component.
- * @param {number} fromIndex Index of the element to remove.
- * @private
- */
-function enqueueRemove(parentID, fromIndex) {
-  // NOTE: Null values reduce hidden classes.
-  updateQueue.push({
-    parentID: parentID,
-    parentNode: null,
-    type: ReactMultiChildUpdateTypes.REMOVE_NODE,
-    markupIndex: null,
-    content: null,
-    fromIndex: fromIndex,
-    toIndex: null
-  });
-}
-
-/**
- * Enqueues setting the markup of a node.
- *
- * @param {string} parentID ID of the parent component.
- * @param {string} markup Markup that renders into an element.
- * @private
- */
-function enqueueSetMarkup(parentID, markup) {
-  // NOTE: Null values reduce hidden classes.
-  updateQueue.push({
-    parentID: parentID,
-    parentNode: null,
-    type: ReactMultiChildUpdateTypes.SET_MARKUP,
-    markupIndex: null,
-    content: markup,
-    fromIndex: null,
-    toIndex: null
-  });
-}
-
-/**
- * Enqueues setting the text content.
- *
- * @param {string} parentID ID of the parent component.
- * @param {string} textContent Text content to set.
- * @private
- */
-function enqueueTextContent(parentID, textContent) {
-  // NOTE: Null values reduce hidden classes.
-  updateQueue.push({
-    parentID: parentID,
-    parentNode: null,
-    type: ReactMultiChildUpdateTypes.TEXT_CONTENT,
-    markupIndex: null,
-    content: textContent,
-    fromIndex: null,
-    toIndex: null
-  });
-}
-
-/**
- * Processes any enqueued updates.
- *
- * @private
- */
-function processQueue() {
-  if (updateQueue.length) {
-    ReactComponentEnvironment.processChildrenUpdates(updateQueue, markupQueue);
-    clearQueue();
-  }
-}
-
-/**
- * Clears any enqueued updates.
- *
- * @private
- */
-function clearQueue() {
-  updateQueue.length = 0;
-  markupQueue.length = 0;
-}
-
-/**
- * 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 ("development" !== 'production') {
-        if (this._currentElement) {
-          try {
-            ReactCurrentOwner.current = this._currentElement._owner;
-            return ReactChildReconciler.instantiateChildren(nestedChildren, transaction, context);
-          } finally {
-            ReactCurrentOwner.current = null;
-          }
-        }
-      }
-      return ReactChildReconciler.instantiateChildren(nestedChildren, transaction, context);
-    },
-
-    _reconcilerUpdateChildren: function (prevChildren, nextNestedChildrenElements, transaction, context) {
-      var nextChildren;
-      if ("development" !== 'production') {
-        if (this._currentElement) {
-          try {
-            ReactCurrentOwner.current = this._currentElement._owner;
-            nextChildren = flattenChildren(nextNestedChildrenElements);
-          } finally {
-            ReactCurrentOwner.current = null;
-          }
-          return ReactChildReconciler.updateChildren(prevChildren, nextChildren, transaction, context);
-        }
-      }
-      nextChildren = flattenChildren(nextNestedChildrenElements);
-      return ReactChildReconciler.updateChildren(prevChildren, nextChildren, transaction, context);
-    },
-
-    /**
-     * 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];
-          // Inlined for performance, see `ReactInstanceHandles.createReactID`.
-          var rootID = this._rootNodeID + name;
-          var mountImage = ReactReconciler.mountComponent(child, rootID, transaction, context);
-          child._mountIndex = index++;
-          mountImages.push(mountImage);
-        }
-      }
-      return mountImages;
-    },
-
-    /**
-     * Replaces any rendered children with a text content string.
-     *
-     * @param {string} nextContent String of content.
-     * @internal
-     */
-    updateTextContent: function (nextContent) {
-      updateDepth++;
-      var errorThrown = true;
-      try {
-        var prevChildren = this._renderedChildren;
-        // Remove any rendered children.
-        ReactChildReconciler.unmountChildren(prevChildren);
-        // TODO: The setTextContent operation should be enough
-        for (var name in prevChildren) {
-          if (prevChildren.hasOwnProperty(name)) {
-            this._unmountChild(prevChildren[name]);
-          }
-        }
-        // Set new text content.
-        this.setTextContent(nextContent);
-        errorThrown = false;
-      } finally {
-        updateDepth--;
-        if (!updateDepth) {
-          if (errorThrown) {
-            clearQueue();
-          } else {
-            processQueue();
-          }
-        }
-      }
-    },
-
-    /**
-     * Replaces any rendered children with a markup string.
-     *
-     * @param {string} nextMarkup String of markup.
-     * @internal
-     */
-    updateMarkup: function (nextMarkup) {
-      updateDepth++;
-      var errorThrown = true;
-      try {
-        var prevChildren = this._renderedChildren;
-        // Remove any rendered children.
-        ReactChildReconciler.unmountChildren(prevChildren);
-        for (var name in prevChildren) {
-          if (prevChildren.hasOwnProperty(name)) {
-            this._unmountChildByName(prevChildren[name], name);
-          }
-        }
-        this.setMarkup(nextMarkup);
-        errorThrown = false;
-      } finally {
-        updateDepth--;
-        if (!updateDepth) {
-          if (errorThrown) {
-            clearQueue();
-          } else {
-            processQueue();
-          }
-        }
-      }
-    },
-
-    /**
-     * Updates the rendered children with new children.
-     *
-     * @param {?object} nextNestedChildrenElements Nested child element maps.
-     * @param {ReactReconcileTransaction} transaction
-     * @internal
-     */
-    updateChildren: function (nextNestedChildrenElements, transaction, context) {
-      updateDepth++;
-      var errorThrown = true;
-      try {
-        this._updateChildren(nextNestedChildrenElements, transaction, context);
-        errorThrown = false;
-      } finally {
-        updateDepth--;
-        if (!updateDepth) {
-          if (errorThrown) {
-            clearQueue();
-          } else {
-            processQueue();
-          }
-        }
-      }
-    },
-
-    /**
-     * Improve performance by isolating this hot code path from the try/catch
-     * block in `updateChildren`.
-     *
-     * @param {?object} nextNestedChildrenElements Nested child element maps.
-     * @param {ReactReconcileTransaction} transaction
-     * @final
-     * @protected
-     */
-    _updateChildren: function (nextNestedChildrenElements, transaction, context) {
-      var prevChildren = this._renderedChildren;
-      var nextChildren = this._reconcilerUpdateChildren(prevChildren, nextNestedChildrenElements, transaction, context);
-      this._renderedChildren = nextChildren;
-      if (!nextChildren && !prevChildren) {
-        return;
-      }
-      var name;
-      // `nextIndex` will increment for each child in `nextChildren`, but
-      // `lastIndex` will be the last index visited in `prevChildren`.
-      var lastIndex = 0;
-      var nextIndex = 0;
-      for (name in nextChildren) {
-        if (!nextChildren.hasOwnProperty(name)) {
-          continue;
-        }
-        var prevChild = prevChildren && prevChildren[name];
-        var nextChild = nextChildren[name];
-        if (prevChild === nextChild) {
-          this.moveChild(prevChild, 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);
-            this._unmountChild(prevChild);
-          }
-          // The child must be instantiated before it's mounted.
-          this._mountChildByNameAtIndex(nextChild, name, nextIndex, transaction, context);
-        }
-        nextIndex++;
-      }
-      // Remove children that are no longer present.
-      for (name in prevChildren) {
-        if (prevChildren.hasOwnProperty(name) && !(nextChildren && nextChildren.hasOwnProperty(name))) {
-          this._unmountChild(prevChildren[name]);
-        }
-      }
-    },
-
-    /**
-     * Unmounts all rendered children. This should be used to clean up children
-     * when this component is unmounted.
-     *
-     * @internal
-     */
-    unmountChildren: function () {
-      var renderedChildren = this._renderedChildren;
-      ReactChildReconciler.unmountChildren(renderedChildren);
-      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, 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) {
-        enqueueMove(this._rootNodeID, child._mountIndex, toIndex);
-      }
-    },
-
-    /**
-     * Creates a child component.
-     *
-     * @param {ReactComponent} child Component to create.
-     * @param {string} mountImage Markup to insert.
-     * @protected
-     */
-    createChild: function (child, mountImage) {
-      enqueueInsertMarkup(this._rootNodeID, mountImage, child._mountIndex);
-    },
-
-    /**
-     * Removes a child component.
-     *
-     * @param {ReactComponent} child Child to remove.
-     * @protected
-     */
-    removeChild: function (child) {
-      enqueueRemove(this._rootNodeID, child._mountIndex);
-    },
-
-    /**
-     * Sets this text content string.
-     *
-     * @param {string} textContent Text content to set.
-     * @protected
-     */
-    setTextContent: function (textContent) {
-      enqueueTextContent(this._rootNodeID, textContent);
-    },
-
-    /**
-     * Sets this markup string.
-     *
-     * @param {string} markup Markup to set.
-     * @protected
-     */
-    setMarkup: function (markup) {
-      enqueueSetMarkup(this._rootNodeID, markup);
-    },
-
-    /**
-     * 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
-     */
-    _mountChildByNameAtIndex: function (child, name, index, transaction, context) {
-      // Inlined for performance, see `ReactInstanceHandles.createReactID`.
-      var rootID = this._rootNodeID + name;
-      var mountImage = ReactReconciler.mountComponent(child, rootID, transaction, context);
-      child._mountIndex = index;
-      this.createChild(child, 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) {
-      this.removeChild(child);
-      child._mountIndex = null;
-    }
-
-  }
-
-};
-
-module.exports = ReactMultiChild;
-},{"109":109,"27":27,"32":32,"34":34,"67":67,"76":76}],67:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactMultiChildUpdateTypes
- */
-
-'use strict';
-
-var keyMirror = _dereq_(147);
-
-/**
- * When a component's children are updated, a series of update configuration
- * objects are created in order to batch and serialize the required changes.
- *
- * Enumerates all the possible types of update configurations.
- *
- * @internal
- */
-var ReactMultiChildUpdateTypes = keyMirror({
-  INSERT_MARKUP: null,
-  MOVE_EXISTING: null,
-  REMOVE_NODE: null,
-  SET_MARKUP: null,
-  TEXT_CONTENT: null
-});
-
-module.exports = ReactMultiChildUpdateTypes;
-},{"147":147}],68:[function(_dereq_,module,exports){
-/**
- * Copyright 2014-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactNativeComponent
- */
-
-'use strict';
-
-var assign = _dereq_(23);
-var invariant = _dereq_(144);
-
-var autoGenerateWrapperClass = null;
-var genericComponentClass = null;
-// This registry keeps track of wrapper classes around native tags.
-var tagToComponentClass = {};
-var textComponentClass = null;
-
-var ReactNativeComponentInjection = {
-  // 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;
-  },
-  // This accepts a keyed object with classes as values. Each key represents a
-  // tag. That particular tag will use this class instead of the generic one.
-  injectComponentClasses: function (componentClasses) {
-    assign(tagToComponentClass, componentClasses);
-  }
-};
-
-/**
- * Get a composite component wrapper class for a specific tag.
- *
- * @param {ReactElement} element The tag for which to get the class.
- * @return {function} The React class constructor function.
- */
-function getComponentClassForElement(element) {
-  if (typeof element.type === 'function') {
-    return element.type;
-  }
-  var tag = element.type;
-  var componentClass = tagToComponentClass[tag];
-  if (componentClass == null) {
-    tagToComponentClass[tag] = componentClass = autoGenerateWrapperClass(tag);
-  }
-  return componentClass;
-}
-
-/**
- * Get a native 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 ? "development" !== 'production' ? invariant(false, 'There is no registered component for the tag %s', element.type) : invariant(false) : undefined;
-  return new genericComponentClass(element.type, element.props);
-}
-
-/**
- * @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 ReactNativeComponent = {
-  getComponentClassForElement: getComponentClassForElement,
-  createInternalComponent: createInternalComponent,
-  createInstanceForText: createInstanceForText,
-  isTextComponent: isTextComponent,
-  injection: ReactNativeComponentInjection
-};
-
-module.exports = ReactNativeComponent;
-},{"144":144,"23":23}],69:[function(_dereq_,module,exports){
-/**
- * Copyright 2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactNoopUpdateQueue
- */
-
-'use strict';
-
-var warning = _dereq_(155);
-
-function warnTDZ(publicInstance, callerName) {
-  if ("development" !== 'production') {
-    "development" !== 'production' ? 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, publicInstance.constructor && publicInstance.constructor.displayName || '') : undefined;
-  }
-}
-
-/**
- * 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) {
-    warnTDZ(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) {
-    warnTDZ(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) {
-    warnTDZ(publicInstance, 'setState');
-  },
-
-  /**
-   * Sets a subset of the props.
-   *
-   * @param {ReactClass} publicInstance The instance that should rerender.
-   * @param {object} partialProps Subset of the next props.
-   * @internal
-   */
-  enqueueSetProps: function (publicInstance, partialProps) {
-    warnTDZ(publicInstance, 'setProps');
-  },
-
-  /**
-   * Replaces all of the props.
-   *
-   * @param {ReactClass} publicInstance The instance that should rerender.
-   * @param {object} props New props.
-   * @internal
-   */
-  enqueueReplaceProps: function (publicInstance, props) {
-    warnTDZ(publicInstance, 'replaceProps');
-  }
-
-};
-
-module.exports = ReactNoopUpdateQueue;
-},{"155":155}],70:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactOwner
- */
-
-'use strict';
-
-var invariant = _dereq_(144);
-
-/**
- * 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 = {
-
-  /**
-   * @param {?object} object
-   * @return {boolean} True if `object` is a valid owner.
-   * @final
-   */
-  isValidOwner: function (object) {
-    return !!(object && typeof object.attachRef === 'function' && typeof object.detachRef === 'function');
-  },
-
-  /**
-   * 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) {
-    !ReactOwner.isValidOwner(owner) ? "development" !== 'production' ? 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).') : invariant(false) : undefined;
-    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) {
-    !ReactOwner.isValidOwner(owner) ? "development" !== 'production' ? 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).') : invariant(false) : undefined;
-    // Check that `component` is still the current ref because we do not want to
-    // detach the ref if another component stole it.
-    if (owner.getPublicInstance().refs[ref] === component.getPublicInstance()) {
-      owner.detachRef(ref);
-    }
-  }
-
-};
-
-module.exports = ReactOwner;
-},{"144":144}],71:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactPerf
- * @typechecks static-only
- */
-
-'use strict';
-
-/**
- * ReactPerf is a general AOP system designed to measure performance. This
- * module only has the hooks: see ReactDefaultPerf for the analysis tool.
- */
-var ReactPerf = {
-  /**
-   * Boolean to enable/disable measurement. Set to false by default to prevent
-   * accidental logging and perf loss.
-   */
-  enableMeasure: false,
-
-  /**
-   * Holds onto the measure function in use. By default, don't measure
-   * anything, but we'll override this if we inject a measure function.
-   */
-  storedMeasure: _noMeasure,
-
-  /**
-   * @param {object} object
-   * @param {string} objectName
-   * @param {object<string>} methodNames
-   */
-  measureMethods: function (object, objectName, methodNames) {
-    if ("development" !== 'production') {
-      for (var key in methodNames) {
-        if (!methodNames.hasOwnProperty(key)) {
-          continue;
-        }
-        object[key] = ReactPerf.measure(objectName, methodNames[key], object[key]);
-      }
-    }
-  },
-
-  /**
-   * Use this to wrap methods you want to measure. Zero overhead in production.
-   *
-   * @param {string} objName
-   * @param {string} fnName
-   * @param {function} func
-   * @return {function}
-   */
-  measure: function (objName, fnName, func) {
-    if ("development" !== 'production') {
-      var measuredFunc = null;
-      var wrapper = function () {
-        if (ReactPerf.enableMeasure) {
-          if (!measuredFunc) {
-            measuredFunc = ReactPerf.storedMeasure(objName, fnName, func);
-          }
-          return measuredFunc.apply(this, arguments);
-        }
-        return func.apply(this, arguments);
-      };
-      wrapper.displayName = objName + '_' + fnName;
-      return wrapper;
-    }
-    return func;
-  },
-
-  injection: {
-    /**
-     * @param {function} measure
-     */
-    injectMeasure: function (measure) {
-      ReactPerf.storedMeasure = measure;
-    }
-  }
-};
-
-/**
- * Simply passes through the measured function, without measuring it.
- *
- * @param {string} objName
- * @param {string} fnName
- * @param {function} func
- * @return {function}
- */
-function _noMeasure(objName, fnName, func) {
-  return func;
-}
-
-module.exports = ReactPerf;
-},{}],72:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactPropTypeLocationNames
- */
-
-'use strict';
-
-var ReactPropTypeLocationNames = {};
-
-if ("development" !== 'production') {
-  ReactPropTypeLocationNames = {
-    prop: 'prop',
-    context: 'context',
-    childContext: 'child context'
-  };
-}
-
-module.exports = ReactPropTypeLocationNames;
-},{}],73:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactPropTypeLocations
- */
-
-'use strict';
-
-var keyMirror = _dereq_(147);
-
-var ReactPropTypeLocations = keyMirror({
-  prop: null,
-  context: null,
-  childContext: null
-});
-
-module.exports = ReactPropTypeLocations;
-},{"147":147}],74:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactPropTypes
- */
-
-'use strict';
-
-var ReactElement = _dereq_(52);
-var ReactPropTypeLocationNames = _dereq_(72);
-
-var emptyFunction = _dereq_(136);
-var getIteratorFn = _dereq_(115);
-
-/**
- * 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>>';
-
-var ReactPropTypes = {
-  array: createPrimitiveTypeChecker('array'),
-  bool: createPrimitiveTypeChecker('boolean'),
-  func: createPrimitiveTypeChecker('function'),
-  number: createPrimitiveTypeChecker('number'),
-  object: createPrimitiveTypeChecker('object'),
-  string: createPrimitiveTypeChecker('string'),
-
-  any: createAnyTypeChecker(),
-  arrayOf: createArrayOfTypeChecker,
-  element: createElementTypeChecker(),
-  instanceOf: createInstanceTypeChecker,
-  node: createNodeChecker(),
-  objectOf: createObjectOfTypeChecker,
-  oneOf: createEnumTypeChecker,
-  oneOfType: createUnionTypeChecker,
-  shape: createShapeTypeChecker
-};
-
-function createChainableTypeChecker(validate) {
-  function checkType(isRequired, props, propName, componentName, location, propFullName) {
-    componentName = componentName || ANONYMOUS;
-    propFullName = propFullName || propName;
-    if (props[propName] == null) {
-      var locationName = ReactPropTypeLocationNames[location];
-      if (isRequired) {
-        return new Error('Required ' + locationName + ' `' + propFullName + '` was not specified in ' + ('`' + componentName + '`.'));
-      }
-      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) {
-    var propValue = props[propName];
-    var propType = getPropType(propValue);
-    if (propType !== expectedType) {
-      var locationName = ReactPropTypeLocationNames[location];
-      // `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 Error('Invalid ' + locationName + ' `' + propFullName + '` of type ' + ('`' + preciseType + '` supplied to `' + componentName + '`, expected ') + ('`' + expectedType + '`.'));
-    }
-    return null;
-  }
-  return createChainableTypeChecker(validate);
-}
-
-function createAnyTypeChecker() {
-  return createChainableTypeChecker(emptyFunction.thatReturns(null));
-}
-
-function createArrayOfTypeChecker(typeChecker) {
-  function validate(props, propName, componentName, location, propFullName) {
-    var propValue = props[propName];
-    if (!Array.isArray(propValue)) {
-      var locationName = ReactPropTypeLocationNames[location];
-      var propType = getPropType(propValue);
-      return new Error('Invalid ' + locationName + ' `' + 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 + ']');
-      if (error instanceof Error) {
-        return error;
-      }
-    }
-    return null;
-  }
-  return createChainableTypeChecker(validate);
-}
-
-function createElementTypeChecker() {
-  function validate(props, propName, componentName, location, propFullName) {
-    if (!ReactElement.isValidElement(props[propName])) {
-      var locationName = ReactPropTypeLocationNames[location];
-      return new Error('Invalid ' + locationName + ' `' + propFullName + '` 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 locationName = ReactPropTypeLocationNames[location];
-      var expectedClassName = expectedClass.name || ANONYMOUS;
-      var actualClassName = getClassName(props[propName]);
-      return new Error('Invalid ' + locationName + ' `' + propFullName + '` of type ' + ('`' + actualClassName + '` supplied to `' + componentName + '`, expected ') + ('instance of `' + expectedClassName + '`.'));
-    }
-    return null;
-  }
-  return createChainableTypeChecker(validate);
-}
-
-function createEnumTypeChecker(expectedValues) {
-  if (!Array.isArray(expectedValues)) {
-    return createChainableTypeChecker(function () {
-      return new Error('Invalid argument supplied to oneOf, expected an instance of array.');
-    });
-  }
-
-  function validate(props, propName, componentName, location, propFullName) {
-    var propValue = props[propName];
-    for (var i = 0; i < expectedValues.length; i++) {
-      if (propValue === expectedValues[i]) {
-        return null;
-      }
-    }
-
-    var locationName = ReactPropTypeLocationNames[location];
-    var valuesString = JSON.stringify(expectedValues);
-    return new Error('Invalid ' + locationName + ' `' + propFullName + '` of value `' + propValue + '` ' + ('supplied to `' + componentName + '`, expected one of ' + valuesString + '.'));
-  }
-  return createChainableTypeChecker(validate);
-}
-
-function createObjectOfTypeChecker(typeChecker) {
-  function validate(props, propName, componentName, location, propFullName) {
-    var propValue = props[propName];
-    var propType = getPropType(propValue);
-    if (propType !== 'object') {
-      var locationName = ReactPropTypeLocationNames[location];
-      return new Error('Invalid ' + locationName + ' `' + 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);
-        if (error instanceof Error) {
-          return error;
-        }
-      }
-    }
-    return null;
-  }
-  return createChainableTypeChecker(validate);
-}
-
-function createUnionTypeChecker(arrayOfTypeCheckers) {
-  if (!Array.isArray(arrayOfTypeCheckers)) {
-    return createChainableTypeChecker(function () {
-      return new Error('Invalid argument supplied to oneOfType, expected an instance of array.');
-    });
-  }
-
-  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) == null) {
-        return null;
-      }
-    }
-
-    var locationName = ReactPropTypeLocationNames[location];
-    return new Error('Invalid ' + locationName + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`.'));
-  }
-  return createChainableTypeChecker(validate);
-}
-
-function createNodeChecker() {
-  function validate(props, propName, componentName, location, propFullName) {
-    if (!isNode(props[propName])) {
-      var locationName = ReactPropTypeLocationNames[location];
-      return new Error('Invalid ' + locationName + ' `' + 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') {
-      var locationName = ReactPropTypeLocationNames[location];
-      return new Error('Invalid ' + locationName + ' `' + 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);
-      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 || ReactElement.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;
-  }
-}
-
-// 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';
-  }
-  return propType;
-}
-
-// This handles more types than `getPropType`. Only used for error messages.
-// See `createPrimitiveTypeChecker`.
-function getPreciseType(propValue) {
-  var propType = getPropType(propValue);
-  if (propType === 'object') {
-    if (propValue instanceof Date) {
-      return 'date';
-    } else if (propValue instanceof RegExp) {
-      return 'regexp';
-    }
-  }
-  return propType;
-}
-
-// Returns class name of the object, if any.
-function getClassName(propValue) {
-  if (!propValue.constructor || !propValue.constructor.name) {
-    return '<<anonymous>>';
-  }
-  return propValue.constructor.name;
-}
-
-module.exports = ReactPropTypes;
-},{"115":115,"136":136,"52":52,"72":72}],75:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactReconcileTransaction
- * @typechecks static-only
- */
-
-'use strict';
-
-var CallbackQueue = _dereq_(6);
-var PooledClass = _dereq_(24);
-var ReactBrowserEventEmitter = _dereq_(26);
-var ReactDOMFeatureFlags = _dereq_(39);
-var ReactInputSelection = _dereq_(60);
-var Transaction = _dereq_(100);
-
-var assign = _dereq_(23);
-
-/**
- * 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 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];
-
-/**
- * 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(forceHTML) {
-  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
-  // `ReactTextComponent` checks it in `mountComponent`.`
-  this.renderToStaticMarkup = false;
-  this.reactMountReady = CallbackQueue.getPooled(null);
-  this.useCreateElement = !forceHTML && ReactDOMFeatureFlags.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;
-  },
-
-  /**
-   * `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, Mixin);
-
-PooledClass.addPoolingTo(ReactReconcileTransaction);
-
-module.exports = ReactReconcileTransaction;
-},{"100":100,"23":23,"24":24,"26":26,"39":39,"6":6,"60":60}],76:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactReconciler
- */
-
-'use strict';
-
-var ReactRef = _dereq_(77);
-
-/**
- * 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 {string} rootID DOM ID of the root node.
-   * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
-   * @return {?string} Rendered markup to be inserted into the DOM.
-   * @final
-   * @internal
-   */
-  mountComponent: function (internalInstance, rootID, transaction, context) {
-    var markup = internalInstance.mountComponent(rootID, transaction, context);
-    if (internalInstance._currentElement && internalInstance._currentElement.ref != null) {
-      transaction.getReactMountReady().enqueue(attachRefs, internalInstance);
-    }
-    return markup;
-  },
-
-  /**
-   * Releases any resources allocated by `mountComponent`.
-   *
-   * @final
-   * @internal
-   */
-  unmountComponent: function (internalInstance) {
-    ReactRef.detachRefs(internalInstance, internalInstance._currentElement);
-    internalInstance.unmountComponent();
-  },
-
-  /**
-   * 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;
-    }
-
-    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);
-    }
-  },
-
-  /**
-   * Flush any dirty changes in a component.
-   *
-   * @param {ReactComponent} internalInstance
-   * @param {ReactReconcileTransaction} transaction
-   * @internal
-   */
-  performUpdateIfNecessary: function (internalInstance, transaction) {
-    internalInstance.performUpdateIfNecessary(transaction);
-  }
-
-};
-
-module.exports = ReactReconciler;
-},{"77":77}],77:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactRef
- */
-
-'use strict';
-
-var ReactOwner = _dereq_(70);
-
-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 || element === false) {
-    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 prevEmpty = prevElement === null || prevElement === false;
-  var nextEmpty = nextElement === null || nextElement === false;
-
-  return(
-    // This has a few false positives w/r/t empty components.
-    prevEmpty || nextEmpty || nextElement._owner !== prevElement._owner || nextElement.ref !== prevElement.ref
-  );
-};
-
-ReactRef.detachRefs = function (instance, element) {
-  if (element === null || element === false) {
-    return;
-  }
-  var ref = element.ref;
-  if (ref != null) {
-    detachRef(ref, instance, element._owner);
-  }
-};
-
-module.exports = ReactRef;
-},{"70":70}],78:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactRootIndex
- * @typechecks
- */
-
-'use strict';
-
-var ReactRootIndexInjection = {
-  /**
-   * @param {function} _createReactRootIndex
-   */
-  injectCreateReactRootIndex: function (_createReactRootIndex) {
-    ReactRootIndex.createReactRootIndex = _createReactRootIndex;
-  }
-};
-
-var ReactRootIndex = {
-  createReactRootIndex: null,
-  injection: ReactRootIndexInjection
-};
-
-module.exports = ReactRootIndex;
-},{}],79:[function(_dereq_,module,exports){
-/**
- * Copyright 2014-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactServerBatchingStrategy
- * @typechecks
- */
-
-'use strict';
-
-var ReactServerBatchingStrategy = {
-  isBatchingUpdates: false,
-  batchedUpdates: function (callback) {
-    // Don't do anything here. During the server rendering we don't want to
-    // schedule any updates. We will simply ignore them.
-  }
-};
-
-module.exports = ReactServerBatchingStrategy;
-},{}],80:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @typechecks static-only
- * @providesModule ReactServerRendering
- */
-'use strict';
-
-var ReactDefaultBatchingStrategy = _dereq_(48);
-var ReactElement = _dereq_(52);
-var ReactInstanceHandles = _dereq_(61);
-var ReactMarkupChecksum = _dereq_(64);
-var ReactServerBatchingStrategy = _dereq_(79);
-var ReactServerRenderingTransaction = _dereq_(81);
-var ReactUpdates = _dereq_(83);
-
-var emptyObject = _dereq_(137);
-var instantiateReactComponent = _dereq_(118);
-var invariant = _dereq_(144);
-
-/**
- * @param {ReactElement} element
- * @return {string} the HTML markup
- */
-function renderToString(element) {
-  !ReactElement.isValidElement(element) ? "development" !== 'production' ? invariant(false, 'renderToString(): You must pass a valid ReactElement.') : invariant(false) : undefined;
-
-  var transaction;
-  try {
-    ReactUpdates.injection.injectBatchingStrategy(ReactServerBatchingStrategy);
-
-    var id = ReactInstanceHandles.createReactRootID();
-    transaction = ReactServerRenderingTransaction.getPooled(false);
-
-    return transaction.perform(function () {
-      var componentInstance = instantiateReactComponent(element, null);
-      var markup = componentInstance.mountComponent(id, transaction, emptyObject);
-      return ReactMarkupChecksum.addChecksumToMarkup(markup);
-    }, null);
-  } finally {
-    ReactServerRenderingTransaction.release(transaction);
-    // Revert to the DOM batching strategy since these two renderers
-    // currently share these stateful modules.
-    ReactUpdates.injection.injectBatchingStrategy(ReactDefaultBatchingStrategy);
-  }
-}
-
-/**
- * @param {ReactElement} element
- * @return {string} the HTML markup, without the extra React ID and checksum
- * (for generating static pages)
- */
-function renderToStaticMarkup(element) {
-  !ReactElement.isValidElement(element) ? "development" !== 'production' ? invariant(false, 'renderToStaticMarkup(): You must pass a valid ReactElement.') : invariant(false) : undefined;
-
-  var transaction;
-  try {
-    ReactUpdates.injection.injectBatchingStrategy(ReactServerBatchingStrategy);
-
-    var id = ReactInstanceHandles.createReactRootID();
-    transaction = ReactServerRenderingTransaction.getPooled(true);
-
-    return transaction.perform(function () {
-      var componentInstance = instantiateReactComponent(element, null);
-      return componentInstance.mountComponent(id, transaction, emptyObject);
-    }, null);
-  } finally {
-    ReactServerRenderingTransaction.release(transaction);
-    // Revert to the DOM batching strategy since these two renderers
-    // currently share these stateful modules.
-    ReactUpdates.injection.injectBatchingStrategy(ReactDefaultBatchingStrategy);
-  }
-}
-
-module.exports = {
-  renderToString: renderToString,
-  renderToStaticMarkup: renderToStaticMarkup
-};
-},{"118":118,"137":137,"144":144,"48":48,"52":52,"61":61,"64":64,"79":79,"81":81,"83":83}],81:[function(_dereq_,module,exports){
-/**
- * Copyright 2014-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactServerRenderingTransaction
- * @typechecks
- */
-
-'use strict';
-
-var PooledClass = _dereq_(24);
-var CallbackQueue = _dereq_(6);
-var Transaction = _dereq_(100);
-
-var assign = _dereq_(23);
-var emptyFunction = _dereq_(136);
-
-/**
- * Provides a `CallbackQueue` queue for collecting `onDOMReady` callbacks
- * during the performing of the transaction.
- */
-var ON_DOM_READY_QUEUEING = {
-  /**
-   * Initializes the internal `onDOMReady` queue.
-   */
-  initialize: function () {
-    this.reactMountReady.reset();
-  },
-
-  close: emptyFunction
-};
-
-/**
- * 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 = [ON_DOM_READY_QUEUEING];
-
-/**
- * @class ReactServerRenderingTransaction
- * @param {boolean} renderToStaticMarkup
- */
-function ReactServerRenderingTransaction(renderToStaticMarkup) {
-  this.reinitializeTransaction();
-  this.renderToStaticMarkup = renderToStaticMarkup;
-  this.reactMountReady = CallbackQueue.getPooled(null);
-  this.useCreateElement = false;
-}
-
-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 this.reactMountReady;
-  },
-
-  /**
-   * `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(ReactServerRenderingTransaction.prototype, Transaction.Mixin, Mixin);
-
-PooledClass.addPoolingTo(ReactServerRenderingTransaction);
-
-module.exports = ReactServerRenderingTransaction;
-},{"100":100,"136":136,"23":23,"24":24,"6":6}],82:[function(_dereq_,module,exports){
-/**
- * Copyright 2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactUpdateQueue
- */
-
-'use strict';
-
-var ReactCurrentOwner = _dereq_(34);
-var ReactElement = _dereq_(52);
-var ReactInstanceMap = _dereq_(62);
-var ReactUpdates = _dereq_(83);
-
-var assign = _dereq_(23);
-var invariant = _dereq_(144);
-var warning = _dereq_(155);
-
-function enqueueUpdate(internalInstance) {
-  ReactUpdates.enqueueUpdate(internalInstance);
-}
-
-function getInternalInstanceReadyForUpdate(publicInstance, callerName) {
-  var internalInstance = ReactInstanceMap.get(publicInstance);
-  if (!internalInstance) {
-    if ("development" !== 'production') {
-      // 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.
-      "development" !== 'production' ? 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, publicInstance.constructor.displayName) : undefined;
-    }
-    return null;
-  }
-
-  if ("development" !== 'production') {
-    "development" !== 'production' ? warning(ReactCurrentOwner.current == null, '%s(...): Cannot update during an existing state transition ' + '(such as within `render`). Render methods should be a pure function ' + 'of props and state.', callerName) : undefined;
-  }
-
-  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 ("development" !== 'production') {
-      var owner = ReactCurrentOwner.current;
-      if (owner !== null) {
-        "development" !== 'production' ? 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') : undefined;
-        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.
-   * @internal
-   */
-  enqueueCallback: function (publicInstance, callback) {
-    !(typeof callback === 'function') ? "development" !== 'production' ? invariant(false, 'enqueueCallback(...): You called `setProps`, `replaceProps`, ' + '`setState`, `replaceState`, or `forceUpdate` with a callback that ' + 'isn\'t callable.') : invariant(false) : undefined;
-    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) {
-    !(typeof callback === 'function') ? "development" !== 'production' ? invariant(false, 'enqueueCallback(...): You called `setProps`, `replaceProps`, ' + '`setState`, `replaceState`, or `forceUpdate` with a callback that ' + 'isn\'t callable.') : invariant(false) : undefined;
-    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) {
-    var internalInstance = getInternalInstanceReadyForUpdate(publicInstance, 'replaceState');
-
-    if (!internalInstance) {
-      return;
-    }
-
-    internalInstance._pendingStateQueue = [completeState];
-    internalInstance._pendingReplaceState = true;
-
-    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) {
-    var internalInstance = getInternalInstanceReadyForUpdate(publicInstance, 'setState');
-
-    if (!internalInstance) {
-      return;
-    }
-
-    var queue = internalInstance._pendingStateQueue || (internalInstance._pendingStateQueue = []);
-    queue.push(partialState);
-
-    enqueueUpdate(internalInstance);
-  },
-
-  /**
-   * Sets a subset of the props.
-   *
-   * @param {ReactClass} publicInstance The instance that should rerender.
-   * @param {object} partialProps Subset of the next props.
-   * @internal
-   */
-  enqueueSetProps: function (publicInstance, partialProps) {
-    var internalInstance = getInternalInstanceReadyForUpdate(publicInstance, 'setProps');
-    if (!internalInstance) {
-      return;
-    }
-    ReactUpdateQueue.enqueueSetPropsInternal(internalInstance, partialProps);
-  },
-
-  enqueueSetPropsInternal: function (internalInstance, partialProps) {
-    var topLevelWrapper = internalInstance._topLevelWrapper;
-    !topLevelWrapper ? "development" !== 'production' ? invariant(false, 'setProps(...): You called `setProps` on a ' + 'component with a parent. This is an anti-pattern since props will ' + 'get reactively updated when rendered. Instead, change the owner\'s ' + '`render` method to pass the correct value as props to the component ' + 'where it is created.') : invariant(false) : undefined;
-
-    // Merge with the pending element if it exists, otherwise with existing
-    // element props.
-    var wrapElement = topLevelWrapper._pendingElement || topLevelWrapper._currentElement;
-    var element = wrapElement.props;
-    var props = assign({}, element.props, partialProps);
-    topLevelWrapper._pendingElement = ReactElement.cloneAndReplaceProps(wrapElement, ReactElement.cloneAndReplaceProps(element, props));
-
-    enqueueUpdate(topLevelWrapper);
-  },
-
-  /**
-   * Replaces all of the props.
-   *
-   * @param {ReactClass} publicInstance The instance that should rerender.
-   * @param {object} props New props.
-   * @internal
-   */
-  enqueueReplaceProps: function (publicInstance, props) {
-    var internalInstance = getInternalInstanceReadyForUpdate(publicInstance, 'replaceProps');
-    if (!internalInstance) {
-      return;
-    }
-    ReactUpdateQueue.enqueueReplacePropsInternal(internalInstance, props);
-  },
-
-  enqueueReplacePropsInternal: function (internalInstance, props) {
-    var topLevelWrapper = internalInstance._topLevelWrapper;
-    !topLevelWrapper ? "development" !== 'production' ? invariant(false, 'replaceProps(...): You called `replaceProps` on a ' + 'component with a parent. This is an anti-pattern since props will ' + 'get reactively updated when rendered. Instead, change the owner\'s ' + '`render` method to pass the correct value as props to the component ' + 'where it is created.') : invariant(false) : undefined;
-
-    // Merge with the pending element if it exists, otherwise with existing
-    // element props.
-    var wrapElement = topLevelWrapper._pendingElement || topLevelWrapper._currentElement;
-    var element = wrapElement.props;
-    topLevelWrapper._pendingElement = ReactElement.cloneAndReplaceProps(wrapElement, ReactElement.cloneAndReplaceProps(element, props));
-
-    enqueueUpdate(topLevelWrapper);
-  },
-
-  enqueueElementInternal: function (internalInstance, newElement) {
-    internalInstance._pendingElement = newElement;
-    enqueueUpdate(internalInstance);
-  }
-
-};
-
-module.exports = ReactUpdateQueue;
-},{"144":144,"155":155,"23":23,"34":34,"52":52,"62":62,"83":83}],83:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactUpdates
- */
-
-'use strict';
-
-var CallbackQueue = _dereq_(6);
-var PooledClass = _dereq_(24);
-var ReactPerf = _dereq_(71);
-var ReactReconciler = _dereq_(76);
-var Transaction = _dereq_(100);
-
-var assign = _dereq_(23);
-var invariant = _dereq_(144);
-
-var dirtyComponents = [];
-var asapCallbackQueue = CallbackQueue.getPooled();
-var asapEnqueued = false;
-
-var batchingStrategy = null;
-
-function ensureInjected() {
-  !(ReactUpdates.ReactReconcileTransaction && batchingStrategy) ? "development" !== 'production' ? invariant(false, 'ReactUpdates: must inject a reconcile transaction class and batching ' + 'strategy') : invariant(false) : undefined;
-}
-
-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( /* forceHTML */false);
-}
-
-assign(ReactUpdatesFlushTransaction.prototype, Transaction.Mixin, {
-  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.Mixin.perform.call(this, this.reconcileTransaction.perform, this.reconcileTransaction, method, scope, a);
-  }
-});
-
-PooledClass.addPoolingTo(ReactUpdatesFlushTransaction);
-
-function batchedUpdates(callback, a, b, c, d, e) {
-  ensureInjected();
-  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) ? "development" !== 'production' ? invariant(false, 'Expected flush transaction\'s stored dirty-components length (%s) to ' + 'match dirty-components array length (%s).', len, dirtyComponents.length) : invariant(false) : undefined;
-
-  // 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);
-
-  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;
-
-    ReactReconciler.performUpdateIfNecessary(component, transaction.reconcileTransaction);
-
-    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);
-    }
-  }
-};
-flushBatchedUpdates = ReactPerf.measure('ReactUpdates', 'flushBatchedUpdates', flushBatchedUpdates);
-
-/**
- * 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 setProps, 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);
-}
-
-/**
- * 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) {
-  !batchingStrategy.isBatchingUpdates ? "development" !== 'production' ? invariant(false, 'ReactUpdates.asap: Can\'t enqueue an asap callback in a context where' + 'updates are not being batched.') : invariant(false) : undefined;
-  asapCallbackQueue.enqueue(callback, context);
-  asapEnqueued = true;
-}
-
-var ReactUpdatesInjection = {
-  injectReconcileTransaction: function (ReconcileTransaction) {
-    !ReconcileTransaction ? "development" !== 'production' ? invariant(false, 'ReactUpdates: must provide a reconcile transaction class') : invariant(false) : undefined;
-    ReactUpdates.ReactReconcileTransaction = ReconcileTransaction;
-  },
-
-  injectBatchingStrategy: function (_batchingStrategy) {
-    !_batchingStrategy ? "development" !== 'production' ? invariant(false, 'ReactUpdates: must provide a batching strategy') : invariant(false) : undefined;
-    !(typeof _batchingStrategy.batchedUpdates === 'function') ? "development" !== 'production' ? invariant(false, 'ReactUpdates: must provide a batchedUpdates() function') : invariant(false) : undefined;
-    !(typeof _batchingStrategy.isBatchingUpdates === 'boolean') ? "development" !== 'production' ? invariant(false, 'ReactUpdates: must provide an isBatchingUpdates boolean attribute') : invariant(false) : undefined;
-    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;
-},{"100":100,"144":144,"23":23,"24":24,"6":6,"71":71,"76":76}],84:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ReactVersion
- */
-
-'use strict';
-
-module.exports = '0.14.7';
-},{}],85:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule SVGDOMPropertyConfig
- */
-
-'use strict';
-
-var DOMProperty = _dereq_(10);
-
-var MUST_USE_ATTRIBUTE = DOMProperty.injection.MUST_USE_ATTRIBUTE;
-
-var NS = {
-  xlink: 'http://www.w3.org/1999/xlink',
-  xml: 'http://www.w3.org/XML/1998/namespace'
-};
-
-var SVGDOMPropertyConfig = {
-  Properties: {
-    clipPath: MUST_USE_ATTRIBUTE,
-    cx: MUST_USE_ATTRIBUTE,
-    cy: MUST_USE_ATTRIBUTE,
-    d: MUST_USE_ATTRIBUTE,
-    dx: MUST_USE_ATTRIBUTE,
-    dy: MUST_USE_ATTRIBUTE,
-    fill: MUST_USE_ATTRIBUTE,
-    fillOpacity: MUST_USE_ATTRIBUTE,
-    fontFamily: MUST_USE_ATTRIBUTE,
-    fontSize: MUST_USE_ATTRIBUTE,
-    fx: MUST_USE_ATTRIBUTE,
-    fy: MUST_USE_ATTRIBUTE,
-    gradientTransform: MUST_USE_ATTRIBUTE,
-    gradientUnits: MUST_USE_ATTRIBUTE,
-    markerEnd: MUST_USE_ATTRIBUTE,
-    markerMid: MUST_USE_ATTRIBUTE,
-    markerStart: MUST_USE_ATTRIBUTE,
-    offset: MUST_USE_ATTRIBUTE,
-    opacity: MUST_USE_ATTRIBUTE,
-    patternContentUnits: MUST_USE_ATTRIBUTE,
-    patternUnits: MUST_USE_ATTRIBUTE,
-    points: MUST_USE_ATTRIBUTE,
-    preserveAspectRatio: MUST_USE_ATTRIBUTE,
-    r: MUST_USE_ATTRIBUTE,
-    rx: MUST_USE_ATTRIBUTE,
-    ry: MUST_USE_ATTRIBUTE,
-    spreadMethod: MUST_USE_ATTRIBUTE,
-    stopColor: MUST_USE_ATTRIBUTE,
-    stopOpacity: MUST_USE_ATTRIBUTE,
-    stroke: MUST_USE_ATTRIBUTE,
-    strokeDasharray: MUST_USE_ATTRIBUTE,
-    strokeLinecap: MUST_USE_ATTRIBUTE,
-    strokeOpacity: MUST_USE_ATTRIBUTE,
-    strokeWidth: MUST_USE_ATTRIBUTE,
-    textAnchor: MUST_USE_ATTRIBUTE,
-    transform: MUST_USE_ATTRIBUTE,
-    version: MUST_USE_ATTRIBUTE,
-    viewBox: MUST_USE_ATTRIBUTE,
-    x1: MUST_USE_ATTRIBUTE,
-    x2: MUST_USE_ATTRIBUTE,
-    x: MUST_USE_ATTRIBUTE,
-    xlinkActuate: MUST_USE_ATTRIBUTE,
-    xlinkArcrole: MUST_USE_ATTRIBUTE,
-    xlinkHref: MUST_USE_ATTRIBUTE,
-    xlinkRole: MUST_USE_ATTRIBUTE,
-    xlinkShow: MUST_USE_ATTRIBUTE,
-    xlinkTitle: MUST_USE_ATTRIBUTE,
-    xlinkType: MUST_USE_ATTRIBUTE,
-    xmlBase: MUST_USE_ATTRIBUTE,
-    xmlLang: MUST_USE_ATTRIBUTE,
-    xmlSpace: MUST_USE_ATTRIBUTE,
-    y1: MUST_USE_ATTRIBUTE,
-    y2: MUST_USE_ATTRIBUTE,
-    y: MUST_USE_ATTRIBUTE
-  },
-  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: {
-    clipPath: 'clip-path',
-    fillOpacity: 'fill-opacity',
-    fontFamily: 'font-family',
-    fontSize: 'font-size',
-    gradientTransform: 'gradientTransform',
-    gradientUnits: 'gradientUnits',
-    markerEnd: 'marker-end',
-    markerMid: 'marker-mid',
-    markerStart: 'marker-start',
-    patternContentUnits: 'patternContentUnits',
-    patternUnits: 'patternUnits',
-    preserveAspectRatio: 'preserveAspectRatio',
-    spreadMethod: 'spreadMethod',
-    stopColor: 'stop-color',
-    stopOpacity: 'stop-opacity',
-    strokeDasharray: 'stroke-dasharray',
-    strokeLinecap: 'stroke-linecap',
-    strokeOpacity: 'stroke-opacity',
-    strokeWidth: 'stroke-width',
-    textAnchor: 'text-anchor',
-    viewBox: 'viewBox',
-    xlinkActuate: 'xlink:actuate',
-    xlinkArcrole: 'xlink:arcrole',
-    xlinkHref: 'xlink:href',
-    xlinkRole: 'xlink:role',
-    xlinkShow: 'xlink:show',
-    xlinkTitle: 'xlink:title',
-    xlinkType: 'xlink:type',
-    xmlBase: 'xml:base',
-    xmlLang: 'xml:lang',
-    xmlSpace: 'xml:space'
-  }
-};
-
-module.exports = SVGDOMPropertyConfig;
-},{"10":10}],86:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule SelectEventPlugin
- */
-
-'use strict';
-
-var EventConstants = _dereq_(15);
-var EventPropagators = _dereq_(19);
-var ExecutionEnvironment = _dereq_(130);
-var ReactInputSelection = _dereq_(60);
-var SyntheticEvent = _dereq_(92);
-
-var getActiveElement = _dereq_(139);
-var isTextInputElement = _dereq_(120);
-var keyOf = _dereq_(148);
-var shallowEqual = _dereq_(153);
-
-var topLevelTypes = EventConstants.topLevelTypes;
-
-var skipSelectionChangeEvent = ExecutionEnvironment.canUseDOM && 'documentMode' in document && document.documentMode <= 11;
-
-var eventTypes = {
-  select: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onSelect: null }),
-      captured: keyOf({ onSelectCapture: null })
-    },
-    dependencies: [topLevelTypes.topBlur, topLevelTypes.topContextMenu, topLevelTypes.topFocus, topLevelTypes.topKeyDown, topLevelTypes.topMouseDown, topLevelTypes.topMouseUp, topLevelTypes.topSelectionChange]
-  }
-};
-
-var activeElement = null;
-var activeElementID = null;
-var lastSelection = null;
-var mouseDown = false;
-
-// Track whether a listener exists for this plugin. If none exist, we do
-// not extract events.
-var hasListener = false;
-var ON_SELECT_KEY = keyOf({ onSelect: null });
-
-/**
- * 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, activeElementID, 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,
-
-  /**
-   * @param {string} topLevelType Record from `EventConstants`.
-   * @param {DOMEventTarget} topLevelTarget The listening component root node.
-   * @param {string} topLevelTargetID ID of `topLevelTarget`.
-   * @param {object} nativeEvent Native browser event.
-   * @return {*} An accumulation of synthetic events.
-   * @see {EventPluginHub.extractEvents}
-   */
-  extractEvents: function (topLevelType, topLevelTarget, topLevelTargetID, nativeEvent, nativeEventTarget) {
-    if (!hasListener) {
-      return null;
-    }
-
-    switch (topLevelType) {
-      // Track the input node that has focus.
-      case topLevelTypes.topFocus:
-        if (isTextInputElement(topLevelTarget) || topLevelTarget.contentEditable === 'true') {
-          activeElement = topLevelTarget;
-          activeElementID = topLevelTargetID;
-          lastSelection = null;
-        }
-        break;
-      case topLevelTypes.topBlur:
-        activeElement = null;
-        activeElementID = null;
-        lastSelection = null;
-        break;
-
-      // Don't fire the event while the user is dragging. This matches the
-      // semantics of the native select event.
-      case topLevelTypes.topMouseDown:
-        mouseDown = true;
-        break;
-      case topLevelTypes.topContextMenu:
-      case topLevelTypes.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 topLevelTypes.topSelectionChange:
-        if (skipSelectionChangeEvent) {
-          break;
-        }
-      // falls through
-      case topLevelTypes.topKeyDown:
-      case topLevelTypes.topKeyUp:
-        return constructSelectEvent(nativeEvent, nativeEventTarget);
-    }
-
-    return null;
-  },
-
-  didPutListener: function (id, registrationName, listener) {
-    if (registrationName === ON_SELECT_KEY) {
-      hasListener = true;
-    }
-  }
-};
-
-module.exports = SelectEventPlugin;
-},{"120":120,"130":130,"139":139,"148":148,"15":15,"153":153,"19":19,"60":60,"92":92}],87:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ServerReactRootIndex
- * @typechecks
- */
-
-'use strict';
-
-/**
- * Size of the reactRoot ID space. We generate random numbers for React root
- * IDs and if there's a collision the events and DOM update system will
- * get confused. In the future we need a way to generate GUIDs but for
- * now this will work on a smaller scale.
- */
-var GLOBAL_MOUNT_POINT_MAX = Math.pow(2, 53);
-
-var ServerReactRootIndex = {
-  createReactRootIndex: function () {
-    return Math.ceil(Math.random() * GLOBAL_MOUNT_POINT_MAX);
-  }
-};
-
-module.exports = ServerReactRootIndex;
-},{}],88:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule SimpleEventPlugin
- */
-
-'use strict';
-
-var EventConstants = _dereq_(15);
-var EventListener = _dereq_(129);
-var EventPropagators = _dereq_(19);
-var ReactMount = _dereq_(65);
-var SyntheticClipboardEvent = _dereq_(89);
-var SyntheticEvent = _dereq_(92);
-var SyntheticFocusEvent = _dereq_(93);
-var SyntheticKeyboardEvent = _dereq_(95);
-var SyntheticMouseEvent = _dereq_(96);
-var SyntheticDragEvent = _dereq_(91);
-var SyntheticTouchEvent = _dereq_(97);
-var SyntheticUIEvent = _dereq_(98);
-var SyntheticWheelEvent = _dereq_(99);
-
-var emptyFunction = _dereq_(136);
-var getEventCharCode = _dereq_(111);
-var invariant = _dereq_(144);
-var keyOf = _dereq_(148);
-
-var topLevelTypes = EventConstants.topLevelTypes;
-
-var eventTypes = {
-  abort: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onAbort: true }),
-      captured: keyOf({ onAbortCapture: true })
-    }
-  },
-  blur: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onBlur: true }),
-      captured: keyOf({ onBlurCapture: true })
-    }
-  },
-  canPlay: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onCanPlay: true }),
-      captured: keyOf({ onCanPlayCapture: true })
-    }
-  },
-  canPlayThrough: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onCanPlayThrough: true }),
-      captured: keyOf({ onCanPlayThroughCapture: true })
-    }
-  },
-  click: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onClick: true }),
-      captured: keyOf({ onClickCapture: true })
-    }
-  },
-  contextMenu: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onContextMenu: true }),
-      captured: keyOf({ onContextMenuCapture: true })
-    }
-  },
-  copy: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onCopy: true }),
-      captured: keyOf({ onCopyCapture: true })
-    }
-  },
-  cut: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onCut: true }),
-      captured: keyOf({ onCutCapture: true })
-    }
-  },
-  doubleClick: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onDoubleClick: true }),
-      captured: keyOf({ onDoubleClickCapture: true })
-    }
-  },
-  drag: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onDrag: true }),
-      captured: keyOf({ onDragCapture: true })
-    }
-  },
-  dragEnd: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onDragEnd: true }),
-      captured: keyOf({ onDragEndCapture: true })
-    }
-  },
-  dragEnter: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onDragEnter: true }),
-      captured: keyOf({ onDragEnterCapture: true })
-    }
-  },
-  dragExit: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onDragExit: true }),
-      captured: keyOf({ onDragExitCapture: true })
-    }
-  },
-  dragLeave: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onDragLeave: true }),
-      captured: keyOf({ onDragLeaveCapture: true })
-    }
-  },
-  dragOver: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onDragOver: true }),
-      captured: keyOf({ onDragOverCapture: true })
-    }
-  },
-  dragStart: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onDragStart: true }),
-      captured: keyOf({ onDragStartCapture: true })
-    }
-  },
-  drop: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onDrop: true }),
-      captured: keyOf({ onDropCapture: true })
-    }
-  },
-  durationChange: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onDurationChange: true }),
-      captured: keyOf({ onDurationChangeCapture: true })
-    }
-  },
-  emptied: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onEmptied: true }),
-      captured: keyOf({ onEmptiedCapture: true })
-    }
-  },
-  encrypted: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onEncrypted: true }),
-      captured: keyOf({ onEncryptedCapture: true })
-    }
-  },
-  ended: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onEnded: true }),
-      captured: keyOf({ onEndedCapture: true })
-    }
-  },
-  error: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onError: true }),
-      captured: keyOf({ onErrorCapture: true })
-    }
-  },
-  focus: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onFocus: true }),
-      captured: keyOf({ onFocusCapture: true })
-    }
-  },
-  input: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onInput: true }),
-      captured: keyOf({ onInputCapture: true })
-    }
-  },
-  keyDown: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onKeyDown: true }),
-      captured: keyOf({ onKeyDownCapture: true })
-    }
-  },
-  keyPress: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onKeyPress: true }),
-      captured: keyOf({ onKeyPressCapture: true })
-    }
-  },
-  keyUp: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onKeyUp: true }),
-      captured: keyOf({ onKeyUpCapture: true })
-    }
-  },
-  load: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onLoad: true }),
-      captured: keyOf({ onLoadCapture: true })
-    }
-  },
-  loadedData: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onLoadedData: true }),
-      captured: keyOf({ onLoadedDataCapture: true })
-    }
-  },
-  loadedMetadata: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onLoadedMetadata: true }),
-      captured: keyOf({ onLoadedMetadataCapture: true })
-    }
-  },
-  loadStart: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onLoadStart: true }),
-      captured: keyOf({ onLoadStartCapture: true })
-    }
-  },
-  // Note: We do not allow listening to mouseOver events. Instead, use the
-  // onMouseEnter/onMouseLeave created by `EnterLeaveEventPlugin`.
-  mouseDown: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onMouseDown: true }),
-      captured: keyOf({ onMouseDownCapture: true })
-    }
-  },
-  mouseMove: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onMouseMove: true }),
-      captured: keyOf({ onMouseMoveCapture: true })
-    }
-  },
-  mouseOut: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onMouseOut: true }),
-      captured: keyOf({ onMouseOutCapture: true })
-    }
-  },
-  mouseOver: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onMouseOver: true }),
-      captured: keyOf({ onMouseOverCapture: true })
-    }
-  },
-  mouseUp: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onMouseUp: true }),
-      captured: keyOf({ onMouseUpCapture: true })
-    }
-  },
-  paste: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onPaste: true }),
-      captured: keyOf({ onPasteCapture: true })
-    }
-  },
-  pause: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onPause: true }),
-      captured: keyOf({ onPauseCapture: true })
-    }
-  },
-  play: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onPlay: true }),
-      captured: keyOf({ onPlayCapture: true })
-    }
-  },
-  playing: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onPlaying: true }),
-      captured: keyOf({ onPlayingCapture: true })
-    }
-  },
-  progress: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onProgress: true }),
-      captured: keyOf({ onProgressCapture: true })
-    }
-  },
-  rateChange: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onRateChange: true }),
-      captured: keyOf({ onRateChangeCapture: true })
-    }
-  },
-  reset: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onReset: true }),
-      captured: keyOf({ onResetCapture: true })
-    }
-  },
-  scroll: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onScroll: true }),
-      captured: keyOf({ onScrollCapture: true })
-    }
-  },
-  seeked: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onSeeked: true }),
-      captured: keyOf({ onSeekedCapture: true })
-    }
-  },
-  seeking: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onSeeking: true }),
-      captured: keyOf({ onSeekingCapture: true })
-    }
-  },
-  stalled: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onStalled: true }),
-      captured: keyOf({ onStalledCapture: true })
-    }
-  },
-  submit: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onSubmit: true }),
-      captured: keyOf({ onSubmitCapture: true })
-    }
-  },
-  suspend: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onSuspend: true }),
-      captured: keyOf({ onSuspendCapture: true })
-    }
-  },
-  timeUpdate: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onTimeUpdate: true }),
-      captured: keyOf({ onTimeUpdateCapture: true })
-    }
-  },
-  touchCancel: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onTouchCancel: true }),
-      captured: keyOf({ onTouchCancelCapture: true })
-    }
-  },
-  touchEnd: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onTouchEnd: true }),
-      captured: keyOf({ onTouchEndCapture: true })
-    }
-  },
-  touchMove: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onTouchMove: true }),
-      captured: keyOf({ onTouchMoveCapture: true })
-    }
-  },
-  touchStart: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onTouchStart: true }),
-      captured: keyOf({ onTouchStartCapture: true })
-    }
-  },
-  volumeChange: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onVolumeChange: true }),
-      captured: keyOf({ onVolumeChangeCapture: true })
-    }
-  },
-  waiting: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onWaiting: true }),
-      captured: keyOf({ onWaitingCapture: true })
-    }
-  },
-  wheel: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({ onWheel: true }),
-      captured: keyOf({ onWheelCapture: true })
-    }
-  }
-};
-
-var topLevelEventsToDispatchConfig = {
-  topAbort: eventTypes.abort,
-  topBlur: eventTypes.blur,
-  topCanPlay: eventTypes.canPlay,
-  topCanPlayThrough: eventTypes.canPlayThrough,
-  topClick: eventTypes.click,
-  topContextMenu: eventTypes.contextMenu,
-  topCopy: eventTypes.copy,
-  topCut: eventTypes.cut,
-  topDoubleClick: eventTypes.doubleClick,
-  topDrag: eventTypes.drag,
-  topDragEnd: eventTypes.dragEnd,
-  topDragEnter: eventTypes.dragEnter,
-  topDragExit: eventTypes.dragExit,
-  topDragLeave: eventTypes.dragLeave,
-  topDragOver: eventTypes.dragOver,
-  topDragStart: eventTypes.dragStart,
-  topDrop: eventTypes.drop,
-  topDurationChange: eventTypes.durationChange,
-  topEmptied: eventTypes.emptied,
-  topEncrypted: eventTypes.encrypted,
-  topEnded: eventTypes.ended,
-  topError: eventTypes.error,
-  topFocus: eventTypes.focus,
-  topInput: eventTypes.input,
-  topKeyDown: eventTypes.keyDown,
-  topKeyPress: eventTypes.keyPress,
-  topKeyUp: eventTypes.keyUp,
-  topLoad: eventTypes.load,
-  topLoadedData: eventTypes.loadedData,
-  topLoadedMetadata: eventTypes.loadedMetadata,
-  topLoadStart: eventTypes.loadStart,
-  topMouseDown: eventTypes.mouseDown,
-  topMouseMove: eventTypes.mouseMove,
-  topMouseOut: eventTypes.mouseOut,
-  topMouseOver: eventTypes.mouseOver,
-  topMouseUp: eventTypes.mouseUp,
-  topPaste: eventTypes.paste,
-  topPause: eventTypes.pause,
-  topPlay: eventTypes.play,
-  topPlaying: eventTypes.playing,
-  topProgress: eventTypes.progress,
-  topRateChange: eventTypes.rateChange,
-  topReset: eventTypes.reset,
-  topScroll: eventTypes.scroll,
-  topSeeked: eventTypes.seeked,
-  topSeeking: eventTypes.seeking,
-  topStalled: eventTypes.stalled,
-  topSubmit: eventTypes.submit,
-  topSuspend: eventTypes.suspend,
-  topTimeUpdate: eventTypes.timeUpdate,
-  topTouchCancel: eventTypes.touchCancel,
-  topTouchEnd: eventTypes.touchEnd,
-  topTouchMove: eventTypes.touchMove,
-  topTouchStart: eventTypes.touchStart,
-  topVolumeChange: eventTypes.volumeChange,
-  topWaiting: eventTypes.waiting,
-  topWheel: eventTypes.wheel
-};
-
-for (var type in topLevelEventsToDispatchConfig) {
-  topLevelEventsToDispatchConfig[type].dependencies = [type];
-}
-
-var ON_CLICK_KEY = keyOf({ onClick: null });
-var onClickListeners = {};
-
-var SimpleEventPlugin = {
-
-  eventTypes: eventTypes,
-
-  /**
-   * @param {string} topLevelType Record from `EventConstants`.
-   * @param {DOMEventTarget} topLevelTarget The listening component root node.
-   * @param {string} topLevelTargetID ID of `topLevelTarget`.
-   * @param {object} nativeEvent Native browser event.
-   * @return {*} An accumulation of synthetic events.
-   * @see {EventPluginHub.extractEvents}
-   */
-  extractEvents: function (topLevelType, topLevelTarget, topLevelTargetID, nativeEvent, nativeEventTarget) {
-    var dispatchConfig = topLevelEventsToDispatchConfig[topLevelType];
-    if (!dispatchConfig) {
-      return null;
-    }
-    var EventConstructor;
-    switch (topLevelType) {
-      case topLevelTypes.topAbort:
-      case topLevelTypes.topCanPlay:
-      case topLevelTypes.topCanPlayThrough:
-      case topLevelTypes.topDurationChange:
-      case topLevelTypes.topEmptied:
-      case topLevelTypes.topEncrypted:
-      case topLevelTypes.topEnded:
-      case topLevelTypes.topError:
-      case topLevelTypes.topInput:
-      case topLevelTypes.topLoad:
-      case topLevelTypes.topLoadedData:
-      case topLevelTypes.topLoadedMetadata:
-      case topLevelTypes.topLoadStart:
-      case topLevelTypes.topPause:
-      case topLevelTypes.topPlay:
-      case topLevelTypes.topPlaying:
-      case topLevelTypes.topProgress:
-      case topLevelTypes.topRateChange:
-      case topLevelTypes.topReset:
-      case topLevelTypes.topSeeked:
-      case topLevelTypes.topSeeking:
-      case topLevelTypes.topStalled:
-      case topLevelTypes.topSubmit:
-      case topLevelTypes.topSuspend:
-      case topLevelTypes.topTimeUpdate:
-      case topLevelTypes.topVolumeChange:
-      case topLevelTypes.topWaiting:
-        // HTML Events
-        // @see http://www.w3.org/TR/html5/index.html#events-0
-        EventConstructor = SyntheticEvent;
-        break;
-      case topLevelTypes.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 topLevelTypes.topKeyDown:
-      case topLevelTypes.topKeyUp:
-        EventConstructor = SyntheticKeyboardEvent;
-        break;
-      case topLevelTypes.topBlur:
-      case topLevelTypes.topFocus:
-        EventConstructor = SyntheticFocusEvent;
-        break;
-      case topLevelTypes.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 topLevelTypes.topContextMenu:
-      case topLevelTypes.topDoubleClick:
-      case topLevelTypes.topMouseDown:
-      case topLevelTypes.topMouseMove:
-      case topLevelTypes.topMouseOut:
-      case topLevelTypes.topMouseOver:
-      case topLevelTypes.topMouseUp:
-        EventConstructor = SyntheticMouseEvent;
-        break;
-      case topLevelTypes.topDrag:
-      case topLevelTypes.topDragEnd:
-      case topLevelTypes.topDragEnter:
-      case topLevelTypes.topDragExit:
-      case topLevelTypes.topDragLeave:
-      case topLevelTypes.topDragOver:
-      case topLevelTypes.topDragStart:
-      case topLevelTypes.topDrop:
-        EventConstructor = SyntheticDragEvent;
-        break;
-      case topLevelTypes.topTouchCancel:
-      case topLevelTypes.topTouchEnd:
-      case topLevelTypes.topTouchMove:
-      case topLevelTypes.topTouchStart:
-        EventConstructor = SyntheticTouchEvent;
-        break;
-      case topLevelTypes.topScroll:
-        EventConstructor = SyntheticUIEvent;
-        break;
-      case topLevelTypes.topWheel:
-        EventConstructor = SyntheticWheelEvent;
-        break;
-      case topLevelTypes.topCopy:
-      case topLevelTypes.topCut:
-      case topLevelTypes.topPaste:
-        EventConstructor = SyntheticClipboardEvent;
-        break;
-    }
-    !EventConstructor ? "development" !== 'production' ? invariant(false, 'SimpleEventPlugin: Unhandled event type, `%s`.', topLevelType) : invariant(false) : undefined;
-    var event = EventConstructor.getPooled(dispatchConfig, topLevelTargetID, nativeEvent, nativeEventTarget);
-    EventPropagators.accumulateTwoPhaseDispatches(event);
-    return event;
-  },
-
-  didPutListener: function (id, 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.
-    if (registrationName === ON_CLICK_KEY) {
-      var node = ReactMount.getNode(id);
-      if (!onClickListeners[id]) {
-        onClickListeners[id] = EventListener.listen(node, 'click', emptyFunction);
-      }
-    }
-  },
-
-  willDeleteListener: function (id, registrationName) {
-    if (registrationName === ON_CLICK_KEY) {
-      onClickListeners[id].remove();
-      delete onClickListeners[id];
-    }
-  }
-
-};
-
-module.exports = SimpleEventPlugin;
-},{"111":111,"129":129,"136":136,"144":144,"148":148,"15":15,"19":19,"65":65,"89":89,"91":91,"92":92,"93":93,"95":95,"96":96,"97":97,"98":98,"99":99}],89:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule SyntheticClipboardEvent
- * @typechecks static-only
- */
-
-'use strict';
-
-var SyntheticEvent = _dereq_(92);
-
-/**
- * @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) {
-  SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
-}
-
-SyntheticEvent.augmentClass(SyntheticClipboardEvent, ClipboardEventInterface);
-
-module.exports = SyntheticClipboardEvent;
-},{"92":92}],90:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule SyntheticCompositionEvent
- * @typechecks static-only
- */
-
-'use strict';
-
-var SyntheticEvent = _dereq_(92);
-
-/**
- * @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) {
-  SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
-}
-
-SyntheticEvent.augmentClass(SyntheticCompositionEvent, CompositionEventInterface);
-
-module.exports = SyntheticCompositionEvent;
-},{"92":92}],91:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule SyntheticDragEvent
- * @typechecks static-only
- */
-
-'use strict';
-
-var SyntheticMouseEvent = _dereq_(96);
-
-/**
- * @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) {
-  SyntheticMouseEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
-}
-
-SyntheticMouseEvent.augmentClass(SyntheticDragEvent, DragEventInterface);
-
-module.exports = SyntheticDragEvent;
-},{"96":96}],92:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule SyntheticEvent
- * @typechecks static-only
- */
-
-'use strict';
-
-var PooledClass = _dereq_(24);
-
-var assign = _dereq_(23);
-var emptyFunction = _dereq_(136);
-var warning = _dereq_(155);
-
-/**
- * @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 {string} dispatchMarker Marker identifying the event target.
- * @param {object} nativeEvent Native browser event.
- */
-function SyntheticEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) {
-  this.dispatchConfig = dispatchConfig;
-  this.dispatchMarker = dispatchMarker;
-  this.nativeEvent = nativeEvent;
-
-  var Interface = this.constructor.Interface;
-  for (var propName in Interface) {
-    if (!Interface.hasOwnProperty(propName)) {
-      continue;
-    }
-    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;
-}
-
-assign(SyntheticEvent.prototype, {
-
-  preventDefault: function () {
-    this.defaultPrevented = true;
-    var event = this.nativeEvent;
-    if ("development" !== 'production') {
-      "development" !== 'production' ? warning(event, 'This synthetic event is reused for performance reasons. If you\'re ' + 'seeing this, you\'re calling `preventDefault` on a ' + 'released/nullified synthetic event. This is a no-op. See ' + 'https://fb.me/react-event-pooling for more information.') : undefined;
-    }
-    if (!event) {
-      return;
-    }
-
-    if (event.preventDefault) {
-      event.preventDefault();
-    } else {
-      event.returnValue = false;
-    }
-    this.isDefaultPrevented = emptyFunction.thatReturnsTrue;
-  },
-
-  stopPropagation: function () {
-    var event = this.nativeEvent;
-    if ("development" !== 'production') {
-      "development" !== 'production' ? warning(event, 'This synthetic event is reused for performance reasons. If you\'re ' + 'seeing this, you\'re calling `stopPropagation` on a ' + 'released/nullified synthetic event. This is a no-op. See ' + 'https://fb.me/react-event-pooling for more information.') : undefined;
-    }
-    if (!event) {
-      return;
-    }
-
-    if (event.stopPropagation) {
-      event.stopPropagation();
-    } else {
-      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) {
-      this[propName] = null;
-    }
-    this.dispatchConfig = null;
-    this.dispatchMarker = null;
-    this.nativeEvent = null;
-  }
-
-});
-
-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 prototype = Object.create(Super.prototype);
-  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);
-};
-
-PooledClass.addPoolingTo(SyntheticEvent, PooledClass.fourArgumentPooler);
-
-module.exports = SyntheticEvent;
-},{"136":136,"155":155,"23":23,"24":24}],93:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule SyntheticFocusEvent
- * @typechecks static-only
- */
-
-'use strict';
-
-var SyntheticUIEvent = _dereq_(98);
-
-/**
- * @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) {
-  SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
-}
-
-SyntheticUIEvent.augmentClass(SyntheticFocusEvent, FocusEventInterface);
-
-module.exports = SyntheticFocusEvent;
-},{"98":98}],94:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule SyntheticInputEvent
- * @typechecks static-only
- */
-
-'use strict';
-
-var SyntheticEvent = _dereq_(92);
-
-/**
- * @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) {
-  SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
-}
-
-SyntheticEvent.augmentClass(SyntheticInputEvent, InputEventInterface);
-
-module.exports = SyntheticInputEvent;
-},{"92":92}],95:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule SyntheticKeyboardEvent
- * @typechecks static-only
- */
-
-'use strict';
-
-var SyntheticUIEvent = _dereq_(98);
-
-var getEventCharCode = _dereq_(111);
-var getEventKey = _dereq_(112);
-var getEventModifierState = _dereq_(113);
-
-/**
- * @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) {
-  SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
-}
-
-SyntheticUIEvent.augmentClass(SyntheticKeyboardEvent, KeyboardEventInterface);
-
-module.exports = SyntheticKeyboardEvent;
-},{"111":111,"112":112,"113":113,"98":98}],96:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule SyntheticMouseEvent
- * @typechecks static-only
- */
-
-'use strict';
-
-var SyntheticUIEvent = _dereq_(98);
-var ViewportMetrics = _dereq_(101);
-
-var getEventModifierState = _dereq_(113);
-
-/**
- * @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) {
-  SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
-}
-
-SyntheticUIEvent.augmentClass(SyntheticMouseEvent, MouseEventInterface);
-
-module.exports = SyntheticMouseEvent;
-},{"101":101,"113":113,"98":98}],97:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule SyntheticTouchEvent
- * @typechecks static-only
- */
-
-'use strict';
-
-var SyntheticUIEvent = _dereq_(98);
-
-var getEventModifierState = _dereq_(113);
-
-/**
- * @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) {
-  SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
-}
-
-SyntheticUIEvent.augmentClass(SyntheticTouchEvent, TouchEventInterface);
-
-module.exports = SyntheticTouchEvent;
-},{"113":113,"98":98}],98:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule SyntheticUIEvent
- * @typechecks static-only
- */
-
-'use strict';
-
-var SyntheticEvent = _dereq_(92);
-
-var getEventTarget = _dereq_(114);
-
-/**
- * @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 != null && 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) {
-  SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
-}
-
-SyntheticEvent.augmentClass(SyntheticUIEvent, UIEventInterface);
-
-module.exports = SyntheticUIEvent;
-},{"114":114,"92":92}],99:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule SyntheticWheelEvent
- * @typechecks static-only
- */
-
-'use strict';
-
-var SyntheticMouseEvent = _dereq_(96);
-
-/**
- * @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) {
-  SyntheticMouseEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
-}
-
-SyntheticMouseEvent.augmentClass(SyntheticWheelEvent, WheelEventInterface);
-
-module.exports = SyntheticWheelEvent;
-},{"96":96}],100:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule Transaction
- */
-
-'use strict';
-
-var invariant = _dereq_(144);
-
-/**
- * `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 Mixin = {
-  /**
-   * 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;
-  },
-
-  /**
-   * 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) {
-    !!this.isInTransaction() ? "development" !== 'production' ? invariant(false, 'Transaction.perform(...): Cannot initialize a transaction when there ' + 'is already an outstanding transaction.') : invariant(false) : undefined;
-    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] = Transaction.OBSERVED_ERROR;
-        this.wrapperInitData[i] = wrapper.initialize ? wrapper.initialize.call(this) : null;
-      } finally {
-        if (this.wrapperInitData[i] === Transaction.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() ? "development" !== 'production' ? invariant(false, 'Transaction.closeAll(): Cannot close transaction when none are open.') : invariant(false) : undefined;
-    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 !== Transaction.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;
-  }
-};
-
-var Transaction = {
-
-  Mixin: Mixin,
-
-  /**
-   * Token to look for to determine if an error occurred.
-   */
-  OBSERVED_ERROR: {}
-
-};
-
-module.exports = Transaction;
-},{"144":144}],101:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ViewportMetrics
- */
-
-'use strict';
-
-var ViewportMetrics = {
-
-  currentScrollLeft: 0,
-
-  currentScrollTop: 0,
-
-  refreshScrollValues: function (scrollPosition) {
-    ViewportMetrics.currentScrollLeft = scrollPosition.x;
-    ViewportMetrics.currentScrollTop = scrollPosition.y;
-  }
-
-};
-
-module.exports = ViewportMetrics;
-},{}],102:[function(_dereq_,module,exports){
-/**
- * Copyright 2014-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule accumulateInto
- */
-
-'use strict';
-
-var invariant = _dereq_(144);
-
-/**
- *
- * 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) ? "development" !== 'production' ? invariant(false, 'accumulateInto(...): Accumulated items must not be null or undefined.') : invariant(false) : undefined;
-  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).
-  var currentIsArray = Array.isArray(current);
-  var nextIsArray = Array.isArray(next);
-
-  if (currentIsArray && nextIsArray) {
-    current.push.apply(current, next);
-    return current;
-  }
-
-  if (currentIsArray) {
-    current.push(next);
-    return current;
-  }
-
-  if (nextIsArray) {
-    // A bit too dangerous to mutate `next`.
-    return [current].concat(next);
-  }
-
-  return [current, next];
-}
-
-module.exports = accumulateInto;
-},{"144":144}],103:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule adler32
- */
-
-'use strict';
-
-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) {
-    for (; i < Math.min(i + 4096, m); 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;
-},{}],104:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule canDefineProperty
- */
-
-'use strict';
-
-var canDefineProperty = false;
-if ("development" !== 'production') {
-  try {
-    Object.defineProperty({}, 'x', { get: function () {} });
-    canDefineProperty = true;
-  } catch (x) {
-    // IE will fail on defineProperty
-  }
-}
-
-module.exports = canDefineProperty;
-},{}],105:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule dangerousStyleValue
- * @typechecks static-only
- */
-
-'use strict';
-
-var CSSProperty = _dereq_(4);
-
-var isUnitlessNumber = CSSProperty.isUnitlessNumber;
-
-/**
- * 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`.
- * @return {string} Normalized style value with dimensions applied.
- */
-function dangerousStyleValue(name, value) {
-  // 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 (isNonNumeric || value === 0 || isUnitlessNumber.hasOwnProperty(name) && isUnitlessNumber[name]) {
-    return '' + value; // cast to string
-  }
-
-  if (typeof value === 'string') {
-    value = value.trim();
-  }
-  return value + 'px';
-}
-
-module.exports = dangerousStyleValue;
-},{"4":4}],106:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule deprecated
- */
-
-'use strict';
-
-var assign = _dereq_(23);
-var warning = _dereq_(155);
-
-/**
- * This will log a single deprecation notice per function and forward the call
- * on to the new API.
- *
- * @param {string} fnName The name of the function
- * @param {string} newModule The module that fn will exist in
- * @param {string} newPackage The module that fn will exist in
- * @param {*} ctx The context this forwarded call should run in
- * @param {function} fn The function to forward on to
- * @return {function} The function that will warn once and then call fn
- */
-function deprecated(fnName, newModule, newPackage, ctx, fn) {
-  var warned = false;
-  if ("development" !== 'production') {
-    var newFn = function () {
-      "development" !== 'production' ? warning(warned,
-      // Require examples in this string must be split to prevent React's
-      // build tools from mistaking them for real requires.
-      // Otherwise the build tools will attempt to build a '%s' module.
-      'React.%s is deprecated. Please use %s.%s from require' + '(\'%s\') ' + 'instead.', fnName, newModule, fnName, newPackage) : undefined;
-      warned = true;
-      return fn.apply(ctx, arguments);
-    };
-    // We need to make sure all properties of the original fn are copied over.
-    // In particular, this is needed to support PropTypes
-    return assign(newFn, fn);
-  }
-
-  return fn;
-}
-
-module.exports = deprecated;
-},{"155":155,"23":23}],107:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule escapeTextContentForBrowser
- */
-
-'use strict';
-
-var ESCAPE_LOOKUP = {
-  '&': '&amp;',
-  '>': '&gt;',
-  '<': '&lt;',
-  '"': '&quot;',
-  '\'': '&#x27;'
-};
-
-var ESCAPE_REGEX = /[&><"']/g;
-
-function escaper(match) {
-  return ESCAPE_LOOKUP[match];
-}
-
-/**
- * Escapes text to prevent scripting attacks.
- *
- * @param {*} text Text value to escape.
- * @return {string} An escaped string.
- */
-function escapeTextContentForBrowser(text) {
-  return ('' + text).replace(ESCAPE_REGEX, escaper);
-}
-
-module.exports = escapeTextContentForBrowser;
-},{}],108:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule findDOMNode
- * @typechecks static-only
- */
-
-'use strict';
-
-var ReactCurrentOwner = _dereq_(34);
-var ReactInstanceMap = _dereq_(62);
-var ReactMount = _dereq_(65);
-
-var invariant = _dereq_(144);
-var warning = _dereq_(155);
-
-/**
- * Returns the DOM node rendered by this element.
- *
- * @param {ReactComponent|DOMElement} componentOrElement
- * @return {?DOMElement} The root node of this element.
- */
-function findDOMNode(componentOrElement) {
-  if ("development" !== 'production') {
-    var owner = ReactCurrentOwner.current;
-    if (owner !== null) {
-      "development" !== 'production' ? warning(owner._warnedAboutRefsInRender, '%s is accessing getDOMNode or 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') : undefined;
-      owner._warnedAboutRefsInRender = true;
-    }
-  }
-  if (componentOrElement == null) {
-    return null;
-  }
-  if (componentOrElement.nodeType === 1) {
-    return componentOrElement;
-  }
-  if (ReactInstanceMap.has(componentOrElement)) {
-    return ReactMount.getNodeFromInstance(componentOrElement);
-  }
-  !(componentOrElement.render == null || typeof componentOrElement.render !== 'function') ? "development" !== 'production' ? invariant(false, 'findDOMNode was called on an unmounted component.') : invariant(false) : undefined;
-  !false ? "development" !== 'production' ? invariant(false, 'Element appears to be neither ReactComponent nor DOMNode (keys: %s)', Object.keys(componentOrElement)) : invariant(false) : undefined;
-}
-
-module.exports = findDOMNode;
-},{"144":144,"155":155,"34":34,"62":62,"65":65}],109:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule flattenChildren
- */
-
-'use strict';
-
-var traverseAllChildren = _dereq_(127);
-var warning = _dereq_(155);
-
-/**
- * @param {function} traverseContext Context passed through traversal.
- * @param {?ReactComponent} child React child component.
- * @param {!string} name String name of key path to child.
- */
-function flattenSingleChildIntoContext(traverseContext, child, name) {
-  // We found a component instance.
-  var result = traverseContext;
-  var keyUnique = result[name] === undefined;
-  if ("development" !== 'production') {
-    "development" !== 'production' ? warning(keyUnique, '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.', name) : undefined;
-  }
-  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) {
-  if (children == null) {
-    return children;
-  }
-  var result = {};
-  traverseAllChildren(children, flattenSingleChildIntoContext, result);
-  return result;
-}
-
-module.exports = flattenChildren;
-},{"127":127,"155":155}],110:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule forEachAccumulated
- */
-
-'use strict';
-
-/**
- * @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).
- */
-var forEachAccumulated = function (arr, cb, scope) {
-  if (Array.isArray(arr)) {
-    arr.forEach(cb, scope);
-  } else if (arr) {
-    cb.call(scope, arr);
-  }
-};
-
-module.exports = forEachAccumulated;
-},{}],111:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule getEventCharCode
- * @typechecks static-only
- */
-
-'use strict';
-
-/**
- * `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;
-},{}],112:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule getEventKey
- * @typechecks static-only
- */
-
-'use strict';
-
-var getEventCharCode = _dereq_(111);
-
-/**
- * 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;
-},{"111":111}],113:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule getEventModifierState
- * @typechecks static-only
- */
-
-'use strict';
-
-/**
- * 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;
-},{}],114:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule getEventTarget
- * @typechecks static-only
- */
-
-'use strict';
-
-/**
- * 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;
-  // 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;
-},{}],115:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule getIteratorFn
- * @typechecks static-only
- */
-
-'use strict';
-
-/* 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;
-},{}],116:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule getNodeForCharacterOffset
- */
-
-'use strict';
-
-/**
- * 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;
-},{}],117:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule getTextContentAccessor
- */
-
-'use strict';
-
-var ExecutionEnvironment = _dereq_(130);
-
-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;
-},{"130":130}],118:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule instantiateReactComponent
- * @typechecks static-only
- */
-
-'use strict';
-
-var ReactCompositeComponent = _dereq_(33);
-var ReactEmptyComponent = _dereq_(54);
-var ReactNativeComponent = _dereq_(68);
-
-var assign = _dereq_(23);
-var invariant = _dereq_(144);
-var warning = _dereq_(155);
-
-// To avoid a cyclic dependency, we create the final class in this module
-var ReactCompositeComponentWrapper = function () {};
-assign(ReactCompositeComponentWrapper.prototype, ReactCompositeComponent.Mixin, {
-  _instantiateReactComponent: instantiateReactComponent
-});
-
-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
- * @return {object} A new instance of the element's constructor.
- * @protected
- */
-function instantiateReactComponent(node) {
-  var instance;
-
-  if (node === null || node === false) {
-    instance = new ReactEmptyComponent(instantiateReactComponent);
-  } else if (typeof node === 'object') {
-    var element = node;
-    !(element && (typeof element.type === 'function' || typeof element.type === 'string')) ? "development" !== 'production' ? invariant(false, 'Element type is invalid: expected a string (for built-in components) ' + 'or a class/function (for composite components) but got: %s.%s', element.type == null ? element.type : typeof element.type, getDeclarationErrorAddendum(element._owner)) : invariant(false) : undefined;
-
-    // Special case string values
-    if (typeof element.type === 'string') {
-      instance = ReactNativeComponent.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);
-    } else {
-      instance = new ReactCompositeComponentWrapper();
-    }
-  } else if (typeof node === 'string' || typeof node === 'number') {
-    instance = ReactNativeComponent.createInstanceForText(node);
-  } else {
-    !false ? "development" !== 'production' ? invariant(false, 'Encountered invalid React node of type %s', typeof node) : invariant(false) : undefined;
-  }
-
-  if ("development" !== 'production') {
-    "development" !== 'production' ? warning(typeof instance.construct === 'function' && typeof instance.mountComponent === 'function' && typeof instance.receiveComponent === 'function' && typeof instance.unmountComponent === 'function', 'Only React Components can be mounted.') : undefined;
-  }
-
-  // Sets up the instance. This can probably just move into the constructor now.
-  instance.construct(node);
-
-  // 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 ("development" !== 'production') {
-    instance._isOwnerNecessary = false;
-    instance._warnedAboutRefsInRender = false;
-  }
-
-  // Internal instances should fully constructed at this point, so they should
-  // not get any new fields added to them at this point.
-  if ("development" !== 'production') {
-    if (Object.preventExtensions) {
-      Object.preventExtensions(instance);
-    }
-  }
-
-  return instance;
-}
-
-module.exports = instantiateReactComponent;
-},{"144":144,"155":155,"23":23,"33":33,"54":54,"68":68}],119:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule isEventSupported
- */
-
-'use strict';
-
-var ExecutionEnvironment = _dereq_(130);
-
-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;
-},{"130":130}],120:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule isTextInputElement
- */
-
-'use strict';
-
-/**
- * @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();
-  return nodeName && (nodeName === 'input' && supportedInputTypes[elem.type] || nodeName === 'textarea');
-}
-
-module.exports = isTextInputElement;
-},{}],121:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule onlyChild
- */
-'use strict';
-
-var ReactElement = _dereq_(52);
-
-var invariant = _dereq_(144);
-
-/**
- * Returns the first child in a collection of children and verifies that there
- * is only one child in the collection. 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 {ReactComponent} The first and only `ReactComponent` contained in the
- * structure.
- */
-function onlyChild(children) {
-  !ReactElement.isValidElement(children) ? "development" !== 'production' ? invariant(false, 'onlyChild must be passed a children with exactly one child.') : invariant(false) : undefined;
-  return children;
-}
-
-module.exports = onlyChild;
-},{"144":144,"52":52}],122:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule quoteAttributeValueForBrowser
- */
-
-'use strict';
-
-var escapeTextContentForBrowser = _dereq_(107);
-
-/**
- * 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;
-},{"107":107}],123:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
-* @providesModule renderSubtreeIntoContainer
-*/
-
-'use strict';
-
-var ReactMount = _dereq_(65);
-
-module.exports = ReactMount.renderSubtreeIntoContainer;
-},{"65":65}],124:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule setInnerHTML
- */
-
-/* globals MSApp */
-
-'use strict';
-
-var ExecutionEnvironment = _dereq_(130);
-
-var WHITESPACE_TEST = /^[ \r\n\t\f]/;
-var NONVISIBLE_TEST = /<(!--|link|noscript|meta|script|style)[ \r\n\t\f\/>]/;
-
-/**
- * Set the innerHTML property of a node, ensuring that whitespace is preserved
- * even in IE8.
- *
- * @param {DOMElement} node
- * @param {string} html
- * @internal
- */
-var setInnerHTML = function (node, html) {
-  node.innerHTML = html;
-};
-
-// Win8 apps: Allow all html to be inserted
-if (typeof MSApp !== 'undefined' && MSApp.execUnsafeLocalFunction) {
-  setInnerHTML = function (node, html) {
-    MSApp.execUnsafeLocalFunction(function () {
-      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;
-      }
-    };
-  }
-}
-
-module.exports = setInnerHTML;
-},{"130":130}],125:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule setTextContent
- */
-
-'use strict';
-
-var ExecutionEnvironment = _dereq_(130);
-var escapeTextContentForBrowser = _dereq_(107);
-var setInnerHTML = _dereq_(124);
-
-/**
- * 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) {
-  node.textContent = text;
-};
-
-if (ExecutionEnvironment.canUseDOM) {
-  if (!('textContent' in document.documentElement)) {
-    setTextContent = function (node, text) {
-      setInnerHTML(node, escapeTextContentForBrowser(text));
-    };
-  }
-}
-
-module.exports = setTextContent;
-},{"107":107,"124":124,"130":130}],126:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule shouldUpdateReactComponent
- * @typechecks static-only
- */
-
-'use strict';
-
-/**
- * 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;
-  }
-  return false;
-}
-
-module.exports = shouldUpdateReactComponent;
-},{}],127:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule traverseAllChildren
- */
-
-'use strict';
-
-var ReactCurrentOwner = _dereq_(34);
-var ReactElement = _dereq_(52);
-var ReactInstanceHandles = _dereq_(61);
-
-var getIteratorFn = _dereq_(115);
-var invariant = _dereq_(144);
-var warning = _dereq_(155);
-
-var SEPARATOR = ReactInstanceHandles.SEPARATOR;
-var SUBSEPARATOR = ':';
-
-/**
- * TODO: Test that a single child and an array with one item have the same key
- * pattern.
- */
-
-var userProvidedKeyEscaperLookup = {
-  '=': '=0',
-  '.': '=1',
-  ':': '=2'
-};
-
-var userProvidedKeyEscapeRegex = /[=.:]/g;
-
-var didWarnAboutMaps = false;
-
-function userProvidedKeyEscaper(match) {
-  return userProvidedKeyEscaperLookup[match];
-}
-
-/**
- * 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) {
-  if (component && component.key != null) {
-    // Explicit key
-    return wrapUserProvidedKey(component.key);
-  }
-  // Implicit key determined by the index in the set
-  return index.toString(36);
-}
-
-/**
- * Escape a component key so that it is safe to use in a reactid.
- *
- * @param {*} text Component key to be escaped.
- * @return {string} An escaped string.
- */
-function escapeUserProvidedKey(text) {
-  return ('' + text).replace(userProvidedKeyEscapeRegex, userProvidedKeyEscaper);
-}
-
-/**
- * Wrap a `key` value explicitly provided by the user to distinguish it from
- * implicitly-generated keys generated by a component's index in its parent.
- *
- * @param {string} key Value of a user-provided `key` attribute
- * @return {string}
- */
-function wrapUserProvidedKey(key) {
-  return '$' + escapeUserProvidedKey(key);
-}
-
-/**
- * @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' || ReactElement.isValidElement(children)) {
-    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 ("development" !== 'production') {
-          "development" !== 'production' ? 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.') : undefined;
-          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 + wrapUserProvidedKey(entry[0]) + SUBSEPARATOR + getComponentKey(child, 0);
-            subtreeCount += traverseAllChildrenImpl(child, nextName, callback, traverseContext);
-          }
-        }
-      }
-    } else if (type === 'object') {
-      var addendum = '';
-      if ("development" !== 'production') {
-        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);
-      !false ? "development" !== 'production' ? 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) : invariant(false) : undefined;
-    }
-  }
-
-  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;
-},{"115":115,"144":144,"155":155,"34":34,"52":52,"61":61}],128:[function(_dereq_,module,exports){
-/**
- * Copyright 2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule validateDOMNesting
- */
-
-'use strict';
-
-var assign = _dereq_(23);
-var emptyFunction = _dereq_(136);
-var warning = _dereq_(155);
-
-var validateDOMNesting = emptyFunction;
-
-if ("development" !== 'production') {
-  // 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 = {
-    parentTag: 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.parentTag = 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';
-    }
-
-    // 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 'caption':
-      case 'col':
-      case 'colgroup':
-      case 'frame':
-      case 'head':
-      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 = [];
-    /*eslint-disable space-after-keywords */
-    do {
-      /*eslint-enable space-after-keywords */
-      stack.push(instance);
-    } while (instance = instance._currentElement._owner);
-    stack.reverse();
-    return stack;
-  };
-
-  var didWarn = {};
-
-  validateDOMNesting = function (childTag, childInstance, ancestorInfo) {
-    ancestorInfo = ancestorInfo || emptyAncestorInfo;
-    var parentInfo = ancestorInfo.parentTag;
-    var parentTag = parentInfo && parentInfo.tag;
-
-    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;
-
-      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.';
-        }
-        "development" !== 'production' ? warning(false, 'validateDOMNesting(...): <%s> cannot appear as a child of <%s>. ' + 'See %s.%s', childTag, ancestorTag, ownerInfo, info) : undefined;
-      } else {
-        "development" !== 'production' ? warning(false, 'validateDOMNesting(...): <%s> cannot appear as a descendant of ' + '<%s>. See %s.', childTag, ancestorTag, ownerInfo) : undefined;
-      }
-    }
-  };
-
-  validateDOMNesting.ancestorInfoContextKey = '__validateDOMNesting_ancestorInfo$' + Math.random().toString(36).slice(2);
-
-  validateDOMNesting.updatedAncestorInfo = updatedAncestorInfo;
-
-  // For testing
-  validateDOMNesting.isTagValidInContext = function (tag, ancestorInfo) {
-    ancestorInfo = ancestorInfo || emptyAncestorInfo;
-    var parentInfo = ancestorInfo.parentTag;
-    var parentTag = parentInfo && parentInfo.tag;
-    return isTagValidWithParent(tag, parentTag) && !findInvalidAncestorForTag(tag, ancestorInfo);
-  };
-}
-
-module.exports = validateDOMNesting;
-},{"136":136,"155":155,"23":23}],129:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * @providesModule EventListener
- * @typechecks
- */
-
-'use strict';
-
-var emptyFunction = _dereq_(136);
-
-/**
- * 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 (target, eventType, callback) {
-    if (target.addEventListener) {
-      target.addEventListener(eventType, callback, false);
-      return {
-        remove: function () {
-          target.removeEventListener(eventType, callback, false);
-        }
-      };
-    } else if (target.attachEvent) {
-      target.attachEvent('on' + eventType, callback);
-      return {
-        remove: function () {
-          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 (target, eventType, callback) {
-    if (target.addEventListener) {
-      target.addEventListener(eventType, callback, true);
-      return {
-        remove: function () {
-          target.removeEventListener(eventType, callback, true);
-        }
-      };
-    } else {
-      if ("development" !== 'production') {
-        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 () {}
-};
-
-module.exports = EventListener;
-},{"136":136}],130:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule ExecutionEnvironment
- */
-
-'use strict';
-
-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;
-},{}],131:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule camelize
- * @typechecks
- */
-
-"use strict";
-
-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;
-},{}],132:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule camelizeStyleName
- * @typechecks
- */
-
-'use strict';
-
-var camelize = _dereq_(131);
-
-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;
-},{"131":131}],133:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule containsNode
- * @typechecks
- */
-
-'use strict';
-
-var isTextNode = _dereq_(146);
-
-/*eslint-disable no-bitwise */
-
-/**
- * Checks if a given DOM node contains or is another DOM node.
- *
- * @param {?DOMNode} outerNode Outer DOM node.
- * @param {?DOMNode} innerNode Inner DOM node.
- * @return {boolean} True if `outerNode` contains or is `innerNode`.
- */
-function containsNode(_x, _x2) {
-  var _again = true;
-
-  _function: while (_again) {
-    var outerNode = _x,
-        innerNode = _x2;
-    _again = false;
-
-    if (!outerNode || !innerNode) {
-      return false;
-    } else if (outerNode === innerNode) {
-      return true;
-    } else if (isTextNode(outerNode)) {
-      return false;
-    } else if (isTextNode(innerNode)) {
-      _x = outerNode;
-      _x2 = innerNode.parentNode;
-      _again = true;
-      continue _function;
-    } else if (outerNode.contains) {
-      return outerNode.contains(innerNode);
-    } else if (outerNode.compareDocumentPosition) {
-      return !!(outerNode.compareDocumentPosition(innerNode) & 16);
-    } else {
-      return false;
-    }
-  }
-}
-
-module.exports = containsNode;
-},{"146":146}],134:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule createArrayFromMixed
- * @typechecks
- */
-
-'use strict';
-
-var toArray = _dereq_(154);
-
-/**
- * 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;
-},{"154":154}],135:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule createNodesFromMarkup
- * @typechecks
- */
-
-/*eslint-disable fb-www/unsafe-html*/
-
-'use strict';
-
-var ExecutionEnvironment = _dereq_(130);
-
-var createArrayFromMixed = _dereq_(134);
-var getMarkupWrap = _dereq_(140);
-var invariant = _dereq_(144);
-
-/**
- * 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 ? "development" !== 'production' ? invariant(false, 'createNodesFromMarkup dummy not initialized') : invariant(false) : undefined;
-  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 ? "development" !== 'production' ? invariant(false, 'createNodesFromMarkup(...): Unexpected <script> element rendered.') : invariant(false) : undefined;
-    createArrayFromMixed(scripts).forEach(handleScript);
-  }
-
-  var nodes = createArrayFromMixed(node.childNodes);
-  while (node.lastChild) {
-    node.removeChild(node.lastChild);
-  }
-  return nodes;
-}
-
-module.exports = createNodesFromMarkup;
-},{"130":130,"134":134,"140":140,"144":144}],136:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule emptyFunction
- */
-
-"use strict";
-
-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.
- */
-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;
-},{}],137:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule emptyObject
- */
-
-'use strict';
-
-var emptyObject = {};
-
-if ("development" !== 'production') {
-  Object.freeze(emptyObject);
-}
-
-module.exports = emptyObject;
-},{}],138:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule focusNode
- */
-
-'use strict';
-
-/**
- * @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;
-},{}],139:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule getActiveElement
- * @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.
- */
-'use strict';
-
-function getActiveElement() /*?DOMElement*/{
-  if (typeof document === 'undefined') {
-    return null;
-  }
-  try {
-    return document.activeElement || document.body;
-  } catch (e) {
-    return document.body;
-  }
-}
-
-module.exports = getActiveElement;
-},{}],140:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule getMarkupWrap
- */
-
-/*eslint-disable fb-www/unsafe-html */
-
-'use strict';
-
-var ExecutionEnvironment = _dereq_(130);
-
-var invariant = _dereq_(144);
-
-/**
- * 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 ? "development" !== 'production' ? invariant(false, 'Markup wrapping node not initialized') : invariant(false) : undefined;
-  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;
-},{"130":130,"144":144}],141:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule getUnboundedScrollPosition
- * @typechecks
- */
-
-'use strict';
-
-/**
- * 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) {
-    return {
-      x: window.pageXOffset || document.documentElement.scrollLeft,
-      y: window.pageYOffset || document.documentElement.scrollTop
-    };
-  }
-  return {
-    x: scrollable.scrollLeft,
-    y: scrollable.scrollTop
-  };
-}
-
-module.exports = getUnboundedScrollPosition;
-},{}],142:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule hyphenate
- * @typechecks
- */
-
-'use strict';
-
-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;
-},{}],143:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule hyphenateStyleName
- * @typechecks
- */
-
-'use strict';
-
-var hyphenate = _dereq_(142);
-
-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;
-},{"142":142}],144:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule invariant
- */
-
-'use strict';
-
-/**
- * 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.
- */
-
-function invariant(condition, format, a, b, c, d, e, f) {
-  if ("development" !== 'production') {
-    if (format === undefined) {
-      throw new Error('invariant requires an error message argument');
-    }
-  }
-
-  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;
-},{}],145:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule isNode
- * @typechecks
- */
-
-/**
- * @param {*} object The object to check.
- * @return {boolean} Whether or not the object is a DOM node.
- */
-'use strict';
-
-function isNode(object) {
-  return !!(object && (typeof Node === 'function' ? object instanceof Node : typeof object === 'object' && typeof object.nodeType === 'number' && typeof object.nodeName === 'string'));
-}
-
-module.exports = isNode;
-},{}],146:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule isTextNode
- * @typechecks
- */
-
-'use strict';
-
-var isNode = _dereq_(145);
-
-/**
- * @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;
-},{"145":145}],147:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule keyMirror
- * @typechecks static-only
- */
-
-'use strict';
-
-var invariant = _dereq_(144);
-
-/**
- * Constructs an enumeration with keys equal to their value.
- *
- * For example:
- *
- *   var COLORS = keyMirror({blue: null, red: null});
- *   var myColor = COLORS.blue;
- *   var isColorValid = !!COLORS[myColor];
- *
- * The last line could not be performed if the values of the generated enum were
- * not equal to their keys.
- *
- *   Input:  {key1: val1, key2: val2}
- *   Output: {key1: key1, key2: key2}
- *
- * @param {object} obj
- * @return {object}
- */
-var keyMirror = function (obj) {
-  var ret = {};
-  var key;
-  !(obj instanceof Object && !Array.isArray(obj)) ? "development" !== 'production' ? invariant(false, 'keyMirror(...): Argument must be an object.') : invariant(false) : undefined;
-  for (key in obj) {
-    if (!obj.hasOwnProperty(key)) {
-      continue;
-    }
-    ret[key] = key;
-  }
-  return ret;
-};
-
-module.exports = keyMirror;
-},{"144":144}],148:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule keyOf
- */
-
-/**
- * Allows extraction of a minified key. Let's the build system minify keys
- * without losing the ability to dynamically use key strings as values
- * themselves. Pass in an object with a single key/val pair and it will return
- * you the string key of that single record. Suppose you want to grab the
- * value for a key 'className' inside of an object. Key/val minification may
- * have aliased that key to be 'xa12'. keyOf({className: null}) will return
- * 'xa12' in that case. Resolve keys you want to use once at startup time, then
- * reuse those resolutions.
- */
-"use strict";
-
-var keyOf = function (oneKeyObj) {
-  var key;
-  for (key in oneKeyObj) {
-    if (!oneKeyObj.hasOwnProperty(key)) {
-      continue;
-    }
-    return key;
-  }
-  return null;
-};
-
-module.exports = keyOf;
-},{}],149:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule mapObject
- */
-
-'use strict';
-
-var hasOwnProperty = Object.prototype.hasOwnProperty;
-
-/**
- * Executes the provided `callback` once for each enumerable own property in the
- * object and constructs a new object from the results. The `callback` is
- * invoked with three arguments:
- *
- *  - the property value
- *  - the property name
- *  - the object being traversed
- *
- * Properties that are added after the call to `mapObject` will not be visited
- * by `callback`. If the values of existing properties are changed, the value
- * passed to `callback` will be the value at the time `mapObject` visits them.
- * Properties that are deleted before being visited are not visited.
- *
- * @grep function objectMap()
- * @grep function objMap()
- *
- * @param {?object} object
- * @param {function} callback
- * @param {*} context
- * @return {?object}
- */
-function mapObject(object, callback, context) {
-  if (!object) {
-    return null;
-  }
-  var result = {};
-  for (var name in object) {
-    if (hasOwnProperty.call(object, name)) {
-      result[name] = callback.call(context, object[name], name, object);
-    }
-  }
-  return result;
-}
-
-module.exports = mapObject;
-},{}],150:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule memoizeStringOnly
- * @typechecks static-only
- */
-
-'use strict';
-
-/**
- * Memoizes the return value of a function that accepts one string argument.
- *
- * @param {function} callback
- * @return {function}
- */
-function memoizeStringOnly(callback) {
-  var cache = {};
-  return function (string) {
-    if (!cache.hasOwnProperty(string)) {
-      cache[string] = callback.call(this, string);
-    }
-    return cache[string];
-  };
-}
-
-module.exports = memoizeStringOnly;
-},{}],151:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule performance
- * @typechecks
- */
-
-'use strict';
-
-var ExecutionEnvironment = _dereq_(130);
-
-var performance;
-
-if (ExecutionEnvironment.canUseDOM) {
-  performance = window.performance || window.msPerformance || window.webkitPerformance;
-}
-
-module.exports = performance || {};
-},{"130":130}],152:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule performanceNow
- * @typechecks
- */
-
-'use strict';
-
-var performance = _dereq_(151);
-
-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 () {
-    return performance.now();
-  };
-} else {
-  performanceNow = function () {
-    return Date.now();
-  };
-}
-
-module.exports = performanceNow;
-},{"151":151}],153:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule shallowEqual
- * @typechecks
- * 
- */
-
-'use strict';
-
-var hasOwnProperty = Object.prototype.hasOwnProperty;
-
-/**
- * Performs equality by iterating through keys on an object and returning false
- * when any key has values which are not strictly equal between the arguments.
- * Returns true when the values of all keys are strictly equal.
- */
-function shallowEqual(objA, objB) {
-  if (objA === objB) {
-    return true;
-  }
-
-  if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
-    return false;
-  }
-
-  var keysA = Object.keys(objA);
-  var keysB = Object.keys(objB);
-
-  if (keysA.length !== keysB.length) {
-    return false;
-  }
-
-  // Test for A's keys different from B.
-  var bHasOwnProperty = hasOwnProperty.bind(objB);
-  for (var i = 0; i < keysA.length; i++) {
-    if (!bHasOwnProperty(keysA[i]) || objA[keysA[i]] !== objB[keysA[i]]) {
-      return false;
-    }
-  }
-
-  return true;
-}
-
-module.exports = shallowEqual;
-},{}],154:[function(_dereq_,module,exports){
-/**
- * Copyright 2013-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule toArray
- * @typechecks
- */
-
-'use strict';
-
-var invariant = _dereq_(144);
-
-/**
- * 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 browse builtin objects can report typeof 'function' (e.g. NodeList in
-  // old versions of Safari).
-  !(!Array.isArray(obj) && (typeof obj === 'object' || typeof obj === 'function')) ? "development" !== 'production' ? invariant(false, 'toArray: Array-like object expected') : invariant(false) : undefined;
-
-  !(typeof length === 'number') ? "development" !== 'production' ? invariant(false, 'toArray: Object needs a length property') : invariant(false) : undefined;
-
-  !(length === 0 || length - 1 in obj) ? "development" !== 'production' ? invariant(false, 'toArray: Object should have keys for indices') : invariant(false) : undefined;
-
-  // 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;
-}
-
-module.exports = toArray;
-},{"144":144}],155:[function(_dereq_,module,exports){
-/**
- * Copyright 2014-2015, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- *
- * @providesModule warning
- */
-
-'use strict';
-
-var emptyFunction = _dereq_(136);
-
-/**
- * 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 ("development" !== 'production') {
-  warning = function (condition, format) {
-    for (var _len = arguments.length, args = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
-      args[_key - 2] = arguments[_key];
-    }
-
-    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) {
-      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) {}
-    }
-  };
-}
-
-module.exports = warning;
-},{"136":136}]},{},[1])(1)
-});
\ No newline at end of file
diff --git a/docs/jsx-compiler.md b/docs/jsx-compiler.md
index bcfa64302c69..85e9775f40d6 100644
--- a/docs/jsx-compiler.md
+++ b/docs/jsx-compiler.md
@@ -1,6 +1,7 @@
 ---
 layout: single
 title: JSX Compiler Service
+permalink: jsx-compiler.html
 id: jsx-compiler
 ---
 
diff --git a/docs/support.md b/docs/support.md
deleted file mode 100644
index 4915455927da..000000000000
--- a/docs/support.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-title: Need help?
-layout: single
-id: support
----
-
-**React** is worked on full-time by Facebook's product infrastructure and Instagram's user interface engineering teams. They're often around and available for questions.
-
-## Stack Overflow
-
-Many members of the community use Stack Overflow to ask questions. Read through the [existing questions](http://stackoverflow.com/questions/tagged/reactjs) tagged with **reactjs** or [ask your own](http://stackoverflow.com/questions/ask?tags=reactjs)!
-
-## Discussion forum
-
-For longer-form conversations about React, we've set up a [discussion forum at **discuss.reactjs.org**](https://discuss.reactjs.org/). This forum is a great place for discussion about best practices and application architecture as well as the future of React. If you have an answerable code-level question, please post it to Stack Overflow instead.
-
-In the forum there's also a category for job posts and a category for discussion of our weekly meeting notes.
-
-## IRC
-
-Many developers and users idle on Freenode.net's IRC network in **[#reactjs on freenode](irc://chat.freenode.net/reactjs)**.
-
-## Twitter
-
-For the latest news about React, [follow **@reactjs** on Twitter](https://twitter.com/reactjs). In addition, you can use the #reactjs hashtag to see what others are saying or add to the conversation.
-
-<div><a class="twitter-timeline" data-dnt="true" data-chrome="nofooter noheader transparent" href="https://twitter.com/search?q=%23reactjs" data-widget-id="342522405270470656"></a></div>
diff --git a/docs/tips/01-introduction.ja-JP.md b/docs/tips/01-introduction.ja-JP.md
deleted file mode 100644
index f4354efee8b4..000000000000
--- a/docs/tips/01-introduction.ja-JP.md
+++ /dev/null
@@ -1,13 +0,0 @@
----
-id: introduction-ja-JP
-title: イントロダクション
-layout: tips
-permalink: introduction-ja-JP.html
-next: inline-styles-ja-JP.html
----
-
-Reactのtipsのセクションでは、あなたの質問の多くに答えられたり、はまりそうな罠に対する注意を行う適当な大きさの情報を提供します。
-
-## コントリビューティング
-
-[Reactのリポジトリ](https://github.com/facebook/react)に[現在のtips](https://github.com/facebook/react/tree/master/docs)の記事のスタイルに沿った形でプルリクエストを投げてください。プルリクエストを投げる前にレビューが必要な場合は[freenodeの #reactjs チャンネル](irc://chat.freenode.net/reactjs)や[discuss.reactjs.org フォーラム](https://discuss.reactjs.org/)で助けを求めることができます。
diff --git a/docs/tips/01-introduction.ko-KR.md b/docs/tips/01-introduction.ko-KR.md
deleted file mode 100644
index b8c0463712c1..000000000000
--- a/docs/tips/01-introduction.ko-KR.md
+++ /dev/null
@@ -1,13 +0,0 @@
----
-id: introduction-ko-KR
-title: 개요
-layout: tips
-permalink: introduction-ko-KR.html
-next: inline-styles-ko-KR.html
----
-
-React 팁 섹션에서는 여러 궁금증을 해결해주고 흔히 하는 실수를 피할 수 있도록 짧은 정보들을 제공합니다.
-
-## 기여하기
-
-[현재 팁](https://github.com/facebook/react/tree/master/docs)의 형식을 따르는 풀 리퀘스트를 [React 저장소](https://github.com/facebook/react)에 보내주세요. PR을 보내기 전에 리뷰가 필요하다면 [freenode의 #reactjs 채널](irc://chat.freenode.net/reactjs)이나 [discuss.reactjs.org 포럼](https://discuss.reactjs.org/)에서 도움을 요청하실 수 있습니다.
diff --git a/docs/tips/01-introduction.md b/docs/tips/01-introduction.md
deleted file mode 100644
index 3a95c767320c..000000000000
--- a/docs/tips/01-introduction.md
+++ /dev/null
@@ -1,13 +0,0 @@
----
-id: introduction
-title: Introduction
-layout: tips
-permalink: introduction.html
-next: inline-styles.html
----
-
-The React tips section provides bite-sized information that can answer lots of questions you might have and warn you against common pitfalls.
-
-## Contributing
-
-Submit a pull request to the [React repository](https://github.com/facebook/react) following the [current tips](https://github.com/facebook/react/tree/master/docs) entries' style. If you have a recipe that needs review prior to submitting a PR you can find help in the [#reactjs channel on freenode](irc://chat.freenode.net/reactjs) or the [discuss.reactjs.org forum](https://discuss.reactjs.org/).
diff --git a/docs/tips/02-inline-styles.ko-KR.md b/docs/tips/02-inline-styles.ko-KR.md
deleted file mode 100644
index f5e0c73d106c..000000000000
--- a/docs/tips/02-inline-styles.ko-KR.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-id: inline-styles-ko-KR
-title: 인라인 스타일
-layout: tips
-permalink: inline-styles-ko-KR.html
-next: if-else-in-JSX-ko-KR.html
-prev: introduction-ko-KR.html
----
-
-React에서는 인라인 스타일을 문자열로 지정하지 않습니다. 대신 스타일 이름을 camelCased 형식으로 바꾼 키와 스타일의 값(주로 문자열입니다 - [자세히 알아보기](/react/tips/style-props-value-px-ko-KR.html))을 가진 객체로 지정됩니다.
-
-```js
-var divStyle = {
-  color: 'white',
-  backgroundImage: 'url(' + imgUrl + ')',
-  WebkitTransition: 'all', // 'W'가 대문자임에 주의하세요
-  msTransition: 'all' // 'ms'는 유일한 소문자 벤더 프리픽스(vendor prefix)입니다
-};
-
-ReactDOM.render(<div style={divStyle}>Hello World!</div>, mountNode);
-```
-
-스타일 키는 JS에서 DOM 노드의 프로퍼티에 접근하는 것과 일관성있도록 camelCased 형식입니다. (예를 들어 `node.style.backgroundImage`) [`ms`를 제외한](http://www.andismith.com/blog/2012/02/modernizr-prefixed/) 벤더 프리픽스는 대문자로 시작해야 합니다. 따라서 `WebkitTransition`은 대문자 "W"를 사용합니다.
diff --git a/docs/tips/02-inline-styles.md b/docs/tips/02-inline-styles.md
deleted file mode 100644
index 1c4ec969866e..000000000000
--- a/docs/tips/02-inline-styles.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-id: inline-styles
-title: Inline Styles
-layout: tips
-permalink: inline-styles.html
-next: if-else-in-JSX.html
-prev: introduction.html
----
-
-In React, inline styles are not specified as a string. Instead they are specified with an object whose key is the camelCased version of the style name, and whose value is the style's value, usually a string ([more on that later](/react/tips/style-props-value-px.html)):
-
-```js
-var divStyle = {
-  color: 'white',
-  backgroundImage: 'url(' + imgUrl + ')',
-  WebkitTransition: 'all', // note the capital 'W' here
-  msTransition: 'all' // 'ms' is the only lowercase vendor prefix
-};
-
-ReactDOM.render(<div style={divStyle}>Hello World!</div>, mountNode);
-```
-
-Style keys are camelCased in order to be consistent with accessing the properties on DOM nodes from JS (e.g. `node.style.backgroundImage`). Vendor prefixes [other than `ms`](http://www.andismith.com/blog/2012/02/modernizr-prefixed/) should begin with a capital letter. This is why `WebkitTransition` has an uppercase "W".
diff --git a/docs/tips/03-if-else-in-JSX.ko-KR.md b/docs/tips/03-if-else-in-JSX.ko-KR.md
deleted file mode 100644
index ca5da4b89c4a..000000000000
--- a/docs/tips/03-if-else-in-JSX.ko-KR.md
+++ /dev/null
@@ -1,81 +0,0 @@
----
-id: if-else-in-JSX-ko-KR
-title: JSX에서 If-Else
-layout: tips
-permalink: if-else-in-JSX-ko-KR.html
-prev: inline-styles-ko-KR.html
-next: self-closing-tag-ko-KR.html
----
-
-JSX 안에서는 `if-else` 구문이 작동하지 않습니다. 왜냐하면 JSX가 그저 함수 호출과 객체 생성의 편의 문법이기 때문입니다. 다음의 기본적인 예제를 살펴봅시다.
-
-```js
-// 이 JSX 코드는
-ReactDOM.render(<div id="msg">Hello World!</div>, mountNode);
-
-// 다음의 JS 코드로 변환됩니다.
-ReactDOM.render(React.createElement("div", {id:"msg"}, "Hello World!"), mountNode);
-```
-
-그렇기 때문에 `if` 구문을 넣을 수 없습니다. 다음 예제를 봅시다.
-
-```js
-// 이 JSX 코드는
-<div id={if (condition) { 'msg' }}>Hello World!</div>
-
-// 다음의 JS 코드로 변환됩니다.
-React.createElement("div", {id: if (condition) { 'msg' }}, "Hello World!");
-```
-
-이는 올바른 JS가 아닙니다. 대신 삼항 연산자를 사용할 수 있습니다.
-
-```js
-ReactDOM.render(<div id={condition ? 'msg' : ''}>Hello World!</div>, mountNode);
-```
-
-삼항 연산자가 충분하지 않다면 JSX구문 밖에서 `if` 문을 사용해 어떤 컴포넌트가 사용될 지 결정할 수 있습니다.
-
-```js
-var loginButton;
-if (loggedIn) {
-  loginButton = <LogoutButton />;
-} else {
-  loginButton = <LoginButton />;
-}
-
-return (
-  <nav>
-    <Home />
-    {loginButton}
-  </nav>
-);
-```
-
-"inline"을 좀더 선호한다면, JSX _안에_ [즉시 평가되는 함수 표현식](https://en.wikipedia.org/wiki/Immediately-invoked_function_expression)을 선언하세요.
-
-```js
-return (
-  <section>
-    <h1>Color</h1>
-    <h3>Name</h3>
-    <p>{this.state.color || "white"}</p>
-    <h3>Hex</h3>
-    <p>
-      {(() => {
-        switch (this.state.color) {
-          case "red":   return "#FF0000";
-          case "green": return "#00FF00";
-          case "blue":  return "#0000FF";
-          default:      return "#FFFFFF";
-        }
-      })()}
-    </p>
-  </section>
-);
-```
-
-> 주의:
->
-> 위의 예제에 있는 ES6 [화살표 함수](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)는 `this`의 값을 구문적으로 바인드하기위해 사용되었습니다.
-
-[Babel REPL](https://babeljs.io/repl/)로 지금 바로 사용해보세요.
diff --git a/docs/tips/03-if-else-in-JSX.md b/docs/tips/03-if-else-in-JSX.md
deleted file mode 100644
index a22a6cf818db..000000000000
--- a/docs/tips/03-if-else-in-JSX.md
+++ /dev/null
@@ -1,81 +0,0 @@
----
-id: if-else-in-JSX
-title: If-Else in JSX
-layout: tips
-permalink: if-else-in-JSX.html
-prev: inline-styles.html
-next: self-closing-tag.html
----
-
-`if-else` statements don't work inside JSX. This is because JSX is just syntactic sugar for function calls and object construction. Take this basic example:
-
-```js
-// This JSX:
-ReactDOM.render(<div id="msg">Hello World!</div>, mountNode);
-
-// Is transformed to this JS:
-ReactDOM.render(React.createElement("div", {id:"msg"}, "Hello World!"), mountNode);
-```
-
-This means that `if` statements don't fit in. Take this example:
-
-```js
-// This JSX:
-<div id={if (condition) { 'msg' }}>Hello World!</div>
-
-// Is transformed to this JS:
-React.createElement("div", {id: if (condition) { 'msg' }}, "Hello World!");
-```
-
-That's not valid JS. You probably want to make use of a ternary expression:
-
-```js
-ReactDOM.render(<div id={condition ? 'msg' : null}>Hello World!</div>, mountNode);
-```
-
-If a ternary expression isn't robust enough, you can use `if` statements outside of your JSX to determine which components should be used:
-
-```js
-var loginButton;
-if (loggedIn) {
-  loginButton = <LogoutButton />;
-} else {
-  loginButton = <LoginButton />;
-}
-
-return (
-  <nav>
-    <Home />
-    {loginButton}
-  </nav>
-);
-```
-
-Or if you prefer a more "inline" aesthetic, define [immediately-invoked function expressions](https://en.wikipedia.org/wiki/Immediately-invoked_function_expression) _inside_ your JSX:
-
-```js
-return (
-  <section>
-    <h1>Color</h1>
-    <h3>Name</h3>
-    <p>{this.state.color || "white"}</p>
-    <h3>Hex</h3>
-    <p>
-      {(() => {
-        switch (this.state.color) {
-          case "red":   return "#FF0000";
-          case "green": return "#00FF00";
-          case "blue":  return "#0000FF";
-          default:      return "#FFFFFF";
-        }
-      })()}
-    </p>
-  </section>
-);
-```
-
-> Note:
->
-> In the example above, an ES6 [arrow function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) is utilized to lexically bind the value of `this`.
-
-Try using it today with the [Babel REPL](https://babeljs.io/repl/).
diff --git a/docs/tips/04-self-closing-tag.ja-JP.md b/docs/tips/04-self-closing-tag.ja-JP.md
deleted file mode 100644
index 2c411d7e111a..000000000000
--- a/docs/tips/04-self-closing-tag.ja-JP.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-id: self-closing-tag-ja-JP
-title: 自己終了タグ
-layout: tips
-permalink: self-closing-tag-ja-JP.html
-prev: if-else-in-JSX-ja-JP.html
-next: maximum-number-of-jsx-root-nodes-ja-JP.html
----
-
-JSXでは、 `<MyComponent />` 単体は正しいですが、 `<MyComponent>` は正しくありません。 全てのタグは、自己終了の形式または対応する終了タグ( `</MyComponent>` )で閉じるべきです。
-
-> 注意:
->
-> 全てのReactコンポーネントは `<div />` のように自己終了タグになり得ます。 `<div></div>` もまた同様です。
diff --git a/docs/tips/04-self-closing-tag.ko-KR.md b/docs/tips/04-self-closing-tag.ko-KR.md
deleted file mode 100644
index a4529592572b..000000000000
--- a/docs/tips/04-self-closing-tag.ko-KR.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-id: self-closing-tag-ko-KR
-title: 자기 자신을 닫는 태그
-layout: tips
-permalink: self-closing-tag-ko-KR.html
-prev: if-else-in-JSX-ko-KR.html
-next: maximum-number-of-jsx-root-nodes-ko-KR.html
----
-
-JSX에서 `<MyComponent>`는 유효하지 않고 `<MyComponent />`만 유효합니다. 모든 태그는 닫혀야 합니다. 자기 자신을 닫는 형식을 사용하거나 대응되는 닫는 태그(`</MyComponent>`)가 필요합니다.
-
-> 주의:
->
-> 모든 React 컴포넌트는 자기 자신을 닫을 수 있습니다: `<div />`. `<div></div>`와 동일합니다.
diff --git a/docs/tips/04-self-closing-tag.md b/docs/tips/04-self-closing-tag.md
deleted file mode 100644
index 7c0a72fa8e9d..000000000000
--- a/docs/tips/04-self-closing-tag.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-id: self-closing-tag
-title: Self-Closing Tag
-layout: tips
-permalink: self-closing-tag.html
-prev: if-else-in-JSX.html
-next: maximum-number-of-jsx-root-nodes.html
----
-
-In JSX, `<MyComponent />` alone is valid while `<MyComponent>` isn't. All tags must be closed, either with the self-closing format or with a corresponding closing tag (`</MyComponent>`).
-
-> Note:
->
-> Every React component can be self-closing: `<div />`. `<div></div>` is also an equivalent.
diff --git a/docs/tips/05-maximum-number-of-jsx-root-nodes.ko-KR.md b/docs/tips/05-maximum-number-of-jsx-root-nodes.ko-KR.md
deleted file mode 100644
index d5288104aab8..000000000000
--- a/docs/tips/05-maximum-number-of-jsx-root-nodes.ko-KR.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-id: maximum-number-of-jsx-root-nodes-ko-KR
-title: JSX 루트 노드의 최대 갯수
-layout: tips
-permalink: maximum-number-of-jsx-root-nodes-ko-KR.html
-prev: self-closing-tag-ko-KR.html
-next: style-props-value-px-ko-KR.html
----
-
-현재 컴포넌트의 `render`는 한 노드만 리턴할 수 있습니다. 만약 `div` 배열을 리턴하려면, `div`, `span`과 같은 다른 컴포넌트로 한 번 더 싸주어야 합니다. 
-
-JSX는 일반 JS로 컴파일 함을 잊지말아야 합니다. 두개의 함수를 리턴하는 것은 문법적으로 맞지 않습니다. 이와 마찬가지로, 한 삼항 연산자 안에 한개 이상의 자식 컴포넌트를 넣으면 안됩니다.
diff --git a/docs/tips/05-maximum-number-of-jsx-root-nodes.md b/docs/tips/05-maximum-number-of-jsx-root-nodes.md
deleted file mode 100644
index d3e026f70a44..000000000000
--- a/docs/tips/05-maximum-number-of-jsx-root-nodes.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-id: maximum-number-of-jsx-root-nodes
-title: Maximum Number of JSX Root Nodes
-layout: tips
-permalink: maximum-number-of-jsx-root-nodes.html
-prev: self-closing-tag.html
-next: style-props-value-px.html
----
-
-Currently, in a component's `render`, you can only return one node; if you have, say, a list of `div`s to return, you must wrap your components within a `div`, `span` or any other component.
-
-Don't forget that JSX compiles into regular JS; returning two functions doesn't really make syntactic sense. Likewise, don't put more than one child in a ternary.
diff --git a/docs/tips/06-style-props-value-px.ko-KR.md b/docs/tips/06-style-props-value-px.ko-KR.md
deleted file mode 100644
index a955afc8f407..000000000000
--- a/docs/tips/06-style-props-value-px.ko-KR.md
+++ /dev/null
@@ -1,46 +0,0 @@
----
-id: style-props-value-px-ko-KR
-title: 스타일 속성에서 특정 픽셀 값 넣는 간단한 방법 
-layout: tips
-permalink: style-props-value-px-ko-KR.html
-prev: maximum-number-of-jsx-root-nodes-ko-KR.html
-next: children-props-type-ko-KR.html
----
-
-인라인 `style` prop에서 픽셀 값을 넣을때, React가 자동으로 숫자뒤에 "px"를 붙여줍니다. 다음과 같이 동작합니다:
-
-```js
-var divStyle = {height: 10}; // "height:10px" 로 렌더링 됩니다.
-ReactDOM.render(<div style={divStyle}>Hello World!</div>, mountNode);
-```
-
-더 자세한 이야기는 [Inline Styles](/react/tips/inline-styles-ko-KR.html)를 참고해 주시기 바랍니다.
-
-개발 하다보면 CSS 속성들이 단위 없이 그대로 유지되어야 할 때가 있을 겁니다. 아래의 프로퍼티들은 자동으로 "px"가 붙지 않는 속성 리스트 입니다:
-
-- `animationIterationCount`
-- `boxFlex`
-- `boxFlexGroup`
-- `boxOrdinalGroup`
-- `columnCount`
-- `fillOpacity`
-- `flex`
-- `flexGrow`
-- `flexPositive`
-- `flexShrink`
-- `flexNegative`
-- `flexOrder`
-- `fontWeight`
-- `lineClamp`
-- `lineHeight`
-- `opacity`
-- `order`
-- `orphans`
-- `stopOpacity`
-- `strokeDashoffset`
-- `strokeOpacity`
-- `strokeWidth`
-- `tabSize`
-- `widows`
-- `zIndex`
-- `zoom`
diff --git a/docs/tips/06-style-props-value-px.md b/docs/tips/06-style-props-value-px.md
deleted file mode 100644
index 02473a08ec03..000000000000
--- a/docs/tips/06-style-props-value-px.md
+++ /dev/null
@@ -1,46 +0,0 @@
----
-id: style-props-value-px
-title: Shorthand for Specifying Pixel Values in style props
-layout: tips
-permalink: style-props-value-px.html
-prev: maximum-number-of-jsx-root-nodes.html
-next: children-props-type.html
----
-
-When specifying a pixel value for your inline `style` prop, React automatically appends the string "px" for you after your number value, so this works:
-
-```js
-var divStyle = {height: 10}; // rendered as "height:10px"
-ReactDOM.render(<div style={divStyle}>Hello World!</div>, mountNode);
-```
-
-See [Inline Styles](/react/tips/inline-styles.html) for more info.
-
-Sometimes you _do_ want to keep the CSS properties unitless. Here's a list of properties that won't get the automatic "px" suffix:
-
-- `animationIterationCount`
-- `boxFlex`
-- `boxFlexGroup`
-- `boxOrdinalGroup`
-- `columnCount`
-- `fillOpacity`
-- `flex`
-- `flexGrow`
-- `flexPositive`
-- `flexShrink`
-- `flexNegative`
-- `flexOrder`
-- `fontWeight`
-- `lineClamp`
-- `lineHeight`
-- `opacity`
-- `order`
-- `orphans`
-- `stopOpacity`
-- `strokeDashoffset`
-- `strokeOpacity`
-- `strokeWidth`
-- `tabSize`
-- `widows`
-- `zIndex`
-- `zoom`
diff --git a/docs/tips/07-children-props-type.ko-KR.md b/docs/tips/07-children-props-type.ko-KR.md
deleted file mode 100644
index ee8a3d48bde1..000000000000
--- a/docs/tips/07-children-props-type.ko-KR.md
+++ /dev/null
@@ -1,49 +0,0 @@
----
-id: children-props-type-ko-KR
-title: 자식 속성들의 타입
-layout: tips
-permalink: children-props-type-ko-KR.html
-prev: style-props-value-px-ko-KR.html
-next: controlled-input-null-value-ko-KR.html
----
-
-컴포넌트의 자식들(`this.props.children`)은 대부분 컴포넌트의 배열로 들어갑니다:
-
-```js
-var GenericWrapper = React.createClass({
-  componentDidMount: function() {
-    console.log(Array.isArray(this.props.children)); // => true
-  },
-
-  render: function() {
-    return <div />;
-  }
-});
-
-ReactDOM.render(
-  <GenericWrapper><span/><span/><span/></GenericWrapper>,
-  mountNode
-);
-```
-
-하지만 자식이 하나만 있는 경우, `this.props.children`는 _배열 래퍼(wrapper)없이_ 싱글 자식 컴포넌트가 됩니다. 이렇게 함으로써 배열 할당을 줄일 수 있습니다.
-
-```js
-var GenericWrapper = React.createClass({
-  componentDidMount: function() {
-    console.log(Array.isArray(this.props.children)); // => false
-
-    // 경고 : 산출된 5 값은 'hello' 스트링의 길이 입니다. 존재하지 않는 배열 래퍼의 길이인 1이 아닙니다!
-
-    console.log(this.props.children.length);
-  },
-
-  render: function() {
-    return <div />;
-  }
-});
-
-ReactDOM.render(<GenericWrapper>hello</GenericWrapper>, mountNode);
-```
-
-`this.props.children`을 쉽게 다룰 수 있도록 [React.Children utilities](/react/docs/top-level-api-ko-KR.html#react.children)를 제공하고 있습니다.
diff --git a/docs/tips/07-children-props-type.md b/docs/tips/07-children-props-type.md
deleted file mode 100644
index 3785ae898a22..000000000000
--- a/docs/tips/07-children-props-type.md
+++ /dev/null
@@ -1,49 +0,0 @@
----
-id: children-props-type
-title: Type of the Children props
-layout: tips
-permalink: children-props-type.html
-prev: style-props-value-px.html
-next: controlled-input-null-value.html
----
-
-Usually, a component's children (`this.props.children`) is an array of components:
-
-```js
-var GenericWrapper = React.createClass({
-  componentDidMount: function() {
-    console.log(Array.isArray(this.props.children)); // => true
-  },
-
-  render: function() {
-    return <div />;
-  }
-});
-
-ReactDOM.render(
-  <GenericWrapper><span/><span/><span/></GenericWrapper>,
-  mountNode
-);
-```
-
-However, when there is only a single child, `this.props.children` will be the single child component itself _without the array wrapper_. This saves an array allocation.
-
-```js
-var GenericWrapper = React.createClass({
-  componentDidMount: function() {
-    console.log(Array.isArray(this.props.children)); // => false
-
-    // warning: yields 5 for length of the string 'hello', not 1 for the
-    // length of the non-existent array wrapper!
-    console.log(this.props.children.length);
-  },
-
-  render: function() {
-    return <div />;
-  }
-});
-
-ReactDOM.render(<GenericWrapper>hello</GenericWrapper>, mountNode);
-```
-
-To make `this.props.children` easy to deal with, we've provided the [React.Children utilities](/react/docs/top-level-api.html#react.children).
diff --git a/docs/tips/08-controlled-input-null-value.ko-KR.md b/docs/tips/08-controlled-input-null-value.ko-KR.md
deleted file mode 100644
index a9c754d6c36c..000000000000
--- a/docs/tips/08-controlled-input-null-value.ko-KR.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-id: controlled-input-null-value-ko-KR
-title: 제어되는 input 내의 null 값
-layout: tips
-permalink: controlled-input-null-value-ko-KR.html
-prev: children-props-type-ko-KR.html
-next: componentWillReceiveProps-not-triggered-after-mounting-ko-KR.html
----
-
-[제어되는 컴포넌트들](/react/docs/forms-ko-KR.html)의 `value` 속성 값을 지정하면 유저에 의해 입력값을 바꿀 수 없습니다.
-
-`value`가 정해져 있는데도 입력값을 변경할 수 있는 문제를 겪고 있다면 실수로 `value`를 `undefined`나 `null`로 설정한 것일 수 있습니다.
-
-아래 짧은 예제가 있습니다; 렌더링 후, 잠시 뒤에 텍스트를 고칠 수 있는 상태가 되는 것을 확인 하실 수 있습니다.
-
-```js
-ReactDOM.render(<input value="hi" />, mountNode);
-
-setTimeout(function() {
-  ReactDOM.render(<input value={null} />, mountNode);
-}, 1000);
-```
diff --git a/docs/tips/08-controlled-input-null-value.md b/docs/tips/08-controlled-input-null-value.md
deleted file mode 100644
index 55b88eff932f..000000000000
--- a/docs/tips/08-controlled-input-null-value.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-id: controlled-input-null-value
-title: Value of null for Controlled Input
-layout: tips
-permalink: controlled-input-null-value.html
-prev: children-props-type.html
-next: componentWillReceiveProps-not-triggered-after-mounting.html
----
-
-Specifying the `value` prop on a [controlled component](/react/docs/forms.html) prevents the user from changing the input unless you desire so.
-
-You might have run into a problem where `value` is specified, but the input can still be changed without consent. In this case, you might have accidentally set `value` to `undefined` or `null`.
-
-The snippet below shows this phenomenon; after a second, the text becomes editable.
-
-```js
-ReactDOM.render(<input value="hi" />, mountNode);
-
-setTimeout(function() {
-  ReactDOM.render(<input value={null} />, mountNode);
-}, 1000);
-```
diff --git a/docs/tips/09-componentWillReceiveProps-not-triggered-after-mounting.ko-KR.md b/docs/tips/09-componentWillReceiveProps-not-triggered-after-mounting.ko-KR.md
deleted file mode 100644
index bbee76b3fc92..000000000000
--- a/docs/tips/09-componentWillReceiveProps-not-triggered-after-mounting.ko-KR.md
+++ /dev/null
@@ -1,13 +0,0 @@
----
-id: componentWillReceiveProps-not-triggered-after-mounting-ko-KR
-title: 마운트 후에는 componentWillReceiveProps가 실행되지 않음.
-layout: tips
-permalink: componentWillReceiveProps-not-triggered-after-mounting-ko-KR.html
-prev: controlled-input-null-value-ko-KR.html
-next: props-in-getInitialState-as-anti-pattern-ko-KR.html
----
-
-`componentWillReceiveProps`는 노드가 더해진 후엔 실행되지 않습니다. 이는 설계에 의한 것입니다. [다른 생명주기 메소드](/react/docs/component-specs-ko-KR.html)에서 요구사항에 적합한 것을 찾아보세요.
-
-이러한 이유는 `componentWillReceiveProps`에 종종 예전 props와 액션의 차이를 비교하는 로직이 들어가기 때문입니다. 마운트할 때 트리거되지 않으면, (예전 props가 없다고 해도) 메소드의 형태를 구별하는 데 도움이 됩니다.
-
diff --git a/docs/tips/09-componentWillReceiveProps-not-triggered-after-mounting.md b/docs/tips/09-componentWillReceiveProps-not-triggered-after-mounting.md
deleted file mode 100644
index b4b1cd5c1a64..000000000000
--- a/docs/tips/09-componentWillReceiveProps-not-triggered-after-mounting.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-id: componentWillReceiveProps-not-triggered-after-mounting
-title: componentWillReceiveProps Not Triggered After Mounting
-layout: tips
-permalink: componentWillReceiveProps-not-triggered-after-mounting.html
-prev: controlled-input-null-value.html
-next: props-in-getInitialState-as-anti-pattern.html
----
-
-`componentWillReceiveProps` isn't triggered after the node is put on scene. This is by design. Check out [other lifecycle methods](/react/docs/component-specs.html) for the one that suits your needs.
-
-The reason for that is because `componentWillReceiveProps` often handles the logic of comparing with the old props and acting upon changes; not triggering it at mounting (where there are no old props) helps in defining what the method does.
diff --git a/docs/tips/10-props-in-getInitialState-as-anti-pattern.ko-KR.md b/docs/tips/10-props-in-getInitialState-as-anti-pattern.ko-KR.md
deleted file mode 100644
index 942ace67ac38..000000000000
--- a/docs/tips/10-props-in-getInitialState-as-anti-pattern.ko-KR.md
+++ /dev/null
@@ -1,67 +0,0 @@
----
-id: props-in-getInitialState-as-anti-pattern-ko-KR
-title: getInitialState의 Props는 안티패턴
-layout: tips
-permalink: props-in-getInitialState-as-anti-pattern-ko-KR.html
-prev: componentWillReceiveProps-not-triggered-after-mounting-ko-KR.html
-next: dom-event-listeners-ko-KR.html
----
-
-> 주의 : 
->
-> 이것은 React에만 국한된 팁이 아니고 안티패턴은 평범한 코드 속 에서도 종종 발생합니다. 이 글에서는 React로 간단하게 설명해 보겠습니다.
-
-부모로부터 받은 props를 이용하여 `getInitialState`에서 state를 생성할 때 종종 "진실의 소스", 예를 들어 진짜 데이터가 있는 곳을 중복으로 만들 때가 있습니다. 가능하던 안하던, 나중에 싱크되지 않는 확실한 값을 계산하고 또한 유지보수에도 문제를 야기합니다.
-
-**나쁜 예제:**
-
-```js
-var MessageBox = React.createClass({
-  getInitialState: function() {
-    return {nameWithQualifier: 'Mr. ' + this.props.name};
-  },
-
-  render: function() {
-    return <div>{this.state.nameWithQualifier}</div>;
-  }
-});
-
-ReactDOM.render(<MessageBox name="Rogers"/>, mountNode);
-```
-
-더 나은 코드:
-
-```js
-var MessageBox = React.createClass({
-  render: function() {
-    return <div>{'Mr. ' + this.props.name}</div>;
-  }
-});
-
-ReactDOM.render(<MessageBox name="Rogers"/>, mountNode);
-```
-
-(복잡한 로직이라, 메소드에서 계산하는 부분만 떼어 왔습니다.)
-
-하지만 여기서 싱크를 맞출 목적이 아님을 명확히 할 수 있다면, 이것은 안티 패턴이 **아닙니다.**
-
-
-
-```js
-var Counter = React.createClass({
-  getInitialState: function() {
-    // initial로 시작하는 메소드는 내부에서 받은 어떠한 값을 초기화 할 목적이 있다는 것을 나타냅니다.
-    return {count: this.props.initialCount};
-  },
-
-  handleClick: function() {
-    this.setState({count: this.state.count + 1});
-  },
-
-  render: function() {
-    return <div onClick={this.handleClick}>{this.state.count}</div>;
-  }
-});
-
-ReactDOM.render(<Counter initialCount={7}/>, mountNode);
-```
diff --git a/docs/tips/10-props-in-getInitialState-as-anti-pattern.md b/docs/tips/10-props-in-getInitialState-as-anti-pattern.md
deleted file mode 100644
index 70b41bf95f61..000000000000
--- a/docs/tips/10-props-in-getInitialState-as-anti-pattern.md
+++ /dev/null
@@ -1,68 +0,0 @@
----
-id: props-in-getInitialState-as-anti-pattern
-title: Props in getInitialState Is an Anti-Pattern
-layout: tips
-permalink: props-in-getInitialState-as-anti-pattern.html
-prev: componentWillReceiveProps-not-triggered-after-mounting.html
-next: dom-event-listeners.html
----
-
-> Note:
->
-> This isn't really a React-specific tip, as such anti-patterns often occur in code in general; in this case, React simply points them out more clearly.
-
-Using props to generate state in `getInitialState` often leads to duplication of "source of truth", i.e. where the real data is. This is because `getInitialState` is only invoked when the component is first created.
-
-Whenever possible, compute values on-the-fly to ensure that they don't get out of sync later on and cause maintenance trouble.
-
-**Bad example:**
-
-```js
-var MessageBox = React.createClass({
-  getInitialState: function() {
-    return {nameWithQualifier: 'Mr. ' + this.props.name};
-  },
-
-  render: function() {
-    return <div>{this.state.nameWithQualifier}</div>;
-  }
-});
-
-ReactDOM.render(<MessageBox name="Rogers"/>, mountNode);
-```
-
-Better:
-
-```js
-var MessageBox = React.createClass({
-  render: function() {
-    return <div>{'Mr. ' + this.props.name}</div>;
-  }
-});
-
-ReactDOM.render(<MessageBox name="Rogers"/>, mountNode);
-```
-
-(For more complex logic, simply isolate the computation in a method.)
-
-However, it's **not** an anti-pattern if you make it clear that the prop is only seed data for the component's internally-controlled state:
-
-```js
-var Counter = React.createClass({
-  getInitialState: function() {
-    // naming it initialX clearly indicates that the only purpose
-    // of the passed down prop is to initialize something internally
-    return {count: this.props.initialCount};
-  },
-
-  handleClick: function() {
-    this.setState({count: this.state.count + 1});
-  },
-
-  render: function() {
-    return <div onClick={this.handleClick}>{this.state.count}</div>;
-  }
-});
-
-ReactDOM.render(<Counter initialCount={7}/>, mountNode);
-```
diff --git a/docs/tips/11-dom-event-listeners.ko-KR.md b/docs/tips/11-dom-event-listeners.ko-KR.md
deleted file mode 100644
index 527765551a3a..000000000000
--- a/docs/tips/11-dom-event-listeners.ko-KR.md
+++ /dev/null
@@ -1,45 +0,0 @@
----
-id: dom-event-listeners-ko-KR
-title: 컴포넌트에서 DOM 이벤트 리스너
-layout: tips
-permalink: dom-event-listeners-ko-KR.html
-prev: props-in-getInitialState-as-anti-pattern-ko-KR.html
-next: initial-ajax-ko-KR.html
----
-
-> 주의:
->
-> 이 글은 React에서 제공되지 않은 DOM 이벤트를 어떻게 붙이는지 설명합니다. ([더 자세한 정보는 여기에서 보세요.](/react/docs/events-ko-KR.html)). 이는 jQuery 같은 다른 라이브러리들을 통합할 때 좋습니다.
-
-윈도우 크기를 조절해봅시다.
-
-```js
-var Box = React.createClass({
-  getInitialState: function() {
-    return {windowWidth: window.innerWidth};
-  },
-
-  handleResize: function(e) {
-    this.setState({windowWidth: window.innerWidth});
-  },
-
-  componentDidMount: function() {
-    window.addEventListener('resize', this.handleResize);
-  },
-
-  componentWillUnmount: function() {
-    window.removeEventListener('resize', this.handleResize);
-  },
-
-  render: function() {
-    return <div>Current window width: {this.state.windowWidth}</div>;
-  }
-});
-
-ReactDOM.render(<Box />, mountNode);
-```
-
-컴포넌트가 마운트 되고 DOM 표현을 가지게 되면 `componentDidMount`가 호출됩니다. 일반적인 DOM 이벤트를 붙이는 곳으로 여기를 종종 사용합니다.
-
-이벤트 콜백은 원래 엘리먼트 대신 React 컴포넌트에 바인드하는 걸 주의합시다. React는 [오토바인드](/react/docs/interactivity-and-dynamic-uis-ko-KR.html#under-the-hood-autobinding-and-event-delegation) 과정에서 메서드를 현재 컴포넌트 인스턴스로 바인드합니다.
-
diff --git a/docs/tips/11-dom-event-listeners.md b/docs/tips/11-dom-event-listeners.md
deleted file mode 100644
index 141ec0b974f4..000000000000
--- a/docs/tips/11-dom-event-listeners.md
+++ /dev/null
@@ -1,44 +0,0 @@
----
-id: dom-event-listeners
-title: DOM Event Listeners in a Component
-layout: tips
-permalink: dom-event-listeners.html
-prev: props-in-getInitialState-as-anti-pattern.html
-next: initial-ajax.html
----
-
-> Note:
->
-> This entry shows how to attach DOM events not provided by React ([check here for more info](/react/docs/events.html)). This is good for integrations with other libraries such as jQuery.
-
-Try to resize the window:
-
-```js
-var Box = React.createClass({
-  getInitialState: function() {
-    return {windowWidth: window.innerWidth};
-  },
-
-  handleResize: function(e) {
-    this.setState({windowWidth: window.innerWidth});
-  },
-
-  componentDidMount: function() {
-    window.addEventListener('resize', this.handleResize);
-  },
-
-  componentWillUnmount: function() {
-    window.removeEventListener('resize', this.handleResize);
-  },
-
-  render: function() {
-    return <div>Current window width: {this.state.windowWidth}</div>;
-  }
-});
-
-ReactDOM.render(<Box />, mountNode);
-```
-
-`componentDidMount` is called after the component is mounted and has a DOM representation. This is often a place where you would attach generic DOM events.
-
-Notice that the event callback is bound to the react component and not the original element. React automatically binds methods to the current component instance for you through a process of [autobinding](/react/docs/interactivity-and-dynamic-uis.html#under-the-hood-autobinding-and-event-delegation).
diff --git a/docs/tips/12-initial-ajax.ko-KR.md b/docs/tips/12-initial-ajax.ko-KR.md
deleted file mode 100644
index 3e2b5a50f2ee..000000000000
--- a/docs/tips/12-initial-ajax.ko-KR.md
+++ /dev/null
@@ -1,51 +0,0 @@
----
-id: initial-ajax-ko-KR
-title: AJAX를 통해 초기 데이터 읽어오기
-layout: tips
-permalink: initial-ajax-ko-KR.html
-prev: dom-event-listeners-ko-KR.html
-next: false-in-jsx-ko-KR.html
----
-
-`componentDidMount`에서 데이터를 가져옵니다. 응답이 올 때 데이터가 state에 저장되고 렌더링을 시작하여 UI를 갱신합니다.
-
-비동기 요청의 응답을 처리하여 state를 변경하기 전에, 컴포넌트가 여전히 마운트되었는지를 확인하기 위해 `this.isMounted()`를 사용합니다.
-
-이 예제는 희망하는 Github 사용자의 최근 gist를 가져옵니다.
-
-```js
-var UserGist = React.createClass({
-  getInitialState: function() {
-    return {
-      username: '',
-      lastGistUrl: ''
-    };
-  },
-
-  componentDidMount: function() {
-    $.get(this.props.source, function(result) {
-      var lastGist = result[0];
-      if (this.isMounted()) {
-        this.setState({
-          username: lastGist.owner.login,
-          lastGistUrl: lastGist.html_url
-        });
-      }
-    }.bind(this));
-  },
-
-  render: function() {
-    return (
-      <div>
-        {this.state.username}'s last gist is
-        <a href={this.state.lastGistUrl}>here</a>.
-      </div>
-    );
-  }
-});
-
-ReactDOM.render(
-  <UserGist source="https://api.github.com/users/octocat/gists" />,
-  mountNode
-);
-```
diff --git a/docs/tips/12-initial-ajax.md b/docs/tips/12-initial-ajax.md
deleted file mode 100644
index e8d4c960a12a..000000000000
--- a/docs/tips/12-initial-ajax.md
+++ /dev/null
@@ -1,53 +0,0 @@
----
-id: initial-ajax
-title: Load Initial Data via AJAX
-layout: tips
-permalink: initial-ajax.html
-prev: dom-event-listeners.html
-next: false-in-jsx.html
----
-
-Fetch data in `componentDidMount`. When the response arrives, store the data in state, triggering a render to update your UI.
-
-When fetching data asynchronously, use `componentWillUnmount` to cancel any outstanding requests before the component is unmounted.
-
-This example fetches the desired Github user's latest gist:
-
-```js
-var UserGist = React.createClass({
-  getInitialState: function() {
-    return {
-      username: '',
-      lastGistUrl: ''
-    };
-  },
-
-  componentDidMount: function() {
-    this.serverRequest = $.get(this.props.source, function (result) {
-      var lastGist = result[0];
-      this.setState({
-        username: lastGist.owner.login,
-        lastGistUrl: lastGist.html_url
-      });
-    }.bind(this));
-  },
-
-  componentWillUnmount: function() {
-    this.serverRequest.abort();
-  },
-
-  render: function() {
-    return (
-      <div>
-        {this.state.username}'s last gist is
-        <a href={this.state.lastGistUrl}>here</a>.
-      </div>
-    );
-  }
-});
-
-ReactDOM.render(
-  <UserGist source="https://api.github.com/users/octocat/gists" />,
-  mountNode
-);
-```
diff --git a/docs/tips/13-false-in-jsx.ko-KR.md b/docs/tips/13-false-in-jsx.ko-KR.md
deleted file mode 100644
index fddb6dccaff5..000000000000
--- a/docs/tips/13-false-in-jsx.ko-KR.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-id: false-in-jsx-ko-KR
-title: JSX에서 False
-layout: tips
-permalink: false-in-jsx-ko-KR.html
-prev: initial-ajax-ko-KR.html
-next: communicate-between-components-ko-KR.html
----
-
-`false` 렌더링이 여러 상황에서 어떻게 다뤄지는지 봅시다.
-
-`id="false"`로 렌더링
-
-```js
-ReactDOM.render(<div id={false} />, mountNode);
-```
-
-문자열 `"false"`를 입력값으로
-
-```js
-ReactDOM.render(<input value={false} />, mountNode);
-```
-
-자식 없음
-
-```js
-ReactDOM.render(<div>{false}</div>, mountNode);
-```
-
-`div` 자식으로 쓰인 문자열 `"false"`를 렌더링하지 않은 것은 더 일반적인 사용 사례를 허용하기 위함입니다. `<div>{x > 1 && '하나 이상의 아이템을 가졌습니다.'}</div>`
diff --git a/docs/tips/13-false-in-jsx.md b/docs/tips/13-false-in-jsx.md
deleted file mode 100644
index 144b91e08736..000000000000
--- a/docs/tips/13-false-in-jsx.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-id: false-in-jsx
-title: False in JSX
-layout: tips
-permalink: false-in-jsx.html
-prev: initial-ajax.html
-next: communicate-between-components.html
----
-
-Here's how `false` renders in different situations:
-
-Renders as `id="false"`:
-
-```js
-ReactDOM.render(<div id={false} />, mountNode);
-```
-
-String `"false"` as input value:
-
-```js
-ReactDOM.render(<input value={false} />, mountNode);
-```
-
-No child:
-
-```js
-ReactDOM.render(<div>{false}</div>, mountNode);
-```
-
-The reason why this one doesn't render as the string `"false"` as a `div` child is to allow the more common use-case: `<div>{x > 1 && 'You have more than one item'}</div>`.
diff --git a/docs/tips/14-communicate-between-components.ko-KR.md b/docs/tips/14-communicate-between-components.ko-KR.md
deleted file mode 100644
index 7feb6864d3fd..000000000000
--- a/docs/tips/14-communicate-between-components.ko-KR.md
+++ /dev/null
@@ -1,39 +0,0 @@
----
-id: communicate-between-components-ko-KR
-title: 컴포넌트간의 통신
-layout: tips
-permalink: communicate-between-components-ko-KR.html
-prev: false-in-jsx-ko-KR.html
-next: expose-component-functions-ko-KR.html
----
-
-부모-자식 통신을 위해서는, 간단히 [props를 넘기면 됩니다](/react/docs/multiple-components-ko-KR.html).
-
-자식-부모 통신을 위해서는:
-`GroceryList` 컴포넌트가 배열로 생성된 아이템 목록을 가지고 있다고 해봅시다. 목록의 아이템이 클릭되면 아이템의 이름이 보이길 원할 겁니다:
-
-```js
-var handleClick = function(i, props) {
-  console.log('클릭한 아이템: ' + props.items[i]);
-}
-
-function GroceryList(props) {  
-  return (
-    <div>
-      {props.items.map(function(item, i) {
-        return (
-          <div onClick={handleClick.bind(this, i, props)} key={i}>{item}</div>
-        );
-      })}
-    </div>
-  );
-}
-
-ReactDOM.render(
-  <GroceryList items={['사과', '바나나', '크랜베리']} />, mountNode
-);
-```
-
-`bind(this, arg1, arg2, ...)`의 사용을 확인하세요: 간단히 `handleClick`에 인자를 더 넘겼습니다. 이는 React의 새로운 컨셉이 아닙니다; 그냥 JavaScript죠.
-
-부모-자식 관계가 없는 두 컴포넌트간의 통신을 위해, 별도로 전역(global) 이벤트 시스템을 사용할 수 있습니다. `componentDidMount()`에서 이벤트를 구독하고, `componentWillUnmount()`에서 해제합니다. 이벤트를 받으면 `setState()`를 호출합니다. [Flux](https://facebook.github.io/flux/) 패턴은 이를 정리하는 방법 중 하나입니다.
diff --git a/docs/tips/14-communicate-between-components.md b/docs/tips/14-communicate-between-components.md
deleted file mode 100644
index 3038be7ccb35..000000000000
--- a/docs/tips/14-communicate-between-components.md
+++ /dev/null
@@ -1,39 +0,0 @@
----
-id: communicate-between-components
-title: Communicate Between Components
-layout: tips
-permalink: communicate-between-components.html
-prev: false-in-jsx.html
-next: expose-component-functions.html
----
-
-For parent-child communication, simply [pass props](/react/docs/multiple-components.html).
-
-For child-parent communication:
-Say your `GroceryList` component has a list of items generated through an array. When a list item is clicked, you want to display its name:
-
-```js
-var handleClick = function(i, props) {
-  console.log('You clicked: ' + props.items[i]);
-}
-
-function GroceryList(props) {  
-  return (
-    <div>
-      {props.items.map(function(item, i) {
-        return (
-          <div onClick={handleClick.bind(this, i, props)} key={i}>{item}</div>
-        );
-      })}
-    </div>
-  );
-}
-
-ReactDOM.render(
-  <GroceryList items={['Apple', 'Banana', 'Cranberry']} />, mountNode
-);
-```
-
-Notice the use of `bind(this, arg1, arg2, ...)`: we're simply passing more arguments to `handleClick`. This is not a new React concept; it's just JavaScript.
-
-For communication between two components that don't have a parent-child relationship, you can set up your own global event system. Subscribe to events in `componentDidMount()`, unsubscribe in `componentWillUnmount()`, and call `setState()` when you receive an event. [Flux](https://facebook.github.io/flux/) pattern is one of the possible ways to arrange this.
diff --git a/docs/tips/15-expose-component-functions.ko-KR.md b/docs/tips/15-expose-component-functions.ko-KR.md
deleted file mode 100644
index 0648961b1398..000000000000
--- a/docs/tips/15-expose-component-functions.ko-KR.md
+++ /dev/null
@@ -1,59 +0,0 @@
----
-id: expose-component-functions-ko-KR
-title: 컴포넌트 함수 드러내기
-layout: tips
-permalink: expose-component-functions-ko-KR.html
-prev: communicate-between-components-ko-KR.html
-next: children-undefined-ko-KR.html
----
-
-[컴포넌트간의 통신](/react/tips/communicate-between-components-ko-KR.html)을 위한 (일반적이지 않은) 또다른 방법이 있습니다: 단순히 부모의 호출을 위해 자식 컴포넌트의 메소드를 노출하는 겁니다. 
-
-할일 목록을 생각해보죠. 아이템을 클릭하면 제거되고, 하나가 남으면 애니메이션 효과를 줍니다:
-
-```js
-var Todo = React.createClass({
-  render: function() {
-    return <div onClick={this.props.onClick}>{this.props.title}</div>;
-  },
-
-  //이 컴포넌트는 `ref` 어트리뷰트를 통해 부모에게 다뤄질 것입니다
-  animate: function() {
-    console.log('%s이 애니메이팅하는것처럼 속입니다', this.props.title);
-  }
-});
-
-var Todos = React.createClass({
-  getInitialState: function() {
-    return {items: ['사과', '바나나', '크랜베리']};
-  },
-
-  handleClick: function(index) {
-    var items = this.state.items.filter(function(item, i) {
-      return index !== i;
-    });
-    this.setState({items: items}, function() {
-      if (items.length === 1) {
-        this.refs.item0.animate();
-      }
-    }.bind(this));
-  },
-
-  render: function() {
-    return (
-      <div>
-        {this.state.items.map(function(item, i) {
-          var boundClick = this.handleClick.bind(this, i);
-          return (
-            <Todo onClick={boundClick} key={i} title={item} ref={'item' + i} />
-          );
-        }, this)}
-      </div>
-    );
-  }
-});
-
-ReactDOM.render(<Todos />, mountNode);
-```
-
-다른 방법으로는, `isLastUnfinishedItem` prop을 `todo`에 넘기는 방식으로 원하는 바를 이룰수도 있습니다. `componentDidUpdate`에서 prop을 확인하고 스스로 애니메이션 효과를 주는겁니다; 하지만 애니메이션 제어를 위해 다른 prop들을 넘기게 되면 이는 금새 난잡해질 수 있습니다.
diff --git a/docs/tips/15-expose-component-functions.md b/docs/tips/15-expose-component-functions.md
deleted file mode 100644
index 7eaadb366580..000000000000
--- a/docs/tips/15-expose-component-functions.md
+++ /dev/null
@@ -1,59 +0,0 @@
----
-id: expose-component-functions
-title: Expose Component Functions
-layout: tips
-permalink: expose-component-functions.html
-prev: communicate-between-components.html
-next: children-undefined.html
----
-
-There's another (uncommon) way of [communicating between components](/react/tips/communicate-between-components.html): simply expose a method on the child component for the parent to call.
-
-Say a list of todos, which upon clicking get removed. If there's only one unfinished todo left, animate it:
-
-```js
-var Todo = React.createClass({
-  render: function() {
-    return <div onClick={this.props.onClick}>{this.props.title}</div>;
-  },
-
-  //this component will be accessed by the parent through the `ref` attribute
-  animate: function() {
-    console.log('Pretend %s is animating', this.props.title);
-  }
-});
-
-var Todos = React.createClass({
-  getInitialState: function() {
-    return {items: ['Apple', 'Banana', 'Cranberry']};
-  },
-
-  handleClick: function(index) {
-    var items = this.state.items.filter(function(item, i) {
-      return index !== i;
-    });
-    this.setState({items: items}, function() {
-      if (items.length === 1) {
-        this.refs.item0.animate();
-      }
-    }.bind(this));
-  },
-
-  render: function() {
-    return (
-      <div>
-        {this.state.items.map(function(item, i) {
-          var boundClick = this.handleClick.bind(this, i);
-          return (
-            <Todo onClick={boundClick} key={i} title={item} ref={'item' + i} />
-          );
-        }, this)}
-      </div>
-    );
-  }
-});
-
-ReactDOM.render(<Todos />, mountNode);
-```
-
-Alternatively, you could have achieved this by passing the `todo` an `isLastUnfinishedItem` prop, let it check this prop in `componentDidUpdate`, then animate itself; however, this quickly gets messy if you pass around different props to control animations.
diff --git a/docs/tips/16-references-to-components.ko-KR.md b/docs/tips/16-references-to-components.ko-KR.md
deleted file mode 100644
index 3e9058a986e4..000000000000
--- a/docs/tips/16-references-to-components.ko-KR.md
+++ /dev/null
@@ -1,10 +0,0 @@
----
-id: references-to-components-ko-KR
-title: 컴포넌트 참조
-layout: tips
-permalink: references-to-components-ko-KR.html
-prev: expose-component-functions-ko-KR.html
-next: children-undefined-ko-KR.html
----
-
-이 페이지는 이동되었습니다. [refs](/react/docs/more-about-refs-ko-KR.html)
diff --git a/docs/tips/16-references-to-components.md b/docs/tips/16-references-to-components.md
deleted file mode 100644
index b0e1e5744ba8..000000000000
--- a/docs/tips/16-references-to-components.md
+++ /dev/null
@@ -1,10 +0,0 @@
----
-id: references-to-components
-title: References to Components
-layout: tips
-permalink: references-to-components.html
-prev: expose-component-functions.html
-next: children-undefined.html
----
-
-This page has moved to: [refs](/react/docs/more-about-refs.html).
diff --git a/docs/tips/17-children-undefined.ko-KR.md b/docs/tips/17-children-undefined.ko-KR.md
deleted file mode 100644
index 8b795734de34..000000000000
--- a/docs/tips/17-children-undefined.ko-KR.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-id: children-undefined-ko-KR
-title: 정의되지 않은 this.props.children
-layout: tips
-permalink: children-undefined-ko-KR.html
-prev: expose-component-functions-ko-KR.html
-next: use-react-with-other-libraries-ko-KR.html
----
-
-`this.props.children`을 통해 자식 컴포넌트에 접근할 수 없습니다. `this.props.children`은 소유자에 의해 자식이 **전달**되도록 지정합니다:
-
-```js
-var App = React.createClass({
-  componentDidMount: function() {
-    // 이는 `span`을 참조하지 않습니다! 
-    // 마지막 줄의 `<App></App>` 사이의 정의되지 않은 자식을 참조합니다.
-    console.log(this.props.children);
-  },
-
-  render: function() {
-    return <div><span/><span/></div>;
-  }
-});
-
-ReactDOM.render(<App></App>, mountNode);
-```
-
-서브 컴포넌트(`span`)에 억세스하려면, [refs](/react/docs/more-about-refs.html)를 넣으세요.
diff --git a/docs/tips/17-children-undefined.md b/docs/tips/17-children-undefined.md
deleted file mode 100644
index fb29c2f5b8b7..000000000000
--- a/docs/tips/17-children-undefined.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-id: children-undefined
-title: this.props.children undefined
-layout: tips
-permalink: children-undefined.html
-prev: expose-component-functions.html
-next: use-react-with-other-libraries.html
----
-
-You can't access the children of your component through `this.props.children`. `this.props.children` designates the children being **passed onto you** by the owner:
-
-```js
-var App = React.createClass({
-  componentDidMount: function() {
-    // This doesn't refer to the `span`s! It refers to the children between
-    // last line's `<App></App>`, which are undefined.
-    console.log(this.props.children);
-  },
-
-  render: function() {
-    return <div><span/><span/></div>;
-  }
-});
-
-ReactDOM.render(<App></App>, mountNode);
-```
-
-To access your own subcomponents (the `span`s), place [refs](/react/docs/more-about-refs.html) on them.
diff --git a/docs/tips/18-use-react-with-other-libraries.ko-KR.md b/docs/tips/18-use-react-with-other-libraries.ko-KR.md
deleted file mode 100644
index 9dfd1d46c5a9..000000000000
--- a/docs/tips/18-use-react-with-other-libraries.ko-KR.md
+++ /dev/null
@@ -1,39 +0,0 @@
----
-id: use-react-with-other-libraries-ko-KR
-title: React와 다른 라이브러리를 함께 사용하기
-layout: tips
-permalink: use-react-with-other-libraries-ko-KR.html
-prev: children-undefined-ko-KR.html
-next: dangerously-set-inner-html-ko-KR.html
----
-
-React만으로 만들 필요는 없습니다. 컴포넌트의 [생명주기 이벤트](/react/docs/component-specs-ko-KR.html#lifecycle-methods), 특히 `componentDidMount`와 `componentDidUpdate`는 다른 라이브러리들의 로직을 넣기에 좋은 장소입니다.
-
-```js
-var App = React.createClass({
-  getInitialState: function() {
-    return {myModel: new myBackboneModel({items: [1, 2, 3]})};
-  },
-
-  componentDidMount: function() {
-    $(this.refs.placeholder).append($('<span />'));
-  },
-
-  componentWillUnmount: function() {
-    // 정리는 여기서 합니다
-  },
-
-  shouldComponentUpdate: function() {
-    // 이 컴포넌트를 다시는 업데이트하지 않도록 하죠.
-    return false;
-  },
-
-  render: function() {
-    return <div ref="placeholder"/>;
-  }
-});
-
-ReactDOM.render(<App />, mountNode);
-```
-
-이 방식으로 별도의 [이벤트 리스너](/react/tips/dom-event-listeners-ko-KR.html)나 [이벤트 스트림](https://baconjs.github.io) 같은 것들을 더할 수 있습니다.
diff --git a/docs/tips/18-use-react-with-other-libraries.md b/docs/tips/18-use-react-with-other-libraries.md
deleted file mode 100644
index fc5634fa8e00..000000000000
--- a/docs/tips/18-use-react-with-other-libraries.md
+++ /dev/null
@@ -1,39 +0,0 @@
----
-id: use-react-with-other-libraries
-title: Use React with Other Libraries
-layout: tips
-permalink: use-react-with-other-libraries.html
-prev: children-undefined.html
-next: dangerously-set-inner-html.html
----
-
-You don't have to go full React. The component [lifecycle events](/react/docs/component-specs.html#lifecycle-methods), especially `componentDidMount` and `componentDidUpdate`, are good places to put your other libraries' logic.
-
-```js
-var App = React.createClass({
-  getInitialState: function() {
-    return {myModel: new myBackboneModel({items: [1, 2, 3]})};
-  },
-
-  componentDidMount: function() {
-    $(this.refs.placeholder).append($('<span />'));
-  },
-
-  componentWillUnmount: function() {
-    // Clean up work here.
-  },
-
-  shouldComponentUpdate: function() {
-    // Let's just never update this component again.
-    return false;
-  },
-
-  render: function() {
-    return <div ref="placeholder"/>;
-  }
-});
-
-ReactDOM.render(<App />, mountNode);
-```
-
-You can attach your own [event listeners](/react/tips/dom-event-listeners.html) and even [event streams](https://baconjs.github.io) this way.
diff --git a/docs/tips/19-dangerously-set-inner-html.ko-KR.md b/docs/tips/19-dangerously-set-inner-html.ko-KR.md
deleted file mode 100644
index a5c920005795..000000000000
--- a/docs/tips/19-dangerously-set-inner-html.ko-KR.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-id: dangerously-set-inner-html-ko-KR
-title: Dangerously Set innerHTML
-layout: tips
-permalink: dangerously-set-inner-html-ko-KR.html
-prev: children-undefined-ko-KR.html
----
-
-부적절히 `innerHTML`를 사용하면 [사이트 간 스크립팅 (XSS)](https://en.wikipedia.org/wiki/Cross-site_scripting) 공격에 노출됩니다. 화면의 사용자 입력을 정제하다(sanitize) 오류를 내기 쉬우며, 적절하게 사용자의 입력을 정제하지 못하면 인터넷 상 [웹 취약점의 원인](https://owasptop10.googlecode.com/files/OWASP%20Top%2010%20-%202013.pdf)이 됩니다.
-
-우리 설계철학은 안전을 "쉽게" 얻는 것입니다. 개발자는 그들의 의도를 명시적으로 알려야만 "안전하지 않는" 연산을 할 수 있습니다. `dangerouslySetInnerHTML` prop의 이름은 의도적으로 무섭게 만든 것인데, prop 값은 문자열이 아닌 객체이고 정제된 데이터를 지정하는데 쓸 수 있습니다.
-
-보안 영향을 완전히 이해했다면, 데이터에서 나쁜 부분을 완전히 제거하고 `__html` 키와 정제된 값을 담은 새로운 객체를 만듭시다. 여기에 JSX 문법을 쓴 예제가 있습니다.
-
-```js
-function createMarkup() { return {__html: 'First &middot; Second'}; };
-<div dangerouslySetInnerHTML={createMarkup()} />
-```
-
-부주의하게 `<div dangerouslySetInnerHTML={getUsername()} />`를 쓰면 `getUsername()`가 `{__html: ''}` 객체 대신 순수 `문자열`을 반환하기 때문에 렌더링이 안되는 것이 요점입니다. `{__html:...}` 문장 속의 의도는 "type/taint" 같이 숙고하는 것입니다. 함수는 이 래퍼 객체를 사용하여 정제된 객체를 반환할 수 있는 데 뒤 따라오는 `dangerouslySetInnerHTML`에 표시할 데이터를 전달합니다. 이런 이유로 `<div dangerouslySetInnerHTML={{'{{'}}__html: getMarkup()}} />`의 형태의 코드를 작성하는 것은 추천하지 않습니다.
-
-이 기능성은 주로 DOM 문자열을 다루는 라이브러리와 협동하기 위한 목적으로 제공하며, 포함할 HTML은 잘 정제되어야 합니다. (예: XML 검증을 통과)
-
-더 완벽한 사용 예제를 보려면 [대문](/react/)의 최신 예제를 참조하세요.
diff --git a/docs/tips/19-dangerously-set-inner-html.md b/docs/tips/19-dangerously-set-inner-html.md
deleted file mode 100644
index f580f5d08ac2..000000000000
--- a/docs/tips/19-dangerously-set-inner-html.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-id: dangerously-set-inner-html
-title: Dangerously Set innerHTML
-layout: tips
-permalink: dangerously-set-inner-html.html
-prev: children-undefined.html
----
-
-Improper use of the `innerHTML` can open you up to a [cross-site scripting (XSS)](https://en.wikipedia.org/wiki/Cross-site_scripting) attack.  Sanitizing user input for display is notoriously error-prone, and failure to properly sanitize is one of the [leading causes of web vulnerabilities](https://owasptop10.googlecode.com/files/OWASP%20Top%2010%20-%202013.pdf) on the internet.
-
-Our design philosophy is that it should be “easy” to make things safe, and developers should explicitly state their intent when performing “unsafe” operations.  The prop name `dangerouslySetInnerHTML` is intentionally chosen to be frightening, and the prop value (an object instead of a string) can be used to indicate sanitized data.
-
-After fully understanding the security ramifications and properly sanitizing the data, create a new object containing only the key `__html` and your sanitized data as the value.  Here is an example using the JSX syntax:
-
-```js
-function createMarkup() { return {__html: 'First &middot; Second'}; };
-<div dangerouslySetInnerHTML={createMarkup()} />
-```
-
-The point being that if you unintentionally do say `<div dangerouslySetInnerHTML={getUsername()} />` it will not be rendered because `getUsername()` would return a plain `string` and not a `{__html: ''}` object.  The intent behind the `{__html:...}` syntax is that it be considered a "type/taint" of sorts.  Sanitized data can be returned from a function using this wrapper object, and this marked data can subsequently be passed into `dangerouslySetInnerHTML`.  For this reason, we recommend against writing code of the form `<div dangerouslySetInnerHTML={{'{{'}}__html: getMarkup()}} />`.
-
-This functionality is mainly provided for cooperation with DOM string manipulation libraries, so the HTML provided must be well-formed (ie., pass XML validation).
-
-For a more complete usage example, refer to the last example on the [front page](/react/).
diff --git a/docs/tutorial/tutorial.md b/docs/tutorial/tutorial.md
new file mode 100644
index 000000000000..2577c5ca5660
--- /dev/null
+++ b/docs/tutorial/tutorial.md
@@ -0,0 +1,1100 @@
+---
+id: tutorial
+title: "Tutorial: Intro To React"
+layout: tutorial
+sectionid: tutorial
+permalink: /tutorial/tutorial.html
+redirect_from:
+  - "docs/tutorial.html"
+  - "docs/why-react.html"
+  - "docs/tutorial-ja-JP.html"
+  - "docs/tutorial-ko-KR.html"
+  - "docs/tutorial-zh-CN.html"
+---
+
+## Before We Start
+
+### What We're Building
+
+Today, we're going to build an interactive tic-tac-toe game.
+
+If you like, you can check out the final result here: [Final Result](https://codepen.io/gaearon/pen/gWWZgR?editors=0010). Don't worry if the code doesn't make sense to you yet, or if it uses an unfamiliar syntax. We will be learning how to build this game step by step throughout this tutorial.
+
+Try playing the game. You can also click on a link in the move list to go "back in time" and see what the board looked like just after that move was made.
+
+Once you get a little familiar with the game, feel free to close that tab, as we'll start from a simpler template in the next sections.
+
+### Prerequisites
+
+We'll assume some familiarity with HTML and JavaScript but you should be able to follow along even if you haven't used them before.
+
+If you need a refresher on JavaScript, we recommend reading [this guide](https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript). Note that we're also using some features from ES6, a recent version of JavaScript. In this tutorial, we're using [arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions), [classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes), [`let`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let), and [`const`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const) statements. You can use <a href="http://babeljs.io/repl/#?babili=false&evaluate=true&lineWrap=false&presets=es2015%2Creact&experimental=false&loose=false&spec=false&code=const%20element%20%3D%20%3Ch1%3EHello%2C%20world!%3C%2Fh1%3E%3B%0Aconst%20container%20%3D%20document.getElementById('root')%3B%0AReactDOM.render(element%2C%20container)%3B%0A">Babel REPL</a> to check what ES6 code compiles to.
+
+### How to Follow Along
+
+There are two ways to complete this tutorial: you could either write the code right in the browser, or you could set up a local development environment on your machine. You can choose either option depending on what you feel comfortable with.
+
+#### If You Prefer to Write Code in the Browser
+
+This is the quickest way to get started!
+
+First, open this [starter code](https://codepen.io/gaearon/pen/oWWQNa?editors=0010) in a new tab. It should display an empty tic-tac-toe field. We will be editing that code during this tutorial.
+
+You can now skip the next section about setting up a local development environment and head straight to the [overview](#overview).
+
+#### If You Prefer to Write Code in Your Editor
+
+Alternatively, you can set up a project on your computer.
+
+Note: **this is completely optional and not required for this tutorial!**
+
+This is more work, but lets you work from the comfort of your editor.
+
+If you want to do it, here are the steps to follow:
+
+1. Make sure you have a recent version of [Node.js](https://nodejs.org/en/) installed.
+2. Follow the [installation instructions](/react/docs/installation.html#creating-a-new-application) to create a new project.
+3. Delete all files in the `src/` folder of the new project.
+4. Add a file named `index.css` in the `src/` folder with [this CSS code](https://codepen.io/gaearon/pen/oWWQNa?editors=0100).
+5. Add a file named `index.js` in the `src/` folder with [this JS code](https://codepen.io/gaearon/pen/oWWQNa?editors=0010), and then add three lines to the top of it:
+
+    ```js
+    import React from 'react';
+    import ReactDOM from 'react-dom';
+    import './index.css';
+    ```
+
+Now if you run `npm start` in the project folder and open `http://localhost:3000` in the browser, you should see an empty tic-tac-toe field.
+
+We recommend following [these instructions](http://babeljs.io/docs/editors) to configure syntax highlighting for your editor.
+
+### Help, I'm Stuck!
+
+If you get stuck, check out the [community support resources](https://facebook.github.io/react/community/support.html). In particular, [Reactiflux chat](/react/community/support.html#reactiflux-chat) is a great way to get quick help. If you don't get a good answer anywhere, please file an issue, and we'll help you out.
+
+With this out of the way, let's get started!
+
+## Overview
+
+### What is React?
+
+React is a declarative, efficient, and flexible JavaScript library for building user interfaces.
+
+React has a few different kinds of components, but we'll start with `React.Component` subclasses:
+
+```javascript
+class ShoppingList extends React.Component {
+  render() {
+    return (
+      <div className="shopping-list">
+        <h1>Shopping List for {this.props.name}</h1>
+        <ul>
+          <li>Instagram</li>
+          <li>WhatsApp</li>
+          <li>Oculus</li>
+        </ul>
+      </div>
+    );
+  }
+}
+
+// Example usage: <ShoppingList name="Mark" />
+```
+
+We'll get to the funny XML-like tags in a second. Your components tell React what you want to render – then React will efficiently update and render just the right components when your data changes.
+
+Here, ShoppingList is a **React component class**, or **React component type**. A component takes in parameters, called `props`, and returns a hierarchy of views to display via the `render` method.
+
+The `render` method returns a *description* of what you want to render, and then React takes that description and renders it to the screen. In particular, `render` returns a **React element**, which is a lightweight description of what to render. Most React developers use a special syntax called JSX which makes it easier to write these structures. The `<div />` syntax is transformed at build time to `React.createElement('div')`. The example above is equivalent to:
+
+```javascript
+return React.createElement('div', {className: 'shopping-list'},
+  React.createElement('h1', /* ... h1 children ... */),
+  React.createElement('ul', /* ... ul children ... */)
+);
+```
+
+[See full expanded version.](https://babeljs.io/repl/#?babili=false&evaluate=false&lineWrap=false&presets=react&targets=&browsers=&builtIns=false&debug=false&experimental=false&loose=false&spec=false&playground=true&code=%3Cdiv%20className%3D%22shopping-list%22%3E%0A%20%20%3Ch1%3EShopping%20List%20for%20%7Bprops.name%7D%3C%2Fh1%3E%0A%20%20%3Cul%3E%0A%20%20%20%20%3Cli%3EInstagram%3C%2Fli%3E%0A%20%20%20%20%3Cli%3EWhatsApp%3C%2Fli%3E%0A%20%20%20%20%3Cli%3EOculus%3C%2Fli%3E%0A%20%20%3C%2Ful%3E%0A%3C%2Fdiv%3E)
+
+If you're curious, `createElement()` is described in more detail in the [API reference](/react/docs/react-api.html#createelement), but we won't be using it directly in this tutorial. Instead, we will keep using JSX.
+
+You can put any JavaScript expression within braces inside JSX. Each React element is a real JavaScript object that you can store in a variable or pass around your program.
+
+The `ShoppingList` component only renders built-in DOM components, but you can compose custom React components just as easily, by writing `<ShoppingList />`. Each component is encapsulated so it can operate independently, which allows you to build complex UIs out of simple components.
+
+### Getting Started
+
+Start with this example: [Starter Code](https://codepen.io/gaearon/pen/oWWQNa?editors=0010).
+
+It contains the shell of what we're building today. We've provided the styles so you only need to worry about the JavaScript.
+
+In particular, we have three components:
+
+* Square
+* Board
+* Game
+
+The Square component renders a single `<button>`, the Board renders 9 squares, and the Game component renders a board with some placeholders that we'll fill in later. None of the components are interactive at this point.
+
+### Passing Data Through Props
+
+Just to get our feet wet, let's try passing some data from the Board component to the Square component.
+
+In Board's `renderSquare` method, change the code to pass a `value` prop to the Square:
+
+```js{3}
+class Board extends React.Component {
+  renderSquare(i) {
+    return <Square value={i} />;
+  }
+```
+
+Then change Square's `render` method to show that value by replacing `{/* TODO */}` with `{this.props.value}`:
+
+```js{5}
+class Square extends React.Component {
+  render() {
+    return (
+      <button className="square">
+        {this.props.value}
+      </button>
+    );
+  }
+}
+```
+
+Before:
+
+![React Devtools](/react/img/tutorial/tictac-empty.png)
+
+After: You should see a number in each square in the rendered output.
+
+![React Devtools](/react/img/tutorial/tictac-numbers.png)
+
+[View the current code.](https://codepen.io/gaearon/pen/aWWQOG?editors=0010)
+
+### An Interactive Component
+
+Let's make the Square component fill in an "X" when you click it. Try changing the button tag returned in the `render()` function of the Square like this:
+
+```javascript{4}
+class Square extends React.Component {
+  render() {
+    return (
+      <button className="square" onClick={() => alert('click')}>
+        {this.props.value}
+      </button>
+    );
+  }
+}
+```
+
+If you click on a square now, you should get an alert in your browser.
+
+This uses the new JavaScript [arrow function](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions) syntax. Note that we're passing a function as the `onClick` prop. Doing `onClick={alert('click')}` would alert immediately instead of when the button is clicked.
+
+React components can have state by setting `this.state` in the constructor, which should be considered private to the component. Let's store the current value of the square in state, and change it when the square is clicked.
+
+First, add a constructor to the class to initialize the state:
+
+```javascript{2-7}
+class Square extends React.Component {
+  constructor() {
+    super();
+    this.state = {
+      value: null,
+    };
+  }
+
+  render() {
+    return (
+      <button className="square" onClick={() => alert('click')}>
+        {this.props.value}
+      </button>
+    );
+  }
+}
+```
+
+In [JavaScript classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes), you need to explicitly call `super();` when defining the constructor of a subclass.
+
+Now change the Square `render` method to display the value from the current state, and to toggle it on click:
+
+* Replace `this.props.value` with `this.state.value` inside the `<button>` tag.
+* Replace the `() => alert()` event handler with `() => this.setState({value: 'X'})`.
+
+Now the `<button>` tag looks like this:
+
+```javascript{10-12}
+class Square extends React.Component {
+  constructor() {
+    super();
+    this.state = {
+      value: null,
+    };
+  }
+
+  render() {
+    return (
+      <button className="square" onClick={() => this.setState({value: 'X'})}>
+        {this.state.value}
+      </button>
+    );
+  }
+}
+```
+
+Whenever `this.setState` is called, an update to the component is scheduled, causing React to merge in the passed state update and rerender the component along with its descendants. When the component rerenders, `this.state.value` will be `'X'` so you'll see an X in the grid.
+
+If you click on any square, an X should show up in it.
+
+[View the current code.](https://codepen.io/gaearon/pen/VbbVLg?editors=0010)
+
+### Developer Tools
+
+The React Devtools extension for [Chrome](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en) and [Firefox](https://addons.mozilla.org/en-US/firefox/addon/react-devtools/) lets you inspect a React component tree in your browser devtools.
+
+<img src="/react/img/tutorial/devtools.png" alt="React Devtools" style="max-width: 100%">
+
+It lets you inspect the props and state of any of the components in your tree.
+
+After installing it, you can right-click any element on the page, click "Inspect" to open the developer tools, and the React tab will appear as the last tab to the right.
+
+**However, note there are a few extra steps to get it working with CodePen:**
+
+1. Log in or register and confirm your email (required to prevent spam).
+2. Click the "Fork" button.
+3. Click "Change View" and then choose "Debug mode".
+4. In the new tab that opens, the devtools should now have a React tab.
+
+## Lifting State Up
+
+We now have the basic building blocks for a tic-tac-toe game. But right now, the state is encapsulated in each Square component. To make a fully-working game, we now need to check if one player has won the game, and alternate placing X and O in the squares. To check if someone has won, we'll need to have the value of all 9 squares in one place, rather than split up across the Square components.
+
+You might think that Board should just inquire what the current state of each Square is. Although it is technically possible to do this in React, it is discouraged because it tends to make code difficult to understand, more brittle, and harder to refactor.
+
+Instead, the best solution here is to store this state in the Board component instead of in each Square – and the Board component can tell each Square what to display, like how we made each square display its index earlier.
+
+**When you want to aggregate data from multiple children or to have two child components communicate with each other, move the state upwards so that it lives in the parent component. The parent can then pass the state back down to the children via props, so that the child components are always in sync with each other and with the parent.**
+
+Pulling state upwards like this is common when refactoring React components, so let's take this opportunity to try it out. Add a constructor to the Board and set its initial state to contain an array with 9 nulls, corresponding to the 9 squares:
+
+```javascript{2-7}
+class Board extends React.Component {
+  constructor() {
+    super();
+    this.state = {
+      squares: Array(9).fill(null),
+    };
+  }
+
+  renderSquare(i) {
+    return <Square value={i} />;
+  }
+
+  render() {
+    const status = 'Next player: X';
+
+    return (
+      <div>
+        <div className="status">{status}</div>
+        <div className="board-row">
+          {this.renderSquare(0)}
+          {this.renderSquare(1)}
+          {this.renderSquare(2)}
+        </div>
+        <div className="board-row">
+          {this.renderSquare(3)}
+          {this.renderSquare(4)}
+          {this.renderSquare(5)}
+        </div>
+        <div className="board-row">
+          {this.renderSquare(6)}
+          {this.renderSquare(7)}
+          {this.renderSquare(8)}
+        </div>
+      </div>
+    );
+  }
+}
+```
+
+We'll fill it in later so that a board looks something like
+
+```javascript
+[
+  'O', null, 'X',
+  'X', 'X', 'O',
+  'O', null, null,
+]
+```
+
+Board's `renderSquare` method currently looks like this:
+
+```javascript
+  renderSquare(i) {
+    return <Square value={i} />;
+  }
+```
+
+Modify it to pass a `value` prop to Square.
+
+```javascript{2}
+  renderSquare(i) {
+    return <Square value={this.state.squares[i]} />;
+  }
+```
+
+[View the current code.](https://codepen.io/gaearon/pen/gWWQPY?editors=0010)
+
+Now we need to change what happens when a square is clicked. The Board component now stores which squares are filled, which means we need some way for Square to update the state of Board. Since component state is considered private, we can't update Board's state directly from Square.
+
+The usual pattern here is pass down a function from Board to Square that gets called when the square is clicked. Change `renderSquare` in Board again so that it reads:
+
+```javascript{5}
+  renderSquare(i) {
+    return (
+      <Square
+        value={this.state.squares[i]}
+        onClick={() => this.handleClick(i)}
+      />
+    );
+  }
+```
+
+We split the returned element into multiple lines for readability, and added parens around it so that JavaScript doesn't insert a semicolon after `return` and break our code.
+
+Now we're passing down two props from Board to Square: `value` and `onClick`. The latter is a function that Square can call. Let's make the following changes to Square:
+
+* Replace `this.state.value` with `this.props.value` in Square's `render`.
+* Replace `this.setState()` with `this.props.onClick()` in Square's `render`.
+* Delete `constructor` definition from Square because it doesn't have state anymore.
+
+After these changes, the whole Square component looks like this:
+
+```javascript{1,2,4,5}
+class Square extends React.Component {
+  render() {
+    return (
+      <button className="square" onClick={() => this.props.onClick()}>
+        {this.props.value}
+      </button>
+    );
+  }
+}
+```
+
+Now when the square is clicked, it calls the `onClick` function that was passed by Board. Let's recap what happens here:
+
+1. The `onClick` prop on the built-in DOM `<button>` component tells React to set up a click event listener.
+2. When the button is clicked, React will call the `onClick` event handler defined in Square's `render()` method.
+3. This event handler calls `this.props.onClick()`. Square's props were specified by the Board.
+4. Board passed `onClick={() => this.handleClick(i)}` to Square, so, when called, it runs `this.handleClick(i)` on the Board.
+5. We have not defined the `handleClick()` method on the Board yet, so the code crashes.
+
+Note that `onClick` on the DOM `<button>` component has a special meaning to React, but we could have called `onClick` prop in Square and `handleClick` in Board something else. It is, however, a common convention in React apps to use `on*` names for the handler prop names and `handle*` for their implementations.
+
+Try clicking a square – you should get an error because we haven't defined `handleClick` yet. Add it to the Board class.
+
+```javascript{9-13}
+class Board extends React.Component {
+  constructor() {
+    super();
+    this.state = {
+      squares: Array(9).fill(null),
+    };
+  }
+
+  handleClick(i) {
+    const squares = this.state.squares.slice();
+    squares[i] = 'X';
+    this.setState({squares: squares});
+  }
+
+  renderSquare(i) {
+    return (
+      <Square
+        value={this.state.squares[i]}
+        onClick={() => this.handleClick(i)}
+      />
+    );
+  }
+
+  render() {
+    const status = 'Next player: X';
+
+    return (
+      <div>
+        <div className="status">{status}</div>
+        <div className="board-row">
+          {this.renderSquare(0)}
+          {this.renderSquare(1)}
+          {this.renderSquare(2)}
+        </div>
+        <div className="board-row">
+          {this.renderSquare(3)}
+          {this.renderSquare(4)}
+          {this.renderSquare(5)}
+        </div>
+        <div className="board-row">
+          {this.renderSquare(6)}
+          {this.renderSquare(7)}
+          {this.renderSquare(8)}
+        </div>
+      </div>
+    );
+  }
+}
+```
+
+[View the current code.](https://codepen.io/gaearon/pen/ybbQJX?editors=0010)
+
+We call `.slice()` to copy the `squares` array instead of mutating the existing array. Jump ahead a [section](/react/tutorial/tutorial.html#why-immutability-is-important) to learn why immutability is important.
+
+Now you should be able to click in squares to fill them again, but the state is stored in the Board component instead of in each Square, which lets us continue building the game. Note how whenever Board's state changes, the Square components rerender automatically.
+
+Square no longer keeps its own state; it receives its value from its parent Board and informs its parent when it's clicked. We call components like this **controlled components**.
+
+### Why Immutability Is Important
+
+In the previous code example, we suggest using the `.slice()` operator to copy the `squares` array prior to making changes and to prevent mutating the existing array. Let's talk about what this means and why it is an important concept to learn.
+
+There are generally two ways for changing data. The first method is to *mutate* the data by directly changing the values of a variable. The second method is to replace the data with a new copy of the object that also includes desired changes.
+
+#### Data change with mutation
+```javascript
+var player = {score: 1, name: 'Jeff'};
+player.score = 2;
+// Now player is {score: 2, name: 'Jeff'}
+```
+
+#### Data change without mutation
+```javascript
+var player = {score: 1, name: 'Jeff'};
+
+var newPlayer = Object.assign({}, player, {score: 2});
+// Now player is unchanged, but newPlayer is {score: 2, name: 'Jeff'}
+
+// Or if you are using object spread syntax proposal, you can write:
+// var newPlayer = {...player, score: 2};
+```
+
+The end result is the same but by not mutating (or changing the underlying data) directly we now have an added benefit that can help us increase component and overall application performance.
+
+#### Easier Undo/Redo and Time Travel
+
+Immutability also makes some complex features much easier to implement. For example, further in this tutorial we will implement time travel between different stages of the game. Avoiding data mutations lets us keep a reference to older versions of the data, and switch between them if we need to.
+
+#### Tracking Changes
+
+Determining if a mutated object has changed is complex because changes are made directly to the object. This then requires comparing the current object to a previous copy, traversing the entire object tree, and comparing each variable and value. This process can become increasingly complex.
+
+Determining how an immutable object has changed is considerably easier. If the object being referenced is different from before, then the object has changed. That's it.
+
+#### Determining When to Re-render in React
+
+The biggest benefit of immutability in React comes when you build simple _pure components_. Since immutable data can more easily determine if changes have been made it also helps to determine when a component requires being re-rendered.
+
+To learn more about `shouldComponentUpdate()` and how you can build *pure components* take a look at [Optimizing Performance](/react/docs/optimizing-performance.html#examples).
+
+### Functional Components
+
+We've removed the constructor, and in fact, React supports a simpler syntax called **functional components** for component types like Square that only consist of a `render` method. Rather than define a class extending `React.Component`, simply write a function that takes props and returns what should be rendered.
+
+Replace the whole Square class with this function:
+
+```javascript
+function Square(props) {
+  return (
+    <button className="square" onClick={props.onClick}>
+      {props.value}
+    </button>
+  );
+}
+```
+
+You'll need to change `this.props` to `props` both times it appears. Many components in your apps will be able to be written as functional components: these components tend to be easier to write and React will optimize them more in the future.
+
+While we're cleaning up the code, we also changed `onClick={() => props.onClick()}` to just `onClick={props.onClick}`, as passing the function down is enough for our example. Note that `onClick={props.onClick()}` would not work because it would call `props.onClick` immediately instead of passing it down.
+
+[View the current code.](https://codepen.io/gaearon/pen/QvvJOv?editors=0010)
+
+### Taking Turns
+
+An obvious defect in our game is that only X can play. Let's fix that.
+
+Let's default the first move to be by 'X'. Modify our starting state in our Board constructor.
+
+```javascript{6}
+class Board extends React.Component {
+  constructor() {
+    super();
+    this.state = {
+      squares: Array(9).fill(null),
+      xIsNext: true,
+    };
+  }
+```
+
+Each time we move we shall toggle `xIsNext` by flipping the boolean value and saving the state. Now update Board's `handleClick` function to flip the value of `xIsNext`.
+
+```javascript{3,6}
+  handleClick(i) {
+    const squares = this.state.squares.slice();
+    squares[i] = this.state.xIsNext ? 'X' : 'O';
+    this.setState({
+      squares: squares,
+      xIsNext: !this.state.xIsNext,
+    });
+  }
+```
+
+Now X and O take turns. Next, change the "status" text in Board's `render` so that it also displays who is next.
+
+```javascript{2}
+  render() {
+    const status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
+
+    return (
+      // the rest has not changed
+```
+
+After these changes you should have this Board component:
+
+```javascript{6,11-16,29}
+class Board extends React.Component {
+  constructor() {
+    super();
+    this.state = {
+      squares: Array(9).fill(null),
+      xIsNext: true,
+    };
+  }
+
+  handleClick(i) {
+    const squares = this.state.squares.slice();
+    squares[i] = this.state.xIsNext ? 'X' : 'O';
+    this.setState({
+      squares: squares,
+      xIsNext: !this.state.xIsNext,
+    });
+  }
+
+  renderSquare(i) {
+    return (
+      <Square
+        value={this.state.squares[i]}
+        onClick={() => this.handleClick(i)}
+      />
+    );
+  }
+
+  render() {
+    const status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
+
+    return (
+      <div>
+        <div className="status">{status}</div>
+        <div className="board-row">
+          {this.renderSquare(0)}
+          {this.renderSquare(1)}
+          {this.renderSquare(2)}
+        </div>
+        <div className="board-row">
+          {this.renderSquare(3)}
+          {this.renderSquare(4)}
+          {this.renderSquare(5)}
+        </div>
+        <div className="board-row">
+          {this.renderSquare(6)}
+          {this.renderSquare(7)}
+          {this.renderSquare(8)}
+        </div>
+      </div>
+    );
+  }
+}
+```
+
+[View the current code.](https://codepen.io/gaearon/pen/KmmrBy?editors=0010)
+
+### Declaring a Winner
+
+Let's show when a game is won. Add this helper function to the end of the file:
+
+```javascript
+function calculateWinner(squares) {
+  const lines = [
+    [0, 1, 2],
+    [3, 4, 5],
+    [6, 7, 8],
+    [0, 3, 6],
+    [1, 4, 7],
+    [2, 5, 8],
+    [0, 4, 8],
+    [2, 4, 6],
+  ];
+  for (let i = 0; i < lines.length; i++) {
+    const [a, b, c] = lines[i];
+    if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
+      return squares[a];
+    }
+  }
+  return null;
+}
+```
+
+You can call it in Board's `render` function to check if anyone has won the game and make the status text show "Winner: [X/O]" when someone wins.
+
+Replace the `status` declaration in Board's `render` with this code:
+
+```javascript{2-8}
+  render() {
+    const winner = calculateWinner(this.state.squares);
+    let status;
+    if (winner) {
+      status = 'Winner: ' + winner;
+    } else {
+      status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
+    }
+
+    return (
+      // the rest has not changed
+```
+
+You can now change `handleClick` in Board to return early and ignore the click if someone has already won the game or if a square is already filled:
+
+```javascript{3-5}
+  handleClick(i) {
+    const squares = this.state.squares.slice();
+    if (calculateWinner(squares) || squares[i]) {
+      return;
+    }
+    squares[i] = this.state.xIsNext ? 'X' : 'O';
+    this.setState({
+      squares: squares,
+      xIsNext: !this.state.xIsNext,
+    });
+  }
+```
+
+Congratulations! You now have a working tic-tac-toe game. And now you know the basics of React. So *you're* probably the real winner here.
+
+[View the current code.](https://codepen.io/gaearon/pen/LyyXgK?editors=0010)
+
+## Storing a History
+
+Let's make it possible to revisit old states of the board so we can see what it looked like after any of the previous moves. We're already creating a new `squares` array each time a move is made, which means we can easily store the past board states simultaneously.
+
+Let's plan to store an object like this in state:
+
+```javascript
+history = [
+  {
+    squares: [
+      null, null, null,
+      null, null, null,
+      null, null, null,
+    ]
+  },
+  {
+    squares: [
+      null, null, null,
+      null, 'X', null,
+      null, null, null,
+    ]
+  },
+  // ...
+]
+```
+
+We'll want the top-level Game component to be responsible for displaying the list of moves. So just as we pulled the state up before from Square into Board, let's now pull it up again from Board into Game – so that we have all the information we need at the top level.
+
+First, set up the initial state for Game by adding a constructor to it:
+
+```javascript{2-10}
+class Game extends React.Component {
+  constructor() {
+    super();
+    this.state = {
+      history: [{
+        squares: Array(9).fill(null),
+      }],
+      xIsNext: true,
+    };
+  }
+
+  render() {
+    return (
+      <div className="game">
+        <div className="game-board">
+          <Board />
+        </div>
+        <div className="game-info">
+          <div>{/* status */}</div>
+          <ol>{/* TODO */}</ol>
+        </div>
+      </div>
+    );
+  }
+}
+```
+
+Then change Board so that it takes `squares` via props and has its own `onClick` prop specified by Game, like the transformation we made for Square earlier. You can pass the location of each square into the click handler so that we still know which square was clicked. Here is a list of steps you need to do:
+
+* Delete the `constructor` in Board.
+* Replace `this.state.squares[i]` with `this.props.squares[i]` in Board's `renderSquare`.
+* Replace `this.handleClick(i)` with `this.props.onClick(i)` in Board's `renderSquare`.
+
+Now the whole Board component looks like this:
+
+```javascript{17,18}
+class Board extends React.Component {
+  handleClick(i) {
+    const squares = this.state.squares.slice();
+    if (calculateWinner(squares) || squares[i]) {
+      return;
+    }
+    squares[i] = this.state.xIsNext ? 'X' : 'O';
+    this.setState({
+      squares: squares,
+      xIsNext: !this.state.xIsNext,
+    });
+  }
+
+  renderSquare(i) {
+    return (
+      <Square
+        value={this.props.squares[i]}
+        onClick={() => this.props.onClick(i)}
+      />
+    );
+  }
+
+  render() {
+    const winner = calculateWinner(this.state.squares);
+    let status;
+    if (winner) {
+      status = 'Winner: ' + winner;
+    } else {
+      status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
+    }
+
+    return (
+      <div>
+        <div className="status">{status}</div>
+        <div className="board-row">
+          {this.renderSquare(0)}
+          {this.renderSquare(1)}
+          {this.renderSquare(2)}
+        </div>
+        <div className="board-row">
+          {this.renderSquare(3)}
+          {this.renderSquare(4)}
+          {this.renderSquare(5)}
+        </div>
+        <div className="board-row">
+          {this.renderSquare(6)}
+          {this.renderSquare(7)}
+          {this.renderSquare(8)}
+        </div>
+      </div>
+    );
+  }
+}
+```
+
+Game's `render` should look at the most recent history entry and can take over calculating the game status:
+
+```javascript{2-11,16-19,22}
+  render() {
+    const history = this.state.history;
+    const current = history[history.length - 1];
+    const winner = calculateWinner(current.squares);
+
+    let status;
+    if (winner) {
+      status = 'Winner: ' + winner;
+    } else {
+      status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
+    }
+
+    return (
+      <div className="game">
+        <div className="game-board">
+          <Board
+            squares={current.squares}
+            onClick={(i) => this.handleClick(i)}
+          />
+        </div>
+        <div className="game-info">
+          <div>{status}</div>
+          <ol>{/* TODO */}</ol>
+        </div>
+      </div>
+    );
+  }
+```
+
+Since Game is now rendering the status, we can delete `<div className="status">{status}</div>` and the code calculating the status from the Board's `render` function:
+
+```js{1-4}
+  render() {
+    return (
+      <div>
+        <div className="board-row">
+          {this.renderSquare(0)}
+          {this.renderSquare(1)}
+          {this.renderSquare(2)}
+        </div>
+        <div className="board-row">
+          {this.renderSquare(3)}
+          {this.renderSquare(4)}
+          {this.renderSquare(5)}
+        </div>
+        <div className="board-row">
+          {this.renderSquare(6)}
+          {this.renderSquare(7)}
+          {this.renderSquare(8)}
+        </div>
+      </div>
+    );
+  }
+```
+
+Next, we need to move the `handleClick` method implementation from Board to Game. You can cut it from the Board class, and paste it into the Game class.
+
+We also need to change it a little, since Game state is structured differently. Game's `handleClick` can push a new entry onto the stack by concatenating the new history entry to make a new history array.
+
+```javascript{2-4,10-12}
+  handleClick(i) {
+    const history = this.state.history;
+    const current = history[history.length - 1];
+    const squares = current.squares.slice();
+    if (calculateWinner(squares) || squares[i]) {
+      return;
+    }
+    squares[i] = this.state.xIsNext ? 'X' : 'O';
+    this.setState({
+      history: history.concat([{
+        squares: squares
+      }]),
+      xIsNext: !this.state.xIsNext,
+    });
+  }
+```
+
+At this point, Board only needs `renderSquare` and `render`; the state initialization and click handler should both live in Game.
+
+[View the current code.](https://codepen.io/gaearon/pen/EmmOqJ?editors=0010)
+
+### Showing the Moves
+
+Let's show the previous moves made in the game so far. We learned earlier that React elements are first-class JS objects and we can store them or pass them around. To render multiple items in React, we pass an array of React elements. The most common way to build that array is to map over your array of data. Let's do that in the `render` method of Game:
+
+```javascript{6-15,34}
+  render() {
+    const history = this.state.history;
+    const current = history[history.length - 1];
+    const winner = calculateWinner(current.squares);
+
+    const moves = history.map((step, move) => {
+      const desc = move ?
+        'Move #' + move :
+        'Game start';
+      return (
+        <li>
+          <a href="#" onClick={() => this.jumpTo(move)}>{desc}</a>
+        </li>
+      );
+    });
+
+    let status;
+    if (winner) {
+      status = 'Winner: ' + winner;
+    } else {
+      status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
+    }
+
+    return (
+      <div className="game">
+        <div className="game-board">
+          <Board
+            squares={current.squares}
+            onClick={(i) => this.handleClick(i)}
+          />
+        </div>
+        <div className="game-info">
+          <div>{status}</div>
+          <ol>{moves}</ol>
+        </div>
+      </div>
+    );
+  }
+```
+
+[View the current code.](https://codepen.io/gaearon/pen/EmmGEa?editors=0010)
+
+For each step in the history, we create a list item `<li>` with a link `<a>` inside it that goes nowhere (`href="#"`) but has a click handler which we'll implement shortly. With this code, you should see a list of the moves that have been made in the game, along with a warning that says:
+
+>  Warning:
+>  Each child in an array or iterator should have a unique "key" prop. Check the render method of "Game".
+
+Let's talk about what that warning means.
+
+### Keys
+
+When you render a list of items, React always stores some info about each item in the list. If you render a component that has state, that state needs to be stored – and regardless of how you implement your components, React stores a reference to the backing native views.
+
+When you update that list, React needs to determine what has changed. You could've added, removed, rearranged, or updated items in the list.
+
+Imagine transitioning from
+
+```html
+<li>Alexa: 7 tasks left</li>
+<li>Ben: 5 tasks left</li>
+```
+
+to
+
+```html
+<li>Ben: 9 tasks left</li>
+<li>Claudia: 8 tasks left</li>
+<li>Alexa: 5 tasks left</li>
+```
+
+To a human eye, it looks likely that Alexa and Ben swapped places and Claudia was added – but React is just a computer program and doesn't know what you intended it to do. As a result, React asks you to specify a *key* property on each element in a list, a string to differentiate each component from its siblings. In this case, `alexa`, `ben`, `claudia` might be sensible keys; if the items correspond to objects in a database, the database ID is usually a good choice:
+
+```html
+<li key={user.id}>{user.name}: {user.taskCount} tasks left</li>
+```
+
+`key` is a special property that's reserved by React (along with `ref`, a more advanced feature). When an element is created, React pulls off the `key` property and stores the key directly on the returned element. Even though it may look like it is part of props, it cannot be referenced with `this.props.key`. React uses the key automatically while deciding which children to update; there is no way for a component to inquire about its own key.
+
+When a list is rerendered, React takes each element in the new version and looks for one with a matching key in the previous list. When a key is added to the set, a component is created; when a key is removed, a component is destroyed. Keys tell React about the identity of each component, so that it can maintain the state across rerenders. If you change the key of a component, it will be completely destroyed and recreated with a new state.
+
+**It's strongly recommended that you assign proper keys whenever you build dynamic lists.** If you don't have an appropriate key handy, you may want to consider restructuring your data so that you do.
+
+If you don't specify any key, React will warn you and fall back to using the array index as a key – which is not the correct choice if you ever reorder elements in the list or add/remove items anywhere but the bottom of the list. Explicitly passing `key={i}` silences the warning but has the same problem so isn't recommended in most cases.
+
+Component keys don't need to be globally unique, only unique relative to the immediate siblings.
+
+
+### Implementing Time Travel
+
+For our move list, we already have a unique ID for each step: the number of the move when it happened. In the Game's `render` method, add the key as `<li key={move}>` and the key warning should disappear:
+
+```js{6}
+    const moves = history.map((step, move) => {
+      const desc = move ?
+        'Move #' + move :
+        'Game start';
+      return (
+        <li key={move}>
+          <a href="#" onClick={() => this.jumpTo(move)}>{desc}</a>
+        </li>
+      );
+    });
+```
+
+[View the current code.](https://codepen.io/gaearon/pen/PmmXRE?editors=0010)
+
+Clicking any of the move links throws an error because `jumpTo` is undefined. Let's add a new key to Game's state to indicate which step we're currently viewing.
+
+First, add `stepNumber: 0` to the initial state in Game's `constructor`:
+
+```js{8}
+class Game extends React.Component {
+  constructor() {
+    super();
+    this.state = {
+      history: [{
+        squares: Array(9).fill(null),
+      }],
+      stepNumber: 0,
+      xIsNext: true,
+    };
+  }
+```
+
+Next, we'll define the `jumpTo` method in Game to update that state. We also want to update `xIsNext`. We set `xIsNext` to true if the index of the move number is an even number.
+
+Add a method called `jumpTo` to the Game class:
+
+```javascript{5-10}
+  handleClick(i) {
+    // this method has not changed
+  }
+
+  jumpTo(step) {
+    this.setState({
+      stepNumber: step,
+      xIsNext: (step % 2) ? false : true,
+    });
+  }
+
+  render() {
+    // this method has not changed
+  }
+```
+
+Then update `stepNumber` when a new move is made by adding `stepNumber: history.length` to the state update in Game's `handleClick`:
+
+```javascript{2,13}
+  handleClick(i) {
+    const history = this.state.history.slice(0, this.state.stepNumber + 1);
+    const current = history[history.length - 1];
+    const squares = current.squares.slice();
+    if (calculateWinner(squares) || squares[i]) {
+      return;
+    }
+    squares[i] = this.state.xIsNext ? 'X' : 'O';
+    this.setState({
+      history: history.concat([{
+        squares: squares
+      }]),
+      stepNumber: history.length,
+      xIsNext: !this.state.xIsNext,
+    });
+  }
+```
+
+Now you can modify Game's `render` to read from that step in the history:
+
+```javascript{3}
+  render() {
+    const history = this.state.history;
+    const current = history[this.state.stepNumber];
+    const winner = calculateWinner(current.squares);
+
+    // the rest has not changed
+```
+
+[View the current code.](https://codepen.io/gaearon/pen/gWWZgR?editors=0010)
+
+If you click any move link now, the board should immediately update to show what the game looked like at that time.
+
+You may also want to update `handleClick` to be aware of `stepNumber` when reading the current board state so that you can go back in time then click in the board to create a new entry. (Hint: It's easiest to `.slice()` off the extra elements from `history` at the very top of `handleClick`.)
+
+### Wrapping Up
+
+Now, you've made a tic-tac-toe game that:
+
+* lets you play tic-tac-toe,
+* indicates when one player has won the game,
+* stores the history of moves during the game,
+* allows players to jump back in time to see older versions of the game board.
+
+Nice work! We hope you now feel like you have a decent grasp on how React works.
+
+Check out the final result here: [Final Result](https://codepen.io/gaearon/pen/gWWZgR?editors=0010).
+
+If you have extra time or want to practice your new skills, here are some ideas for improvements you could make, listed in order of increasing difficulty:
+
+1. Display the move locations in the format "(1, 3)" instead of "6".
+2. Bold the currently-selected item in the move list.
+3. Rewrite Board to use two loops to make the squares instead of hardcoding them.
+4. Add a toggle button that lets you sort the moves in either ascending or descending order.
+5. When someone wins, highlight the three squares that caused the win.
+
+Throughout this tutorial, we have touched on a number of React concepts including elements, components, props, and state. For a more in-depth explanation for each of these topics, check out [the rest of the documentation](/react/docs/hello-world.html). To learn more about defining components, check out the [`React.Component` API reference](/react/docs/react-component.html).
diff --git a/docs/warnings/dont-call-proptypes.md b/docs/warnings/dont-call-proptypes.md
new file mode 100644
index 000000000000..05da5c04c73e
--- /dev/null
+++ b/docs/warnings/dont-call-proptypes.md
@@ -0,0 +1,97 @@
+---
+title: Don't Call PropTypes Warning
+layout: single
+permalink: warnings/dont-call-proptypes.html
+---
+
+> Note:
+> `React.PropTypes` is deprecated as of React v15.5. Please use [the `prop-types` library instead](https://github.com/reactjs/prop-types).
+
+In a future major release of React, the code that implements PropType validation functions will be stripped in production. Once this happens, any code that calls these functions manually (that isn't stripped in production) will throw an error.
+
+### Declaring PropTypes is still fine
+
+The normal usage of PropTypes is still supported:
+
+```javascript
+Button.propTypes = {
+  highlighted: React.PropTypes.bool
+};
+```
+
+Nothing changes here.
+
+### Don’t call PropTypes directly
+
+Using PropTypes in any other way than annotating React components with them is no longer supported:
+
+```javascript
+var apiShape = React.PropTypes.shape({
+  body: React.PropTypes.object,
+  statusCode: React.PropTypes.number.isRequired
+}).isRequired;
+
+// Not supported!
+var error = apiShape(json, 'response');
+```
+
+If you depend on using PropTypes like this, we encourage you to use or create a fork of PropTypes (such as [these](https://github.com/aackerman/PropTypes) [two](https://github.com/developit/proptypes) packages).
+
+If you don't fix the warning, this code will crash in production with React 16.
+
+### If you don't call PropTypes directly but still get the warning
+
+Inspect the stack trace produced by the warning. You will find the component definition responsible for the PropTypes direct call. Most likely, the issue is due to third-party PropTypes that wrap React’s PropTypes, for example:
+
+```js
+Button.propTypes = {
+  highlighted: ThirdPartyPropTypes.deprecated(
+    React.PropTypes.bool,
+    'Use `active` prop instead'
+  )
+}
+```
+
+In this case, `ThirdPartyPropTypes.deprecated` is a wrapper calling `React.PropTypes.bool`. This pattern by itself is fine, but triggers a false positive because React thinks you are calling PropTypes directly. The next section explains how to fix this problem for a library implementing something like `ThirdPartyPropTypes`. If it's not a library you wrote, you can file an issue against it.
+
+### Fixing the false positive in third party PropTypes
+
+If you are an author of a third party PropTypes library and you let consumers wrap existing React PropTypes, they might start seeing this warning coming from your library. This happens because React doesn't see a "secret" last argument that [it passes](https://github.com/facebook/react/pull/7132) to detect manual PropTypes calls.
+
+Here is how to fix it. We will use `deprecated` from [react-bootstrap/react-prop-types](https://github.com/react-bootstrap/react-prop-types/blob/0d1cd3a49a93e513325e3258b28a82ce7d38e690/src/deprecated.js) as an example. The current implementation only passes down the `props`, `propName`, and `componentName` arguments:
+
+```javascript
+export default function deprecated(propType, explanation) {
+  return function validate(props, propName, componentName) {
+    if (props[propName] != null) {
+      const message = `"${propName}" property of "${componentName}" has been deprecated.\n${explanation}`;
+      if (!warned[message]) {
+        warning(false, message);
+        warned[message] = true;
+      }
+    }
+
+    return propType(props, propName, componentName);
+  };
+}
+```
+
+In order to fix the false positive, make sure you pass **all** arguments down to the wrapped PropType. This is easy to do with the ES6 `...rest` notation:
+
+```javascript
+export default function deprecated(propType, explanation) {
+  return function validate(props, propName, componentName, ...rest) { // Note ...rest here
+    if (props[propName] != null) {
+      const message = `"${propName}" property of "${componentName}" has been deprecated.\n${explanation}`;
+      if (!warned[message]) {
+        warning(false, message);
+        warned[message] = true;
+      }
+    }
+
+    return propType(props, propName, componentName, ...rest); // and here
+  };
+}
+```
+
+This will silence the warning.
diff --git a/docs/warnings/invalid-aria-prop.md b/docs/warnings/invalid-aria-prop.md
new file mode 100644
index 000000000000..53ebdd9bc406
--- /dev/null
+++ b/docs/warnings/invalid-aria-prop.md
@@ -0,0 +1,11 @@
+---
+title: Invalid ARIA Prop Warning
+layout: single
+permalink: warnings/invalid-aria-prop.html
+---
+
+The invalid-aria-prop warning will fire if you attempt to render a DOM element with an aria-* prop that does not exist in the Web Accessibility Initiative (WAI) Accessible Rich Internet Application (ARIA) [specification](https://www.w3.org/TR/wai-aria-1.1/#states_and_properties).
+
+1. If you feel that you are using a valid prop, check the spelling carefully. `aria-labelledby` and `aria-activedescendant` are often misspelled.
+
+2. React does not yet recognize the attribute you specified. This will likely be fixed in a future version of React. However, React currently strips all unknown attributes, so specifying them in your React app will not cause them to be rendered
\ No newline at end of file
diff --git a/docs/warnings/legacy-factories.md b/docs/warnings/legacy-factories.md
new file mode 100644
index 000000000000..25fc5aaacd18
--- /dev/null
+++ b/docs/warnings/legacy-factories.md
@@ -0,0 +1,59 @@
+---
+title: React Element Factories and JSX Warning
+layout: single
+permalink: warnings/legacy-factories.html
+---
+
+You probably came here because your code is calling your component as a plain function call. This is now deprecated:
+
+```javascript
+var MyComponent = require('MyComponent');
+
+function render() {
+  return MyComponent({ foo: 'bar' });  // WARNING
+}
+```
+
+## JSX
+
+React components can no longer be called directly like this. Instead [you can use JSX](/react/docs/jsx-in-depth.html).
+
+```javascript
+var React = require('react');
+var MyComponent = require('MyComponent');
+
+function render() {
+  return <MyComponent foo="bar" />;
+}
+```
+
+## Without JSX
+
+If you don't want to, or can't use JSX, then you'll need to wrap your component in a factory before calling it:
+
+```javascript
+var React = require('react');
+var MyComponent = React.createFactory(require('MyComponent'));
+
+function render() {
+  return MyComponent({ foo: 'bar' });
+}
+```
+
+This is an easy upgrade path if you have a lot of existing function calls.
+
+## Dynamic components without JSX
+
+If you get a component class from a dynamic source, then it might be unnecessary to create a factory that you immediately invoke. Instead you can just create your element inline:
+
+```javascript
+var React = require('react');
+
+function render(MyComponent) {
+  return React.createElement(MyComponent, { foo: 'bar' });
+}
+```
+
+## In Depth
+
+[Read more about WHY we're making this change.](https://gist.github.com/sebmarkbage/d7bce729f38730399d28)
diff --git a/docs/warnings/refs-must-have-owner.md b/docs/warnings/refs-must-have-owner.md
new file mode 100644
index 000000000000..59a953df5d5d
--- /dev/null
+++ b/docs/warnings/refs-must-have-owner.md
@@ -0,0 +1,27 @@
+---
+title: Refs Must Have Owner Warning
+layout: single
+permalink: warnings/refs-must-have-owner.html
+---
+
+You are probably here because you got the following error messages:
+
+> Warning:
+>
+> 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.
+
+This usually means one of two things:
+
+- You are trying to add a `ref` to an element that is being created outside of a component's render() function.
+- You have multiple (conflicting) copies of React loaded (eg. due to a misconfigured NPM dependency)
+
+
+## Invalid Refs
+
+Only a ReactOwner can have refs. This usually means that you're trying to add a ref to a component that doesn't have an owner (that is, was not created inside of another component's `render` method). Try rendering this component inside of a new top-level component which will hold the ref.
+
+## Multiple copies of React
+
+Bower does a good job of deduplicating dependencies, but NPM does not. If you aren't doing anything (fancy) with refs, there is a good chance that the problem is not with your refs, but rather an issue with having multiple copies of React loaded into your project. Sometimes, when you pull in a third-party module via npm, you will get a duplicate copy of the dependency library, and this can create problems.
+
+If you are using npm... `npm ls` or `npm ls react` might help illuminate.
diff --git a/docs/warnings/special-props.md b/docs/warnings/special-props.md
new file mode 100644
index 000000000000..cdd6b26522a5
--- /dev/null
+++ b/docs/warnings/special-props.md
@@ -0,0 +1,9 @@
+---
+title: Special Props Warning
+layout: single
+permalink: warnings/special-props.html
+---
+
+Most props on a JSX element are passed on to the component, however, there are two special props (`ref` and `key`) which are used by React, and are thus not forwarded to the component.
+
+For instance, attempting to access `this.props.key` from a component (eg. the render function) is not defined.  If you need to access the same value within the child component, you should pass it as a different prop (ex: `<ListItemWrapper key={result.id} id={result.id} />`). While this may seem redundant, it's important to separate app logic from reconciling hints.
diff --git a/docs/warnings/unknown-prop.md b/docs/warnings/unknown-prop.md
new file mode 100644
index 000000000000..eb7585f650d1
--- /dev/null
+++ b/docs/warnings/unknown-prop.md
@@ -0,0 +1,63 @@
+---
+title: Unknown Prop Warning
+layout: single
+permalink: warnings/unknown-prop.html
+---
+The unknown-prop warning will fire if you attempt to render a DOM element with a prop that is not recognized by React as a legal DOM attribute/property. You should ensure that your DOM elements do not have spurious props floating around.
+
+There are a couple of likely reasons this warning could be appearing:
+
+1. Are you using `{...this.props}` or `cloneElement(element, this.props)`? Your component is transferring its own props directly to a child element (eg. https://facebook.github.io/react/docs/transferring-props.html). When transferring props to a child component, you should ensure that you are not accidentally forwarding props that were intended to be interpreted by the parent component.
+
+2. You are using a non-standard DOM attribute on a native DOM node, perhaps to represent custom data. If you are trying to attach custom data to a standard DOM element, consider using a custom data attribute as described [on MDN](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Using_data_attributes).
+
+3. React does not yet recognize the attribute you specified. This will likely be fixed in a future version of React. However, React currently strips all unknown attributes, so specifying them in your React app will not cause them to be rendered.
+
+4. You are using a React component without an upper case. React interprets it as a DOM tag because [React JSX transform uses the upper vs. lower case convention to distinguish between user-defined components and DOM tags](/react/docs/jsx-in-depth.html#user-defined-components-must-be-capitalized).
+
+---
+
+To fix this, composite components should "consume" any prop that is intended for the composite component and not intended for the child component. Example:
+
+**Bad:** Unexpected `layout` prop is forwarded to the `div` tag.
+
+```js
+function MyDiv(props) {
+  if (props.layout === 'horizontal') {
+    // BAD! Because you know for sure "layout" is not a prop that <div> understands.
+    return <div {...props} style={getHorizontalStyle()} />
+  } else {
+    // BAD! Because you know for sure "layout" is not a prop that <div> understands.
+    return <div {...props} style={getVerticalStyle()} />
+  }
+}
+```
+
+**Good:** The spread operator can be used to pull variables off props, and put the remaining props into a variable.
+
+```js
+function MyDiv(props) {
+  const { layout, ...rest } = props
+  if (layout === 'horizontal') {
+    return <div {...rest} style={getHorizontalStyle()} />
+  } else {
+    return <div {...rest} style={getVerticalStyle()} />
+  }
+}
+```
+
+**Good:** You can also assign the props to a new object and delete the keys that you're using from the new object. Be sure not to delete the props from the original `this.props` object, since that object should be considered immutable.
+
+```js
+function MyDiv(props) {
+
+  const divProps = Object.assign({}, props);
+  delete divProps.layout;
+
+  if (props.layout === 'horizontal') {
+    return <div {...divProps} style={getHorizontalStyle()} />
+  } else {
+    return <div {...divProps} style={getVerticalStyle()} />
+  }
+}
+```
diff --git a/examples/README.md b/examples/README.md
deleted file mode 100644
index 53d7a6445b8e..000000000000
--- a/examples/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# React Examples
-
-Here are some small React demos. Some use [JSX](https://facebook.github.io/react/docs/jsx-in-depth.html) and some include third-party library integration.
-
-For more fully-featured examples, check out [React TodoMVC](http://todomvc.com/examples/react/) and [React + Backbone TodoMVC](http://todomvc.com/examples/react-backbone/).
diff --git a/examples/basic-commonjs/.babelrc b/examples/basic-commonjs/.babelrc
deleted file mode 100644
index 05786794195f..000000000000
--- a/examples/basic-commonjs/.babelrc
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-  "presets": ["react", "es2015"]
-}
diff --git a/examples/basic-commonjs/README.md b/examples/basic-commonjs/README.md
deleted file mode 100644
index 87025c46e216..000000000000
--- a/examples/basic-commonjs/README.md
+++ /dev/null
@@ -1,9 +0,0 @@
-# Basic example of using React with Browserify
-
-Run `npm install` in the directory to install React from npm. Then run:
-
-```sh
-npm start
-```
-
-to produce `bundle.js` with example code and React.
diff --git a/examples/basic-commonjs/index.html b/examples/basic-commonjs/index.html
deleted file mode 100644
index 0b6c023c3f71..000000000000
--- a/examples/basic-commonjs/index.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Basic CommonJS Example with Browserify</title>
-    <link rel="stylesheet" href="../shared/css/base.css" />
-  </head>
-  <body>
-    <h1>Basic CommonJS Example with Browserify</h1>
-    <div id="container">
-      <p>
-        To install React, follow the instructions on
-        <a href="https://github.com/facebook/react/">GitHub</a>.
-      </p>
-      <p>
-        If you can see this, React is <strong>not</strong> working right.
-        If you checked out the source from GitHub make sure to run <code>grunt</code>.
-      </p>
-    </div>
-    <h4>Example Details</h4>
-    <p>This is written with JSX in a CommonJS module and precompiled to vanilla JS by navigating to the example
-      directory
-      <pre>cd /path/to/react/examples/example-name</pre>
-      and running
-      <pre>npm start</pre>
-      <br>
-      (don't forget to install first) 
-      <pre>npm install</pre>
-      <br>
-    </p>
-    <p>
-      Learn more about React at
-      <a href="https://facebook.github.io/react" target="_blank">facebook.github.io/react</a>.
-    </p>
-    <script src="bundle.js"></script>
-  </body>
-</html>
diff --git a/examples/basic-commonjs/index.js b/examples/basic-commonjs/index.js
deleted file mode 100644
index ef90bbb89c3e..000000000000
--- a/examples/basic-commonjs/index.js
+++ /dev/null
@@ -1,24 +0,0 @@
-'use strict';
-
-var React = require('react');
-var ReactDOM = require('react-dom');
-
-var ExampleApplication = React.createClass({
-  render: function() {
-    var elapsed = Math.round(this.props.elapsed  / 100);
-    var seconds = elapsed / 10 + (elapsed % 10 ? '' : '.0' );
-    var message =
-      'React has been successfully running for ' + seconds + ' seconds.';
-
-    return <p>{message}</p>;
-  }
-});
-
-var start = new Date().getTime();
-
-setInterval(function() {
-  ReactDOM.render(
-    <ExampleApplication elapsed={new Date().getTime() - start} />,
-    document.getElementById('container')
-  );
-}, 50);
diff --git a/examples/basic-commonjs/package.json b/examples/basic-commonjs/package.json
deleted file mode 100644
index 1fcecb63c67a..000000000000
--- a/examples/basic-commonjs/package.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
-  "name": "react-basic-commonjs-example",
-  "description": "Basic example of using React with CommonJS",
-  "private": true,
-  "main": "index.js",
-  "dependencies": {
-    "babel-preset-es2015": "^6.6.0",
-    "babel-preset-react": "^6.5.0",
-    "babelify": "^7.2.0",
-    "browserify": "^11.0.1",
-    "react": "15.0.0-rc.2",
-    "react-dom": "15.0.0-rc.2",
-    "watchify": "^3.4.0"
-  },
-  "scripts": {
-    "build": "browserify ./index.js -t babelify -o bundle.js",
-    "start": "watchify ./index.js -v -t babelify -o bundle.js"
-  }
-}
diff --git a/examples/basic-jsx-external/example.js b/examples/basic-jsx-external/example.js
deleted file mode 100644
index 7d9911eb6cc4..000000000000
--- a/examples/basic-jsx-external/example.js
+++ /dev/null
@@ -1,19 +0,0 @@
-var ExampleApplication = React.createClass({
-  render: function() {
-    var elapsed = Math.round(this.props.elapsed  / 100);
-    var seconds = elapsed / 10 + (elapsed % 10 ? '' : '.0' );
-    var message =
-      'React has been successfully running for ' + seconds + ' seconds.';
-
-    return <p>{message}</p>;
-  }
-});
-
-var start = new Date().getTime();
-
-setInterval(function() {
-  ReactDOM.render(
-    <ExampleApplication elapsed={new Date().getTime() - start} />,
-    document.getElementById('container')
-  );
-}, 50);
diff --git a/examples/basic-jsx-precompile/example.js b/examples/basic-jsx-precompile/example.js
deleted file mode 100644
index 7d9911eb6cc4..000000000000
--- a/examples/basic-jsx-precompile/example.js
+++ /dev/null
@@ -1,19 +0,0 @@
-var ExampleApplication = React.createClass({
-  render: function() {
-    var elapsed = Math.round(this.props.elapsed  / 100);
-    var seconds = elapsed / 10 + (elapsed % 10 ? '' : '.0' );
-    var message =
-      'React has been successfully running for ' + seconds + ' seconds.';
-
-    return <p>{message}</p>;
-  }
-});
-
-var start = new Date().getTime();
-
-setInterval(function() {
-  ReactDOM.render(
-    <ExampleApplication elapsed={new Date().getTime() - start} />,
-    document.getElementById('container')
-  );
-}, 50);
diff --git a/examples/basic-jsx-precompile/index.html b/examples/basic-jsx-precompile/index.html
deleted file mode 100644
index 88720b6a015b..000000000000
--- a/examples/basic-jsx-precompile/index.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Basic Example with Precompiled JSX</title>
-    <link rel="stylesheet" href="../shared/css/base.css" />
-  </head>
-  <body>
-    <h1>Basic Example with Precompiled JSX</h1>
-    <div id="container">
-      <p>
-        If you can see this, React is <strong>not</strong> running. Try running:
-      </p>
-      <pre>npm install -g babel-cli
-cd examples/basic-jsx-precompile/
-npm install babel-preset-react
-babel example.js --presets react --out-dir=build</pre>
-    </div>
-    <h4>Example Details</h4>
-    <p>This is written with JSX in a separate file and precompiled to vanilla JS by running:</p>
-
-    <p><i>With Babel lower than 6.0</i></p>
-    <pre>npm install -g babel
-cd examples/basic-jsx-precompile/
-babel example.js --out-dir=build</pre>
-
-	<p><i>With Babel 6.0 or higher</i></p>
-    <pre>npm install -g babel-cli
-cd examples/basic-jsx-precompile/
-npm install babel-preset-react
-babel example.js --presets react --out-dir=build</pre>
-    <p>
-      Learn more about React at
-      <a href="https://facebook.github.io/react" target="_blank">facebook.github.io/react</a>.
-    </p>
-    <script src="../../build/react.js"></script>
-    <script src="../../build/react-dom.js"></script>
-    <script src="build/example.js"></script>
-  </body>
-</html>
diff --git a/examples/basic/index.html b/examples/basic/index.html
deleted file mode 100644
index 9fc1fb3c30cd..000000000000
--- a/examples/basic/index.html
+++ /dev/null
@@ -1,52 +0,0 @@
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Basic Example</title>
-    <link rel="stylesheet" href="../shared/css/base.css" />
-  </head>
-  <body>
-    <h1>Basic Example</h1>
-    <div id="container">
-      <p>
-        To install React, follow the instructions on
-        <a href="https://github.com/facebook/react/">GitHub</a>.
-      </p>
-      <p>
-        If you can see this, React is <strong>not</strong> working right.
-        If you checked out the source from GitHub make sure to run <code>grunt</code>.
-      </p>
-    </div>
-    <h4>Example Details</h4>
-    <p>This is written in vanilla JavaScript (without JSX) and transformed in the browser.</p>
-    <p>
-      Learn more about React at
-      <a href="https://facebook.github.io/react" target="_blank">facebook.github.io/react</a>.
-    </p>
-    <script src="../../build/react.js"></script>
-    <script src="../../build/react-dom.js"></script>
-    <script>
-      var ExampleApplication = React.createClass({
-        render: function() {
-          var elapsed = Math.round(this.props.elapsed  / 100);
-          var seconds = elapsed / 10 + (elapsed % 10 ? '' : '.0' );
-          var message =
-            'React has been successfully running for ' + seconds + ' seconds.';
-
-          return React.DOM.p(null, message);
-        }
-      });
-
-      // Call React.createFactory instead of directly call ExampleApplication({...}) in React.render
-      var ExampleApplicationFactory = React.createFactory(ExampleApplication);
-
-      var start = new Date().getTime();
-      setInterval(function() {
-        ReactDOM.render(
-          ExampleApplicationFactory({elapsed: new Date().getTime() - start}),
-          document.getElementById('container')
-        );
-      }, 50);
-    </script>
-  </body>
-</html>
diff --git a/examples/jquery-bootstrap/css/example.css b/examples/jquery-bootstrap/css/example.css
deleted file mode 100644
index d40f2fbd057e..000000000000
--- a/examples/jquery-bootstrap/css/example.css
+++ /dev/null
@@ -1,3 +0,0 @@
-.example {
-  margin: 20px;
-}
\ No newline at end of file
diff --git a/examples/jquery-bootstrap/js/app.js b/examples/jquery-bootstrap/js/app.js
deleted file mode 100644
index c1342d82a76a..000000000000
--- a/examples/jquery-bootstrap/js/app.js
+++ /dev/null
@@ -1,139 +0,0 @@
-'use strict';
-
-// Simple pure-React component so we don't have to remember
-// Bootstrap's classes
-var BootstrapButton = React.createClass({
-  render: function() {
-    return (
-      <a {...this.props}
-        href="javascript:;"
-        role="button"
-        className={(this.props.className || '') + ' btn'} />
-    );
-  }
-});
-
-var BootstrapModal = React.createClass({
-  // The following two methods are the only places we need to
-  // integrate Bootstrap or jQuery with the components lifecycle methods.
-  componentDidMount: function() {
-    // When the component is added, turn it into a modal
-    $(this.refs.root).modal({backdrop: 'static', keyboard: false, show: false});
-
-    // Bootstrap's modal class exposes a few events for hooking into modal
-    // functionality. Lets hook into one of them:
-    $(this.refs.root).on('hidden.bs.modal', this.handleHidden);
-  },
-  componentWillUnmount: function() {
-    $(this.refs.root).off('hidden.bs.modal', this.handleHidden);
-  },
-  close: function() {
-    $(this.refs.root).modal('hide');
-  },
-  open: function() {
-    $(this.refs.root).modal('show');
-  },
-  render: function() {
-    var confirmButton = null;
-    var cancelButton = null;
-
-    if (this.props.confirm) {
-      confirmButton = (
-        <BootstrapButton
-          onClick={this.handleConfirm}
-          className="btn-primary">
-          {this.props.confirm}
-        </BootstrapButton>
-      );
-    }
-    if (this.props.cancel) {
-      cancelButton = (
-        <BootstrapButton onClick={this.handleCancel} className="btn-default">
-          {this.props.cancel}
-        </BootstrapButton>
-      );
-    }
-
-    return (
-      <div className="modal fade" ref="root">
-        <div className="modal-dialog">
-          <div className="modal-content">
-            <div className="modal-header">
-              <button
-                type="button"
-                className="close"
-                onClick={this.handleCancel}>
-                &times;
-              </button>
-              <h3>{this.props.title}</h3>
-            </div>
-            <div className="modal-body">
-              {this.props.children}
-            </div>
-            <div className="modal-footer">
-              {cancelButton}
-              {confirmButton}
-            </div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-  handleCancel: function() {
-    if (this.props.onCancel) {
-      this.props.onCancel();
-    }
-  },
-  handleConfirm: function() {
-    if (this.props.onConfirm) {
-      this.props.onConfirm();
-    }
-  },
-  handleHidden: function() {
-    if (this.props.onHidden) {
-      this.props.onHidden();
-    }
-  }
-});
-
-var Example = React.createClass({
-  handleCancel: function() {
-    if (confirm('Are you sure you want to cancel?')) {
-      this.refs.modal.close();
-    }
-  },
-  render: function() {
-    var modal = null;
-    modal = (
-      <BootstrapModal
-        ref="modal"
-        confirm="OK"
-        cancel="Cancel"
-        onCancel={this.handleCancel}
-        onConfirm={this.closeModal}
-        onHidden={this.handleModalDidClose}
-        title="Hello, Bootstrap!">
-          This is a React component powered by jQuery and Bootstrap!
-      </BootstrapModal>
-    );
-    return (
-      <div className="example">
-        {modal}
-        <BootstrapButton onClick={this.openModal} className="btn-default">
-          Open modal
-        </BootstrapButton>
-      </div>
-    );
-  },
-  openModal: function() {
-    this.refs.modal.open();
-  },
-  closeModal: function() {
-    this.refs.modal.close();
-  },
-  handleModalDidClose: function() {
-    alert("The modal has been dismissed!");
-  }
-});
-
-ReactDOM.render(<Example />, document.getElementById('jqueryexample'));
diff --git a/examples/jquery-mobile/README.md b/examples/jquery-mobile/README.md
deleted file mode 100644
index dd9661a363a7..000000000000
--- a/examples/jquery-mobile/README.md
+++ /dev/null
@@ -1,6 +0,0 @@
-jQuery Mobile React Example
-===========================
-
-This example demonstrates how jQuery Mobile applications can be built with React.
-
-The source code is based on jQuery Mobile's [pages-multi-page example](https://github.com/jquery/jquery-mobile/tree/master/demos/pages-multi-page).
diff --git a/examples/jquery-mobile/index.html b/examples/jquery-mobile/index.html
deleted file mode 100644
index b244949b4991..000000000000
--- a/examples/jquery-mobile/index.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<!doctype html>
-<html lang="en">
-<head>
-  <meta charset="utf-8">
-  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
-  <meta name="viewport" content="width=device-width, initial-scale=1">
-  <title>jQuery Mobile React Example</title>
-  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery-mobile/1.4.5/jquery.mobile.min.css" />
-  <link rel="stylesheet" href="https://demos.jquerymobile.com/1.4.5/_assets/css/jqm-demos.css" />
-</head>
-<body class="ui-mobile-viewport ui-overlay-a">
-  <div id="content"></div>
-  <script src="http://code.jquery.com/jquery-2.2.2.min.js"></script>
-  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-mobile/1.4.5/jquery.mobile.min.js"></script>
-  <script src="../../build/react.js"></script>
-  <script src="../../build/react-dom.js"></script>
-  <script src="js/app.js"></script>
-</body>
-</html>
diff --git a/examples/jquery-mobile/js/app.js b/examples/jquery-mobile/js/app.js
deleted file mode 100644
index 1eb728bbd55f..000000000000
--- a/examples/jquery-mobile/js/app.js
+++ /dev/null
@@ -1,191 +0,0 @@
-/**
- * jQuery Mobile React Example
- *
- * Main application script.
- * For variety, this example is written in 100% JSHint-compliant JavaScript, not in JSX.
- *
- * Component structure:
- *
- * - App
- *   |-- JQueryMobilePage (one)
- *   |   |-- JQueryMobileHeader
- *   |   |-- JQueryMobileContent
- *   |   |   |-- PageOneContent
- *   |   |       |-- JQueryMobileButton
- *   |   |-- JQueryMobileFooter
- *   |-- JQueryMobilePage (two)
- *   |   |-- JQueryMobileHeader
- *   |   |-- JQueryMobileContent
- *   |   |   |-- PageTwoContent
- *   |   |       |-- JQueryMobileButton
- *   |   |-- JQueryMobileFooter
- *   |-- JQueryMobilePage (popup)
- *       |-- JQueryMobileHeader
- *       |-- JQueryMobileContent
- *       |   |-- PagePopUpContent
- *       |       |-- JQueryMobileButton
- *       |-- JQueryMobileFooter
- */
-
- /* global document, React */
-
-'use strict';
-
-/** Main application component. */
-var App = React.createClass({
-  displayName: 'App',
-
-  render: function() {
-    return React.DOM.div({className:'app'},
-      JQueryMobilePage({id:'one'}, PageOneContent(null)),
-      JQueryMobilePage({id:'two'}, PageTwoContent(null)),
-      JQueryMobilePage({id:'popup', headerTheme:'b'}, PagePopUpContent(null))
-    );
-  }
-});
-App = React.createFactory(App);
-
-/** jQuery Mobile button component. */
-var JQueryMobileButton = React.createClass({
-  displayName: 'JQueryMobileButton',
-
-  getDefaultProps: function() {
-    return {className:'ui-btn ui-shadow ui-corner-all'};
-  },
-
-  render: function() {
-    return React.DOM.p(null,
-      React.DOM.a(this.props, this.props.children)
-    );
-  }
-});
-JQueryMobileButton = React.createFactory(JQueryMobileButton);
-
-/** jQuery Mobile page content component. */
-var JQueryMobileContent = React.createClass({
-  displayName: 'JQueryMobileContent',
-
-  render: function() {
-    return React.DOM.div({role:'main', className:'ui-content'},
-      this.props.children
-    );
-  }
-});
-JQueryMobileContent = React.createFactory(JQueryMobileContent);
-
-/** jQuery Mobile footer component. */
-var JQueryMobileFooter = React.createClass({
-  displayName: 'JQueryMobileFooter',
-
-  render: function() {
-    return React.DOM.div({'data-role':'footer'},
-      React.DOM.h4(null, 'Page footer')
-    );
-  }
-});
-JQueryMobileFooter = React.createFactory(JQueryMobileFooter);
-
-/** jQuery Mobile header component. */
-var JQueryMobileHeader = React.createClass({
-  displayName: 'JQueryMobileHeader',
-
-  render: function() {
-    return React.DOM.div({'data-role':'header', 'data-theme':this.props.headerTheme},
-      React.DOM.h1(null, this.props.title)
-    );
-  }
-});
-JQueryMobileHeader = React.createFactory(JQueryMobileHeader);
-
-/** jQuery Mobile page component. */
-var JQueryMobilePage = React.createClass({
-  displayName: 'JQueryMobilePage',
-
-  getDefaultProps: function() {
-    return {'data-role':'page', 'data-theme':'a', headerTheme:'a'};
-  },
-
-  render: function() {
-    var props = {};
-    for (var key in this.props) {
-      props[key] = this.props[key];
-    }
-    return React.DOM.div(props,
-      JQueryMobileHeader({title:'Page ' + this.props.id, headerTheme:this.props.headerTheme}),
-      JQueryMobileContent(null, this.props.children),
-      JQueryMobileFooter(null)
-    );
-  }
-});
-JQueryMobilePage = React.createFactory(JQueryMobilePage);
-
-/** Application page one component. */
-var PageOneContent = React.createClass({
-  displayName: 'PageOneContent',
-
-  render: function() {
-    return React.DOM.div(null,
-      React.DOM.h2(null, 'One'),
-      React.DOM.p(null,
-        'I have an ',
-        React.DOM.code(null, 'id'),
-        ' of "one" on my page container. I\'m first in the source order so I\'m shown when the page loads.'
-      ),
-      React.DOM.p(null, 'This is a multi-page boilerplate template that you can copy to build your first jQuery Mobile page. This template contains multiple "page" containers inside, unlike a single page template that has just one page within it.'),
-      React.DOM.p(null, 'Just view the source and copy the code to get started. All the CSS and JS is linked to the jQuery CDN versions so this is super easy to set up. Remember to include a meta viewport tag in the head to set the zoom level.'),
-      React.DOM.p(null,
-        'You link to internal pages by referring to the ',
-        React.DOM.code(null, 'id'),
-        ' of the page you want to show. For example, to ',
-        React.DOM.a({href:'#two'}, 'link'),
-        ' to the page with an ',
-        React.DOM.code(null, 'id'),
-        ' of "two", my link would have a ',
-        React.DOM.code(null, 'href="#two"'),
-        ' in the code.'
-      ),
-      React.DOM.h3(null, 'Show internal pages:'),
-      JQueryMobileButton({href:'#two'}, 'Show page "two"'),
-      JQueryMobileButton({href:'#popup', 'data-rel':'dialog', 'data-transition':'pop'}, 'Show page "popup" (as a dialog)')
-    );
-  }
-});
-PageOneContent = React.createFactory(PageOneContent);
-
-/** Application page two component. */
-var PageTwoContent = React.createClass({
-  displayName: 'PageTwoContent',
-
-  render: function() {
-    return React.DOM.div(null,
-      React.DOM.h2(null, 'Two'),
-      React.DOM.p(null, 'I have an id of "two" on my page container. I\'m the second page container in this multi-page template.'),
-      React.DOM.p(null, 'Notice that the theme is different for this page because we\'ve added a few ',
-        React.DOM.code(null, 'data-theme'),
-        ' swatch assigments here to show off how flexible it is. You can add any content or widget to these pages, but we\'re keeping these simple.'),
-      JQueryMobileButton({href:'#one', 'data-direction':'reverse', className:'ui-btn ui-shadow ui-corner-all ui-btn-b'}, 'Back to page "one"')
-    );
-  }
-});
-PageTwoContent = React.createFactory(PageTwoContent);
-
-/** Application popup page component. */
-var PagePopUpContent = React.createClass({
-  displayName: 'PagePopUpContent',
-
-  render: function() {
-    return React.DOM.div(null,
-      React.DOM.h2(null, 'Popup'),
-      React.DOM.p(null, 'I have an id of "popup" on my page container and only look like a dialog because the link to me had a ',
-        React.DOM.code(null, 'data-rel="dialog"'),
-        ' attribute which gives me this inset look and a ',
-        React.DOM.code(null, 'data-transition="pop"'),
-        ' attribute to change the transition to pop. Without this, I\'d be styled as a normal page.'),
-      JQueryMobileButton({href:'#one', 'data-rel':'back', className:'ui-btn ui-shadow ui-corner-all ui-btn-inline ui-icon-back ui-btn-icon-left'}, 'Back to page "one"')
-    );
-  }
-});
-PagePopUpContent = React.createFactory(PagePopUpContent);
-
-// Render application.
-ReactDOM.render(App(null), document.getElementById('content'));
diff --git a/examples/quadratic/example.js b/examples/quadratic/example.js
deleted file mode 100644
index c86ba29aabc9..000000000000
--- a/examples/quadratic/example.js
+++ /dev/null
@@ -1,59 +0,0 @@
-var QuadraticCalculator = React.createClass({
-  getInitialState: function() {
-    return {
-      a: 1,
-      b: 3,
-      c: -4
-    };
-  },
-
-  /**
-   * This function will be re-bound in render multiple times. Each .bind() will
-   * create a new function that calls this with the appropriate key as well as
-   * the event. The key is the key in the state object that the value should be
-   * mapped from.
-   */
-  handleInputChange: function(key, event) {
-    var partialState = {};
-    partialState[key] = parseFloat(event.target.value);
-    this.setState(partialState);
-  },
-
-  render: function() {
-    var a = this.state.a;
-    var b = this.state.b;
-    var c = this.state.c;
-    var root = Math.sqrt(Math.pow(b, 2) - 4 * a * c);
-    var denominator = 2 * a;
-    var x1 = (-b + root) / denominator;
-    var x2 = (-b - root) / denominator;
-    return (
-      <div>
-        <strong>
-          <em>ax</em><sup>2</sup> + <em>bx</em> + <em>c</em> = 0
-        </strong>
-        <h4>Solve for <em>x</em>:</h4>
-        <p>
-          <label>
-            a: <input type="number" value={a} onChange={this.handleInputChange.bind(null, 'a')} />
-          </label>
-          <br />
-          <label>
-            b: <input type="number" value={b} onChange={this.handleInputChange.bind(null, 'b')} />
-          </label>
-          <br />
-          <label>
-            c: <input type="number" value={c} onChange={this.handleInputChange.bind(null, 'c')} />
-          </label>
-          <br />
-          x: <strong>{x1}, {x2}</strong>
-        </p>
-      </div>
-    );
-  }
-});
-
-ReactDOM.render(
-  <QuadraticCalculator />,
-  document.getElementById('container')
-);
diff --git a/examples/shared/css/base.css b/examples/shared/css/base.css
deleted file mode 100644
index bf382be3891c..000000000000
--- a/examples/shared/css/base.css
+++ /dev/null
@@ -1,62 +0,0 @@
-body {
-  background: #fff;
-  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
-  font-size: 15px;
-  line-height: 1.7;
-  margin: 0;
-  padding: 30px;
-}
-
-a {
-  color: #4183c4;
-  text-decoration: none;
-}
-
-a:hover {
-  text-decoration: underline;
-}
-
-code {
-  background-color: #f8f8f8;
-  border: 1px solid #ddd;
-  border-radius: 3px;
-  font-family: "Bitstream Vera Sans Mono", Consolas, Courier, monospace;
-  font-size: 12px;
-  margin: 0 2px;
-  padding: 0px 5px;
-}
-
-h1, h2, h3, h4 {
-  font-weight: bold;
-  margin: 0 0 15px;
-  padding: 0;
-}
-
-h1 {
-  border-bottom: 1px solid #ddd;
-  font-size: 2.5em;
-  font-weight: bold;
-  margin: 0 0 15px;
-  padding: 0;
-}
-
-h2 {
-  border-bottom: 1px solid #eee;
-  font-size: 2em;
-}
-
-h3 {
-  font-size: 1.5em;
-}
-
-h4 {
-  font-size: 1.2em;
-}
-
-p, ul {
-  margin: 15px 0;
-}
-
-ul {
-  padding-left: 30px;
-}
diff --git a/examples/transitions/transition.css b/examples/transitions/transition.css
deleted file mode 100644
index ee851d113608..000000000000
--- a/examples/transitions/transition.css
+++ /dev/null
@@ -1,44 +0,0 @@
-.example-enter,
-.example-leave {
-  -webkit-transition: all .25s;
-  transition: all .25s;
-}
-
-.example-enter,
-.example-leave.example-leave-active {
-  opacity: 0.01;
-}
-
-.example-leave.example-leave-active {
-  margin-left: -128px;
-}
-
-.example-enter {
-  margin-left: 128px;
-}
-
-.example-enter.example-enter-active,
-.example-leave {
-  margin-left: 0;
-  opacity: 1;
-}
-
-.animateExample {
-  display: block;
-  height: 128px;
-  position: relative;
-  width: 384px;
-}
-
-.animateItem {
-  color: white;
-  font-size: 36px;
-  font-weight: bold;
-  height: 128px;
-  line-height: 128px;
-  position: absolute;
-  text-align: center;
-  -webkit-transition: all .25s; /* TODO: make this a move animation */
-  transition: all .25s; /* TODO: make this a move animation */
-  width: 128px;
-}
diff --git a/examples/webcomponents/index.html b/examples/webcomponents/index.html
index 6342690dc55d..7eccc805bf87 100644
--- a/examples/webcomponents/index.html
+++ b/examples/webcomponents/index.html
@@ -37,7 +37,7 @@ <h4>Example Details</h4>
 
       // Define WebComponent
       var proto = Object.create(HTMLElement.prototype, {
-        createdCallback: {
+        attachedCallback: {
           value: function() {
             var mountPoint = document.createElement('span');
             this.createShadowRoot().appendChild(mountPoint);
diff --git a/fixtures/README.md b/fixtures/README.md
new file mode 100644
index 000000000000..0c9646ce4d11
--- /dev/null
+++ b/fixtures/README.md
@@ -0,0 +1,50 @@
+# Manual Testing Fixtures
+
+This folder exists for **React contributors** only.  
+If you use React you don't need to worry about it.
+
+These fixtures verify that the built React distributions are usable in different environments.  
+**They are not running automatically.** (At least not yet, feel free to contribute to automate them.)
+
+Run them when you make changes to how we package React, ReactDOM, and addons.
+
+## How to Run
+
+First, build React and the fixtures:
+
+```
+cd react
+npm run build
+
+cd fixtures
+node build-all.js
+```
+
+Then run a local server at the root of the repo, e.g.
+
+```
+npm i -g pushstate-server
+cd ..
+pushstate-server .
+```
+
+(Too complicated? Send a PR to simplify this :-).
+
+Then open the corresponding URLs, for example:
+
+```
+open http://localhost:9000/fixtures/globals.html
+open http://localhost:9000/fixtures/requirejs.html
+open http://localhost:9000/fixtures/systemjs.html
+open http://localhost:9000/fixtures/browserify/index.html
+open http://localhost:9000/fixtures/brunch/index.html
+open http://localhost:9000/fixtures/rjs/index.html
+open http://localhost:9000/fixtures/systemjs-builder/index.html
+open http://localhost:9000/fixtures/webpack/index.html
+open http://localhost:9000/fixtures/webpack-alias/index.html
+```
+
+You should see two things:
+
+* "Hello World" fading in with an animation.
+* No errors in the console.
diff --git a/fixtures/browserify/.gitignore b/fixtures/browserify/.gitignore
new file mode 100644
index 000000000000..66b00e6a05af
--- /dev/null
+++ b/fixtures/browserify/.gitignore
@@ -0,0 +1 @@
+output.js
diff --git a/fixtures/browserify/index.html b/fixtures/browserify/index.html
new file mode 100644
index 000000000000..d2b798e524e5
--- /dev/null
+++ b/fixtures/browserify/index.html
@@ -0,0 +1,16 @@
+<html>
+  <body>
+    <style>
+      .example-appear {
+        opacity: 0.01;
+      }
+
+      .example-appear.example-appear-active {
+        opacity: 1;
+        transition: opacity .5s ease-in;
+      }
+    </style>
+    <div id="container"></div>
+    <script src="output.js"></script>
+  </body>
+</html>
\ No newline at end of file
diff --git a/fixtures/browserify/input.js b/fixtures/browserify/input.js
new file mode 100644
index 000000000000..da6cc5d0ff1f
--- /dev/null
+++ b/fixtures/browserify/input.js
@@ -0,0 +1,16 @@
+var React = require('react');
+var CSSTransitionGroup = require('react-addons-css-transition-group');
+var ReactDOM = require('react-dom');
+
+ReactDOM.render(
+  React.createElement(CSSTransitionGroup, {
+    transitionName: 'example',
+    transitionAppear: true,
+    transitionAppearTimeout: 500,
+    transitionEnterTimeout: 0,
+    transitionLeaveTimeout: 0,
+  }, React.createElement('h1', null,
+    'Hello World!'
+  )),
+  document.getElementById('container')
+);
diff --git a/fixtures/browserify/package.json b/fixtures/browserify/package.json
new file mode 100644
index 000000000000..dbcf1dd834aa
--- /dev/null
+++ b/fixtures/browserify/package.json
@@ -0,0 +1,10 @@
+{
+  "name": "webpack-test",
+  "private": true,
+  "dependencies": {
+    "browserify": "^13.3.0"
+  },
+  "scripts": {
+    "build": "rm -f output.js && NODE_PATH=../../build/packages browserify ./input.js -o output.js"
+  }
+}
diff --git a/fixtures/brunch/.gitignore b/fixtures/brunch/.gitignore
new file mode 100644
index 000000000000..b8d1dfad58f8
--- /dev/null
+++ b/fixtures/brunch/.gitignore
@@ -0,0 +1,2 @@
+output.js
+output.js.map
\ No newline at end of file
diff --git a/fixtures/brunch/app/initialize.js b/fixtures/brunch/app/initialize.js
new file mode 100644
index 000000000000..da6cc5d0ff1f
--- /dev/null
+++ b/fixtures/brunch/app/initialize.js
@@ -0,0 +1,16 @@
+var React = require('react');
+var CSSTransitionGroup = require('react-addons-css-transition-group');
+var ReactDOM = require('react-dom');
+
+ReactDOM.render(
+  React.createElement(CSSTransitionGroup, {
+    transitionName: 'example',
+    transitionAppear: true,
+    transitionAppearTimeout: 500,
+    transitionEnterTimeout: 0,
+    transitionLeaveTimeout: 0,
+  }, React.createElement('h1', null,
+    'Hello World!'
+  )),
+  document.getElementById('container')
+);
diff --git a/fixtures/brunch/config.js b/fixtures/brunch/config.js
new file mode 100644
index 000000000000..ba12fc72c23d
--- /dev/null
+++ b/fixtures/brunch/config.js
@@ -0,0 +1,10 @@
+exports.config = {
+  paths: {
+    public: '.',
+  },
+  files: {
+    javascripts: {
+      joinTo: 'output.js',
+    },
+  },
+};
diff --git a/fixtures/brunch/index.html b/fixtures/brunch/index.html
new file mode 100644
index 000000000000..859d98d0f2be
--- /dev/null
+++ b/fixtures/brunch/index.html
@@ -0,0 +1,17 @@
+<html>
+  <body>
+    <style>
+      .example-appear {
+        opacity: 0.01;
+      }
+
+      .example-appear.example-appear-active {
+        opacity: 1;
+        transition: opacity .5s ease-in;
+      }
+    </style>
+    <div id="container"></div>
+    <script src="output.js"></script>
+    <script>require('initialize');</script>
+  </body>
+</html>
\ No newline at end of file
diff --git a/fixtures/brunch/input.js b/fixtures/brunch/input.js
new file mode 100644
index 000000000000..da6cc5d0ff1f
--- /dev/null
+++ b/fixtures/brunch/input.js
@@ -0,0 +1,16 @@
+var React = require('react');
+var CSSTransitionGroup = require('react-addons-css-transition-group');
+var ReactDOM = require('react-dom');
+
+ReactDOM.render(
+  React.createElement(CSSTransitionGroup, {
+    transitionName: 'example',
+    transitionAppear: true,
+    transitionAppearTimeout: 500,
+    transitionEnterTimeout: 0,
+    transitionLeaveTimeout: 0,
+  }, React.createElement('h1', null,
+    'Hello World!'
+  )),
+  document.getElementById('container')
+);
diff --git a/fixtures/brunch/package.json b/fixtures/brunch/package.json
new file mode 100644
index 000000000000..d00bcc0ef023
--- /dev/null
+++ b/fixtures/brunch/package.json
@@ -0,0 +1,10 @@
+{
+  "name": "brunch-test",
+  "devDependencies": {
+      "brunch": "^2.9.1",
+      "javascript-brunch": "^2.0.0"
+  },
+  "scripts": {
+    "build": "rm -rf public && ln -fs ../../../build/packages/react node_modules/react && ln -fs ../../../build/packages/react-dom node_modules/react-dom && ln -fs ../../../build/packages/react-addons-css-transition-group node_modules/react-addons-css-transition-group && brunch build"
+  }
+}
\ No newline at end of file
diff --git a/fixtures/build-all.js b/fixtures/build-all.js
new file mode 100644
index 000000000000..b5620c0fa32e
--- /dev/null
+++ b/fixtures/build-all.js
@@ -0,0 +1,30 @@
+var fs = require('fs');
+var path = require('path');
+var { spawnSync } = require('child_process');
+
+var fixtureDirs = fs.readdirSync(__dirname).filter((file) => {
+  return fs.statSync(path.join(__dirname, file)).isDirectory();
+});
+
+var cmdArgs = [
+  {cmd: 'npm', args: ['install']},
+  {cmd: 'npm', args: ['run', 'build']},
+];
+
+for (const dir of fixtureDirs) {
+  for (const cmdArg of cmdArgs) {
+    const opts = {
+      cwd: path.join(__dirname, dir),
+      stdio: 'inherit',
+    };
+    let result = spawnSync(cmdArg.cmd, cmdArg.args, opts);
+    if (result.status !== 0) {
+      throw new Error('Failed to build fixtures.');
+    }
+  }
+}
+
+console.log('-------------------------');
+console.log('All fixtures were built!');
+console.log('Now make sure to open each HTML file in this directory and each index.html in subdirectories.');
+console.log('-------------------------');
diff --git a/fixtures/dom/src/components/fixtures/number-inputs/NumberInputDecimal.js b/fixtures/dom/src/components/fixtures/number-inputs/NumberInputDecimal.js
new file mode 100644
index 000000000000..552deb04d7d4
--- /dev/null
+++ b/fixtures/dom/src/components/fixtures/number-inputs/NumberInputDecimal.js
@@ -0,0 +1,33 @@
+const React = window.React;
+
+import Fixture from '../../Fixture';
+
+class NumberInputDecimal extends React.Component {
+  state = { value: '.98' };
+  changeValue = () => {
+    this.setState({
+      value: '0.98',
+    });
+  }
+  render() {
+    const {value} = this.state;
+    return (
+      <Fixture>
+        <div>{this.props.children}</div>
+
+        <div className="control-box">
+          <input
+            type="number"
+            value={value}
+            onChange={(e) => {
+             this.setState({value: e.target.value}); 
+            }}
+          />
+          <button onClick={this.changeValue}>change.98 to 0.98</button>
+        </div>
+      </Fixture>
+    );
+  }
+}
+
+export default NumberInputDecimal;
diff --git a/fixtures/globals.html b/fixtures/globals.html
new file mode 100644
index 000000000000..4c3b99dbcaa8
--- /dev/null
+++ b/fixtures/globals.html
@@ -0,0 +1,31 @@
+<html>
+  <body>
+    <script src="../build/react-with-addons.js"></script>
+    <script src="../build/react-dom.js"></script>
+    <style>
+      .example-appear {
+        opacity: 0.01;
+      }
+      .example-appear.example-appear-active {
+        opacity: 1;
+        transition: opacity .5s ease-in;
+      }
+    </style>
+    <div id="container"></div>
+    <script>
+      var CSSTransitionGroup = React.addons.CSSTransitionGroup;
+      ReactDOM.render(
+        React.createElement(CSSTransitionGroup, {
+          transitionName: 'example',
+          transitionAppear: true,
+          transitionAppearTimeout: 500,
+          transitionEnterTimeout: 0,
+          transitionLeaveTimeout: 0,
+        }, React.createElement('h1', null,
+          'Hello World!'
+        )),
+        document.getElementById('container')
+      );
+    </script>
+  </body>
+</html>
diff --git a/fixtures/requirejs.html b/fixtures/requirejs.html
new file mode 100644
index 000000000000..ccba52815463
--- /dev/null
+++ b/fixtures/requirejs.html
@@ -0,0 +1,39 @@
+<html>
+  <body>
+    <script src="https://unpkg.com/requirejs@2.3.2/require.js"></script>
+    <style>
+      .example-appear {
+        opacity: 0.01;
+      }
+
+      .example-appear.example-appear-active {
+        opacity: 1;
+        transition: opacity .5s ease-in;
+      }
+    </style>
+    <div id="container"></div>
+    <script>
+      requirejs.config({
+        paths: {
+          react: '../build/react-with-addons',
+          'react-dom': '../build/react-dom'
+        }
+      });
+      require(['react', 'react-dom'], function(React, ReactDOM) {
+        var CSSTransitionGroup = React.addons.CSSTransitionGroup;
+        ReactDOM.render(
+          React.createElement(CSSTransitionGroup, {
+            transitionName: 'example',
+            transitionAppear: true,
+            transitionAppearTimeout: 500,
+            transitionEnterTimeout: 0,
+            transitionLeaveTimeout: 0,
+          }, React.createElement('h1', null,
+            'Hello World!'
+          )),
+          document.getElementById('container')
+        );
+      });
+    </script>
+  </body>
+</html>
diff --git a/fixtures/rjs/.gitignore b/fixtures/rjs/.gitignore
new file mode 100644
index 000000000000..fa213fe698b1
--- /dev/null
+++ b/fixtures/rjs/.gitignore
@@ -0,0 +1 @@
+output.js
\ No newline at end of file
diff --git a/fixtures/rjs/config.js b/fixtures/rjs/config.js
new file mode 100644
index 000000000000..f15dc1100355
--- /dev/null
+++ b/fixtures/rjs/config.js
@@ -0,0 +1,10 @@
+module.exports = {
+  baseUrl: '.',
+  name: 'input',
+  out: 'output.js',
+  optimize: 'none',
+  paths: {
+    react: '../../build/react-with-addons',
+    'react-dom': '../../build/react-dom',
+  },
+};
diff --git a/fixtures/rjs/index.html b/fixtures/rjs/index.html
new file mode 100644
index 000000000000..24995379a122
--- /dev/null
+++ b/fixtures/rjs/index.html
@@ -0,0 +1,17 @@
+<html>
+  <body>
+    <style>
+      .example-appear {
+        opacity: 0.01;
+      }
+
+      .example-appear.example-appear-active {
+        opacity: 1;
+        transition: opacity .5s ease-in;
+      }
+    </style>
+    <div id="container"></div>
+    <script src="https://unpkg.com/requirejs@2.3.2/require.js"></script>
+    <script src="output.js"></script>
+  </body>
+</html>
\ No newline at end of file
diff --git a/fixtures/rjs/input.js b/fixtures/rjs/input.js
new file mode 100644
index 000000000000..2b0deee96c2c
--- /dev/null
+++ b/fixtures/rjs/input.js
@@ -0,0 +1,15 @@
+require(['react', 'react-dom'], function(React, ReactDOM) {
+  var CSSTransitionGroup = React.addons.CSSTransitionGroup;
+  ReactDOM.render(
+    React.createElement(CSSTransitionGroup, {
+      transitionName: 'example',
+      transitionAppear: true,
+      transitionAppearTimeout: 500,
+      transitionEnterTimeout: 0,
+      transitionLeaveTimeout: 0,
+    }, React.createElement('h1', null,
+      'Hello World!'
+    )),
+    document.getElementById('container')
+  );
+});
diff --git a/fixtures/rjs/package.json b/fixtures/rjs/package.json
new file mode 100644
index 000000000000..bc94a37011ee
--- /dev/null
+++ b/fixtures/rjs/package.json
@@ -0,0 +1,10 @@
+{
+  "name": "rjs-test",
+  "private": true,
+  "dependencies": {
+    "requirejs": "^2.3.2"
+  },
+  "scripts": {
+    "build": "rm -f output.js && r.js -o config.js"
+  }
+}
diff --git a/fixtures/systemjs-builder/.gitignore b/fixtures/systemjs-builder/.gitignore
new file mode 100644
index 000000000000..fa213fe698b1
--- /dev/null
+++ b/fixtures/systemjs-builder/.gitignore
@@ -0,0 +1 @@
+output.js
\ No newline at end of file
diff --git a/fixtures/systemjs-builder/build.js b/fixtures/systemjs-builder/build.js
new file mode 100644
index 000000000000..d476c09a6462
--- /dev/null
+++ b/fixtures/systemjs-builder/build.js
@@ -0,0 +1,12 @@
+var Builder = require('systemjs-builder');
+
+var builder = new Builder('/', './config.js');
+builder
+  .buildStatic('./input.js', './output.js')
+  .then(function() {
+    console.log('Build complete');
+  })
+  .catch(function(err) {
+    console.log('Build error');
+    console.log(err);
+  });
diff --git a/fixtures/systemjs-builder/config.js b/fixtures/systemjs-builder/config.js
new file mode 100644
index 000000000000..baed2db8c624
--- /dev/null
+++ b/fixtures/systemjs-builder/config.js
@@ -0,0 +1,6 @@
+System.config({
+  paths: {
+    react: '../../build/react-with-addons.js',
+    'react-dom': '../../build/react-dom.js',
+  },
+});
diff --git a/fixtures/systemjs-builder/index.html b/fixtures/systemjs-builder/index.html
new file mode 100644
index 000000000000..d2b798e524e5
--- /dev/null
+++ b/fixtures/systemjs-builder/index.html
@@ -0,0 +1,16 @@
+<html>
+  <body>
+    <style>
+      .example-appear {
+        opacity: 0.01;
+      }
+
+      .example-appear.example-appear-active {
+        opacity: 1;
+        transition: opacity .5s ease-in;
+      }
+    </style>
+    <div id="container"></div>
+    <script src="output.js"></script>
+  </body>
+</html>
\ No newline at end of file
diff --git a/fixtures/systemjs-builder/input.js b/fixtures/systemjs-builder/input.js
new file mode 100644
index 000000000000..27d5c10086ca
--- /dev/null
+++ b/fixtures/systemjs-builder/input.js
@@ -0,0 +1,16 @@
+import React from 'react';
+import ReactDOM from 'react-dom';
+
+var CSSTransitionGroup = React.addons.CSSTransitionGroup;
+ReactDOM.render(
+  React.createElement(CSSTransitionGroup, {
+    transitionName: 'example',
+    transitionAppear: true,
+    transitionAppearTimeout: 500,
+    transitionEnterTimeout: 0,
+    transitionLeaveTimeout: 0,
+  }, React.createElement('h1', null,
+    'Hello World!'
+  )),
+  document.getElementById('container')
+);
diff --git a/fixtures/systemjs-builder/package.json b/fixtures/systemjs-builder/package.json
new file mode 100644
index 000000000000..b4c6acdccad5
--- /dev/null
+++ b/fixtures/systemjs-builder/package.json
@@ -0,0 +1,10 @@
+{
+  "name": "systemjs-builder-test",
+  "private": true,
+  "dependencies": {
+    "systemjs-builder": "^0.15.34"
+  },
+  "scripts": {
+    "build": "rm -f output.js && node build.js"
+  }
+}
diff --git a/fixtures/systemjs.html b/fixtures/systemjs.html
new file mode 100644
index 000000000000..9c4430791cb8
--- /dev/null
+++ b/fixtures/systemjs.html
@@ -0,0 +1,46 @@
+<html>
+  <body>
+    <script src="https://unpkg.com/systemjs@0.19.41/dist/system.js"></script>
+    <style>
+      .example-appear {
+        opacity: 0.01;
+      }
+
+      .example-appear.example-appear-active {
+        opacity: 1;
+        transition: opacity .5s ease-in;
+      }
+    </style>
+    <div id="container"></div>
+    <script>
+      System.config({
+        paths: {
+          react: '../build/react-with-addons.js',
+          'react-dom': '../build/react-dom.js'
+        }
+      });
+
+      Promise.all([
+        System.import("react"),
+        System.import("react-dom")
+      ]).then(function (deps) {
+        var React = deps[0];
+        var ReactDOM = deps[1];
+
+        var CSSTransitionGroup = React.addons.CSSTransitionGroup;
+        ReactDOM.render(
+          React.createElement(CSSTransitionGroup, {
+            transitionName: 'example',
+            transitionAppear: true,
+            transitionAppearTimeout: 500,
+            transitionEnterTimeout: 0,
+            transitionLeaveTimeout: 0,
+          }, React.createElement('h1', null,
+            'Hello World!'
+          )),
+          document.getElementById('container')
+        );
+      });
+    </script>
+  </body>
+</html>
\ No newline at end of file
diff --git a/fixtures/webpack-alias/.gitignore b/fixtures/webpack-alias/.gitignore
new file mode 100644
index 000000000000..fa213fe698b1
--- /dev/null
+++ b/fixtures/webpack-alias/.gitignore
@@ -0,0 +1 @@
+output.js
\ No newline at end of file
diff --git a/fixtures/webpack-alias/config.js b/fixtures/webpack-alias/config.js
new file mode 100644
index 000000000000..dcc0c3a90721
--- /dev/null
+++ b/fixtures/webpack-alias/config.js
@@ -0,0 +1,13 @@
+module.exports = {
+  entry: './input',
+  output: {
+    filename: 'output.js',
+  },
+  resolve: {
+    root: '../../build/packages',
+    alias: {
+      'react': 'react/dist/react-with-addons',
+      'react-dom': 'react-dom/dist/react-dom',
+    },
+  },
+};
diff --git a/fixtures/webpack-alias/index.html b/fixtures/webpack-alias/index.html
new file mode 100644
index 000000000000..d2b798e524e5
--- /dev/null
+++ b/fixtures/webpack-alias/index.html
@@ -0,0 +1,16 @@
+<html>
+  <body>
+    <style>
+      .example-appear {
+        opacity: 0.01;
+      }
+
+      .example-appear.example-appear-active {
+        opacity: 1;
+        transition: opacity .5s ease-in;
+      }
+    </style>
+    <div id="container"></div>
+    <script src="output.js"></script>
+  </body>
+</html>
\ No newline at end of file
diff --git a/fixtures/webpack-alias/input.js b/fixtures/webpack-alias/input.js
new file mode 100644
index 000000000000..f1e2d79e23c8
--- /dev/null
+++ b/fixtures/webpack-alias/input.js
@@ -0,0 +1,16 @@
+var React = require('react');
+var ReactDOM = require('react-dom');
+
+var CSSTransitionGroup = React.addons.CSSTransitionGroup;
+ReactDOM.render(
+  React.createElement(CSSTransitionGroup, {
+    transitionName: 'example',
+    transitionAppear: true,
+    transitionAppearTimeout: 500,
+    transitionEnterTimeout: 0,
+    transitionLeaveTimeout: 0,
+  }, React.createElement('h1', null,
+    'Hello World!'
+  )),
+  document.getElementById('container')
+);
diff --git a/fixtures/webpack-alias/package.json b/fixtures/webpack-alias/package.json
new file mode 100644
index 000000000000..8ea2da478bbe
--- /dev/null
+++ b/fixtures/webpack-alias/package.json
@@ -0,0 +1,10 @@
+{
+  "name": "webpack-test",
+  "private": true,
+  "dependencies": {
+    "webpack": "^1.14.0"
+  },
+  "scripts": {
+    "build": "rm -f output.js && webpack --config config.js"
+  }
+}
diff --git a/fixtures/webpack-alias/yarn.lock b/fixtures/webpack-alias/yarn.lock
new file mode 100644
index 000000000000..0301abbbaeb3
--- /dev/null
+++ b/fixtures/webpack-alias/yarn.lock
@@ -0,0 +1,1331 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+abbrev@1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f"
+
+acorn@^3.0.0:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a"
+
+ajv@^4.9.1:
+  version "4.11.5"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.5.tgz#b6ee74657b993a01dce44b7944d56f485828d5bd"
+  dependencies:
+    co "^4.6.0"
+    json-stable-stringify "^1.0.1"
+
+align-text@^0.1.1, align-text@^0.1.3:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
+  dependencies:
+    kind-of "^3.0.2"
+    longest "^1.0.1"
+    repeat-string "^1.5.2"
+
+amdefine@>=0.0.4:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
+
+ansi-regex@^2.0.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
+
+anymatch@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507"
+  dependencies:
+    arrify "^1.0.0"
+    micromatch "^2.1.5"
+
+aproba@^1.0.3:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.1.tgz#95d3600f07710aa0e9298c726ad5ecf2eacbabab"
+
+are-we-there-yet@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz#80e470e95a084794fe1899262c5667c6e88de1b3"
+  dependencies:
+    delegates "^1.0.0"
+    readable-stream "^2.0.0 || ^1.1.13"
+
+arr-diff@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf"
+  dependencies:
+    arr-flatten "^1.0.1"
+
+arr-flatten@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b"
+
+array-unique@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
+
+arrify@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
+
+asn1@~0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86"
+
+assert-plus@1.0.0, assert-plus@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
+
+assert-plus@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234"
+
+assert@^1.1.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91"
+  dependencies:
+    util "0.10.3"
+
+async-each@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
+
+async@^0.9.0:
+  version "0.9.2"
+  resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d"
+
+async@^1.3.0:
+  version "1.5.2"
+  resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
+
+async@~0.2.6:
+  version "0.2.10"
+  resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1"
+
+asynckit@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+
+aws-sign2@~0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f"
+
+aws4@^1.2.1:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e"
+
+balanced-match@^0.4.1:
+  version "0.4.2"
+  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
+
+base64-js@^1.0.2:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1"
+
+bcrypt-pbkdf@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d"
+  dependencies:
+    tweetnacl "^0.14.3"
+
+big.js@^3.1.3:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.1.3.tgz#4cada2193652eb3ca9ec8e55c9015669c9806978"
+
+binary-extensions@^1.0.0:
+  version "1.8.0"
+  resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.8.0.tgz#48ec8d16df4377eae5fa5884682480af4d95c774"
+
+block-stream@*:
+  version "0.0.9"
+  resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a"
+  dependencies:
+    inherits "~2.0.0"
+
+boom@2.x.x:
+  version "2.10.1"
+  resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f"
+  dependencies:
+    hoek "2.x.x"
+
+brace-expansion@^1.0.0:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9"
+  dependencies:
+    balanced-match "^0.4.1"
+    concat-map "0.0.1"
+
+braces@^1.8.2:
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7"
+  dependencies:
+    expand-range "^1.8.1"
+    preserve "^0.2.0"
+    repeat-element "^1.1.2"
+
+browserify-aes@0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-0.4.0.tgz#067149b668df31c4b58533e02d01e806d8608e2c"
+  dependencies:
+    inherits "^2.0.1"
+
+browserify-zlib@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d"
+  dependencies:
+    pako "~0.2.0"
+
+buffer-shims@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51"
+
+buffer@^4.9.0:
+  version "4.9.1"
+  resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298"
+  dependencies:
+    base64-js "^1.0.2"
+    ieee754 "^1.1.4"
+    isarray "^1.0.0"
+
+builtin-status-codes@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
+
+camelcase@^1.0.2:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39"
+
+caseless@~0.12.0:
+  version "0.12.0"
+  resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
+
+center-align@^0.1.1:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad"
+  dependencies:
+    align-text "^0.1.3"
+    lazy-cache "^1.0.3"
+
+chokidar@^1.0.0:
+  version "1.6.1"
+  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.6.1.tgz#2f4447ab5e96e50fb3d789fd90d4c72e0e4c70c2"
+  dependencies:
+    anymatch "^1.3.0"
+    async-each "^1.0.0"
+    glob-parent "^2.0.0"
+    inherits "^2.0.1"
+    is-binary-path "^1.0.0"
+    is-glob "^2.0.0"
+    path-is-absolute "^1.0.0"
+    readdirp "^2.0.0"
+  optionalDependencies:
+    fsevents "^1.0.0"
+
+cliui@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1"
+  dependencies:
+    center-align "^0.1.1"
+    right-align "^0.1.1"
+    wordwrap "0.0.2"
+
+clone@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149"
+
+co@^4.6.0:
+  version "4.6.0"
+  resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
+
+code-point-at@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
+
+combined-stream@^1.0.5, combined-stream@~1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009"
+  dependencies:
+    delayed-stream "~1.0.0"
+
+concat-map@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+
+console-browserify@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10"
+  dependencies:
+    date-now "^0.1.4"
+
+console-control-strings@^1.0.0, console-control-strings@~1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
+
+constants-browserify@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
+
+core-util-is@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
+
+cryptiles@2.x.x:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8"
+  dependencies:
+    boom "2.x.x"
+
+crypto-browserify@3.3.0:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.3.0.tgz#b9fc75bb4a0ed61dcf1cd5dae96eb30c9c3e506c"
+  dependencies:
+    browserify-aes "0.4.0"
+    pbkdf2-compat "2.0.1"
+    ripemd160 "0.2.0"
+    sha.js "2.2.6"
+
+dashdash@^1.12.0:
+  version "1.14.1"
+  resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
+  dependencies:
+    assert-plus "^1.0.0"
+
+date-now@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
+
+debug@^2.2.0:
+  version "2.6.3"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.3.tgz#0f7eb8c30965ec08c72accfa0130c8b79984141d"
+  dependencies:
+    ms "0.7.2"
+
+decamelize@^1.0.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
+
+deep-extend@~0.4.0:
+  version "0.4.1"
+  resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.1.tgz#efe4113d08085f4e6f9687759810f807469e2253"
+
+delayed-stream@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+
+delegates@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
+
+domain-browser@^1.1.1:
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc"
+
+ecc-jsbn@~0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505"
+  dependencies:
+    jsbn "~0.1.0"
+
+emojis-list@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
+
+enhanced-resolve@~0.9.0:
+  version "0.9.1"
+  resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz#4d6e689b3725f86090927ccc86cd9f1635b89e2e"
+  dependencies:
+    graceful-fs "^4.1.2"
+    memory-fs "^0.2.0"
+    tapable "^0.1.8"
+
+errno@^0.1.3:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d"
+  dependencies:
+    prr "~0.0.0"
+
+events@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924"
+
+expand-brackets@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
+  dependencies:
+    is-posix-bracket "^0.1.0"
+
+expand-range@^1.8.1:
+  version "1.8.2"
+  resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337"
+  dependencies:
+    fill-range "^2.1.0"
+
+extend@~3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4"
+
+extglob@^0.3.1:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1"
+  dependencies:
+    is-extglob "^1.0.0"
+
+extsprintf@1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550"
+
+filename-regex@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775"
+
+fill-range@^2.1.0:
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723"
+  dependencies:
+    is-number "^2.1.0"
+    isobject "^2.0.0"
+    randomatic "^1.1.3"
+    repeat-element "^1.1.2"
+    repeat-string "^1.5.2"
+
+for-in@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
+
+for-own@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce"
+  dependencies:
+    for-in "^1.0.1"
+
+forever-agent@~0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
+
+form-data@~2.1.1:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4"
+  dependencies:
+    asynckit "^0.4.0"
+    combined-stream "^1.0.5"
+    mime-types "^2.1.12"
+
+fs.realpath@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+
+fsevents@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.1.tgz#f19fd28f43eeaf761680e519a203c4d0b3d31aff"
+  dependencies:
+    nan "^2.3.0"
+    node-pre-gyp "^0.6.29"
+
+fstream-ignore@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105"
+  dependencies:
+    fstream "^1.0.0"
+    inherits "2"
+    minimatch "^3.0.0"
+
+fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2:
+  version "1.0.11"
+  resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171"
+  dependencies:
+    graceful-fs "^4.1.2"
+    inherits "~2.0.0"
+    mkdirp ">=0.5 0"
+    rimraf "2"
+
+gauge@~2.7.1:
+  version "2.7.3"
+  resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.3.tgz#1c23855f962f17b3ad3d0dc7443f304542edfe09"
+  dependencies:
+    aproba "^1.0.3"
+    console-control-strings "^1.0.0"
+    has-unicode "^2.0.0"
+    object-assign "^4.1.0"
+    signal-exit "^3.0.0"
+    string-width "^1.0.1"
+    strip-ansi "^3.0.1"
+    wide-align "^1.1.0"
+
+getpass@^0.1.1:
+  version "0.1.6"
+  resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6"
+  dependencies:
+    assert-plus "^1.0.0"
+
+glob-base@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
+  dependencies:
+    glob-parent "^2.0.0"
+    is-glob "^2.0.0"
+
+glob-parent@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28"
+  dependencies:
+    is-glob "^2.0.0"
+
+glob@^7.0.5:
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
+  dependencies:
+    fs.realpath "^1.0.0"
+    inflight "^1.0.4"
+    inherits "2"
+    minimatch "^3.0.2"
+    once "^1.3.0"
+    path-is-absolute "^1.0.0"
+
+graceful-fs@^4.1.2:
+  version "4.1.11"
+  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
+
+har-schema@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e"
+
+har-validator@~4.2.1:
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a"
+  dependencies:
+    ajv "^4.9.1"
+    har-schema "^1.0.5"
+
+has-flag@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
+
+has-unicode@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
+
+hawk@~3.1.3:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4"
+  dependencies:
+    boom "2.x.x"
+    cryptiles "2.x.x"
+    hoek "2.x.x"
+    sntp "1.x.x"
+
+hoek@2.x.x:
+  version "2.16.3"
+  resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed"
+
+http-signature@~1.1.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf"
+  dependencies:
+    assert-plus "^0.2.0"
+    jsprim "^1.2.2"
+    sshpk "^1.7.0"
+
+https-browserify@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82"
+
+ieee754@^1.1.4:
+  version "1.1.8"
+  resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4"
+
+indexof@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d"
+
+inflight@^1.0.4:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+  dependencies:
+    once "^1.3.0"
+    wrappy "1"
+
+inherits@2, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
+
+inherits@2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
+
+ini@~1.3.0:
+  version "1.3.4"
+  resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e"
+
+interpret@^0.6.4:
+  version "0.6.6"
+  resolved "https://registry.yarnpkg.com/interpret/-/interpret-0.6.6.tgz#fecd7a18e7ce5ca6abfb953e1f86213a49f1625b"
+
+is-binary-path@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
+  dependencies:
+    binary-extensions "^1.0.0"
+
+is-buffer@^1.0.2:
+  version "1.1.5"
+  resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc"
+
+is-dotfile@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d"
+
+is-equal-shallow@^0.1.3:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534"
+  dependencies:
+    is-primitive "^2.0.0"
+
+is-extendable@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
+
+is-extglob@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
+
+is-fullwidth-code-point@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
+  dependencies:
+    number-is-nan "^1.0.0"
+
+is-glob@^2.0.0, is-glob@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
+  dependencies:
+    is-extglob "^1.0.0"
+
+is-number@^2.0.2, is-number@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
+  dependencies:
+    kind-of "^3.0.2"
+
+is-posix-bracket@^0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
+
+is-primitive@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
+
+is-typedarray@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
+
+isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
+
+isobject@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
+  dependencies:
+    isarray "1.0.0"
+
+isstream@~0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
+
+jodid25519@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967"
+  dependencies:
+    jsbn "~0.1.0"
+
+jsbn@~0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
+
+json-schema@0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
+
+json-stable-stringify@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af"
+  dependencies:
+    jsonify "~0.0.0"
+
+json-stringify-safe@~5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
+
+json5@^0.5.0:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
+
+jsonify@~0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
+
+jsprim@^1.2.2:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.0.tgz#a3b87e40298d8c380552d8cc7628a0bb95a22918"
+  dependencies:
+    assert-plus "1.0.0"
+    extsprintf "1.0.2"
+    json-schema "0.2.3"
+    verror "1.3.6"
+
+kind-of@^3.0.2:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47"
+  dependencies:
+    is-buffer "^1.0.2"
+
+lazy-cache@^1.0.3:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
+
+loader-utils@^0.2.11:
+  version "0.2.17"
+  resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348"
+  dependencies:
+    big.js "^3.1.3"
+    emojis-list "^2.0.0"
+    json5 "^0.5.0"
+    object-assign "^4.0.1"
+
+longest@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
+
+memory-fs@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.2.0.tgz#f2bb25368bc121e391c2520de92969caee0a0290"
+
+memory-fs@~0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.3.0.tgz#7bcc6b629e3a43e871d7e29aca6ae8a7f15cbb20"
+  dependencies:
+    errno "^0.1.3"
+    readable-stream "^2.0.1"
+
+micromatch@^2.1.5:
+  version "2.3.11"
+  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
+  dependencies:
+    arr-diff "^2.0.0"
+    array-unique "^0.2.1"
+    braces "^1.8.2"
+    expand-brackets "^0.1.4"
+    extglob "^0.3.1"
+    filename-regex "^2.0.0"
+    is-extglob "^1.0.0"
+    is-glob "^2.0.1"
+    kind-of "^3.0.2"
+    normalize-path "^2.0.1"
+    object.omit "^2.0.0"
+    parse-glob "^3.0.4"
+    regex-cache "^0.4.2"
+
+mime-db@~1.27.0:
+  version "1.27.0"
+  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1"
+
+mime-types@^2.1.12, mime-types@~2.1.7:
+  version "2.1.15"
+  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed"
+  dependencies:
+    mime-db "~1.27.0"
+
+minimatch@^3.0.0, minimatch@^3.0.2:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774"
+  dependencies:
+    brace-expansion "^1.0.0"
+
+minimist@0.0.8, minimist@~0.0.1:
+  version "0.0.8"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
+
+minimist@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
+
+"mkdirp@>=0.5 0", mkdirp@^0.5.1, mkdirp@~0.5.0:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
+  dependencies:
+    minimist "0.0.8"
+
+ms@0.7.2:
+  version "0.7.2"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765"
+
+nan@^2.3.0:
+  version "2.6.1"
+  resolved "https://registry.yarnpkg.com/nan/-/nan-2.6.1.tgz#8c84f7b14c96b89f57fbc838012180ec8ca39a01"
+
+node-libs-browser@^0.7.0:
+  version "0.7.0"
+  resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-0.7.0.tgz#3e272c0819e308935e26674408d7af0e1491b83b"
+  dependencies:
+    assert "^1.1.1"
+    browserify-zlib "^0.1.4"
+    buffer "^4.9.0"
+    console-browserify "^1.1.0"
+    constants-browserify "^1.0.0"
+    crypto-browserify "3.3.0"
+    domain-browser "^1.1.1"
+    events "^1.0.0"
+    https-browserify "0.0.1"
+    os-browserify "^0.2.0"
+    path-browserify "0.0.0"
+    process "^0.11.0"
+    punycode "^1.2.4"
+    querystring-es3 "^0.2.0"
+    readable-stream "^2.0.5"
+    stream-browserify "^2.0.1"
+    stream-http "^2.3.1"
+    string_decoder "^0.10.25"
+    timers-browserify "^2.0.2"
+    tty-browserify "0.0.0"
+    url "^0.11.0"
+    util "^0.10.3"
+    vm-browserify "0.0.4"
+
+node-pre-gyp@^0.6.29:
+  version "0.6.34"
+  resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.34.tgz#94ad1c798a11d7fc67381b50d47f8cc18d9799f7"
+  dependencies:
+    mkdirp "^0.5.1"
+    nopt "^4.0.1"
+    npmlog "^4.0.2"
+    rc "^1.1.7"
+    request "^2.81.0"
+    rimraf "^2.6.1"
+    semver "^5.3.0"
+    tar "^2.2.1"
+    tar-pack "^3.4.0"
+
+nopt@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
+  dependencies:
+    abbrev "1"
+    osenv "^0.1.4"
+
+normalize-path@^2.0.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
+  dependencies:
+    remove-trailing-separator "^1.0.1"
+
+npmlog@^4.0.2:
+  version "4.0.2"
+  resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.0.2.tgz#d03950e0e78ce1527ba26d2a7592e9348ac3e75f"
+  dependencies:
+    are-we-there-yet "~1.1.2"
+    console-control-strings "~1.1.0"
+    gauge "~2.7.1"
+    set-blocking "~2.0.0"
+
+number-is-nan@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
+
+oauth-sign@~0.8.1:
+  version "0.8.2"
+  resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
+
+object-assign@^4.0.1, object-assign@^4.1.0:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+
+object.omit@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
+  dependencies:
+    for-own "^0.1.4"
+    is-extendable "^0.1.1"
+
+once@^1.3.0, once@^1.3.3:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+  dependencies:
+    wrappy "1"
+
+optimist@~0.6.0:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
+  dependencies:
+    minimist "~0.0.1"
+    wordwrap "~0.0.2"
+
+os-browserify@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.2.1.tgz#63fc4ccee5d2d7763d26bbf8601078e6c2e0044f"
+
+os-homedir@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
+
+os-tmpdir@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
+
+osenv@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644"
+  dependencies:
+    os-homedir "^1.0.0"
+    os-tmpdir "^1.0.0"
+
+pako@~0.2.0:
+  version "0.2.9"
+  resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
+
+parse-glob@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
+  dependencies:
+    glob-base "^0.3.0"
+    is-dotfile "^1.0.0"
+    is-extglob "^1.0.0"
+    is-glob "^2.0.0"
+
+path-browserify@0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a"
+
+path-is-absolute@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+
+pbkdf2-compat@2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/pbkdf2-compat/-/pbkdf2-compat-2.0.1.tgz#b6e0c8fa99494d94e0511575802a59a5c142f288"
+
+performance-now@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5"
+
+preserve@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
+
+process-nextick-args@~1.0.6:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
+
+process@^0.11.0:
+  version "0.11.9"
+  resolved "https://registry.yarnpkg.com/process/-/process-0.11.9.tgz#7bd5ad21aa6253e7da8682264f1e11d11c0318c1"
+
+prr@~0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a"
+
+punycode@1.3.2:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
+
+punycode@^1.2.4, punycode@^1.4.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
+
+qs@~6.4.0:
+  version "6.4.0"
+  resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
+
+querystring-es3@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
+
+querystring@0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
+
+randomatic@^1.1.3:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb"
+  dependencies:
+    is-number "^2.0.2"
+    kind-of "^3.0.2"
+
+rc@^1.1.7:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.1.tgz#2e03e8e42ee450b8cb3dce65be1bf8974e1dfd95"
+  dependencies:
+    deep-extend "~0.4.0"
+    ini "~1.3.0"
+    minimist "^1.2.0"
+    strip-json-comments "~2.0.1"
+
+"readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.1.4, readable-stream@^2.2.6:
+  version "2.2.6"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.6.tgz#8b43aed76e71483938d12a8d46c6cf1a00b1f816"
+  dependencies:
+    buffer-shims "^1.0.0"
+    core-util-is "~1.0.0"
+    inherits "~2.0.1"
+    isarray "~1.0.0"
+    process-nextick-args "~1.0.6"
+    string_decoder "~0.10.x"
+    util-deprecate "~1.0.1"
+
+readdirp@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78"
+  dependencies:
+    graceful-fs "^4.1.2"
+    minimatch "^3.0.2"
+    readable-stream "^2.0.2"
+    set-immediate-shim "^1.0.1"
+
+regex-cache@^0.4.2:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145"
+  dependencies:
+    is-equal-shallow "^0.1.3"
+    is-primitive "^2.0.0"
+
+remove-trailing-separator@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.0.1.tgz#615ebb96af559552d4bf4057c8436d486ab63cc4"
+
+repeat-element@^1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a"
+
+repeat-string@^1.5.2:
+  version "1.6.1"
+  resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
+
+request@^2.81.0:
+  version "2.81.0"
+  resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0"
+  dependencies:
+    aws-sign2 "~0.6.0"
+    aws4 "^1.2.1"
+    caseless "~0.12.0"
+    combined-stream "~1.0.5"
+    extend "~3.0.0"
+    forever-agent "~0.6.1"
+    form-data "~2.1.1"
+    har-validator "~4.2.1"
+    hawk "~3.1.3"
+    http-signature "~1.1.0"
+    is-typedarray "~1.0.0"
+    isstream "~0.1.2"
+    json-stringify-safe "~5.0.1"
+    mime-types "~2.1.7"
+    oauth-sign "~0.8.1"
+    performance-now "^0.2.0"
+    qs "~6.4.0"
+    safe-buffer "^5.0.1"
+    stringstream "~0.0.4"
+    tough-cookie "~2.3.0"
+    tunnel-agent "^0.6.0"
+    uuid "^3.0.0"
+
+right-align@^0.1.1:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef"
+  dependencies:
+    align-text "^0.1.1"
+
+rimraf@2, rimraf@^2.5.1, rimraf@^2.6.1:
+  version "2.6.1"
+  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d"
+  dependencies:
+    glob "^7.0.5"
+
+ripemd160@0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-0.2.0.tgz#2bf198bde167cacfa51c0a928e84b68bbe171fce"
+
+safe-buffer@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7"
+
+semver@^5.3.0:
+  version "5.3.0"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
+
+set-blocking@~2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
+
+set-immediate-shim@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61"
+
+setimmediate@^1.0.4:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
+
+sha.js@2.2.6:
+  version "2.2.6"
+  resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.2.6.tgz#17ddeddc5f722fb66501658895461977867315ba"
+
+signal-exit@^3.0.0:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
+
+sntp@1.x.x:
+  version "1.0.9"
+  resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198"
+  dependencies:
+    hoek "2.x.x"
+
+source-list-map@~0.1.7:
+  version "0.1.8"
+  resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-0.1.8.tgz#c550b2ab5427f6b3f21f5afead88c4f5587b2106"
+
+source-map@~0.4.1:
+  version "0.4.4"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b"
+  dependencies:
+    amdefine ">=0.0.4"
+
+source-map@~0.5.1:
+  version "0.5.6"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
+
+sshpk@^1.7.0:
+  version "1.11.0"
+  resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.11.0.tgz#2d8d5ebb4a6fab28ffba37fa62a90f4a3ea59d77"
+  dependencies:
+    asn1 "~0.2.3"
+    assert-plus "^1.0.0"
+    dashdash "^1.12.0"
+    getpass "^0.1.1"
+  optionalDependencies:
+    bcrypt-pbkdf "^1.0.0"
+    ecc-jsbn "~0.1.1"
+    jodid25519 "^1.0.0"
+    jsbn "~0.1.0"
+    tweetnacl "~0.14.0"
+
+stream-browserify@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db"
+  dependencies:
+    inherits "~2.0.1"
+    readable-stream "^2.0.2"
+
+stream-http@^2.3.1:
+  version "2.7.0"
+  resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.7.0.tgz#cec1f4e3b494bc4a81b451808970f8b20b4ed5f6"
+  dependencies:
+    builtin-status-codes "^3.0.0"
+    inherits "^2.0.1"
+    readable-stream "^2.2.6"
+    to-arraybuffer "^1.0.0"
+    xtend "^4.0.0"
+
+string-width@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
+  dependencies:
+    code-point-at "^1.0.0"
+    is-fullwidth-code-point "^1.0.0"
+    strip-ansi "^3.0.0"
+
+string_decoder@^0.10.25, string_decoder@~0.10.x:
+  version "0.10.31"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
+
+stringstream@~0.0.4:
+  version "0.0.5"
+  resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878"
+
+strip-ansi@^3.0.0, strip-ansi@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
+  dependencies:
+    ansi-regex "^2.0.0"
+
+strip-json-comments@~2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
+
+supports-color@^3.1.0:
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
+  dependencies:
+    has-flag "^1.0.0"
+
+tapable@^0.1.8, tapable@~0.1.8:
+  version "0.1.10"
+  resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.1.10.tgz#29c35707c2b70e50d07482b5d202e8ed446dafd4"
+
+tar-pack@^3.4.0:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.0.tgz#23be2d7f671a8339376cbdb0b8fe3fdebf317984"
+  dependencies:
+    debug "^2.2.0"
+    fstream "^1.0.10"
+    fstream-ignore "^1.0.5"
+    once "^1.3.3"
+    readable-stream "^2.1.4"
+    rimraf "^2.5.1"
+    tar "^2.2.1"
+    uid-number "^0.0.6"
+
+tar@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1"
+  dependencies:
+    block-stream "*"
+    fstream "^1.0.2"
+    inherits "2"
+
+timers-browserify@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.2.tgz#ab4883cf597dcd50af211349a00fbca56ac86b86"
+  dependencies:
+    setimmediate "^1.0.4"
+
+to-arraybuffer@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
+
+tough-cookie@~2.3.0:
+  version "2.3.2"
+  resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a"
+  dependencies:
+    punycode "^1.4.1"
+
+tty-browserify@0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
+
+tunnel-agent@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
+  dependencies:
+    safe-buffer "^5.0.1"
+
+tweetnacl@^0.14.3, tweetnacl@~0.14.0:
+  version "0.14.5"
+  resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
+
+uglify-js@~2.7.3:
+  version "2.7.5"
+  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.7.5.tgz#4612c0c7baaee2ba7c487de4904ae122079f2ca8"
+  dependencies:
+    async "~0.2.6"
+    source-map "~0.5.1"
+    uglify-to-browserify "~1.0.0"
+    yargs "~3.10.0"
+
+uglify-to-browserify@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7"
+
+uid-number@^0.0.6:
+  version "0.0.6"
+  resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81"
+
+url@^0.11.0:
+  version "0.11.0"
+  resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
+  dependencies:
+    punycode "1.3.2"
+    querystring "0.2.0"
+
+util-deprecate@~1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+
+util@0.10.3, util@^0.10.3:
+  version "0.10.3"
+  resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9"
+  dependencies:
+    inherits "2.0.1"
+
+uuid@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1"
+
+verror@1.3.6:
+  version "1.3.6"
+  resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c"
+  dependencies:
+    extsprintf "1.0.2"
+
+vm-browserify@0.0.4:
+  version "0.0.4"
+  resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73"
+  dependencies:
+    indexof "0.0.1"
+
+watchpack@^0.2.1:
+  version "0.2.9"
+  resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-0.2.9.tgz#62eaa4ab5e5ba35fdfc018275626e3c0f5e3fb0b"
+  dependencies:
+    async "^0.9.0"
+    chokidar "^1.0.0"
+    graceful-fs "^4.1.2"
+
+webpack-core@~0.6.9:
+  version "0.6.9"
+  resolved "https://registry.yarnpkg.com/webpack-core/-/webpack-core-0.6.9.tgz#fc571588c8558da77be9efb6debdc5a3b172bdc2"
+  dependencies:
+    source-list-map "~0.1.7"
+    source-map "~0.4.1"
+
+webpack@^1.14.0:
+  version "1.14.0"
+  resolved "https://registry.yarnpkg.com/webpack/-/webpack-1.14.0.tgz#54f1ffb92051a328a5b2057d6ae33c289462c823"
+  dependencies:
+    acorn "^3.0.0"
+    async "^1.3.0"
+    clone "^1.0.2"
+    enhanced-resolve "~0.9.0"
+    interpret "^0.6.4"
+    loader-utils "^0.2.11"
+    memory-fs "~0.3.0"
+    mkdirp "~0.5.0"
+    node-libs-browser "^0.7.0"
+    optimist "~0.6.0"
+    supports-color "^3.1.0"
+    tapable "~0.1.8"
+    uglify-js "~2.7.3"
+    watchpack "^0.2.1"
+    webpack-core "~0.6.9"
+
+wide-align@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad"
+  dependencies:
+    string-width "^1.0.1"
+
+window-size@0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
+
+wordwrap@0.0.2:
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
+
+wordwrap@~0.0.2:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
+
+wrappy@1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+
+xtend@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
+
+yargs@~3.10.0:
+  version "3.10.0"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"
+  dependencies:
+    camelcase "^1.0.2"
+    cliui "^2.1.0"
+    decamelize "^1.0.0"
+    window-size "0.1.0"
diff --git a/fixtures/webpack/.gitignore b/fixtures/webpack/.gitignore
new file mode 100644
index 000000000000..fa213fe698b1
--- /dev/null
+++ b/fixtures/webpack/.gitignore
@@ -0,0 +1 @@
+output.js
\ No newline at end of file
diff --git a/fixtures/webpack/config.js b/fixtures/webpack/config.js
new file mode 100644
index 000000000000..685cac24ee90
--- /dev/null
+++ b/fixtures/webpack/config.js
@@ -0,0 +1,9 @@
+module.exports = {
+  entry: './input',
+  output: {
+    filename: 'output.js',
+  },
+  resolve: {
+    root: '../../build/packages',
+  },
+};
diff --git a/fixtures/webpack/index.html b/fixtures/webpack/index.html
new file mode 100644
index 000000000000..d2b798e524e5
--- /dev/null
+++ b/fixtures/webpack/index.html
@@ -0,0 +1,16 @@
+<html>
+  <body>
+    <style>
+      .example-appear {
+        opacity: 0.01;
+      }
+
+      .example-appear.example-appear-active {
+        opacity: 1;
+        transition: opacity .5s ease-in;
+      }
+    </style>
+    <div id="container"></div>
+    <script src="output.js"></script>
+  </body>
+</html>
\ No newline at end of file
diff --git a/fixtures/webpack/input.js b/fixtures/webpack/input.js
new file mode 100644
index 000000000000..da6cc5d0ff1f
--- /dev/null
+++ b/fixtures/webpack/input.js
@@ -0,0 +1,16 @@
+var React = require('react');
+var CSSTransitionGroup = require('react-addons-css-transition-group');
+var ReactDOM = require('react-dom');
+
+ReactDOM.render(
+  React.createElement(CSSTransitionGroup, {
+    transitionName: 'example',
+    transitionAppear: true,
+    transitionAppearTimeout: 500,
+    transitionEnterTimeout: 0,
+    transitionLeaveTimeout: 0,
+  }, React.createElement('h1', null,
+    'Hello World!'
+  )),
+  document.getElementById('container')
+);
diff --git a/fixtures/webpack/package.json b/fixtures/webpack/package.json
new file mode 100644
index 000000000000..8ea2da478bbe
--- /dev/null
+++ b/fixtures/webpack/package.json
@@ -0,0 +1,10 @@
+{
+  "name": "webpack-test",
+  "private": true,
+  "dependencies": {
+    "webpack": "^1.14.0"
+  },
+  "scripts": {
+    "build": "rm -f output.js && webpack --config config.js"
+  }
+}
diff --git a/fixtures/webpack/yarn.lock b/fixtures/webpack/yarn.lock
new file mode 100644
index 000000000000..a0cb4c1eae5a
--- /dev/null
+++ b/fixtures/webpack/yarn.lock
@@ -0,0 +1,1331 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+abbrev@1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f"
+
+acorn@^3.0.0:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a"
+
+ajv@^4.9.1:
+  version "4.11.5"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.5.tgz#b6ee74657b993a01dce44b7944d56f485828d5bd"
+  dependencies:
+    co "^4.6.0"
+    json-stable-stringify "^1.0.1"
+
+align-text@^0.1.1, align-text@^0.1.3:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
+  dependencies:
+    kind-of "^3.0.2"
+    longest "^1.0.1"
+    repeat-string "^1.5.2"
+
+amdefine@>=0.0.4:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
+
+ansi-regex@^2.0.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
+
+anymatch@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507"
+  dependencies:
+    arrify "^1.0.0"
+    micromatch "^2.1.5"
+
+aproba@^1.0.3:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.1.tgz#95d3600f07710aa0e9298c726ad5ecf2eacbabab"
+
+are-we-there-yet@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz#80e470e95a084794fe1899262c5667c6e88de1b3"
+  dependencies:
+    delegates "^1.0.0"
+    readable-stream "^2.0.0 || ^1.1.13"
+
+arr-diff@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf"
+  dependencies:
+    arr-flatten "^1.0.1"
+
+arr-flatten@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b"
+
+array-unique@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
+
+arrify@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
+
+asn1@~0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86"
+
+assert-plus@1.0.0, assert-plus@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
+
+assert-plus@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234"
+
+assert@^1.1.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91"
+  dependencies:
+    util "0.10.3"
+
+async-each@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
+
+async@^0.9.0:
+  version "0.9.2"
+  resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d"
+
+async@^1.3.0:
+  version "1.5.2"
+  resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
+
+async@~0.2.6:
+  version "0.2.10"
+  resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1"
+
+asynckit@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+
+aws-sign2@~0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f"
+
+aws4@^1.2.1:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e"
+
+balanced-match@^0.4.1:
+  version "0.4.2"
+  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
+
+base64-js@^1.0.2:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1"
+
+bcrypt-pbkdf@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d"
+  dependencies:
+    tweetnacl "^0.14.3"
+
+big.js@^3.1.3:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.1.3.tgz#4cada2193652eb3ca9ec8e55c9015669c9806978"
+
+binary-extensions@^1.0.0:
+  version "1.8.0"
+  resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.8.0.tgz#48ec8d16df4377eae5fa5884682480af4d95c774"
+
+block-stream@*:
+  version "0.0.9"
+  resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a"
+  dependencies:
+    inherits "~2.0.0"
+
+boom@2.x.x:
+  version "2.10.1"
+  resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f"
+  dependencies:
+    hoek "2.x.x"
+
+brace-expansion@^1.0.0:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9"
+  dependencies:
+    balanced-match "^0.4.1"
+    concat-map "0.0.1"
+
+braces@^1.8.2:
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7"
+  dependencies:
+    expand-range "^1.8.1"
+    preserve "^0.2.0"
+    repeat-element "^1.1.2"
+
+browserify-aes@0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-0.4.0.tgz#067149b668df31c4b58533e02d01e806d8608e2c"
+  dependencies:
+    inherits "^2.0.1"
+
+browserify-zlib@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d"
+  dependencies:
+    pako "~0.2.0"
+
+buffer-shims@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51"
+
+buffer@^4.9.0:
+  version "4.9.1"
+  resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298"
+  dependencies:
+    base64-js "^1.0.2"
+    ieee754 "^1.1.4"
+    isarray "^1.0.0"
+
+builtin-status-codes@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
+
+camelcase@^1.0.2:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39"
+
+caseless@~0.12.0:
+  version "0.12.0"
+  resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
+
+center-align@^0.1.1:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad"
+  dependencies:
+    align-text "^0.1.3"
+    lazy-cache "^1.0.3"
+
+chokidar@^1.0.0:
+  version "1.6.1"
+  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.6.1.tgz#2f4447ab5e96e50fb3d789fd90d4c72e0e4c70c2"
+  dependencies:
+    anymatch "^1.3.0"
+    async-each "^1.0.0"
+    glob-parent "^2.0.0"
+    inherits "^2.0.1"
+    is-binary-path "^1.0.0"
+    is-glob "^2.0.0"
+    path-is-absolute "^1.0.0"
+    readdirp "^2.0.0"
+  optionalDependencies:
+    fsevents "^1.0.0"
+
+cliui@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1"
+  dependencies:
+    center-align "^0.1.1"
+    right-align "^0.1.1"
+    wordwrap "0.0.2"
+
+clone@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149"
+
+co@^4.6.0:
+  version "4.6.0"
+  resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
+
+code-point-at@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
+
+combined-stream@^1.0.5, combined-stream@~1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009"
+  dependencies:
+    delayed-stream "~1.0.0"
+
+concat-map@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+
+console-browserify@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10"
+  dependencies:
+    date-now "^0.1.4"
+
+console-control-strings@^1.0.0, console-control-strings@~1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
+
+constants-browserify@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
+
+core-util-is@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
+
+cryptiles@2.x.x:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8"
+  dependencies:
+    boom "2.x.x"
+
+crypto-browserify@3.3.0:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.3.0.tgz#b9fc75bb4a0ed61dcf1cd5dae96eb30c9c3e506c"
+  dependencies:
+    browserify-aes "0.4.0"
+    pbkdf2-compat "2.0.1"
+    ripemd160 "0.2.0"
+    sha.js "2.2.6"
+
+dashdash@^1.12.0:
+  version "1.14.1"
+  resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
+  dependencies:
+    assert-plus "^1.0.0"
+
+date-now@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
+
+debug@^2.2.0:
+  version "2.6.3"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.3.tgz#0f7eb8c30965ec08c72accfa0130c8b79984141d"
+  dependencies:
+    ms "0.7.2"
+
+decamelize@^1.0.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
+
+deep-extend@~0.4.0:
+  version "0.4.1"
+  resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.1.tgz#efe4113d08085f4e6f9687759810f807469e2253"
+
+delayed-stream@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+
+delegates@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
+
+domain-browser@^1.1.1:
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc"
+
+ecc-jsbn@~0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505"
+  dependencies:
+    jsbn "~0.1.0"
+
+emojis-list@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
+
+enhanced-resolve@~0.9.0:
+  version "0.9.1"
+  resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz#4d6e689b3725f86090927ccc86cd9f1635b89e2e"
+  dependencies:
+    graceful-fs "^4.1.2"
+    memory-fs "^0.2.0"
+    tapable "^0.1.8"
+
+errno@^0.1.3:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d"
+  dependencies:
+    prr "~0.0.0"
+
+events@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924"
+
+expand-brackets@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
+  dependencies:
+    is-posix-bracket "^0.1.0"
+
+expand-range@^1.8.1:
+  version "1.8.2"
+  resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337"
+  dependencies:
+    fill-range "^2.1.0"
+
+extend@~3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4"
+
+extglob@^0.3.1:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1"
+  dependencies:
+    is-extglob "^1.0.0"
+
+extsprintf@1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550"
+
+filename-regex@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775"
+
+fill-range@^2.1.0:
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723"
+  dependencies:
+    is-number "^2.1.0"
+    isobject "^2.0.0"
+    randomatic "^1.1.3"
+    repeat-element "^1.1.2"
+    repeat-string "^1.5.2"
+
+for-in@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
+
+for-own@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce"
+  dependencies:
+    for-in "^1.0.1"
+
+forever-agent@~0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
+
+form-data@~2.1.1:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4"
+  dependencies:
+    asynckit "^0.4.0"
+    combined-stream "^1.0.5"
+    mime-types "^2.1.12"
+
+fs.realpath@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+
+fsevents@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.1.tgz#f19fd28f43eeaf761680e519a203c4d0b3d31aff"
+  dependencies:
+    nan "^2.3.0"
+    node-pre-gyp "^0.6.29"
+
+fstream-ignore@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105"
+  dependencies:
+    fstream "^1.0.0"
+    inherits "2"
+    minimatch "^3.0.0"
+
+fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2:
+  version "1.0.11"
+  resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171"
+  dependencies:
+    graceful-fs "^4.1.2"
+    inherits "~2.0.0"
+    mkdirp ">=0.5 0"
+    rimraf "2"
+
+gauge@~2.7.1:
+  version "2.7.3"
+  resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.3.tgz#1c23855f962f17b3ad3d0dc7443f304542edfe09"
+  dependencies:
+    aproba "^1.0.3"
+    console-control-strings "^1.0.0"
+    has-unicode "^2.0.0"
+    object-assign "^4.1.0"
+    signal-exit "^3.0.0"
+    string-width "^1.0.1"
+    strip-ansi "^3.0.1"
+    wide-align "^1.1.0"
+
+getpass@^0.1.1:
+  version "0.1.6"
+  resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6"
+  dependencies:
+    assert-plus "^1.0.0"
+
+glob-base@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
+  dependencies:
+    glob-parent "^2.0.0"
+    is-glob "^2.0.0"
+
+glob-parent@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28"
+  dependencies:
+    is-glob "^2.0.0"
+
+glob@^7.0.5:
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
+  dependencies:
+    fs.realpath "^1.0.0"
+    inflight "^1.0.4"
+    inherits "2"
+    minimatch "^3.0.2"
+    once "^1.3.0"
+    path-is-absolute "^1.0.0"
+
+graceful-fs@^4.1.2:
+  version "4.1.11"
+  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
+
+har-schema@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e"
+
+har-validator@~4.2.1:
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a"
+  dependencies:
+    ajv "^4.9.1"
+    har-schema "^1.0.5"
+
+has-flag@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
+
+has-unicode@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
+
+hawk@~3.1.3:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4"
+  dependencies:
+    boom "2.x.x"
+    cryptiles "2.x.x"
+    hoek "2.x.x"
+    sntp "1.x.x"
+
+hoek@2.x.x:
+  version "2.16.3"
+  resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed"
+
+http-signature@~1.1.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf"
+  dependencies:
+    assert-plus "^0.2.0"
+    jsprim "^1.2.2"
+    sshpk "^1.7.0"
+
+https-browserify@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82"
+
+ieee754@^1.1.4:
+  version "1.1.8"
+  resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4"
+
+indexof@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d"
+
+inflight@^1.0.4:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+  dependencies:
+    once "^1.3.0"
+    wrappy "1"
+
+inherits@2, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
+
+inherits@2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
+
+ini@~1.3.0:
+  version "1.3.4"
+  resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e"
+
+interpret@^0.6.4:
+  version "0.6.6"
+  resolved "https://registry.yarnpkg.com/interpret/-/interpret-0.6.6.tgz#fecd7a18e7ce5ca6abfb953e1f86213a49f1625b"
+
+is-binary-path@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
+  dependencies:
+    binary-extensions "^1.0.0"
+
+is-buffer@^1.0.2:
+  version "1.1.5"
+  resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc"
+
+is-dotfile@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d"
+
+is-equal-shallow@^0.1.3:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534"
+  dependencies:
+    is-primitive "^2.0.0"
+
+is-extendable@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
+
+is-extglob@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
+
+is-fullwidth-code-point@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
+  dependencies:
+    number-is-nan "^1.0.0"
+
+is-glob@^2.0.0, is-glob@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
+  dependencies:
+    is-extglob "^1.0.0"
+
+is-number@^2.0.2, is-number@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
+  dependencies:
+    kind-of "^3.0.2"
+
+is-posix-bracket@^0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
+
+is-primitive@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
+
+is-typedarray@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
+
+isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
+
+isobject@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
+  dependencies:
+    isarray "1.0.0"
+
+isstream@~0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
+
+jodid25519@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967"
+  dependencies:
+    jsbn "~0.1.0"
+
+jsbn@~0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
+
+json-schema@0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
+
+json-stable-stringify@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af"
+  dependencies:
+    jsonify "~0.0.0"
+
+json-stringify-safe@~5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
+
+json5@^0.5.0:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
+
+jsonify@~0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
+
+jsprim@^1.2.2:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.0.tgz#a3b87e40298d8c380552d8cc7628a0bb95a22918"
+  dependencies:
+    assert-plus "1.0.0"
+    extsprintf "1.0.2"
+    json-schema "0.2.3"
+    verror "1.3.6"
+
+kind-of@^3.0.2:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47"
+  dependencies:
+    is-buffer "^1.0.2"
+
+lazy-cache@^1.0.3:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
+
+loader-utils@^0.2.11:
+  version "0.2.17"
+  resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348"
+  dependencies:
+    big.js "^3.1.3"
+    emojis-list "^2.0.0"
+    json5 "^0.5.0"
+    object-assign "^4.0.1"
+
+longest@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
+
+memory-fs@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.2.0.tgz#f2bb25368bc121e391c2520de92969caee0a0290"
+
+memory-fs@~0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.3.0.tgz#7bcc6b629e3a43e871d7e29aca6ae8a7f15cbb20"
+  dependencies:
+    errno "^0.1.3"
+    readable-stream "^2.0.1"
+
+micromatch@^2.1.5:
+  version "2.3.11"
+  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
+  dependencies:
+    arr-diff "^2.0.0"
+    array-unique "^0.2.1"
+    braces "^1.8.2"
+    expand-brackets "^0.1.4"
+    extglob "^0.3.1"
+    filename-regex "^2.0.0"
+    is-extglob "^1.0.0"
+    is-glob "^2.0.1"
+    kind-of "^3.0.2"
+    normalize-path "^2.0.1"
+    object.omit "^2.0.0"
+    parse-glob "^3.0.4"
+    regex-cache "^0.4.2"
+
+mime-db@~1.27.0:
+  version "1.27.0"
+  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1"
+
+mime-types@^2.1.12, mime-types@~2.1.7:
+  version "2.1.15"
+  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed"
+  dependencies:
+    mime-db "~1.27.0"
+
+minimatch@^3.0.0, minimatch@^3.0.2:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774"
+  dependencies:
+    brace-expansion "^1.0.0"
+
+minimist@0.0.8, minimist@~0.0.1:
+  version "0.0.8"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
+
+minimist@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
+
+"mkdirp@>=0.5 0", mkdirp@^0.5.1, mkdirp@~0.5.0:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
+  dependencies:
+    minimist "0.0.8"
+
+ms@0.7.2:
+  version "0.7.2"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765"
+
+nan@^2.3.0:
+  version "2.5.1"
+  resolved "https://registry.yarnpkg.com/nan/-/nan-2.5.1.tgz#d5b01691253326a97a2bbee9e61c55d8d60351e2"
+
+node-libs-browser@^0.7.0:
+  version "0.7.0"
+  resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-0.7.0.tgz#3e272c0819e308935e26674408d7af0e1491b83b"
+  dependencies:
+    assert "^1.1.1"
+    browserify-zlib "^0.1.4"
+    buffer "^4.9.0"
+    console-browserify "^1.1.0"
+    constants-browserify "^1.0.0"
+    crypto-browserify "3.3.0"
+    domain-browser "^1.1.1"
+    events "^1.0.0"
+    https-browserify "0.0.1"
+    os-browserify "^0.2.0"
+    path-browserify "0.0.0"
+    process "^0.11.0"
+    punycode "^1.2.4"
+    querystring-es3 "^0.2.0"
+    readable-stream "^2.0.5"
+    stream-browserify "^2.0.1"
+    stream-http "^2.3.1"
+    string_decoder "^0.10.25"
+    timers-browserify "^2.0.2"
+    tty-browserify "0.0.0"
+    url "^0.11.0"
+    util "^0.10.3"
+    vm-browserify "0.0.4"
+
+node-pre-gyp@^0.6.29:
+  version "0.6.34"
+  resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.34.tgz#94ad1c798a11d7fc67381b50d47f8cc18d9799f7"
+  dependencies:
+    mkdirp "^0.5.1"
+    nopt "^4.0.1"
+    npmlog "^4.0.2"
+    rc "^1.1.7"
+    request "^2.81.0"
+    rimraf "^2.6.1"
+    semver "^5.3.0"
+    tar "^2.2.1"
+    tar-pack "^3.4.0"
+
+nopt@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
+  dependencies:
+    abbrev "1"
+    osenv "^0.1.4"
+
+normalize-path@^2.0.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
+  dependencies:
+    remove-trailing-separator "^1.0.1"
+
+npmlog@^4.0.2:
+  version "4.0.2"
+  resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.0.2.tgz#d03950e0e78ce1527ba26d2a7592e9348ac3e75f"
+  dependencies:
+    are-we-there-yet "~1.1.2"
+    console-control-strings "~1.1.0"
+    gauge "~2.7.1"
+    set-blocking "~2.0.0"
+
+number-is-nan@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
+
+oauth-sign@~0.8.1:
+  version "0.8.2"
+  resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
+
+object-assign@^4.0.1, object-assign@^4.1.0:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+
+object.omit@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
+  dependencies:
+    for-own "^0.1.4"
+    is-extendable "^0.1.1"
+
+once@^1.3.0, once@^1.3.3:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+  dependencies:
+    wrappy "1"
+
+optimist@~0.6.0:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
+  dependencies:
+    minimist "~0.0.1"
+    wordwrap "~0.0.2"
+
+os-browserify@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.2.1.tgz#63fc4ccee5d2d7763d26bbf8601078e6c2e0044f"
+
+os-homedir@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
+
+os-tmpdir@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
+
+osenv@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644"
+  dependencies:
+    os-homedir "^1.0.0"
+    os-tmpdir "^1.0.0"
+
+pako@~0.2.0:
+  version "0.2.9"
+  resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
+
+parse-glob@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
+  dependencies:
+    glob-base "^0.3.0"
+    is-dotfile "^1.0.0"
+    is-extglob "^1.0.0"
+    is-glob "^2.0.0"
+
+path-browserify@0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a"
+
+path-is-absolute@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+
+pbkdf2-compat@2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/pbkdf2-compat/-/pbkdf2-compat-2.0.1.tgz#b6e0c8fa99494d94e0511575802a59a5c142f288"
+
+performance-now@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5"
+
+preserve@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
+
+process-nextick-args@~1.0.6:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
+
+process@^0.11.0:
+  version "0.11.9"
+  resolved "https://registry.yarnpkg.com/process/-/process-0.11.9.tgz#7bd5ad21aa6253e7da8682264f1e11d11c0318c1"
+
+prr@~0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a"
+
+punycode@1.3.2:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
+
+punycode@^1.2.4, punycode@^1.4.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
+
+qs@~6.4.0:
+  version "6.4.0"
+  resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
+
+querystring-es3@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
+
+querystring@0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
+
+randomatic@^1.1.3:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb"
+  dependencies:
+    is-number "^2.0.2"
+    kind-of "^3.0.2"
+
+rc@^1.1.7:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.1.tgz#2e03e8e42ee450b8cb3dce65be1bf8974e1dfd95"
+  dependencies:
+    deep-extend "~0.4.0"
+    ini "~1.3.0"
+    minimist "^1.2.0"
+    strip-json-comments "~2.0.1"
+
+"readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.1.4, readable-stream@^2.2.6:
+  version "2.2.6"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.6.tgz#8b43aed76e71483938d12a8d46c6cf1a00b1f816"
+  dependencies:
+    buffer-shims "^1.0.0"
+    core-util-is "~1.0.0"
+    inherits "~2.0.1"
+    isarray "~1.0.0"
+    process-nextick-args "~1.0.6"
+    string_decoder "~0.10.x"
+    util-deprecate "~1.0.1"
+
+readdirp@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78"
+  dependencies:
+    graceful-fs "^4.1.2"
+    minimatch "^3.0.2"
+    readable-stream "^2.0.2"
+    set-immediate-shim "^1.0.1"
+
+regex-cache@^0.4.2:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145"
+  dependencies:
+    is-equal-shallow "^0.1.3"
+    is-primitive "^2.0.0"
+
+remove-trailing-separator@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.0.1.tgz#615ebb96af559552d4bf4057c8436d486ab63cc4"
+
+repeat-element@^1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a"
+
+repeat-string@^1.5.2:
+  version "1.6.1"
+  resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
+
+request@^2.81.0:
+  version "2.81.0"
+  resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0"
+  dependencies:
+    aws-sign2 "~0.6.0"
+    aws4 "^1.2.1"
+    caseless "~0.12.0"
+    combined-stream "~1.0.5"
+    extend "~3.0.0"
+    forever-agent "~0.6.1"
+    form-data "~2.1.1"
+    har-validator "~4.2.1"
+    hawk "~3.1.3"
+    http-signature "~1.1.0"
+    is-typedarray "~1.0.0"
+    isstream "~0.1.2"
+    json-stringify-safe "~5.0.1"
+    mime-types "~2.1.7"
+    oauth-sign "~0.8.1"
+    performance-now "^0.2.0"
+    qs "~6.4.0"
+    safe-buffer "^5.0.1"
+    stringstream "~0.0.4"
+    tough-cookie "~2.3.0"
+    tunnel-agent "^0.6.0"
+    uuid "^3.0.0"
+
+right-align@^0.1.1:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef"
+  dependencies:
+    align-text "^0.1.1"
+
+rimraf@2, rimraf@^2.5.1, rimraf@^2.6.1:
+  version "2.6.1"
+  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d"
+  dependencies:
+    glob "^7.0.5"
+
+ripemd160@0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-0.2.0.tgz#2bf198bde167cacfa51c0a928e84b68bbe171fce"
+
+safe-buffer@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7"
+
+semver@^5.3.0:
+  version "5.3.0"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
+
+set-blocking@~2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
+
+set-immediate-shim@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61"
+
+setimmediate@^1.0.4:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
+
+sha.js@2.2.6:
+  version "2.2.6"
+  resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.2.6.tgz#17ddeddc5f722fb66501658895461977867315ba"
+
+signal-exit@^3.0.0:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
+
+sntp@1.x.x:
+  version "1.0.9"
+  resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198"
+  dependencies:
+    hoek "2.x.x"
+
+source-list-map@~0.1.7:
+  version "0.1.8"
+  resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-0.1.8.tgz#c550b2ab5427f6b3f21f5afead88c4f5587b2106"
+
+source-map@~0.4.1:
+  version "0.4.4"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b"
+  dependencies:
+    amdefine ">=0.0.4"
+
+source-map@~0.5.1:
+  version "0.5.6"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
+
+sshpk@^1.7.0:
+  version "1.11.0"
+  resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.11.0.tgz#2d8d5ebb4a6fab28ffba37fa62a90f4a3ea59d77"
+  dependencies:
+    asn1 "~0.2.3"
+    assert-plus "^1.0.0"
+    dashdash "^1.12.0"
+    getpass "^0.1.1"
+  optionalDependencies:
+    bcrypt-pbkdf "^1.0.0"
+    ecc-jsbn "~0.1.1"
+    jodid25519 "^1.0.0"
+    jsbn "~0.1.0"
+    tweetnacl "~0.14.0"
+
+stream-browserify@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db"
+  dependencies:
+    inherits "~2.0.1"
+    readable-stream "^2.0.2"
+
+stream-http@^2.3.1:
+  version "2.7.0"
+  resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.7.0.tgz#cec1f4e3b494bc4a81b451808970f8b20b4ed5f6"
+  dependencies:
+    builtin-status-codes "^3.0.0"
+    inherits "^2.0.1"
+    readable-stream "^2.2.6"
+    to-arraybuffer "^1.0.0"
+    xtend "^4.0.0"
+
+string-width@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
+  dependencies:
+    code-point-at "^1.0.0"
+    is-fullwidth-code-point "^1.0.0"
+    strip-ansi "^3.0.0"
+
+string_decoder@^0.10.25, string_decoder@~0.10.x:
+  version "0.10.31"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
+
+stringstream@~0.0.4:
+  version "0.0.5"
+  resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878"
+
+strip-ansi@^3.0.0, strip-ansi@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
+  dependencies:
+    ansi-regex "^2.0.0"
+
+strip-json-comments@~2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
+
+supports-color@^3.1.0:
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
+  dependencies:
+    has-flag "^1.0.0"
+
+tapable@^0.1.8, tapable@~0.1.8:
+  version "0.1.10"
+  resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.1.10.tgz#29c35707c2b70e50d07482b5d202e8ed446dafd4"
+
+tar-pack@^3.4.0:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.0.tgz#23be2d7f671a8339376cbdb0b8fe3fdebf317984"
+  dependencies:
+    debug "^2.2.0"
+    fstream "^1.0.10"
+    fstream-ignore "^1.0.5"
+    once "^1.3.3"
+    readable-stream "^2.1.4"
+    rimraf "^2.5.1"
+    tar "^2.2.1"
+    uid-number "^0.0.6"
+
+tar@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1"
+  dependencies:
+    block-stream "*"
+    fstream "^1.0.2"
+    inherits "2"
+
+timers-browserify@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.2.tgz#ab4883cf597dcd50af211349a00fbca56ac86b86"
+  dependencies:
+    setimmediate "^1.0.4"
+
+to-arraybuffer@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
+
+tough-cookie@~2.3.0:
+  version "2.3.2"
+  resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a"
+  dependencies:
+    punycode "^1.4.1"
+
+tty-browserify@0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
+
+tunnel-agent@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
+  dependencies:
+    safe-buffer "^5.0.1"
+
+tweetnacl@^0.14.3, tweetnacl@~0.14.0:
+  version "0.14.5"
+  resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
+
+uglify-js@~2.7.3:
+  version "2.7.5"
+  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.7.5.tgz#4612c0c7baaee2ba7c487de4904ae122079f2ca8"
+  dependencies:
+    async "~0.2.6"
+    source-map "~0.5.1"
+    uglify-to-browserify "~1.0.0"
+    yargs "~3.10.0"
+
+uglify-to-browserify@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7"
+
+uid-number@^0.0.6:
+  version "0.0.6"
+  resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81"
+
+url@^0.11.0:
+  version "0.11.0"
+  resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
+  dependencies:
+    punycode "1.3.2"
+    querystring "0.2.0"
+
+util-deprecate@~1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+
+util@0.10.3, util@^0.10.3:
+  version "0.10.3"
+  resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9"
+  dependencies:
+    inherits "2.0.1"
+
+uuid@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1"
+
+verror@1.3.6:
+  version "1.3.6"
+  resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c"
+  dependencies:
+    extsprintf "1.0.2"
+
+vm-browserify@0.0.4:
+  version "0.0.4"
+  resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73"
+  dependencies:
+    indexof "0.0.1"
+
+watchpack@^0.2.1:
+  version "0.2.9"
+  resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-0.2.9.tgz#62eaa4ab5e5ba35fdfc018275626e3c0f5e3fb0b"
+  dependencies:
+    async "^0.9.0"
+    chokidar "^1.0.0"
+    graceful-fs "^4.1.2"
+
+webpack-core@~0.6.9:
+  version "0.6.9"
+  resolved "https://registry.yarnpkg.com/webpack-core/-/webpack-core-0.6.9.tgz#fc571588c8558da77be9efb6debdc5a3b172bdc2"
+  dependencies:
+    source-list-map "~0.1.7"
+    source-map "~0.4.1"
+
+webpack@^1.14.0:
+  version "1.14.0"
+  resolved "https://registry.yarnpkg.com/webpack/-/webpack-1.14.0.tgz#54f1ffb92051a328a5b2057d6ae33c289462c823"
+  dependencies:
+    acorn "^3.0.0"
+    async "^1.3.0"
+    clone "^1.0.2"
+    enhanced-resolve "~0.9.0"
+    interpret "^0.6.4"
+    loader-utils "^0.2.11"
+    memory-fs "~0.3.0"
+    mkdirp "~0.5.0"
+    node-libs-browser "^0.7.0"
+    optimist "~0.6.0"
+    supports-color "^3.1.0"
+    tapable "~0.1.8"
+    uglify-js "~2.7.3"
+    watchpack "^0.2.1"
+    webpack-core "~0.6.9"
+
+wide-align@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad"
+  dependencies:
+    string-width "^1.0.1"
+
+window-size@0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
+
+wordwrap@0.0.2:
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
+
+wordwrap@~0.0.2:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
+
+wrappy@1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+
+xtend@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
+
+yargs@~3.10.0:
+  version "3.10.0"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"
+  dependencies:
+    camelcase "^1.0.2"
+    cliui "^2.1.0"
+    decamelize "^1.0.0"
+    window-size "0.1.0"
diff --git a/flow/environment.js b/flow/environment.js
new file mode 100644
index 000000000000..fa020bf8aa50
--- /dev/null
+++ b/flow/environment.js
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) 2015-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.
+ *
+ * @flow
+ */
+
+/* eslint-disable */
+
+declare var __REACT_DEVTOOLS_GLOBAL_HOOK__: any; /*?{
+  inject: ?((stuff: Object) => void)
+};*/
+
+// temporary patches for React.Component and React.Element
+declare var ReactComponent: typeof React$Component;
+declare var ReactElement: typeof React$Element;
diff --git a/flow/react-native-host-hooks.js b/flow/react-native-host-hooks.js
new file mode 100644
index 000000000000..7c0a1b5c3910
--- /dev/null
+++ b/flow/react-native-host-hooks.js
@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) 2015-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.
+ *
+ * @flow
+ */
+
+/* eslint-disable */
+
+declare module 'deepDiffer' {
+  declare function exports(one: any, two: any): bool;
+}
+declare module 'deepFreezeAndThrowOnMutationInDev' {
+  declare function exports<T>(obj : T) : T;
+}
+declare module 'flattenStyle' { }
+declare module 'InitializeJavaScriptAppEngine' { }
+declare module 'RCTEventEmitter' {
+  declare function register() : void;
+}
+declare module 'TextInputState' {
+  declare function blurTextInput(object : any) : void;
+  declare function focusTextInput(object : any) : void;
+}
+declare module 'UIManager' {
+  declare var customBubblingEventTypes : Object;
+  declare var customDirectEventTypes : Object;
+  declare function createView() : void;
+  declare function manageChildren() : void;
+  declare function measure() : void;
+  declare function measureInWindow() : void;
+  declare function measureLayout() : void;
+  declare function removeRootView() : void;
+  declare function removeSubviewsFromContainerWithID() : void;
+  declare function replaceExistingNonRootView() : void;
+  declare function setChildren() : void;
+  declare function updateView() : void;
+}
+declare module 'View' {
+  declare var exports : typeof ReactComponent;
+}
diff --git a/grunt/config/browserify.js b/grunt/config/browserify.js
index bfcb01ddda4e..646b14d6db46 100644
--- a/grunt/config/browserify.js
+++ b/grunt/config/browserify.js
@@ -7,11 +7,27 @@ var grunt = require('grunt');
 var UglifyJS = require('uglify-js');
 var uglifyify = require('uglifyify');
 var derequire = require('derequire');
+var aliasify = require('aliasify');
 var collapser = require('bundle-collapser/plugin');
 
 var envifyDev = envify({NODE_ENV: process.env.NODE_ENV || 'development'});
 var envifyProd = envify({NODE_ENV: process.env.NODE_ENV || 'production'});
 
+var shimSharedModules = aliasify.configure({
+  'aliases': {
+    'react/lib/React': 'react/lib/ReactUMDShim',
+    'react/lib/ReactCurrentOwner': 'react/lib/ReactCurrentOwnerUMDShim',
+    'react/lib/ReactComponentTreeHook': 'react/lib/ReactComponentTreeHookUMDShim',
+    'react/lib/getNextDebugID': 'react/lib/getNextDebugIDUMDShim',
+  },
+});
+
+var shimDOMModules = aliasify.configure({
+  'aliases': {
+    './ReactAddonsDOMDependencies': {relative: './ReactAddonsDOMDependenciesUMDShim'},
+  },
+});
+
 var SIMPLE_TEMPLATE =
   grunt.file.read('./grunt/data/header-template-short.txt');
 
@@ -47,10 +63,75 @@ function simpleBannerify(src) {
   );
 }
 
+// What is happening here???
+// I'm glad you asked. It became really hard to make our bundle splitting work.
+// Everything is fine in node and when bundling with those packages, but when
+// using our pre-packaged files, the splitting didn't work. Specifically due to
+// the UMD wrappers defining their own require and creating their own encapsulated
+// "registry" scope, we couldn't require across the boundaries. Webpack tries to
+// be smart and looks for top-level requires (even when aliasing to a bundle),
+// but since we didn't have those, we couldn't require 'react' from 'react-dom'.
+// But we are already shimming in some modules that look for a global React
+// variable. So we replace the UMD wrapper that browserify creates with out own,
+// in 2 steps.
+// 1. We swap out the browserify UMD with a plain function call. This ensures
+// that the internal wrapper doesn't interact with the external state. By the
+// time we're in the internal wrapper it doesn't matter what the external wrapper
+// detected. Browserify insulates its CommonJS system inside closures so can just
+// call that function and return it.
+// 2. We put our own UMD wrapper around that fixed internal function, ensuring
+// React is in scope. This outer wrapper is essentially the same UMD wrapper
+// browserify would create, just handling the scope issue.
+// Is this insane? Yes.
+// Does it work? Yes.
+// Should it go away ASAP? Yes.
+function wrapperify(src) {
+  var toReplace =
+    `function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.${this.data.standalone} = f()}}`;
+  if (src.indexOf(toReplace) === -1) {
+    throw new Error('wrapperify failed to find code to replace');
+  }
+  src = src.replace(
+    toReplace,
+    `function(f){return f()}`
+  );
+  return `
+;(function(f) {
+  // CommonJS
+  if (typeof exports === "object" && typeof module !== "undefined") {
+    module.exports = f(require('react'));
+
+  // RequireJS
+  } else if (typeof define === "function" && define.amd) {
+    define(['react'], f);
+
+  // <script>
+  } else {
+    var g;
+    if (typeof window !== "undefined") {
+      g = window;
+    } else if (typeof global !== "undefined") {
+      g = global;
+    } else if (typeof self !== "undefined") {
+      g = self;
+    } else {
+      // works providing we're not in "use strict";
+      // needed for Java 8 Nashorn
+      // see https://github.com/facebook/react/issues/3037
+      g = this;
+    }
+    g.${this.data.standalone} = f(g.React);
+  }
+})(function(React) {
+  return ${src}
+});
+`;
+}
+
 // Our basic config which we'll add to to make our other builds
 var basic = {
   entries: [
-    './build/modules/ReactUMDEntry.js',
+    './build/node_modules/react/lib/ReactUMDEntry.js',
   ],
   outfile: './build/react.js',
   debug: false,
@@ -63,7 +144,7 @@ var basic = {
 
 var min = {
   entries: [
-    './build/modules/ReactUMDEntry.js',
+    './build/node_modules/react/lib/ReactUMDEntry.js',
   ],
   outfile: './build/react.min.js',
   debug: false,
@@ -81,12 +162,13 @@ var min = {
 
 var addons = {
   entries: [
-    './build/modules/ReactWithAddonsUMDEntry.js',
+    './build/node_modules/react/lib/ReactWithAddonsUMDEntry.js',
   ],
   outfile: './build/react-with-addons.js',
   debug: false,
   standalone: 'React',
   packageName: 'React (with addons)',
+  transforms: [shimDOMModules],
   globalTransforms: [envifyDev],
   plugins: [collapser],
   after: [derequire, simpleBannerify],
@@ -94,13 +176,13 @@ var addons = {
 
 var addonsMin = {
   entries: [
-    './build/modules/ReactWithAddonsUMDEntry.js',
+    './build/node_modules/react/lib/ReactWithAddonsUMDEntry.js',
   ],
   outfile: './build/react-with-addons.min.js',
   debug: false,
   standalone: 'React',
   packageName: 'React (with addons)',
-  transforms: [envifyProd, uglifyify],
+  transforms: [shimDOMModules, envifyProd, uglifyify],
   globalTransforms: [envifyProd],
   plugins: [collapser],
   // No need to derequire because the minifier will mangle
@@ -109,9 +191,112 @@ var addonsMin = {
   after: [minify, bannerify],
 };
 
+// The DOM Builds
+var dom = {
+  entries: [
+    './build/node_modules/react-dom/lib/ReactDOMUMDEntry.js',
+  ],
+  outfile: './build/react-dom.js',
+  debug: false,
+  standalone: 'ReactDOM',
+  // Apply as global transform so that we also envify fbjs and any other deps
+  transforms: [shimSharedModules],
+  globalTransforms: [envifyDev],
+  plugins: [collapser],
+  after: [derequire, wrapperify, simpleBannerify],
+};
+
+var domMin = {
+  entries: [
+    './build/node_modules/react-dom/lib/ReactDOMUMDEntry.js',
+  ],
+  outfile: './build/react-dom.min.js',
+  debug: false,
+  standalone: 'ReactDOM',
+  // Envify twice. The first ensures that when we uglifyify, we have the right
+  // conditions to exclude requires. The global transform runs on deps.
+  transforms: [shimSharedModules, envifyProd, uglifyify],
+  globalTransforms: [envifyProd],
+  plugins: [collapser],
+  // No need to derequire because the minifier will mangle
+  // the "require" calls.
+
+  after: [wrapperify, minify, bannerify],
+};
+
+var domServer = {
+  entries: [
+    './build/node_modules/react-dom/lib/ReactDOMServerUMDEntry.js',
+  ],
+  outfile: './build/react-dom-server.js',
+  debug: false,
+  standalone: 'ReactDOMServer',
+  // Apply as global transform so that we also envify fbjs and any other deps
+  transforms: [shimSharedModules],
+  globalTransforms: [envifyDev],
+  plugins: [collapser],
+  after: [derequire, wrapperify, simpleBannerify],
+};
+
+var domServerMin = {
+  entries: [
+    './build/node_modules/react-dom/lib/ReactDOMServerUMDEntry.js',
+  ],
+  outfile: './build/react-dom-server.min.js',
+  debug: false,
+  standalone: 'ReactDOMServer',
+  // Envify twice. The first ensures that when we uglifyify, we have the right
+  // conditions to exclude requires. The global transform runs on deps.
+  transforms: [shimSharedModules, envifyProd, uglifyify],
+  globalTransforms: [envifyProd],
+  plugins: [collapser],
+  // No need to derequire because the minifier will mangle
+  // the "require" calls.
+
+  after: [wrapperify, minify, bannerify],
+};
+
+var domFiber = {
+  entries: [
+    './build/node_modules/react-dom/lib/ReactDOMFiber.js',
+  ],
+  outfile: './build/react-dom-fiber.js',
+  debug: false,
+  standalone: 'ReactDOMFiber',
+  // Apply as global transform so that we also envify fbjs and any other deps
+  transforms: [shimSharedModules],
+  globalTransforms: [envifyDev],
+  plugins: [collapser],
+  after: [derequire, wrapperify, simpleBannerify],
+};
+
+var domFiberMin = {
+  entries: [
+    './build/node_modules/react-dom/lib/ReactDOMFiber.js',
+  ],
+  outfile: './build/react-dom-fiber.min.js',
+  debug: false,
+  standalone: 'ReactDOMFiber',
+  // Envify twice. The first ensures that when we uglifyify, we have the right
+  // conditions to exclude requires. The global transform runs on deps.
+  transforms: [shimSharedModules, envifyProd, uglifyify],
+  globalTransforms: [envifyProd],
+  plugins: [collapser],
+  // No need to derequire because the minifier will mangle
+  // the "require" calls.
+
+  after: [wrapperify, minify, bannerify],
+};
+
 module.exports = {
   basic: basic,
   min: min,
   addons: addons,
   addonsMin: addonsMin,
+  dom: dom,
+  domMin: domMin,
+  domServer: domServer,
+  domServerMin: domServerMin,
+  domFiber: domFiber,
+  domFiberMin: domFiberMin,
 };
diff --git a/grunt/config/compress.js b/grunt/config/compress.js
deleted file mode 100644
index f2254437760b..000000000000
--- a/grunt/config/compress.js
+++ /dev/null
@@ -1,16 +0,0 @@
-'use strict';
-
-var grunt = require('grunt');
-
-var version = grunt.config.data.pkg.version;
-
-module.exports = {
-  starter: {
-    options: {
-      archive: './build/react-' + version + '.zip',
-    },
-    files: [
-      {cwd: './build/starter', src: ['**'], dest: 'react-' + version + '/'},
-    ],
-  },
-};
diff --git a/grunt/tasks/browserify.js b/grunt/tasks/browserify.js
index 3c9b2c089bf5..50a34d6f687f 100644
--- a/grunt/tasks/browserify.js
+++ b/grunt/tasks/browserify.js
@@ -25,6 +25,16 @@ module.exports = function() {
     entries: entries,
     debug: config.debug, // sourcemaps
     standalone: config.standalone, // global
+    insertGlobalVars: {
+      // We can remove this when we remove the few direct
+      // process.env.NODE_ENV checks against "test".
+      // The intention is to avoid embedding Browserify's `process` shim
+      // because we don't really need it.
+      // See https://github.com/facebook/react/pull/7245 for context.
+      process: function() {
+        return 'undefined';
+      },
+    },
   };
 
   var bundle = browserify(options);
diff --git a/grunt/tasks/eslint.js b/grunt/tasks/eslint.js
deleted file mode 100644
index 4f364a6d9075..000000000000
--- a/grunt/tasks/eslint.js
+++ /dev/null
@@ -1,22 +0,0 @@
-'use strict';
-
-var grunt = require('grunt');
-
-var extension = process.platform === 'win32' ? '.cmd': '';
-
-module.exports = function() {
-  var done = this.async();
-  grunt.util.spawn({
-    cmd: 'node_modules/.bin/eslint' + extension,
-    args: ['.'],
-    opts: {stdio: 'inherit'}, // allows colors to passthrough
-  }, function(err, result, code) {
-    if (err) {
-      grunt.log.error('Lint failed');
-    } else {
-      grunt.log.ok('Lint passed');
-    }
-
-    done(code === 0);
-  });
-};
diff --git a/grunt/tasks/jest.js b/grunt/tasks/jest.js
index da406e911197..c95dfb992cd8 100644
--- a/grunt/tasks/jest.js
+++ b/grunt/tasks/jest.js
@@ -1,93 +1,31 @@
-// We run our own grunt task instead of using grunt-jest so that we can have
-// more control. Specifically we want to set NODE_ENV and make sure stdio is
-// inherited. We also run with --harmony directly so that we don't have to
-// respawn immediately. We should be able to reduce some of this complexity
-// when jest 0.5 is run on top of iojs.
-
 'use strict';
 
-var async = require('async');
-var fs = require('fs');
-var glob = require('glob');
 var grunt = require('grunt');
 var path = require('path');
 
-var rootPath = path.resolve('.');
-var buildPath = path.join(rootPath, 'build');
-var tempConfigPath = path.join(buildPath, 'jest-config.json');
-
-var config = require(path.join(rootPath, 'package.json')).jest;
-
-var collectCoverageOnlyFrom = {
-  'src/**/*.js': {
-    ignore: [
-      'src/**/__tests__/*.js',
-      'src/shared/vendor/third_party/*.js',
-      'src/test/*.js',
-    ],
-  },
-};
-
-function getCollectCoverageOnlyFrom(callback) {
-  var patterns = Object.keys(collectCoverageOnlyFrom);
-  var result = {};
-
-  async.each(patterns, function(pattern) {
-    var options = Object.assign({ nodir: true }, collectCoverageOnlyFrom[pattern]);
-    glob(pattern, options, function(err, files) {
-      (files || []).reduce(function(object, key) {
-        object[key] = true;
-        return object;
-      }, result);
-
-      callback(err);
-    });
-  }, function(err) {
-    callback(err, result);
-  });
-}
-
-function getJestConfig(callback) {
-  var rootDir = path.resolve(buildPath, path.resolve(config.rootDir));
-  getCollectCoverageOnlyFrom(function(err, data) {
-    callback(err, Object.assign({}, config, {
-      rootDir: rootDir,
-      collectCoverage: true,
-      collectCoverageOnlyFrom: data,
-    }));
-  });
-}
-
-function onError(err) {
-  grunt.log.error('jest failed');
-  grunt.log.error(err);
-}
-
-function writeTempConfig(callback) {
-  getJestConfig(function(err, data) {
-    if (err) {
-      callback(err);
-    } else {
-      grunt.file.mkdir(buildPath);
-      fs.writeFile(tempConfigPath, JSON.stringify(data, null, '  '), 'utf8', callback);
-    }
-  });
-}
-
-function run(done, configPath) {
-  grunt.log.writeln('running jest (this may take a while)');
+function run(done, coverage) {
+  grunt.log.writeln('running jest');
 
-  var args = ['--harmony', path.join('node_modules', 'jest-cli', 'bin', 'jest')];
-  if (configPath) {
-    args.push('--config', configPath);
+  var args = [
+    path.join('node_modules', 'jest-cli', 'bin', 'jest'),
+    '--runInBand',
+  ];
+  if (coverage) {
+    args.push('--coverage');
   }
   grunt.util.spawn({
     cmd: 'node',
     args: args,
-    opts: { stdio: 'inherit', env: { NODE_ENV: 'test' } },
+    opts: {
+      stdio: 'inherit',
+      env: Object.assign({}, process.env, {
+        NODE_ENV: 'test',
+      }),
+    },
   }, function(spawnErr, result, code) {
     if (spawnErr) {
-      onError(spawnErr);
+      grunt.log.error('jest failed');
+      grunt.log.error(spawnErr);
     } else {
       grunt.log.ok('jest passed');
     }
@@ -104,15 +42,7 @@ function runJestNormally() {
 
 function runJestWithCoverage() {
   var done = this.async();
-
-  writeTempConfig(function(writeErr) {
-    if (writeErr) {
-      onError(writeErr);
-      return;
-    }
-
-    run(done, tempConfigPath);
-  });
+  run(done, /* coverage */ true);
 }
 
 module.exports = {
diff --git a/grunt/tasks/npm-react-addons.js b/grunt/tasks/npm-react-addons.js
deleted file mode 100644
index 948acebf1c65..000000000000
--- a/grunt/tasks/npm-react-addons.js
+++ /dev/null
@@ -1,133 +0,0 @@
-'use strict';
-
-var fs = require('fs');
-var grunt = require('grunt');
-var path = require('path');
-
-var addons = {
-  CSSTransitionGroup: {
-    module: 'ReactCSSTransitionGroup',
-    name: 'css-transition-group',
-    docs: 'animation',
-  },
-  LinkedStateMixin: {
-    module: 'LinkedStateMixin',
-    name: 'linked-state-mixin',
-    docs: 'two-way-binding-helpers',
-  },
-  Perf: {
-    module: 'ReactDefaultPerf',
-    name: 'perf',
-    docs: 'perf',
-  },
-  PureRenderMixin: {
-    module: 'ReactComponentWithPureRenderMixin',
-    name: 'pure-render-mixin',
-    docs: 'pure-render-mixin',
-  },
-  TestUtils: {
-    module: 'ReactTestUtils',
-    name: 'test-utils',
-    docs: 'test-utils',
-  },
-  TransitionGroup: {
-    module: 'ReactTransitionGroup',
-    name: 'transition-group',
-    docs: 'animation',
-  },
-  createFragment: {
-    module: 'ReactFragment',
-    method: 'create',
-    name: 'create-fragment',
-    docs: 'create-fragment',
-  },
-  shallowCompare: {
-    module: 'shallowCompare',
-    name: 'shallow-compare',
-  },
-  updates: {
-    module: 'update',
-    name: 'update',
-    docs: 'update',
-  },
-};
-
-function generateSource(info) {
-  var pieces = [
-    "module.exports = require('react/lib/",
-    info.module,
-    "')",
-  ];
-  if (info.method) {
-    pieces.push('.', info.method);
-  }
-  pieces.push(';');
-  return pieces.join('');
-}
-
-function buildReleases() {
-  var pkgTemplate = grunt.file.readJSON('./packages/react-addons/package.json');
-
-  Object.keys(addons).map(function(k) {
-    var info = addons[k];
-    var pkgName = 'react-addons-' + info.name;
-    var destDir = 'build/packages/' + pkgName;
-    var destLicense = path.join(destDir, 'LICENSE');
-    var destPatents = path.join(destDir, 'PATENTS');
-
-    var pkgData = Object.assign({}, pkgTemplate);
-    pkgData.name = pkgName;
-
-    grunt.file.mkdir(destDir);
-    var link = info.docs ? info.docs : 'addons';
-    link = `https://facebook.github.io/react/docs/${link}.html`;
-    fs.writeFileSync(path.join(destDir, 'index.js'), generateSource(info));
-    fs.writeFileSync(path.join(destDir, 'package.json'), JSON.stringify(pkgData, null, 2));
-    grunt.file.copy('LICENSE', destLicense);
-    grunt.file.copy('PATENTS', destPatents);
-    fs.writeFileSync(
-      path.join(destDir, 'README.md'),
-      `
-# ${pkgName}
-
-This package provides the React ${k} add-on.
-
-See <${link}> for more information.`.slice(1)
-    );
-  });
-
-}
-
-function packReleases() {
-  var done = this.async();
-  var count = 0;
-
-  var addonKeys = Object.keys(addons);
-
-  addonKeys.forEach(function(k) {
-    var info = addons[k];
-    var pkgName = 'react-addons-' + info.name;
-    var pkgDir = 'build/packages/' + pkgName;
-
-    var spawnCmd = {
-      cmd: 'npm',
-      args: ['pack', pkgDir],
-    };
-    grunt.util.spawn(spawnCmd, function() {
-      var buildSrc = pkgName + '-' + grunt.config.data.pkg.version + '.tgz';
-      var buildDest = 'build/packages/' + pkgName + '.tgz';
-      fs.rename(buildSrc, buildDest, maybeDone);
-    });
-  });
-
-  function maybeDone() {
-    if (++count === addonKeys.length) {
-      done();
-    }
-  }
-}
-
-module.exports = {
-  buildReleases: buildReleases,
-  packReleases: packReleases,
-};
diff --git a/grunt/tasks/npm-react-dom.js b/grunt/tasks/npm-react-dom.js
index 9856f1b6da9e..859e95ac3d34 100644
--- a/grunt/tasks/npm-react-dom.js
+++ b/grunt/tasks/npm-react-dom.js
@@ -5,6 +5,8 @@ var grunt = require('grunt');
 
 var src = 'packages/react-dom/';
 var dest = 'build/packages/react-dom/';
+var modSrc = 'build/node_modules/react-dom/lib';
+var lib = dest + 'lib/';
 var dist = dest + 'dist/';
 var distFiles = [
   'react-dom.js',
@@ -21,6 +23,7 @@ function buildRelease() {
   // Copy to build/packages/react-dom
   var mappings = [].concat(
     grunt.file.expandMapping('**/*', dest, {cwd: src}),
+    grunt.file.expandMapping('**/*', lib, {cwd: modSrc}),
     grunt.file.expandMapping('{LICENSE,PATENTS}', dest)
   );
   mappings.forEach(function(mapping) {
diff --git a/grunt/tasks/npm-react-test.js b/grunt/tasks/npm-react-test.js
new file mode 100644
index 000000000000..370ff1fe5459
--- /dev/null
+++ b/grunt/tasks/npm-react-test.js
@@ -0,0 +1,52 @@
+'use strict';
+
+var fs = require('fs');
+var grunt = require('grunt');
+
+var src = 'packages/react-test-renderer/';
+var dest = 'build/packages/react-test-renderer/';
+var modSrc = 'build/node_modules/react-test-renderer/lib';
+var lib = dest + 'lib/';
+
+function buildRelease() {
+  if (grunt.file.exists(dest)) {
+    grunt.file.delete(dest);
+  }
+
+  // Copy to build/packages/react-native-renderer
+  var mappings = [].concat(
+    grunt.file.expandMapping('**/*', dest, {cwd: src}),
+    grunt.file.expandMapping('**/*', lib, {cwd: modSrc}),
+    grunt.file.expandMapping('{LICENSE,PATENTS}', dest)
+  );
+  mappings.forEach(function(mapping) {
+    var mappingSrc = mapping.src[0];
+    var mappingDest = mapping.dest;
+    if (grunt.file.isDir(mappingSrc)) {
+      grunt.file.mkdir(mappingDest);
+    } else {
+      grunt.file.copy(mappingSrc, mappingDest);
+    }
+  });
+}
+
+function packRelease() {
+  var done = this.async();
+  var spawnCmd = {
+    cmd: 'npm',
+    args: ['pack', 'packages/react-test-renderer'],
+    opts: {
+      cwd: 'build/',
+    },
+  };
+  grunt.util.spawn(spawnCmd, function() {
+    var buildSrc = 'build/react-test-renderer-' + grunt.config.data.pkg.version + '.tgz';
+    var buildDest = 'build/packages/react-test-renderer.tgz';
+    fs.rename(buildSrc, buildDest, done);
+  });
+}
+
+module.exports = {
+  buildRelease: buildRelease,
+  packRelease: packRelease,
+};
diff --git a/grunt/tasks/npm-react.js b/grunt/tasks/npm-react.js
index 2e459ec93b91..038d2fec513c 100644
--- a/grunt/tasks/npm-react.js
+++ b/grunt/tasks/npm-react.js
@@ -5,7 +5,7 @@ var grunt = require('grunt');
 
 var src = 'packages/react/';
 var dest = 'build/packages/react/';
-var modSrc = 'build/modules/';
+var modSrc = 'build/node_modules/react/lib';
 var lib = dest + 'lib/';
 var dist = dest + 'dist/';
 var distFiles = [
diff --git a/grunt/tasks/react-dom.js b/grunt/tasks/react-dom.js
deleted file mode 100644
index 77a68d0656ac..000000000000
--- a/grunt/tasks/react-dom.js
+++ /dev/null
@@ -1,30 +0,0 @@
-'use strict';
-
-var grunt = require('grunt');
-var UglifyJS = require('uglify-js');
-
-var LICENSE_TEMPLATE =
-  grunt.file.read('./grunt/data/header-template-extended.txt');
-
-function build(name, filename) {
-  var srcFile = `vendor/${filename}.js`;
-  var destFile = `build/${filename}.js`;
-  var destFileMin = `build/${filename}.min.js`;
-  var templateData = {
-    package: name,
-    version: grunt.config.data.pkg.version,
-  };
-  var header = grunt.template.process(
-    LICENSE_TEMPLATE,
-    {data: templateData}
-  );
-  var src = grunt.file.read(srcFile);
-  var srcMin = UglifyJS.minify(src, {fromString: true}).code;
-  grunt.file.write(destFile, header + src);
-  grunt.file.write(destFileMin, header + srcMin);
-}
-
-module.exports = function() {
-  build('ReactDOM', 'react-dom');
-  build('ReactDOMServer', 'react-dom-server');
-};
diff --git a/grunt/tasks/release.js b/grunt/tasks/release.js
index 857c2dbdf368..0ddab043d8f5 100644
--- a/grunt/tasks/release.js
+++ b/grunt/tasks/release.js
@@ -15,17 +15,6 @@ var BOWER_FILES = [
   'react-dom-server.min.js',
 ];
 
-var EXAMPLES_PATH = 'examples/';
-var EXAMPLES_GLOB = [EXAMPLES_PATH + '**/*.*'];
-
-var STARTER_PATH = 'starter/';
-var STARTER_GLOB = [STARTER_PATH + '/**/*.*'];
-
-var STARTER_BUILD_PATH = 'build/starter/';
-
-var JS_PATH = 'build/';
-var JS_GLOB = [JS_PATH + '/*.js'];
-
 var VERSION;
 var VERSION_STRING;
 
@@ -98,7 +87,6 @@ function bower() {
 }
 
 function docs() {
-  grunt.file.copy('build/react-' + VERSION + '.zip', 'docs/downloads/react-' + VERSION + '.zip');
   grunt.file.copy('build/react.js', 'docs/js/react.js');
   grunt.file.copy('build/react-dom.js', 'docs/js/react-dom.js');
 }
@@ -108,11 +96,11 @@ function msg() {
   grunt.log.subhead('Release *almost* complete...');
   var steps = [
     'Still todo:',
-    '* put files on CDN',
-    '* add starter pack (git add -f docs/downloads/react-version.zip)',
-    '* push changes to git repositories',
-    '* update docs branch variable in Travis CI',
-    '* publish npm modules',
+    '* push this repo with tags',
+    '* push bower repo with tags',
+    '* run `npm-publish` in rrm',
+    '* create release on github',
+    '* for a major release, update docs branch variable in Travis CI',
     '* announce it on FB/Twitter/mailing list',
   ];
   steps.forEach(function(ln) {
@@ -120,36 +108,10 @@ function msg() {
   });
 }
 
-function starter() {
-  // Copy over examples/ to build/starter/examples/
-  // and starter/ to build/starter/
-
-  grunt.file.expand(EXAMPLES_GLOB).forEach(function(file) {
-    grunt.file.copy(
-      file,
-      STARTER_BUILD_PATH + file
-    );
-  });
-
-  grunt.file.expand(STARTER_GLOB).forEach(function(file) {
-    grunt.file.copy(
-      file,
-      'build/' + file
-    );
-  });
-
-  grunt.file.expand(JS_GLOB).forEach(function(file) {
-    grunt.file.copy(
-      file,
-      STARTER_BUILD_PATH + file
-    );
-  });
-}
 
 module.exports = {
   setup: setup,
   bower: bower,
   docs: docs,
   msg: msg,
-  starter: starter,
 };
diff --git a/grunt/tasks/version-check.js b/grunt/tasks/version-check.js
deleted file mode 100644
index ff6da818c0de..000000000000
--- a/grunt/tasks/version-check.js
+++ /dev/null
@@ -1,35 +0,0 @@
-'use strict';
-
-var grunt = require('grunt');
-
-module.exports = function() {
-  var pkgVersion = grunt.config.data.pkg.version;
-
-  var addonsData = grunt.file.readJSON('./packages/react-addons/package.json');
-  var versions = {
-    'packages/react/package.json':
-      grunt.file.readJSON('./packages/react/package.json').version,
-    'packages/react-dom/package.json':
-      grunt.file.readJSON('./packages/react-dom/package.json').version,
-    'packages/react-addons/package.json (version)': addonsData.version,
-    // Get the "version" without the range bit
-    'packages/react-addons/package.json (react dependency)': addonsData.peerDependencies.react.slice(1),
-    'src/ReactVersion.js': require('../../src/ReactVersion'),
-  };
-
-  // Return true (ok) or false (failed)
-  return Object.keys(versions).reduce(function(prev, name) {
-    var version = versions[name];
-    var ok = true;
-    if (version !== pkgVersion) {
-      grunt.log.error(
-        '%s version does not match package.json. Expected %s, saw %s.',
-        name,
-        pkgVersion,
-        version
-      );
-      ok = false;
-    }
-    return prev && ok;
-  }, true);
-};
diff --git a/gulp/tasks/eslint.js b/gulp/tasks/eslint.js
new file mode 100644
index 000000000000..6d87cdfd4338
--- /dev/null
+++ b/gulp/tasks/eslint.js
@@ -0,0 +1,49 @@
+/**
+ * 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.
+ */
+
+'use strict';
+
+var path = require('path');
+var spawn = require('child_process').spawn;
+
+var extension = process.platform === 'win32' ? '.cmd' : '';
+
+module.exports = function(gulp, plugins) {
+  var gutil = plugins.util;
+
+  return function(done) {
+    spawn(
+      process.execPath,
+      [
+        path.join('node_modules', '.bin', 'eslint' + extension),
+        '.',
+      ],
+      {
+        // Allow colors to pass through
+        stdio: 'inherit',
+      }
+    ).on('close', function(code) {
+      if (code !== 0) {
+        gutil.log(
+          gutil.colors.red(
+            'Lint failed'
+          )
+        );
+        process.exit(code);
+      }
+
+      gutil.log(
+        gutil.colors.green(
+          'Lint passed'
+        )
+      );
+      done();
+    });
+  };
+};
diff --git a/gulp/tasks/flow.js b/gulp/tasks/flow.js
new file mode 100644
index 000000000000..a32d8837b616
--- /dev/null
+++ b/gulp/tasks/flow.js
@@ -0,0 +1,50 @@
+/**
+ * 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.
+ */
+
+'use strict';
+
+var path = require('path');
+var spawn = require('child_process').spawn;
+
+var extension = process.platform === 'win32' ? '.cmd' : '';
+
+module.exports = function(gulp, plugins) {
+  var gutil = plugins.util;
+
+  return function(done) {
+    spawn(
+      process.execPath,
+      [
+        path.join('node_modules', '.bin', 'flow' + extension),
+        'check',
+        '.',
+      ],
+      {
+        // Allow colors to pass through
+        stdio: 'inherit',
+      }
+    ).on('close', function(code) {
+      if (code !== 0) {
+        gutil.log(
+          gutil.colors.red(
+            'Flow failed'
+          )
+        );
+        process.exit(code);
+      }
+
+      gutil.log(
+        gutil.colors.green(
+          'Flow passed'
+        )
+      );
+      done();
+    });
+  };
+};
diff --git a/gulp/tasks/version-check.js b/gulp/tasks/version-check.js
new file mode 100644
index 000000000000..3f84d5c85ab1
--- /dev/null
+++ b/gulp/tasks/version-check.js
@@ -0,0 +1,50 @@
+/**
+ * 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.
+ */
+
+'use strict';
+
+module.exports = function(gulp, plugins) {
+  var gutil = plugins.util;
+
+  return function(done) {
+    var reactVersion = require('../../package.json').version;
+
+    var versions = {
+      'packages/react/package.json':
+        require('../../packages/react/package.json').version,
+      'packages/react-dom/package.json':
+        require('../../packages/react-dom/package.json').version,
+      'packages/react-test-renderer/package.json':
+        require('../../packages/react-test-renderer/package.json').version,
+      'src/ReactVersion.js': require('../../src/ReactVersion'),
+    };
+
+    var allVersionsMatch = true;
+    Object.keys(versions).forEach(function(name) {
+      var version = versions[name];
+      if (version !== reactVersion) {
+        allVersionsMatch = false;
+        gutil.log(
+          gutil.colors.red(
+            '%s version does not match package.json. Expected %s, saw %s.'
+          ),
+          name,
+          reactVersion,
+          version
+        );
+      }
+    });
+
+    if (!allVersionsMatch) {
+      process.exit(1);
+    }
+
+    done();
+  };
+};
diff --git a/gulpfile.js b/gulpfile.js
index f885ea349a67..9c75fd6b5cf3 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -13,45 +13,280 @@ var gulp = require('gulp');
 var babel = require('gulp-babel');
 var flatten = require('gulp-flatten');
 var del = require('del');
+var merge = require('merge-stream');
 
 var babelPluginModules = require('fbjs-scripts/babel-6/rewrite-modules');
+var stripProvidesModule = require('fbjs-scripts/gulp/strip-provides-module');
+var extractErrors = require('./scripts/error-codes/gulp-extract-errors');
+var devExpressionWithCodes = require('./scripts/error-codes/dev-expression-with-codes');
+
+// Load all of the Gulp plugins.
+var plugins = require('gulp-load-plugins')();
+
+function getTask(name) {
+  return require(`./gulp/tasks/${name}`)(gulp, plugins);
+}
 
 var paths = {
   react: {
     src: [
-      'src/**/*.js',
+      'src/umd/ReactUMDEntry.js',
+      'src/umd/ReactWithAddonsUMDEntry.js',
+      'src/umd/shims/**/*.js',
+
+      'src/isomorphic/**/*.js',
+      'src/addons/**/*.js',
+
+      'src/ReactVersion.js',
+      'src/shared/**/*.js',
+      '!src/shared/vendor/**/*.js',
+      '!src/**/__benchmarks__/**/*.js',
       '!src/**/__tests__/**/*.js',
       '!src/**/__mocks__/**/*.js',
+    ],
+    lib: 'build/node_modules/react/lib',
+  },
+  reactDOM: {
+    src: [
+      'src/umd/ReactDOMUMDEntry.js',
+      'src/umd/ReactDOMServerUMDEntry.js',
+
+      'src/renderers/dom/**/*.js',
+      'src/renderers/shared/**/*.js',
+      'src/test/**/*.js', // ReactTestUtils is currently very coupled to DOM.
+
+      // ReactShallowRenderer was moved from ReactTestUtils to ReactTestRenderer but a pointer was left.
+      'src/renderers/testing/ReactShallowRenderer.js',
+      'src/renderers/testing/ReactTestReconcileTransaction.js',
+
+      'src/ReactVersion.js',
+      'src/shared/**/*.js',
       '!src/shared/vendor/**/*.js',
+      '!src/**/__benchmarks__/**/*.js',
+      '!src/**/__tests__/**/*.js',
+      '!src/**/__mocks__/**/*.js',
     ],
-    lib: 'build/modules',
+    lib: 'build/node_modules/react-dom/lib',
+  },
+  reactNative: {
+    src: [
+      'src/renderers/native/**/*.js',
+      'src/renderers/shared/**/*.js',
+
+      'src/ReactVersion.js',
+      'src/shared/**/*.js',
+      '!src/shared/vendor/**/*.js',
+      '!src/**/__benchmarks__/**/*.js',
+      '!src/**/__tests__/**/*.js',
+      '!src/**/__mocks__/**/*.js',
+    ],
+    lib: 'build/node_modules/react-native/lib',
+  },
+  reactShallowRenderer: {
+    src: [
+      // Shallow renderer reuses some DOM code
+      'src/renderers/dom/**/*.js',
+      'src/renderers/testing/**/*.js',
+      'src/renderers/shared/**/*.js',
+
+      'src/ReactVersion.js',
+      'src/shared/**/*.js',
+      '!src/shared/vendor/**/*.js',
+      '!src/**/__benchmarks__/**/*.js',
+      '!src/**/__tests__/**/*.js',
+      '!src/**/__mocks__/**/*.js',
+    ],
+    // We put it into a subfolder of test renderer but
+    // with a separate copy of the reconciler.
+    lib: 'build/node_modules/react-test-renderer/lib/shallow/',
+  },
+  reactTestRenderer: {
+    src: [
+      'src/renderers/testing/**/*.js',
+      'src/renderers/shared/**/*.js',
+
+      'src/ReactVersion.js',
+      'src/shared/**/*.js',
+      '!src/shared/vendor/**/*.js',
+      '!src/**/__benchmarks__/**/*.js',
+      '!src/**/__tests__/**/*.js',
+      '!src/**/__mocks__/**/*.js',
+    ],
+    lib: 'build/node_modules/react-test-renderer/lib',
   },
 };
 
-var babelOpts = {
+var moduleMapBase = Object.assign(
+  {
+    'object-assign': 'object-assign',
+    'create-react-class': 'create-react-class',
+    'create-react-class/factory': 'create-react-class/factory',
+    'prop-types': 'prop-types',
+    'prop-types/factory': 'prop-types/factory',
+  },
+  require('fbjs/module-map')
+);
+
+var moduleMapReact = Object.assign(
+  {
+    // Addons needs to reach into DOM internals
+    ReactDOM: 'react-dom/lib/ReactDOM',
+    ReactInstanceMap: 'react-dom/lib/ReactInstanceMap',
+    ReactTestUtils: 'react-dom/lib/ReactTestUtils',
+    ReactPerf: 'react-dom/lib/ReactPerf',
+    getVendorPrefixedEventName: 'react-dom/lib/getVendorPrefixedEventName',
+  },
+  moduleMapBase
+);
+
+var rendererSharedState = {
+  // Alias
+  React: 'react/lib/React',
+  // Shared state
+  ReactCurrentOwner: 'react/lib/ReactCurrentOwner',
+  ReactComponentTreeHook: 'react/lib/ReactComponentTreeHook',
+  getNextDebugID: 'react/lib/getNextDebugID',
+};
+
+var moduleMapReactDOM = Object.assign(
+  {},
+  rendererSharedState,
+  moduleMapBase
+);
+
+var moduleMapReactNative = Object.assign(
+  {
+    // React Native Hooks
+    deepDiffer: 'react-native/lib/deepDiffer',
+    deepFreezeAndThrowOnMutationInDev: 'react-native/lib/deepFreezeAndThrowOnMutationInDev',
+    flattenStyle: 'react-native/lib/flattenStyle',
+    InitializeJavaScriptAppEngine: 'react-native/lib/InitializeJavaScriptAppEngine',
+    RCTEventEmitter: 'react-native/lib/RCTEventEmitter',
+    TextInputState: 'react-native/lib/TextInputState',
+    UIManager: 'react-native/lib/UIManager',
+    UIManagerStatTracker: 'react-native/lib/UIManagerStatTracker',
+    View: 'react-native/lib/View',
+  },
+  rendererSharedState,
+  moduleMapBase
+);
+
+var moduleMapReactShallowRenderer = Object.assign(
+  {},
+  rendererSharedState,
+  moduleMapBase
+);
+
+var moduleMapReactTestRenderer = Object.assign(
+  {},
+  rendererSharedState,
+  moduleMapBase
+);
+
+var errorCodeOpts = {
+  errorMapFilePath: 'scripts/error-codes/codes.json',
+};
+
+var babelOptsReact = {
+  plugins: [
+    devExpressionWithCodes, // this pass has to run before `rewrite-modules`
+    [babelPluginModules, {map: moduleMapReact}],
+  ],
+};
+
+var babelOptsReactDOM = {
+  plugins: [
+    devExpressionWithCodes, // this pass has to run before `rewrite-modules`
+    [babelPluginModules, {map: moduleMapReactDOM}],
+  ],
+};
+
+var babelOptsReactNative = {
   plugins: [
-    [babelPluginModules, {
-      map: Object.assign(
-        {},
-        require('fbjs/module-map'),
-        {
-          'object-assign': 'object-assign',
-        }
-      ),
-    }],
+    devExpressionWithCodes, // this pass has to run before `rewrite-modules`
+    [babelPluginModules, {map: moduleMapReactNative}],
   ],
 };
 
+var babelOptsReactShallowRenderer = {
+  plugins: [
+    devExpressionWithCodes, // this pass has to run before `rewrite-modules`
+    [babelPluginModules, {map: moduleMapReactShallowRenderer}],
+  ],
+};
+
+var babelOptsReactTestRenderer = {
+  plugins: [
+    devExpressionWithCodes, // this pass has to run before `rewrite-modules`
+    [babelPluginModules, {map: moduleMapReactTestRenderer}],
+  ],
+};
+
+gulp.task('eslint', getTask('eslint'));
+
+gulp.task('lint', ['eslint']);
+
+gulp.task('flow', getTask('flow'));
+
+gulp.task('version-check', getTask('version-check'));
+
 gulp.task('react:clean', function() {
-  return del([paths.react.lib]);
+  return del([
+    paths.react.lib,
+    paths.reactDOM.lib,
+    paths.reactNative.lib,
+    paths.reactShallowRenderer.lib,
+    paths.reactTestRenderer.lib,
+  ]);
 });
 
 gulp.task('react:modules', function() {
-  return gulp
-    .src(paths.react.src)
-    .pipe(babel(babelOpts))
-    .pipe(flatten())
-    .pipe(gulp.dest(paths.react.lib));
+  return merge(
+    gulp
+      .src(paths.react.src)
+      .pipe(babel(babelOptsReact))
+      .pipe(stripProvidesModule())
+      .pipe(flatten())
+      .pipe(gulp.dest(paths.react.lib)),
+
+    gulp
+      .src(paths.reactDOM.src)
+      .pipe(babel(babelOptsReactDOM))
+      .pipe(stripProvidesModule())
+      .pipe(flatten())
+      .pipe(gulp.dest(paths.reactDOM.lib)),
+
+    gulp
+      .src(paths.reactNative.src)
+      .pipe(babel(babelOptsReactNative))
+      .pipe(stripProvidesModule())
+      .pipe(flatten())
+      .pipe(gulp.dest(paths.reactNative.lib)),
+
+    gulp
+      .src(paths.reactShallowRenderer.src)
+      .pipe(stripProvidesModule())
+      .pipe(babel(babelOptsReactShallowRenderer))
+      .pipe(flatten())
+      .pipe(gulp.dest(paths.reactShallowRenderer.lib)),
+
+    gulp
+      .src(paths.reactTestRenderer.src)
+      .pipe(stripProvidesModule())
+      .pipe(babel(babelOptsReactTestRenderer))
+      .pipe(flatten())
+      .pipe(gulp.dest(paths.reactTestRenderer.lib))
+  );
+});
+
+gulp.task('react:extract-errors', function() {
+  return gulp.src([].concat(
+    paths.react.src,
+    paths.reactDOM.src,
+    paths.reactNative.src,
+    paths.reactShallowRenderer.src,
+    paths.reactTestRenderer.src
+  )).pipe(extractErrors(errorCodeOpts));
 });
 
 gulp.task('default', ['react:modules']);
diff --git a/mocks/ReactElementTestChild.js b/mocks/ReactElementTestChild.js
index f2c94d5dd688..2e9d07693304 100644
--- a/mocks/ReactElementTestChild.js
+++ b/mocks/ReactElementTestChild.js
@@ -13,10 +13,10 @@
 
 var React = require('React');
 
-var Child = React.createClass({
-  render: function() {
+class Child extends React.Component {
+  render() {
     return React.createElement('div');
-  },
-});
+  }
+}
 
 module.exports = Child;
diff --git a/mocks/ReactMockedComponentTestComponent.js b/mocks/ReactMockedComponentTestComponent.js
index 903006487374..285265df1487 100644
--- a/mocks/ReactMockedComponentTestComponent.js
+++ b/mocks/ReactMockedComponentTestComponent.js
@@ -13,23 +13,18 @@
 
 var React = require('React');
 
-var ReactMockedComponentTestComponent = React.createClass({
-  getDefaultProps: function() {
-    return {bar: 'baz'};
-  },
+class ReactMockedComponentTestComponent extends React.Component {
+  state = {foo: 'bar'};
 
-  getInitialState: function() {
-    return {foo: 'bar'};
-  },
-
-  hasCustomMethod: function() {
+  hasCustomMethod() {
     return true;
-  },
+  }
 
-  render: function() {
+  render() {
     return <span />;
-  },
+  }
 
-});
+}
+ReactMockedComponentTestComponent.defaultProps = {bar: 'baz'};
 
 module.exports = ReactMockedComponentTestComponent;
diff --git a/package.json b/package.json
index fa96b20baa93..6cbda2c5633a 100644
--- a/package.json
+++ b/package.json
@@ -1,14 +1,18 @@
 {
   "name": "react-build",
   "private": true,
-  "version": "15.0.0-rc.2",
+  "version": "15.6.1",
   "devDependencies": {
+    "aliasify": "^2.0.0",
+    "art": "^0.10.1",
     "async": "^1.5.0",
     "babel-cli": "^6.6.5",
     "babel-core": "^6.0.0",
-    "babel-eslint": "^5.0.0",
+    "babel-eslint": "^7.1.0",
+    "babel-jest": "18.0.0",
     "babel-plugin-check-es2015-constants": "^6.5.0",
     "babel-plugin-syntax-trailing-function-commas": "^6.5.0",
+    "babel-plugin-transform-class-properties": "^6.11.5",
     "babel-plugin-transform-es2015-arrow-functions": "^6.5.2",
     "babel-plugin-transform-es2015-block-scoped-functions": "^6.5.0",
     "babel-plugin-transform-es2015-block-scoping": "^6.5.0",
@@ -25,42 +29,63 @@
     "babel-plugin-transform-es2015-template-literals": "^6.5.2",
     "babel-plugin-transform-es3-member-expression-literals": "^6.5.0",
     "babel-plugin-transform-es3-property-literals": "^6.5.0",
+    "babel-plugin-transform-object-rest-spread": "^6.6.5",
+    "babel-plugin-transform-react-jsx-source": "^6.8.0",
     "babel-preset-react": "^6.5.0",
+    "babel-traverse": "^6.9.0",
+    "babylon": "6.15.0",
     "browserify": "^13.0.0",
     "bundle-collapser": "^1.1.1",
+    "chalk": "^1.1.3",
     "coffee-script": "^1.8.0",
+    "core-js": "^2.2.1",
     "coveralls": "^2.11.6",
     "del": "^2.0.2",
     "derequire": "^2.0.3",
-    "eslint": "1.10.3",
-    "eslint-plugin-react": "4.1.0",
+    "eslint": "^3.10.2",
+    "eslint-config-fbjs": "^1.1.1",
+    "eslint-plugin-babel": "^3.3.0",
+    "eslint-plugin-flowtype": "^2.25.0",
+    "eslint-plugin-react": "^6.7.1",
     "eslint-plugin-react-internal": "file:eslint-rules",
-    "fbjs": "^0.8.0",
+    "fbjs": "^0.8.9",
     "fbjs-scripts": "^0.6.0",
+    "flow-bin": "^0.37.0",
     "glob": "^6.0.1",
     "grunt": "^0.4.5",
     "grunt-cli": "^0.1.13",
     "grunt-compare-size": "^0.4.0",
     "grunt-contrib-clean": "^0.6.0",
-    "grunt-contrib-compress": "^0.14.0",
     "gulp": "^3.9.0",
     "gulp-babel": "^6.0.0",
     "gulp-flatten": "^0.2.0",
+    "gulp-load-plugins": "^1.2.4",
+    "gulp-util": "^3.0.7",
     "gzip-js": "~0.3.2",
-    "jest-cli": "^0.9.0",
+    "jest-cli": "18.0.0",
+    "jest-config": "^18.0.0",
+    "jest-jasmine2": "^18.0.0",
+    "jest-runtime": "^18.0.0",
     "loose-envify": "^1.1.0",
-    "object-assign": "^4.0.1",
+    "merge-stream": "^1.0.0",
+    "object-assign": "^4.1.1",
     "platform": "^1.1.0",
+    "prettier": "^1.2.2",
     "run-sequence": "^1.1.4",
     "through2": "^2.0.0",
     "tmp": "~0.0.28",
-    "typescript": "~1.4.0",
+    "typescript": "~1.8.10",
     "uglify-js": "^2.5.0",
-    "uglifyify": "^3.0.1"
+    "uglifyify": "^3.0.1",
+    "yargs": "^6.3.0"
   },
   "devEngines": {
-    "node": "4.x || 5.x",
-    "npm": "2.x || 3.x"
+    "node": "4.x || 5.x || 6.x || 7.x",
+    "npm": "2.x || 3.x || 4.x"
+  },
+  "dependencies": {
+    "create-react-class": "^15.6.0",
+    "prop-types": "^15.5.10"
   },
   "commonerConfig": {
     "version": 7
@@ -70,32 +95,43 @@
     "linc": "git diff --name-only --diff-filter=ACMRTUB `git merge-base HEAD master` | grep '\\.js$' | xargs eslint --",
     "lint": "grunt lint",
     "postinstall": "node node_modules/fbjs-scripts/node/check-dev-engines.js package.json",
-    "test": "jest"
+    "test": "jest",
+    "flow": "flow",
+    "prettier": "node ./scripts/prettier/index.js write"
   },
   "jest": {
     "modulePathIgnorePatterns": [
       "/.module-cache/",
       "/react/build/"
     ],
-    "persistModuleRegistryBetweenSpecs": true,
     "rootDir": "",
-    "scriptPreprocessor": "scripts/jest/preprocessor.js",
-    "setupEnvScriptFile": "scripts/jest/environment.js",
-    "setupTestFrameworkScriptFile": "scripts/jest/test-framework-setup.js",
-    "testRunner": "jasmine1",
-    "testFileExtensions": [
-      "coffee",
+    "transform": {
+      ".*": "./scripts/jest/preprocessor.js"
+    },
+    "setupFiles": [
+      "./scripts/jest/environment.js"
+    ],
+    "setupTestFrameworkScriptFile": "./scripts/jest/test-framework-setup.js",
+    "testRegex": "/__tests__/",
+    "moduleFileExtensions": [
       "js",
+      "json",
+      "node",
+      "coffee",
       "ts"
     ],
     "testPathDirs": [
       "<rootDir>/eslint-rules",
       "<rootDir>/mocks",
+      "<rootDir>/scripts",
       "<rootDir>/src",
       "node_modules/fbjs"
     ],
-    "unmockedModulePathPatterns": [
-      ""
-    ]
+    "collectCoverageFrom": [
+      "src/**/*.js",
+      "!src/shared/vendor/third_party/*.js",
+      "!src/test/*.js"
+    ],
+    "timers": "fake"
   }
 }
diff --git a/packages/jsx_orphaned_brackets_transformer/.gitignore b/packages/jsx_orphaned_brackets_transformer/.gitignore
deleted file mode 100644
index 3c3629e647f5..000000000000
--- a/packages/jsx_orphaned_brackets_transformer/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-node_modules
diff --git a/packages/jsx_orphaned_brackets_transformer/README.md b/packages/jsx_orphaned_brackets_transformer/README.md
deleted file mode 100644
index e0fa3908edb2..000000000000
--- a/packages/jsx_orphaned_brackets_transformer/README.md
+++ /dev/null
@@ -1,31 +0,0 @@
-# JSX Orphaned Brackets Transformer
-
-React 0.13 no longer parses orphaned > and } as text.
-
-Take this example block:
-
-```js
-<div>
-  > }
-</div>
-```
-
-In 0.12 and below, this would be transformed to the following:
-
-```js
-React.DOM.div(null,
-  "> }",
-)
-```
-
-In 0.13, this will instead throw a parser error.
-
-
-## Usage
-
-The `jsx_orphaned_brackets_transformer` module ships an executable which transforms a file or directory of files. Files will be modified in place, so be sure you are prepared for that.
-
-```sh
-$ npm -g install jsx_orphaned_brackets_transformer
-$ jsx_orphaned_brackets_transformer <path_to_file_or_files>
-```
diff --git a/packages/jsx_orphaned_brackets_transformer/package.json b/packages/jsx_orphaned_brackets_transformer/package.json
deleted file mode 100644
index 44331721825a..000000000000
--- a/packages/jsx_orphaned_brackets_transformer/package.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-  "name": "jsx_orphaned_brackets_transformer",
-  "description": "A utility to update your JSX to work with React 0.13.",
-  "version": "1.0.1",
-  "main": "run.js",
-  "dependencies": {
-    "graceful-fs": "~2.0.0",
-    "jstransform": "~8.2.0",
-    "node-find-files": "0.0.2",
-    "optimist": "~0.6.0"
-  },
-  "bin": {
-    "jsx_orphaned_brackets_transformer": "./run.js"
-  },
-  "license": "BSD-3-Clause",
-  "preferGlobal": true
-}
diff --git a/packages/jsx_orphaned_brackets_transformer/run.js b/packages/jsx_orphaned_brackets_transformer/run.js
deleted file mode 100644
index 7ce8a4a94bbf..000000000000
--- a/packages/jsx_orphaned_brackets_transformer/run.js
+++ /dev/null
@@ -1,166 +0,0 @@
-#!/usr/bin/env node
-
-'use strict';
-
-var FileFinder = require('node-find-files');
-var fs = require('graceful-fs');
-var jstransform = require('jstransform');
-var path = require('path');
-var visitReactTag = require('./transforms/react').visitReactTag;
-/*eslint-disable no-shadow*/
-var S = jstransform.Syntax;
-
-var USAGE =
-  'Read a file (or directory of files) from disk, transform any orphaned ' +
-  '} and > characters to avoid parser errors with React 0.13.';
-
-function _visitFbt(node, path, state) {
-  return false;
-}
-_visitFbt.test = function(node, path, state) {
-  return node.type === S.XJSElement
-         && node.openingElement.name.name === 'fbt';
-};
-
-var VISITORS_LIST = [
-  _visitFbt,
-  visitReactTag,
-];
-
-function _transformSource(source) {
-  return jstransform.transform(VISITORS_LIST, source).code;
-}
-
-function transformDir(dirPath, exclude) {
-  var finder = new FileFinder({
-    rootFolder: dirPath,
-    filterFunction: function(path, stat) {
-      return /\.jsx?$/.test(path) && (!exclude || !exclude.test(path));
-    },
-  });
-
-  var numTransforms = 0;
-  var completeTransforms = 0;
-  var findingComplete = false;
-  function _printProgress() {
-    process.stdout.clearLine();
-    process.stdout.cursorTo(0);
-    process.stdout.write(
-      completeTransforms + '/' + numTransforms + ' transforms complete'
-    );
-
-    if (findingComplete && completeTransforms === numTransforms) {
-      console.log('\ndone!');
-    }
-  }
-
-  finder.on('match', function(pathStr, stat) {
-    fs.readFile(pathStr, 'utf8', function(err, data) {
-      if (err) {
-        err.message = err.message + ' (' + pathStr + ')';
-        throw err;
-      }
-
-      numTransforms++;
-      _printProgress();
-
-      var transformedData;
-      try {
-        transformedData = _transformSource(data);
-      } catch (e) {
-        e.message = e.message + ' (' + pathStr + ')';
-        throw e;
-      }
-
-      if (transformedData !== data) {
-        fs.writeFile(pathStr, transformedData, function(err) {
-          if (err) {
-            err.message = err.message + ' (' + pathStr + ')';
-            throw err;
-          }
-          completeTransforms++;
-          _printProgress();
-        });
-      } else {
-        completeTransforms++;
-        _printProgress();
-      }
-    });
-  });
-
-  finder.on('error', function(err) {
-    console.log('\nError: ', err.stack);
-    throw err;
-  });
-
-  finder.on('complete', function() {
-    findingComplete = true;
-  });
-
-  finder.startSearch();
-}
-
-function transformFile(pathStr) {
-  fs.readFile(pathStr, 'utf8', function(err, data) {
-    if (err) {
-      err.message = err.message + ' (' + pathStr + ')';
-      throw err;
-    }
-
-    var transformedData;
-    try {
-      transformedData = _transformSource(data);
-    } catch (e) {
-      e.message = e.message + ' (' + pathStr + ')';
-      throw e;
-    }
-
-    if (transformedData !== data) {
-      fs.writeFile(pathStr, transformedData, function(err) {
-        if (err) {
-          err.message = err.message + ' (' + pathStr + ')';
-          throw err;
-        }
-        console.log('done!');
-      });
-    } else {
-      console.log('done!');
-    }
-  });
-}
-
-if (require.main === module) {
-  var argv = require('optimist')
-    .usage(USAGE)
-    .argv;
-
-  if (argv._.length === 0) {
-    throw new Error(
-      'Please specify a file or directory path as the first arg!'
-    );
-  }
-
-  argv._.forEach(function(arg) {
-    var absPath = path.resolve(arg);
-
-    fs.stat(absPath, function(err, stat) {
-      if (err) {
-        throw err;
-      }
-
-      if (stat.isFile()) {
-        transformFile(absPath);
-      } else if (stat.isDirectory()) {
-        var exclude = null;
-        if (argv.exclude) {
-          exclude = new RegExp(argv.exclude);
-        }
-        transformDir(absPath, exclude);
-      } else {
-        throw new Error('Unknown filesystem node type: ' + absPath);
-      }
-    });
-  });
-}
-
-exports.transformDir = transformDir;
diff --git a/packages/jsx_orphaned_brackets_transformer/transforms/react.js b/packages/jsx_orphaned_brackets_transformer/transforms/react.js
deleted file mode 100644
index 1d9a28907a19..000000000000
--- a/packages/jsx_orphaned_brackets_transformer/transforms/react.js
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- * 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.
- */
-/*global exports:true*/
-'use strict';
-var jstransform = require('jstransform');
-var Syntax = jstransform.Syntax;
-var utils = require('jstransform/src/utils');
-
-function visitReactTag(traverse, object, path, state) {
-  object.openingElement.attributes.forEach(function(attr, index) {
-    if (attr.value) {
-      traverse(attr.value, path, state);
-    }
-  });
-
-  object.children.forEach(function(child, index) {
-    if (child.type === Syntax.Literal) {
-      codemodXJSLiteral(child, state);
-    } else {
-      traverse(child, path, state);
-    }
-  });
-
-  return false;
-}
-
-visitReactTag.test = function(object, path, state) {
-  return object.type === Syntax.XJSElement;
-};
-
-function codemodXJSLiteral(object, state) {
-  var value = object.raw;
-
-  utils.catchup(object.range[0], state);
-
-  var rightCurlyBracket = '&#125;'; // or {'}'}
-  var rightAngledBracket = '&gt;'; // or {'>'}
-
-  value = value.replace(/\}/g, rightCurlyBracket);
-  value = value.replace(/\>/g, rightAngledBracket);
-
-  utils.append(value, state);
-  utils.move(object.range[1], state);
-}
-
-exports.visitReactTag = visitReactTag;
diff --git a/packages/react-addons/package.json b/packages/react-addons/package.json
deleted file mode 100644
index 0a4747fefdf0..000000000000
--- a/packages/react-addons/package.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-  "name": "react-addons-template",
-  "version": "15.0.0-rc.2",
-  "main": "index.js",
-  "repository": "facebook/react",
-  "keywords": [
-    "react",
-    "react-addon"
-  ],
-  "license": "BSD-3-Clause",
-  "dependencies": {},
-  "peerDependencies": {
-    "react": "^15.0.0-rc.2"
-  }
-}
diff --git a/packages/react-dom-factories/README.md b/packages/react-dom-factories/README.md
new file mode 100644
index 000000000000..3951563f9eb1
--- /dev/null
+++ b/packages/react-dom-factories/README.md
@@ -0,0 +1,20 @@
+# `react-dom-factories`
+
+> Note:
+> `ReactDOMFactories` is a legacy add-on. Consider using
+> `React.createFactory` or JSX instead.
+
+Prior to version 16.0.0, React maintained a whitelist of
+pre-configured DOM factories. These predefined factories have been
+moved to the `react-dom-factories` library.
+
+## Example
+
+```javascript
+import ReactDOM from 'react-dom';
+import DOM from 'react-dom-factories';
+
+const greeting = DOM.div({ className: 'greeting' }, DOM.p(null, 'Hello, world!'));
+
+ReactDOM.render(greeting, document.getElementById('app'))
+```
diff --git a/packages/react-dom-factories/index.js b/packages/react-dom-factories/index.js
new file mode 100644
index 000000000000..ceca5fb48cf4
--- /dev/null
+++ b/packages/react-dom-factories/index.js
@@ -0,0 +1,189 @@
+'use strict';
+
+/**
+ * Copyright 2015-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.
+ */
+
+(function(f) {
+  if (typeof exports === 'object' && typeof module !== 'undefined') {
+    module.exports = f(require('react'));
+    /* global define */
+  } else if (typeof define === 'function' && define.amd) {
+    define(['react'], f);
+  } else {
+    var g;
+    if (typeof window !== 'undefined') {
+      g = window;
+    } else if (typeof global !== 'undefined') {
+      g = global;
+    } else if (typeof self !== 'undefined') {
+      g = self;
+    } else {
+      g = this;
+    }
+
+    if (typeof g.React === 'undefined') {
+      throw Error('React module should be required before ReactDOMFactories');
+    }
+
+    g.ReactDOMFactories = f(g.React);
+  }
+})(function(React) {
+  /**
+   * Create a factory that creates HTML tag elements.
+   */
+  var createDOMFactory = React.createFactory;
+
+  /**
+   * Creates a mapping from supported HTML tags to `ReactDOMComponent` classes.
+   */
+  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'),
+  };
+
+  // due to wrapper and conditionals at the top, this will either become
+  // `module.exports ReactDOMFactories` if that is available,
+  // otherwise it will be defined via `define(['react'], ReactDOMFactories)`
+  // if that is available,
+  // otherwise it will be defined as global variable.
+  return ReactDOMFactories;
+});
+
diff --git a/packages/react-dom-factories/package.json b/packages/react-dom-factories/package.json
new file mode 100644
index 000000000000..86fa9c940348
--- /dev/null
+++ b/packages/react-dom-factories/package.json
@@ -0,0 +1,25 @@
+{
+  "name": "react-dom-factories",
+  "version": "15.6.0",
+  "description": "React package for DOM factory methods.",
+  "main": "index.js",
+  "repository": "facebook/react",
+  "keywords": [
+    "react"
+  ],
+  "license": "BSD-3-Clause",
+  "bugs": {
+    "url": "https://github.com/facebook/react/issues"
+  },
+  "homepage": "https://facebook.github.io/react/",
+  "peerDependencies": {
+    "react": "^15.6.0-rc.1"
+  },
+  "files": [
+    "LICENSE",
+    "PATENTS",
+    "README.md",
+    "index.js",
+    "lib/"
+  ]
+}
diff --git a/packages/react-dom/fiber.js b/packages/react-dom/fiber.js
new file mode 100644
index 000000000000..44ae595f8717
--- /dev/null
+++ b/packages/react-dom/fiber.js
@@ -0,0 +1,3 @@
+'use strict';
+
+module.exports = require('./lib/ReactDOMFiber');
diff --git a/packages/react-dom/index.js b/packages/react-dom/index.js
index 0b5deb28f492..2bf9417936f7 100644
--- a/packages/react-dom/index.js
+++ b/packages/react-dom/index.js
@@ -1,3 +1,3 @@
 'use strict';
 
-module.exports = require('react/lib/ReactDOM');
+module.exports = require('./lib/ReactDOM');
diff --git a/packages/react-dom/package.json b/packages/react-dom/package.json
index 2e4dc9c2709d..61ff7e6c30de 100644
--- a/packages/react-dom/package.json
+++ b/packages/react-dom/package.json
@@ -1,6 +1,6 @@
 {
   "name": "react-dom",
-  "version": "15.0.0-rc.2",
+  "version": "15.6.1",
   "description": "React package for working with the DOM.",
   "main": "index.js",
   "repository": "facebook/react",
@@ -12,8 +12,28 @@
     "url": "https://github.com/facebook/react/issues"
   },
   "homepage": "https://facebook.github.io/react/",
-  "dependencies": {},
+  "dependencies": {
+    "fbjs": "^0.8.9",
+    "loose-envify": "^1.1.0",
+    "object-assign": "^4.1.0",
+    "prop-types": "^15.5.10"
+  },
   "peerDependencies": {
-    "react": "^15.0.0-rc.2"
+    "react": "^15.6.1"
+  },
+  "files": [
+    "LICENSE",
+    "PATENTS",
+    "README.md",
+    "dist/",
+    "lib/",
+    "index.js",
+    "server.js",
+    "test-utils.js"
+  ],
+  "browserify": {
+    "transform": [
+      "loose-envify"
+    ]
   }
 }
diff --git a/packages/react-dom/server.js b/packages/react-dom/server.js
index e56ecb327795..559676109da8 100644
--- a/packages/react-dom/server.js
+++ b/packages/react-dom/server.js
@@ -1,3 +1,3 @@
 'use strict';
 
-module.exports = require('react/lib/ReactDOMServer');
+module.exports = require('./lib/ReactDOMServer');
diff --git a/packages/react-dom/test-utils.js b/packages/react-dom/test-utils.js
new file mode 100644
index 000000000000..778fe9dce27c
--- /dev/null
+++ b/packages/react-dom/test-utils.js
@@ -0,0 +1,3 @@
+'use strict';
+
+module.exports = require('./lib/ReactTestUtils');
diff --git a/packages/react-linked-input/LinkedInput.js b/packages/react-linked-input/LinkedInput.js
deleted file mode 100644
index d40df684a80b..000000000000
--- a/packages/react-linked-input/LinkedInput.js
+++ /dev/null
@@ -1,27 +0,0 @@
-/**
- * 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.
- */
-
-'use strict';
-
-var React = require('react');
-var LinkedValueUtils = require('react/lib/LinkedValueUtils');
-
-class LinkedInput extends React.Component {
-  render() {
-    var newProps = Object.assign({}, this.props);
-    newProps.value = LinkedValueUtils.getValue(this.props);
-    newProps.checked = LinkedValueUtils.getChecked(this.props);
-    delete newProps.valueLink;
-    delete newProps.checkedLink;
-    return React.createElement('input', newProps);
-  }
-}
-
-module.exports = LinkedInput;
-
diff --git a/packages/react-linked-input/README.md b/packages/react-linked-input/README.md
deleted file mode 100644
index 3109ea7df123..000000000000
--- a/packages/react-linked-input/README.md
+++ /dev/null
@@ -1,11 +0,0 @@
-This component supports the ReactLink API (valueLink, etc) for input components.  Support for ReactLink on DOM elements will be removed from React.  This component may be used as a migration plan (so your code doesn't break in the next version of React) or may be used if you just like the ReactLink data binding semantics.  However, this component is not maintained, so use at your own risk.
-
-
-```
-var React = require('react');
-var ReactDOM = require('react-dom');
-var LinkedInput = require('react-linked-input');
-
-var link = {value: 'boo', requestChange: function() {}};
-React.render(<LinkedInput valueLink={link} />, container);
-```
diff --git a/packages/react-linked-input/__test__/LinkedInput-test.js b/packages/react-linked-input/__test__/LinkedInput-test.js
deleted file mode 100644
index fab7c3d5282e..000000000000
--- a/packages/react-linked-input/__test__/LinkedInput-test.js
+++ /dev/null
@@ -1,42 +0,0 @@
-/**
- * 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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-
-describe('LinkedStateMixin', function() {
-  var LinkedInput;
-  var React;
-  var ReactDOM;
-
-  beforeEach(function() {
-    LinkedInput = require('LinkedInput');
-    React = require('React');
-    ReactDOM = require('ReactDOM');
-  });
-
-  it('should basically work', function() {
-    var container = document.createElement('div');
-    var component = ReactDOM.render(<LinkedInput value="foo" onChange={function() {}} />, container);
-    var input = ReactDOM.findDOMNode(component);
-    expect(input.value).toBe('foo');
-    ReactDOM.render(<LinkedInput valueLink={{value: 'boo', requestChange: function() {}}} />, container);
-    expect(input.value).toBe('boo');
-  });
-
-  it('should throw', function() {
-    var container = document.createElement('div');
-    var element = <LinkedInput value="foo" valueLink={{value: 'boo', requestChange: function() {}}} />;
-    expect(function() {
-      ReactDOM.render(element, container);
-    }).toThrow();
-  });
-});
diff --git a/packages/react-linked-input/package.json b/packages/react-linked-input/package.json
deleted file mode 100644
index d6fd48d06ce2..000000000000
--- a/packages/react-linked-input/package.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
-  "name": "react-linked-input",
-  "version": "1.0.0",
-  "description": "LinkedInput supports the ReactLink semantics",
-  "main": "LinkedInput.js",
-  "scripts": {
-    "test": "echo \"Error: no test specified\" && exit 1"
-  },
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/facebook/react.git"
-  },
-  "keywords": [
-    "react",
-    "linkedinput",
-    "input",
-    "linked",
-    "reactlink"
-  ],
-  "author": "",
-  "license": "BSD-3-Clause",
-  "peerDependencies": {
-    "react": "^15.0.0-rc.2"
-  }
-}
diff --git a/packages/react-test-renderer/README.md b/packages/react-test-renderer/README.md
new file mode 100644
index 000000000000..73ad3ae7c3ea
--- /dev/null
+++ b/packages/react-test-renderer/README.md
@@ -0,0 +1,42 @@
+# `react-test-renderer`
+
+This package provides two React renderers that can be used for testing purposes:
+
+#### Test renderer
+
+Renders React components to pure JavaScript objects without depending on the DOM or a native mobile environment. This makes it easy to grab a snapshot of the "DOM tree" rendered by a React DOM or React Native component without using a browser or jsdom.
+
+```jsx
+const ReactTestRenderer = require('react-test-renderer');
+
+const renderer = ReactTestRenderer.create(
+  <Link page="https://www.facebook.com/">Facebook</Link>
+);
+
+console.log(renderer.toJSON());
+// { type: 'a',
+//   props: { href: 'https://www.facebook.com/' },
+//   children: [ 'Facebook' ] }
+```
+
+You can also use Jest's snapshot testing feature to automatically save a copy of the JSON tree to a file and check in your tests that it hasn't changed: http://facebook.github.io/jest/blog/2016/07/27/jest-14.html.
+
+#### Shallow renderer
+
+Shallow rendering lets you render a component "one level deep" and assert facts about what its render method returns, without worrying about the behavior of child components, which are not instantiated or rendered. This does not require a DOM.
+
+```jsx
+const ReactShallowRenderer = require('react-test-renderer/shallow');
+
+const renderer = new ReactShallowRenderer();
+renderer.render(<MyComponent />);
+
+const result = renderer.getRenderOutput();
+expect(result.type).toBe('div');
+expect(result.props.children).toEqual([
+  <span className="heading">Title</span>,
+  <Subcomponent foo="bar" />
+]);
+```
+
+This renderer was previously located in `react-addons-test-utils`.
\ No newline at end of file
diff --git a/packages/react-test-renderer/index.js b/packages/react-test-renderer/index.js
new file mode 100644
index 000000000000..3436e5bb3a7d
--- /dev/null
+++ b/packages/react-test-renderer/index.js
@@ -0,0 +1,3 @@
+'use strict';
+
+module.exports = require('./lib/ReactTestRenderer');
diff --git a/packages/react-test-renderer/package.json b/packages/react-test-renderer/package.json
new file mode 100644
index 000000000000..11fddb4886cb
--- /dev/null
+++ b/packages/react-test-renderer/package.json
@@ -0,0 +1,32 @@
+{
+  "name": "react-test-renderer",
+  "version": "15.6.1",
+  "description": "React package for snapshot testing.",
+  "main": "index.js",
+  "repository": "facebook/react",
+  "keywords": [
+    "react",
+    "react-native",
+    "react-testing"
+  ],
+  "license": "BSD-3-Clause",
+  "bugs": {
+    "url": "https://github.com/facebook/react/issues"
+  },
+  "homepage": "https://facebook.github.io/react/",
+  "dependencies": {
+    "fbjs": "^0.8.9",
+    "object-assign": "^4.1.0"
+  },
+  "peerDependencies": {
+    "react": "^15.6.1"
+  },
+  "files": [
+    "LICENSE",
+    "PATENTS",
+    "README.md",
+    "index.js",
+    "shallow.js",
+    "lib/"
+  ]
+}
diff --git a/packages/react-test-renderer/shallow.js b/packages/react-test-renderer/shallow.js
new file mode 100644
index 000000000000..b911df914229
--- /dev/null
+++ b/packages/react-test-renderer/shallow.js
@@ -0,0 +1,3 @@
+'use strict';
+
+module.exports = require('./lib/shallow/ReactShallowRenderer');
diff --git a/packages/react/README.md b/packages/react/README.md
index 98754e724b6f..740a4f2c064d 100644
--- a/packages/react/README.md
+++ b/packages/react/README.md
@@ -13,11 +13,4 @@ To use React in production mode, set the environment variable `NODE_ENV` to `pro
 
 ```js
 var React = require('react');
-
-// Addons are in separate packages:
-var createFragment = require('react-addons-create-fragment');
-var immutabilityHelpers = require('react-addons-update');
-var CSSTransitionGroup = require('react-addons-css-transition-group');
 ```
-
-For a complete list of addons visit the [addons documentation page](https://facebook.github.io/react/docs/addons.html).
diff --git a/packages/react/lib/ReactDOM.native.js b/packages/react/lib/ReactDOM.native.js
deleted file mode 100644
index bdd9044a8b1c..000000000000
--- a/packages/react/lib/ReactDOM.native.js
+++ /dev/null
@@ -1,12 +0,0 @@
-'use strict';
-
-var ReactUpdates = require('./ReactUpdates');
-
-// TODO: In React Native, ReactTestUtils depends on ./ReactDOM (for
-// renderIntoDocument, which should never be called) and Relay depends on
-// react-dom (for batching). Once those are fixed, nothing in RN should import
-// this module and this file can go away.
-
-module.exports = {
-  unstable_batchedUpdates: ReactUpdates.batchedUpdates,
-};
diff --git a/packages/react/package.json b/packages/react/package.json
index 44989f02b016..66c96cba8e7d 100644
--- a/packages/react/package.json
+++ b/packages/react/package.json
@@ -1,7 +1,7 @@
 {
   "name": "react",
   "description": "React is a JavaScript library for building user interfaces.",
-  "version": "15.0.0-rc.2",
+  "version": "15.6.1",
   "keywords": [
     "react"
   ],
@@ -23,9 +23,11 @@
     "node": ">=0.10.0"
   },
   "dependencies": {
-    "fbjs": "^0.8.0",
+    "create-react-class": "^15.6.0",
+    "fbjs": "^0.8.9",
     "loose-envify": "^1.1.0",
-    "object-assign": "^4.0.1"
+    "object-assign": "^4.1.0",
+    "prop-types": "^15.5.10"
   },
   "browserify": {
     "transform": [
diff --git a/scripts/babel/transform-object-assign-require.js b/scripts/babel/transform-object-assign-require.js
index 649a377005c9..36d32241337a 100644
--- a/scripts/babel/transform-object-assign-require.js
+++ b/scripts/babel/transform-object-assign-require.js
@@ -12,6 +12,20 @@
 module.exports = function autoImporter(babel) {
   const t = babel.types;
 
+  function getAssignIdent(path, file, state) {
+    if (!state.id) {
+      state.id = path.scope.generateUidIdentifier('assign');
+      path.scope.getProgramParent().push({
+        id: state.id,
+        init: t.callExpression(
+          t.identifier('require'),
+          [t.stringLiteral('object-assign')]
+        ),
+      });
+    }
+    return state.id;
+  }
+
   return {
     pre: function() {
       // map from module to generated identifier
@@ -22,17 +36,15 @@ module.exports = function autoImporter(babel) {
       CallExpression: function(path, file) {
         if (path.get('callee').matchesPattern('Object.assign')) {
           // generate identifier and require if it hasn't been already
-          if (!this.id) {
-            this.id = path.scope.generateUidIdentifier('assign');
-            path.scope.getProgramParent().push({
-              id: this.id,
-              init: t.callExpression(
-                t.identifier('require'),
-                [t.stringLiteral('object-assign')]
-              ),
-            });
-          }
-          path.node.callee = this.id;
+          var id = getAssignIdent(path, file, this);
+          path.node.callee = id;
+        }
+      },
+
+      MemberExpression: function(path, file) {
+        if (path.matchesPattern('Object.assign')) {
+          var id = getAssignIdent(path, file, this);
+          path.replaceWith(id);
         }
       },
     },
diff --git a/scripts/bench/README.md b/scripts/bench/README.md
index 7fa8003d5a2e..bfe049add053 100644
--- a/scripts/bench/README.md
+++ b/scripts/bench/README.md
@@ -2,12 +2,21 @@ Work-in-progress benchmarks.
 
 ## Running the suite
 
+You'll need two folders to compare, each of them containing `react.min.js` and `react-dom-server.min.js`. You can run `npm run build` at the repo root to get a `build` folder with these files.
+
+For example, if you want to compare a stable verion against master, you can create folders called `build-stable` and `build-master` and use the benchmark scripts like this:
+
 ```
-$ ./measure.py react-a.min.js >a.txt
-$ ./measure.py react-b.min.js >b.txt
-$ ./analyze.py a.txt b.txt
+$ ./measure.py build-stable stable.txt build-master master.txt
+$ ./analyze.py stable.txt master.txt
 ```
 
+The test measurements (second argument to `analyze`, `master.txt` in this example) will be compared to the control measurements (first argument to `analyze`, `stable.txt` in this example).
+
+Changes with the `-` sign in the output mean `master` is faster than `stable`.
+
+You can name folders any way you like, this was just an example.
+
 ## Running one
 One thing you can do with them is benchmark initial render time for a realistic hierarchy:
 
diff --git a/scripts/bench/bench-pe-es5.js b/scripts/bench/bench-pe-es5.js
index 35927a67f751..9abd28ce8a03 100644
--- a/scripts/bench/bench-pe-es5.js
+++ b/scripts/bench/bench-pe-es5.js
@@ -1,18 +1,234 @@
 (function () {
 
-  var Link0 = React.createClass({
-    displayName: "Link0",
-
-    render: function () {
-      return React.createElement("a", { href: "/", className: "_5ljn", rel: undefined, onClick: function () {} });
-    }
-  });
-
-  var ReactImage1 = React.createClass({
-    displayName: "ReactImage1",
-
-    render: function () {
-      return React.createElement("i", { alt: "", className: "_3-99 img sp_UuU9HmrQ397 sx_7e56e9", src: null });
+  var ReactImage0 = React.createClass({
+    displayName: "ReactImage0",
+
+    render: function () {
+      var props = this.props;
+      if (props.x === 0) {
+        return React.createElement("i", { alt: "", className: "_3-99 img sp_i534r85sjIn sx_538591", src: null });
+      }
+      if (props.x === 15) {
+        return React.createElement("i", { className: "_3ut_ img sp_i534r85sjIn sx_e8ac93", src: null, alt: "" });
+      }
+      if (props.x === 22) {
+        return React.createElement("i", { alt: "", className: "_3-8_ img sp_i534r85sjIn sx_7b15bc", src: null });
+      }
+      if (props.x === 29) {
+        return React.createElement("i", { className: "_1m1s _4540 _p img sp_i534r85sjIn sx_f40b1c", src: null, alt: "" });
+      }
+      if (props.x === 42) {
+        return React.createElement(
+          "i",
+          { alt: "Warning", className: "_585p img sp_i534r85sjIn sx_20273d", src: null },
+          React.createElement(
+            "u",
+            null,
+            "Warning"
+          )
+        );
+      }
+      if (props.x === 67) {
+        return React.createElement("i", { alt: "", className: "_3-8_ img sp_i534r85sjIn sx_b5d079", src: null });
+      }
+      if (props.x === 70) {
+        return React.createElement("i", { src: null, alt: "", className: "img sp_i534r85sjIn sx_29f8c9" });
+      }
+      if (props.x === 76) {
+        return React.createElement("i", { alt: "", className: "_3-8_ img sp_i534r85sjIn sx_ef6a9c", src: null });
+      }
+      if (props.x === 79) {
+        return React.createElement("i", { src: null, alt: "", className: "img sp_i534r85sjIn sx_6f8c43" });
+      }
+      if (props.x === 88) {
+        return React.createElement("i", { src: null, alt: "", className: "img sp_i534r85sjIn sx_e94a2d" });
+      }
+      if (props.x === 91) {
+        return React.createElement("i", { src: null, alt: "", className: "img sp_i534r85sjIn sx_7ed7d4" });
+      }
+      if (props.x === 94) {
+        return React.createElement("i", { src: null, alt: "", className: "img sp_i534r85sjIn sx_930440" });
+      }
+      if (props.x === 98) {
+        return React.createElement("i", { src: null, alt: "", className: "img sp_i534r85sjIn sx_750c83" });
+      }
+      if (props.x === 108) {
+        return React.createElement("i", { src: null, alt: "", className: "img sp_i534r85sjIn sx_73c1bb" });
+      }
+      if (props.x === 111) {
+        return React.createElement("i", { src: null, alt: "", className: "img sp_i534r85sjIn sx_29f28d" });
+      }
+      if (props.x === 126) {
+        return React.createElement("i", { src: null, alt: "", className: "_3-8_ img sp_i534r85sjIn sx_91c59e" });
+      }
+      if (props.x === 127) {
+        return React.createElement("i", { alt: "", className: "_3-99 img sp_i534r85sjIn sx_538591", src: null });
+      }
+      if (props.x === 134) {
+        return React.createElement("i", { src: null, alt: "", className: "_3-8_ img sp_i534r85sjIn sx_c8eb75" });
+      }
+      if (props.x === 135) {
+        return React.createElement("i", { alt: "", className: "_3-99 img sp_i534r85sjIn sx_538591", src: null });
+      }
+      if (props.x === 148) {
+        return React.createElement("i", { className: "_3yz6 _5whs img sp_i534r85sjIn sx_896996", src: null, alt: "" });
+      }
+      if (props.x === 152) {
+        return React.createElement("i", { className: "_5b5p _4gem img sp_i534r85sjIn sx_896996", src: null, alt: "" });
+      }
+      if (props.x === 153) {
+        return React.createElement("i", { className: "_541d img sp_i534r85sjIn sx_2f396a", src: null, alt: "" });
+      }
+      if (props.x === 160) {
+        return React.createElement("i", { src: null, alt: "", className: "img sp_i534r85sjIn sx_31d9b0" });
+      }
+      if (props.x === 177) {
+        return React.createElement("i", { alt: "", className: "_3-99 img sp_i534r85sjIn sx_2c18b7", src: null });
+      }
+      if (props.x === 186) {
+        return React.createElement("i", { src: null, alt: "", className: "img sp_i534r85sjIn sx_0a681f" });
+      }
+      if (props.x === 195) {
+        return React.createElement("i", { className: "_1-lx img sp_OkER5ktbEyg sx_b369b4", src: null, alt: "" });
+      }
+      if (props.x === 198) {
+        return React.createElement("i", { className: "_1-lx img sp_i534r85sjIn sx_96948e", src: null, alt: "" });
+      }
+      if (props.x === 237) {
+        return React.createElement("i", { className: "_541d img sp_i534r85sjIn sx_2f396a", src: null, alt: "" });
+      }
+      if (props.x === 266) {
+        return React.createElement("i", { alt: "", className: "_3-99 img sp_i534r85sjIn sx_538591", src: null });
+      }
+      if (props.x === 314) {
+        return React.createElement("i", { className: "_1cie _1cif img sp_i534r85sjIn sx_6e6820", src: null, alt: "" });
+      }
+      if (props.x === 345) {
+        return React.createElement("i", { className: "_1cie img sp_i534r85sjIn sx_e896cf", src: null, alt: "" });
+      }
+      if (props.x === 351) {
+        return React.createElement("i", { className: "_1cie img sp_i534r85sjIn sx_38fed8", src: null, alt: "" });
+      }
+    }
+  });
+
+  var AbstractLink1 = React.createClass({
+    displayName: "AbstractLink1",
+
+    render: function () {
+      var props = this.props;
+      if (props.x === 1) {
+        return React.createElement(
+          "a",
+          { className: "_387r _55pi _2agf _4jy0 _4jy4 _517h _51sy _42ft", style: { "width": 250, "maxWidth": "250px" }, disabled: null, label: null, href: "#", rel: undefined, onClick: function () {} },
+          null,
+          React.createElement(
+            "span",
+            { className: "_55pe", style: { "maxWidth": "236px" } },
+            null,
+            React.createElement(
+              "span",
+              null,
+              React.createElement(
+                "span",
+                { className: "_48u-" },
+                "Account:"
+              ),
+              " ",
+              "Dick Madanson (10149999073643408)"
+            )
+          ),
+          React.createElement(ReactImage0, { x: 0 })
+        );
+      }
+      if (props.x === 43) {
+        return React.createElement(
+          "a",
+          { className: "_585q _50zy _50-0 _50z- _5upp _42ft", size: "medium", shade: "dark", type: null, title: "Remove", "data-hover": undefined, "data-tooltip-alignh": undefined, "data-tooltip-content": undefined, disabled: null, label: null, href: "#", rel: undefined, onClick: function () {} },
+          undefined,
+          "Remove",
+          undefined
+        );
+      }
+      if (props.x === 49) {
+        return React.createElement(
+          "a",
+          { target: "_blank", href: "/ads/manage/billing.php?act=10149999073643408", rel: undefined, onClick: function () {} },
+          React.createElement(XUIText29, { x: 48 })
+        );
+      }
+      if (props.x === 128) {
+        return React.createElement(
+          "a",
+          { className: " _5bbf _55pi _2agf _4jy0 _4jy4 _517h _51sy _42ft", style: { "maxWidth": "200px" }, disabled: null, label: null, href: "#", rel: undefined, onClick: function () {} },
+          null,
+          React.createElement(
+            "span",
+            { className: "_55pe", style: { "maxWidth": "186px" } },
+            React.createElement(ReactImage0, { x: 126 }),
+            "Search"
+          ),
+          React.createElement(ReactImage0, { x: 127 })
+        );
+      }
+      if (props.x === 136) {
+        return React.createElement(
+          "a",
+          { className: " _5bbf _55pi _2agf _4jy0 _4jy4 _517h _51sy _42ft", style: { "maxWidth": "200px" }, disabled: null, label: null, href: "#", rel: undefined, onClick: function () {} },
+          null,
+          React.createElement(
+            "span",
+            { className: "_55pe", style: { "maxWidth": "186px" } },
+            React.createElement(ReactImage0, { x: 134 }),
+            "Filters"
+          ),
+          React.createElement(ReactImage0, { x: 135 })
+        );
+      }
+      if (props.x === 178) {
+        return React.createElement(
+          "a",
+          { className: "_1_-t _1_-v _42ft", disabled: null, height: "medium", role: "button", label: null, href: "#", rel: undefined, onClick: function () {} },
+          undefined,
+          "Lifetime",
+          React.createElement(ReactImage0, { x: 177 })
+        );
+      }
+      if (props.x === 207) {
+        return React.createElement(
+          "a",
+          { href: "#", rel: undefined, onClick: function () {} },
+          "Create Ad Set"
+        );
+      }
+      if (props.x === 209) {
+        return React.createElement(
+          "a",
+          { href: "#", rel: undefined, onClick: function () {} },
+          "View Ad Set"
+        );
+      }
+      if (props.x === 241) {
+        return React.createElement(
+          "a",
+          { href: "#", rel: undefined, onClick: function () {} },
+          "Set a Limit"
+        );
+      }
+      if (props.x === 267) {
+        return React.createElement(
+          "a",
+          { className: "_p _55pi _2agf _4jy0 _4jy3 _517h _51sy _42ft", style: { "maxWidth": "200px" }, disabled: null, label: null, href: "#", rel: undefined, onClick: function () {} },
+          null,
+          React.createElement(
+            "span",
+            { className: "_55pe", style: { "maxWidth": "186px" } },
+            null,
+            "Links"
+          ),
+          React.createElement(ReactImage0, { x: 266 })
+        );
+      }
     }
   });
 
@@ -20,18 +236,37 @@
     displayName: "Link2",
 
     render: function () {
-      return React.createElement(
-        "a",
-        { style: { "maxWidth": "200px" }, image: null, label: null, imageRight: {}, className: "_387r _55pi _2agf _387r _55pi _4jy0 _4jy3 _517h _51sy _42ft", href: "#", haschevron: true, onClick: function () {}, onToggle: function () {}, size: "medium", use: "default", borderShade: "light", suppressed: false, disabled: null, rel: undefined },
-        null,
-        React.createElement(
-          "span",
-          { className: "_55pe", style: { "maxWidth": "186px" } },
-          null,
-          "Dick Madanson (10149999073643408)"
-        ),
-        React.createElement(ReactImage1, null)
-      );
+      var props = this.props;
+      if (props.x === 2) {
+        return React.createElement(AbstractLink1, { x: 1 });
+      }
+      if (props.x === 44) {
+        return React.createElement(AbstractLink1, { x: 43 });
+      }
+      if (props.x === 50) {
+        return React.createElement(AbstractLink1, { x: 49 });
+      }
+      if (props.x === 129) {
+        return React.createElement(AbstractLink1, { x: 128 });
+      }
+      if (props.x === 137) {
+        return React.createElement(AbstractLink1, { x: 136 });
+      }
+      if (props.x === 179) {
+        return React.createElement(AbstractLink1, { x: 178 });
+      }
+      if (props.x === 208) {
+        return React.createElement(AbstractLink1, { x: 207 });
+      }
+      if (props.x === 210) {
+        return React.createElement(AbstractLink1, { x: 209 });
+      }
+      if (props.x === 242) {
+        return React.createElement(AbstractLink1, { x: 241 });
+      }
+      if (props.x === 268) {
+        return React.createElement(AbstractLink1, { x: 267 });
+      }
     }
   });
 
@@ -39,7 +274,226 @@
     displayName: "AbstractButton3",
 
     render: function () {
-      return React.createElement(Link2, null);
+      var props = this.props;
+      if (props.x === 3) {
+        return React.createElement(Link2, { x: 2 });
+      }
+      if (props.x === 20) {
+        return React.createElement(
+          "button",
+          { className: "_5n7z _4jy0 _4jy4 _517h _51sy _42ft", onClick: function () {}, label: null, type: "submit", value: "1" },
+          undefined,
+          "Discard Changes",
+          undefined
+        );
+      }
+      if (props.x === 23) {
+        return React.createElement(
+          "button",
+          { className: "_5n7z _2yak _4lj- _4jy0 _4jy4 _517h _51sy _42ft _42fr", disabled: true, onClick: function () {}, "data-tooltip-content": "You have no changes to publish", "data-hover": "tooltip", label: null, type: "submit", value: "1" },
+          React.createElement(ReactImage0, { x: 22 }),
+          "Review Changes",
+          undefined
+        );
+      }
+      if (props.x === 45) {
+        return React.createElement(Link2, { x: 44 });
+      }
+      if (props.x === 68) {
+        return React.createElement(
+          "button",
+          { className: "_u_k _4jy0 _4jy4 _517h _51sy _42ft", onClick: function () {}, label: null, type: "submit", value: "1" },
+          React.createElement(ReactImage0, { x: 67 }),
+          "Create Campaign",
+          undefined
+        );
+      }
+      if (props.x === 71) {
+        return React.createElement(
+          "button",
+          { className: "_u_k _3qx6 _p _4jy0 _4jy4 _517h _51sy _42ft", label: null, type: "submit", value: "1" },
+          React.createElement(ReactImage0, { x: 70 }),
+          undefined,
+          undefined
+        );
+      }
+      if (props.x === 77) {
+        return React.createElement(
+          "button",
+          { "aria-label": "Edit", "data-tooltip-content": "Edit Campaigns (Ctrl+U)", "data-hover": "tooltip", className: "_d2_ _u_k noMargin _4jy0 _4jy4 _517h _51sy _42ft", disabled: false, onClick: function () {}, label: null, type: "submit", value: "1" },
+          React.createElement(ReactImage0, { x: 76 }),
+          "Edit",
+          undefined
+        );
+      }
+      if (props.x === 80) {
+        return React.createElement(
+          "button",
+          { className: "_u_k _3qx6 _p _4jy0 _4jy4 _517h _51sy _42ft", disabled: false, label: null, type: "submit", value: "1" },
+          React.createElement(ReactImage0, { x: 79 }),
+          undefined,
+          undefined
+        );
+      }
+      if (props.x === 89) {
+        return React.createElement(
+          "button",
+          { "aria-label": "Revert", className: "_u_k _4jy0 _4jy4 _517h _51sy _42ft _42fr", "data-hover": "tooltip", "data-tooltip-content": "Revert", disabled: true, onClick: function () {}, label: null, type: "submit", value: "1" },
+          React.createElement(ReactImage0, { x: 88 }),
+          undefined,
+          undefined
+        );
+      }
+      if (props.x === 92) {
+        return React.createElement(
+          "button",
+          { "aria-label": "Delete", className: "_u_k _4jy0 _4jy4 _517h _51sy _42ft", "data-hover": "tooltip", "data-tooltip-content": "Delete", disabled: false, onClick: function () {}, label: null, type: "submit", value: "1" },
+          React.createElement(ReactImage0, { x: 91 }),
+          undefined,
+          undefined
+        );
+      }
+      if (props.x === 95) {
+        return React.createElement(
+          "button",
+          { "aria-label": "Duplicate", className: "_u_k _4jy0 _4jy4 _517h _51sy _42ft", "data-hover": "tooltip", "data-tooltip-content": "Duplicate", disabled: false, onClick: function () {}, label: null, type: "submit", value: "1" },
+          React.createElement(ReactImage0, { x: 94 }),
+          undefined,
+          undefined
+        );
+      }
+      if (props.x === 99) {
+        return React.createElement(
+          "button",
+          { "aria-label": "Export & Import", className: "_u_k noMargin _p _4jy0 _4jy4 _517h _51sy _42ft", "data-hover": "tooltip", "data-tooltip-content": "Export & Import", onClick: function () {}, label: null, type: "submit", value: "1" },
+          React.createElement(ReactImage0, { x: 98 }),
+          undefined,
+          undefined
+        );
+      }
+      if (props.x === 109) {
+        return React.createElement(
+          "button",
+          { "aria-label": "Create Report", className: "_u_k _5n7z _4jy0 _4jy4 _517h _51sy _42ft", "data-hover": "tooltip", "data-tooltip-content": "Create Report", disabled: false, style: { "boxSizing": "border-box", "height": "28px", "width": "48px" }, onClick: function () {}, label: null, type: "submit", value: "1" },
+          React.createElement(ReactImage0, { x: 108 }),
+          undefined,
+          undefined
+        );
+      }
+      if (props.x === 112) {
+        return React.createElement(
+          "button",
+          { "aria-label": "Campaign Tags", className: " _5uy7 _4jy0 _4jy4 _517h _51sy _42ft", "data-hover": "tooltip", "data-tooltip-content": "Campaign Tags", disabled: false, haschevron: false, onClick: function () {}, label: null, type: "submit", value: "1" },
+          React.createElement(ReactImage0, { x: 111 }),
+          undefined,
+          undefined
+        );
+      }
+      if (props.x === 130) {
+        return React.createElement(Link2, { x: 129 });
+      }
+      if (props.x === 138) {
+        return React.createElement(Link2, { x: 137 });
+      }
+      if (props.x === 149) {
+        return React.createElement(
+          "button",
+          { className: "_3yz9 _1t-2 _50z- _50zy _50zz _50z- _5upp _42ft", size: "small", onClick: function () {}, shade: "dark", type: "button", title: "Remove", "data-hover": undefined, "data-tooltip-alignh": undefined, "data-tooltip-content": undefined, label: null },
+          undefined,
+          "Remove",
+          undefined
+        );
+      }
+      if (props.x === 156) {
+        return React.createElement(
+          "button",
+          { className: "_5b5u _5b5v _4jy0 _4jy3 _517h _51sy _42ft", onClick: function () {}, label: null, type: "submit", value: "1" },
+          undefined,
+          "Apply",
+          undefined
+        );
+      }
+      if (props.x === 161) {
+        return React.createElement(
+          "button",
+          { className: "_1wdf _4jy0 _517i _517h _51sy _42ft", onClick: function () {}, label: null, type: "submit", value: "1" },
+          React.createElement(ReactImage0, { x: 160 }),
+          undefined,
+          undefined
+        );
+      }
+      if (props.x === 180) {
+        return React.createElement(Link2, { x: 179 });
+      }
+      if (props.x === 187) {
+        return React.createElement(
+          "button",
+          { "aria-label": "List Settings", className: "_u_k _3c5o _1-r0 _4jy0 _4jy4 _517h _51sy _42ft", "data-hover": "tooltip", "data-tooltip-content": "List Settings", onClick: function () {}, label: null, type: "submit", value: "1" },
+          React.createElement(ReactImage0, { x: 186 }),
+          undefined,
+          undefined
+        );
+      }
+      if (props.x === 269) {
+        return React.createElement(Link2, { x: 268 });
+      }
+      if (props.x === 303) {
+        return React.createElement(
+          "button",
+          { className: "_tm3 _tm6 _tm7 _4jy0 _4jy6 _517h _51sy _42ft", "data-tooltip-position": "right", "data-tooltip-content": "Campaigns", "data-hover": "tooltip", onClick: function () {}, label: null, type: "submit", value: "1" },
+          undefined,
+          React.createElement(
+            "div",
+            null,
+            React.createElement("div", { className: "_tma" }),
+            React.createElement("div", { className: "_tm8" }),
+            React.createElement(
+              "div",
+              { className: "_tm9" },
+              1
+            )
+          ),
+          undefined
+        );
+      }
+      if (props.x === 305) {
+        return React.createElement(
+          "button",
+          { className: "_tm4 _tm6 _4jy0 _4jy6 _517h _51sy _42ft", "data-tooltip-position": "right", "data-tooltip-content": "Ad Sets", "data-hover": "tooltip", onClick: function () {}, label: null, type: "submit", value: "1" },
+          undefined,
+          React.createElement(
+            "div",
+            null,
+            React.createElement("div", { className: "_tma" }),
+            React.createElement("div", { className: "_tm8" }),
+            React.createElement(
+              "div",
+              { className: "_tm9" },
+              1
+            )
+          ),
+          undefined
+        );
+      }
+      if (props.x === 307) {
+        return React.createElement(
+          "button",
+          { className: "_tm5 _tm6 _4jy0 _4jy6 _517h _51sy _42ft", "data-tooltip-position": "right", "data-tooltip-content": "Ads", "data-hover": "tooltip", onClick: function () {}, label: null, type: "submit", value: "1" },
+          undefined,
+          React.createElement(
+            "div",
+            null,
+            React.createElement("div", { className: "_tma" }),
+            React.createElement("div", { className: "_tm8" }),
+            React.createElement(
+              "div",
+              { className: "_tm9" },
+              1
+            )
+          ),
+          undefined
+        );
+      }
     }
   });
 
@@ -47,7 +501,73 @@
     displayName: "XUIButton4",
 
     render: function () {
-      return React.createElement(AbstractButton3, null);
+      var props = this.props;
+      if (props.x === 4) {
+        return React.createElement(AbstractButton3, { x: 3 });
+      }
+      if (props.x === 21) {
+        return React.createElement(AbstractButton3, { x: 20 });
+      }
+      if (props.x === 24) {
+        return React.createElement(AbstractButton3, { x: 23 });
+      }
+      if (props.x === 69) {
+        return React.createElement(AbstractButton3, { x: 68 });
+      }
+      if (props.x === 72) {
+        return React.createElement(AbstractButton3, { x: 71 });
+      }
+      if (props.x === 78) {
+        return React.createElement(AbstractButton3, { x: 77 });
+      }
+      if (props.x === 81) {
+        return React.createElement(AbstractButton3, { x: 80 });
+      }
+      if (props.x === 90) {
+        return React.createElement(AbstractButton3, { x: 89 });
+      }
+      if (props.x === 93) {
+        return React.createElement(AbstractButton3, { x: 92 });
+      }
+      if (props.x === 96) {
+        return React.createElement(AbstractButton3, { x: 95 });
+      }
+      if (props.x === 100) {
+        return React.createElement(AbstractButton3, { x: 99 });
+      }
+      if (props.x === 110) {
+        return React.createElement(AbstractButton3, { x: 109 });
+      }
+      if (props.x === 113) {
+        return React.createElement(AbstractButton3, { x: 112 });
+      }
+      if (props.x === 131) {
+        return React.createElement(AbstractButton3, { x: 130 });
+      }
+      if (props.x === 139) {
+        return React.createElement(AbstractButton3, { x: 138 });
+      }
+      if (props.x === 157) {
+        return React.createElement(AbstractButton3, { x: 156 });
+      }
+      if (props.x === 162) {
+        return React.createElement(AbstractButton3, { x: 161 });
+      }
+      if (props.x === 188) {
+        return React.createElement(AbstractButton3, { x: 187 });
+      }
+      if (props.x === 270) {
+        return React.createElement(AbstractButton3, { x: 269 });
+      }
+      if (props.x === 304) {
+        return React.createElement(AbstractButton3, { x: 303 });
+      }
+      if (props.x === 306) {
+        return React.createElement(AbstractButton3, { x: 305 });
+      }
+      if (props.x === 308) {
+        return React.createElement(AbstractButton3, { x: 307 });
+      }
     }
   });
 
@@ -55,7 +575,19 @@
     displayName: "AbstractPopoverButton5",
 
     render: function () {
-      return React.createElement(XUIButton4, null);
+      var props = this.props;
+      if (props.x === 5) {
+        return React.createElement(XUIButton4, { x: 4 });
+      }
+      if (props.x === 132) {
+        return React.createElement(XUIButton4, { x: 131 });
+      }
+      if (props.x === 140) {
+        return React.createElement(XUIButton4, { x: 139 });
+      }
+      if (props.x === 271) {
+        return React.createElement(XUIButton4, { x: 270 });
+      }
     }
   });
 
@@ -63,8938 +595,4506 @@
     displayName: "ReactXUIPopoverButton6",
 
     render: function () {
-      return React.createElement(AbstractPopoverButton5, null);
-    }
-  });
-
-  var AdsPEAccountSelector7 = React.createClass({
-    displayName: "AdsPEAccountSelector7",
-
-    render: function () {
-      return React.createElement(ReactXUIPopoverButton6, { ref: "button" });
-    }
-  });
-
-  var AdsPEAccountSelectorContainer8 = React.createClass({
-    displayName: "AdsPEAccountSelectorContainer8",
-
-    render: function () {
-      return React.createElement(AdsPEAccountSelector7, null);
-    }
-  });
-
-  var AbstractButton9 = React.createClass({
-    displayName: "AbstractButton9",
-
-    render: function () {
-      return React.createElement(
-        "button",
-        { id: "downloadButton", className: "_5lk0 _4jy0 _4jy3 _517h _51sy _42ft", label: null, onClick: function () {}, use: "default", size: "medium", borderShade: "light", suppressed: false, type: "submit", value: "1" },
-        undefined,
-        "Download to Power Editor",
-        undefined
-      );
-    }
-  });
-
-  var XUIButton10 = React.createClass({
-    displayName: "XUIButton10",
-
-    render: function () {
-      return React.createElement(AbstractButton9, null);
-    }
-  });
-
-  var DownloadUploadTimestamp11 = React.createClass({
-    displayName: "DownloadUploadTimestamp11",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        null,
-        "Last downloaded",
-        " ",
-        React.createElement(
-          "abbr",
-          { className: "livetimestamp", "data-utime": 1446062352, "data-shorten": false },
-          "a few seconds ago"
-        )
-      );
-    }
-  });
-
-  var ReactImage12 = React.createClass({
-    displayName: "ReactImage12",
-
-    render: function () {
-      return React.createElement("i", { alt: "", className: "_3-8_ img sp_UuU9HmrQ397 sx_dbc06a", src: null });
-    }
-  });
-
-  var AbstractButton13 = React.createClass({
-    displayName: "AbstractButton13",
-
-    render: function () {
-      return React.createElement(
-        "button",
-        { id: "uploadButton", className: "_5lk0 _4jy0 _4jy3 _517h _51sy _42ft", image: {}, use: "default", label: null, onClick: function () {}, size: "medium", borderShade: "light", suppressed: false, type: "submit", value: "1" },
-        React.createElement(ReactImage12, null),
-        "Upload Changes",
-        undefined
-      );
-    }
-  });
-
-  var XUIButton14 = React.createClass({
-    displayName: "XUIButton14",
-
-    render: function () {
-      return React.createElement(AbstractButton13, null);
+      var props = this.props;
+      if (props.x === 6) {
+        return React.createElement(AbstractPopoverButton5, { x: 5 });
+      }
+      if (props.x === 133) {
+        return React.createElement(AbstractPopoverButton5, { x: 132 });
+      }
+      if (props.x === 141) {
+        return React.createElement(AbstractPopoverButton5, { x: 140 });
+      }
+      if (props.x === 272) {
+        return React.createElement(AbstractPopoverButton5, { x: 271 });
+      }
     }
   });
 
-  var DownloadUploadTimestamp15 = React.createClass({
-    displayName: "DownloadUploadTimestamp15",
+  var BIGAdAccountSelector7 = React.createClass({
+    displayName: "BIGAdAccountSelector7",
 
     render: function () {
-      return React.createElement("div", null);
-    }
-  });
-
-  var AbstractButton16 = React.createClass({
-    displayName: "AbstractButton16",
-
-    render: function () {
-      return React.createElement(
-        "button",
-        { className: "_5ljz _4jy0 _4jy3 _517h _51sy _42ft", label: null, onClick: function () {}, use: "default", size: "medium", borderShade: "light", suppressed: false, type: "submit", value: "1" },
-        undefined,
-        "Help",
-        undefined
-      );
-    }
-  });
-
-  var XUIButton17 = React.createClass({
-    displayName: "XUIButton17",
-
-    render: function () {
-      return React.createElement(AbstractButton16, null);
+      var props = this.props;
+      if (props.x === 7) {
+        return React.createElement(
+          "div",
+          null,
+          React.createElement(ReactXUIPopoverButton6, { x: 6, ref: "openMenuButton" }),
+          null
+        );
+      }
+    }
+  });
+
+  var FluxContainer_AdsPEBIGAdAccountSelectorContainer_8 = React.createClass({
+    displayName: "FluxContainer_AdsPEBIGAdAccountSelectorContainer_8",
+
+    render: function () {
+      var props = this.props;
+      if (props.x === 8) {
+        return React.createElement(BIGAdAccountSelector7, { x: 7 });
+      }
+    }
+  });
+
+  var ErrorBoundary9 = React.createClass({
+    displayName: "ErrorBoundary9",
+
+    render: function () {
+      var props = this.props;
+      if (props.x === 9) {
+        return React.createElement(FluxContainer_AdsPEBIGAdAccountSelectorContainer_8, { x: 8 });
+      }
+      if (props.x === 13) {
+        return React.createElement(FluxContainer_AdsPENavigationBarContainer_12, { x: 12 });
+      }
+      if (props.x === 27) {
+        return React.createElement(FluxContainer_AdsPEPublishButtonContainer_18, { x: 26 });
+      }
+      if (props.x === 32) {
+        return React.createElement(ReactPopoverMenu20, { x: 31 });
+      }
+      if (props.x === 38) {
+        return React.createElement(AdsPEResetDialog24, { x: 37 });
+      }
+      if (props.x === 57) {
+        return React.createElement(FluxContainer_AdsPETopErrorContainer_35, { x: 56 });
+      }
+      if (props.x === 60) {
+        return React.createElement(FluxContainer_AdsGuidanceChannel_36, { x: 59 });
+      }
+      if (props.x === 64) {
+        return React.createElement(FluxContainer_AdsBulkEditDialogContainer_38, { x: 63 });
+      }
+      if (props.x === 124) {
+        return React.createElement(AdsPECampaignGroupToolbarContainer57, { x: 123 });
+      }
+      if (props.x === 170) {
+        return React.createElement(AdsPEFilterContainer72, { x: 169 });
+      }
+      if (props.x === 175) {
+        return React.createElement(AdsPETablePagerContainer75, { x: 174 });
+      }
+      if (props.x === 193) {
+        return React.createElement(AdsPEStatRangeContainer81, { x: 192 });
+      }
+      if (props.x === 301) {
+        return React.createElement(FluxContainer_AdsPEMultiTabDrawerContainer_137, { x: 300 });
+      }
+      if (props.x === 311) {
+        return React.createElement(AdsPEOrganizerContainer139, { x: 310 });
+      }
+      if (props.x === 471) {
+        return React.createElement(AdsPECampaignGroupTableContainer159, { x: 470 });
+      }
+      if (props.x === 475) {
+        return React.createElement(AdsPEContentContainer161, { x: 474 });
+      }
+    }
+  });
+
+  var AdsErrorBoundary10 = React.createClass({
+    displayName: "AdsErrorBoundary10",
+
+    render: function () {
+      var props = this.props;
+      if (props.x === 10) {
+        return React.createElement(ErrorBoundary9, { x: 9 });
+      }
+      if (props.x === 14) {
+        return React.createElement(ErrorBoundary9, { x: 13 });
+      }
+      if (props.x === 28) {
+        return React.createElement(ErrorBoundary9, { x: 27 });
+      }
+      if (props.x === 33) {
+        return React.createElement(ErrorBoundary9, { x: 32 });
+      }
+      if (props.x === 39) {
+        return React.createElement(ErrorBoundary9, { x: 38 });
+      }
+      if (props.x === 58) {
+        return React.createElement(ErrorBoundary9, { x: 57 });
+      }
+      if (props.x === 61) {
+        return React.createElement(ErrorBoundary9, { x: 60 });
+      }
+      if (props.x === 65) {
+        return React.createElement(ErrorBoundary9, { x: 64 });
+      }
+      if (props.x === 125) {
+        return React.createElement(ErrorBoundary9, { x: 124 });
+      }
+      if (props.x === 171) {
+        return React.createElement(ErrorBoundary9, { x: 170 });
+      }
+      if (props.x === 176) {
+        return React.createElement(ErrorBoundary9, { x: 175 });
+      }
+      if (props.x === 194) {
+        return React.createElement(ErrorBoundary9, { x: 193 });
+      }
+      if (props.x === 302) {
+        return React.createElement(ErrorBoundary9, { x: 301 });
+      }
+      if (props.x === 312) {
+        return React.createElement(ErrorBoundary9, { x: 311 });
+      }
+      if (props.x === 472) {
+        return React.createElement(ErrorBoundary9, { x: 471 });
+      }
+      if (props.x === 476) {
+        return React.createElement(ErrorBoundary9, { x: 475 });
+      }
+    }
+  });
+
+  var AdsPENavigationBar11 = React.createClass({
+    displayName: "AdsPENavigationBar11",
+
+    render: function () {
+      var props = this.props;
+      if (props.x === 11) {
+        return React.createElement("div", { className: "_4t_9" });
+      }
+    }
+  });
+
+  var FluxContainer_AdsPENavigationBarContainer_12 = React.createClass({
+    displayName: "FluxContainer_AdsPENavigationBarContainer_12",
+
+    render: function () {
+      var props = this.props;
+      if (props.x === 12) {
+        return React.createElement(AdsPENavigationBar11, { x: 11 });
+      }
+    }
+  });
+
+  var AdsPEDraftSyncStatus13 = React.createClass({
+    displayName: "AdsPEDraftSyncStatus13",
+
+    render: function () {
+      var props = this.props;
+      if (props.x === 16) {
+        return React.createElement(
+          "div",
+          { className: "_3ut-", onClick: function () {} },
+          React.createElement(
+            "span",
+            { className: "_3uu0" },
+            React.createElement(ReactImage0, { x: 15 })
+          )
+        );
+      }
     }
   });
 
-  var ReactImage18 = React.createClass({
-    displayName: "ReactImage18",
+  var FluxContainer_AdsPEDraftSyncStatusContainer_14 = React.createClass({
+    displayName: "FluxContainer_AdsPEDraftSyncStatusContainer_14",
 
     render: function () {
-      return React.createElement("i", { src: null, className: "img sp_UuU9HmrQ397 sx_d5a685" });
+      var props = this.props;
+      if (props.x === 17) {
+        return React.createElement(AdsPEDraftSyncStatus13, { x: 16 });
+      }
     }
   });
 
-  var AbstractButton19 = React.createClass({
-    displayName: "AbstractButton19",
+  var AdsPEDraftErrorsStatus15 = React.createClass({
+    displayName: "AdsPEDraftErrorsStatus15",
 
     render: function () {
-      return React.createElement(
-        "button",
-        { className: "_5ljw _p _4jy0 _4jy3 _517h _51sy _42ft", image: {}, use: "default", size: "medium", borderShade: "light", suppressed: false, label: null, type: "submit", value: "1" },
-        React.createElement(ReactImage18, null),
-        undefined,
-        undefined
-      );
+      var props = this.props;
+      if (props.x === 18) {
+        return null;
+      }
     }
   });
 
-  var XUIButton20 = React.createClass({
-    displayName: "XUIButton20",
+  var FluxContainer_viewFn_16 = React.createClass({
+    displayName: "FluxContainer_viewFn_16",
 
     render: function () {
-      return React.createElement(AbstractButton19, null);
+      var props = this.props;
+      if (props.x === 19) {
+        return React.createElement(AdsPEDraftErrorsStatus15, { x: 18 });
+      }
     }
   });
 
-  var InlineBlock21 = React.createClass({
-    displayName: "InlineBlock21",
+  var AdsPEPublishButton17 = React.createClass({
+    displayName: "AdsPEPublishButton17",
 
     render: function () {
-      return React.createElement(
-        "div",
-        { className: "_5ljz uiPopover _6a _6b", alignh: "right", menu: {}, alignv: "middle", disabled: null, fullWidth: false },
-        React.createElement(XUIButton20, { key: "/.0" })
-      );
+      var props = this.props;
+      if (props.x === 25) {
+        return React.createElement(
+          "div",
+          { className: "_5533" },
+          React.createElement(FluxContainer_AdsPEDraftSyncStatusContainer_14, { x: 17 }),
+          React.createElement(FluxContainer_viewFn_16, { x: 19 }),
+          null,
+          React.createElement(XUIButton4, { x: 21, key: "discard" }),
+          React.createElement(XUIButton4, { x: 24, ref: "reviewChangesButton" })
+        );
+      }
     }
   });
 
-  var ReactPopoverMenu22 = React.createClass({
-    displayName: "ReactPopoverMenu22",
+  var FluxContainer_AdsPEPublishButtonContainer_18 = React.createClass({
+    displayName: "FluxContainer_AdsPEPublishButtonContainer_18",
 
     render: function () {
-      return React.createElement(InlineBlock21, { ref: "root" });
+      var props = this.props;
+      if (props.x === 26) {
+        return React.createElement(AdsPEPublishButton17, { x: 25 });
+      }
     }
   });
 
-  var XUIButtonGroup23 = React.createClass({
-    displayName: "XUIButtonGroup23",
+  var InlineBlock19 = React.createClass({
+    displayName: "InlineBlock19",
 
     render: function () {
-      return React.createElement(
-        "div",
-        { className: "_13xj _51xa", id: "helpButton" },
-        React.createElement(XUIButton17, null),
-        React.createElement(ReactPopoverMenu22, null)
-      );
+      var props = this.props;
+      if (props.x === 30) {
+        return React.createElement(
+          "div",
+          { className: "uiPopover _6a _6b", disabled: null },
+          React.createElement(ReactImage0, { x: 29, key: ".0" })
+        );
+      }
+      if (props.x === 73) {
+        return React.createElement(
+          "div",
+          { className: "uiPopover _6a _6b", disabled: null },
+          React.createElement(XUIButton4, { x: 72, key: ".0" })
+        );
+      }
+      if (props.x === 82) {
+        return React.createElement(
+          "div",
+          { className: "_1nwm uiPopover _6a _6b", disabled: null },
+          React.createElement(XUIButton4, { x: 81, key: ".0" })
+        );
+      }
+      if (props.x === 101) {
+        return React.createElement(
+          "div",
+          { size: "large", className: "uiPopover _6a _6b", disabled: null },
+          React.createElement(XUIButton4, { x: 100, key: ".0" })
+        );
+      }
+      if (props.x === 273) {
+        return React.createElement(
+          "div",
+          { className: "_3-90 uiPopover _6a _6b", style: { "marginTop": 2 }, disabled: null },
+          React.createElement(ReactXUIPopoverButton6, { x: 272, key: ".0" })
+        );
+      }
     }
   });
 
-  var AdsPEResetDialog24 = React.createClass({
-    displayName: "AdsPEResetDialog24",
+  var ReactPopoverMenu20 = React.createClass({
+    displayName: "ReactPopoverMenu20",
 
     render: function () {
-      return React.createElement("span", null);
+      var props = this.props;
+      if (props.x === 31) {
+        return React.createElement(InlineBlock19, { x: 30, ref: "root" });
+      }
+      if (props.x === 74) {
+        return React.createElement(InlineBlock19, { x: 73, ref: "root" });
+      }
+      if (props.x === 83) {
+        return React.createElement(InlineBlock19, { x: 82, ref: "root" });
+      }
+      if (props.x === 102) {
+        return React.createElement(InlineBlock19, { x: 101, ref: "root" });
+      }
+      if (props.x === 274) {
+        return React.createElement(InlineBlock19, { x: 273, ref: "root" });
+      }
     }
   });
 
-  var AdsPETopNav25 = React.createClass({
-    displayName: "AdsPETopNav25",
+  var LeftRight21 = React.createClass({
+    displayName: "LeftRight21",
 
     render: function () {
-      return React.createElement(
-        "div",
-        { className: "_5ljl", id: "ads_pe_top_nav" },
-        React.createElement(
+      var props = this.props;
+      if (props.x === 34) {
+        return React.createElement(
           "div",
-          { ref: "logo", className: "_5ljm" },
-          React.createElement(Link0, null),
+          { className: "clearfix" },
           React.createElement(
             "div",
-            { className: "_5rne" },
+            { key: "left", className: "_ohe lfloat" },
             React.createElement(
-              "span",
-              { className: "_5ljs", "data-testid": "PETopNavLogoText" },
-              "Power Editor"
+              "div",
+              { className: "_34_j" },
+              React.createElement(
+                "div",
+                { className: "_34_k" },
+                React.createElement(AdsErrorBoundary10, { x: 10 })
+              ),
+              React.createElement(
+                "div",
+                { className: "_2u-6" },
+                React.createElement(AdsErrorBoundary10, { x: 14 })
+              )
             )
           ),
           React.createElement(
-            "span",
-            { className: "_5ljt _5lju" },
-            "Dick Madanson"
+            "div",
+            { key: "right", className: "_ohf rfloat" },
+            React.createElement(
+              "div",
+              { className: "_34_m" },
+              React.createElement(
+                "div",
+                { key: "0", className: "_5ju2" },
+                React.createElement(AdsErrorBoundary10, { x: 28 })
+              ),
+              React.createElement(
+                "div",
+                { key: "1", className: "_5ju2" },
+                React.createElement(AdsErrorBoundary10, { x: 33 })
+              )
+            )
           )
-        ),
-        React.createElement(
+        );
+      }
+      if (props.x === 232) {
+        return React.createElement(
           "div",
-          { ref: "leftButtonGroup", className: "_5ljy" },
+          { flex: "right", direction: "left", className: "clearfix" },
           React.createElement(
             "div",
-            { ref: "accountDropdown", className: "_5ljz _5mun" },
-            React.createElement(AdsPEAccountSelectorContainer8, null),
+            { key: "left", className: "_ohe lfloat" },
+            React.createElement(AdsLabeledField104, { x: 231 })
+          ),
+          React.createElement(
+            "div",
+            { key: "right", className: "" },
             React.createElement(
               "div",
-              { className: "_5lj- _5lju" },
-              "Account 10149999073643408"
+              { className: "_42ef" },
+              React.createElement(
+                "div",
+                { className: "_2oc7" },
+                "Clicks to Website"
+              )
             )
+          )
+        );
+      }
+      if (props.x === 235) {
+        return React.createElement(
+          "div",
+          { className: "_3-8x clearfix", flex: "right", direction: "left" },
+          React.createElement(
+            "div",
+            { key: "left", className: "_ohe lfloat" },
+            React.createElement(AdsLabeledField104, { x: 234 })
           ),
           React.createElement(
             "div",
-            { className: "_5ljz" },
-            React.createElement(
-              "div",
-              { className: "_5lj_" },
-              React.createElement(XUIButton10, null)
-            ),
+            { key: "right", className: "" },
             React.createElement(
               "div",
-              { className: "_5lj- _5lju" },
-              React.createElement(DownloadUploadTimestamp11, null)
+              { className: "_42ef" },
+              React.createElement(
+                "div",
+                { className: "_2oc7" },
+                "Auction"
+              )
             )
+          )
+        );
+      }
+      if (props.x === 245) {
+        return React.createElement(
+          "div",
+          { className: "_3-8y clearfix", flex: "right", direction: "left" },
+          React.createElement(
+            "div",
+            { key: "left", className: "_ohe lfloat" },
+            React.createElement(AdsLabeledField104, { x: 240 })
           ),
           React.createElement(
             "div",
-            { className: "_5ljz" },
+            { key: "right", className: "" },
             React.createElement(
               "div",
-              { className: "_5lj_" },
-              React.createElement(XUIButton14, null)
-            ),
-            React.createElement(
-              "div",
-              { className: "_5lj- _5lju" },
-              React.createElement(DownloadUploadTimestamp15, null)
+              { className: "_42ef" },
+              React.createElement(FluxContainer_AdsCampaignGroupSpendCapContainer_107, { x: 244 })
             )
           )
-        ),
-        React.createElement(
+        );
+      }
+      if (props.x === 277) {
+        return React.createElement(
           "div",
-          { ref: "rightButtonGroup", className: "_5lk3" },
-          React.createElement(XUIButtonGroup23, null)
-        ),
-        React.createElement(AdsPEResetDialog24, null)
-      );
-    }
-  });
-
-  var FluxContainer_ja_26 = React.createClass({
-    displayName: "FluxContainer_ja_26",
-
-    render: function () {
-      return React.createElement(AdsPETopNav25, null);
-    }
-  });
-
-  var _wrapper27 = React.createClass({
-    displayName: "_wrapper27",
-
-    render: function () {
-      return React.createElement(
-        "li",
-        { selected: true, focused: false, tabIndex: null, hideFocusRing: true, onClick: function () {}, onMouseDown: function () {}, onFocus: function () {}, onBlur: function () {}, className: "_5vwz _5vwy _45hc _1hqh", wrapper: function () {}, shouldWrapTab: true, mockSpacebarClick: true, role: "presentation" },
-        React.createElement(
-          "a",
-          { ref: "tab", ajaxify: undefined, href: "#", role: "tab", rel: undefined, target: undefined, tabIndex: 0, className: "", "aria-selected": true, onKeyDown: function () {} },
+          { className: "_5dw9 _5dwa clearfix" },
           React.createElement(
             "div",
-            { className: "_4jq5" },
-            "Manage Ads"
+            { key: "left", className: "_ohe lfloat" },
+            React.createElement(XUICardHeaderTitle100, { x: 265, key: ".0" })
           ),
-          React.createElement("span", { className: "_13xf" })
-        )
-      );
+          React.createElement(
+            "div",
+            { key: "right", className: "_ohf rfloat" },
+            React.createElement(FluxContainer_AdsPluginizedLinksMenuContainer_121, { x: 276, key: ".1" })
+          )
+        );
+      }
     }
   });
 
-  var TabBarItem28 = React.createClass({
-    displayName: "TabBarItem28",
+  var AdsUnifiedNavigationLocalNav22 = React.createClass({
+    displayName: "AdsUnifiedNavigationLocalNav22",
 
     render: function () {
-      return React.createElement(_wrapper27, null);
+      var props = this.props;
+      if (props.x === 35) {
+        return React.createElement(
+          "div",
+          { className: "_34_i" },
+          React.createElement(LeftRight21, { x: 34 })
+        );
+      }
     }
   });
 
-  var XUIPageNavigationItem29 = React.createClass({
-    displayName: "XUIPageNavigationItem29",
+  var XUIDialog23 = React.createClass({
+    displayName: "XUIDialog23",
 
     render: function () {
-      return React.createElement(TabBarItem28, null);
+      var props = this.props;
+      if (props.x === 36) {
+        return null;
+      }
     }
   });
 
-  var TabBarItemWrapper30 = React.createClass({
-    displayName: "TabBarItemWrapper30",
+  var AdsPEResetDialog24 = React.createClass({
+    displayName: "AdsPEResetDialog24",
 
     render: function () {
-      return React.createElement(XUIPageNavigationItem29, { key: "MANAGE_ADS" });
+      var props = this.props;
+      if (props.x === 37) {
+        return React.createElement(
+          "span",
+          null,
+          React.createElement(XUIDialog23, { x: 36, key: "dialog/.0" })
+        );
+      }
     }
   });
 
-  var _wrapper31 = React.createClass({
-    displayName: "_wrapper31",
+  var AdsPETopNav25 = React.createClass({
+    displayName: "AdsPETopNav25",
 
     render: function () {
-      return React.createElement(
-        "li",
-        { selected: false, focused: false, tabIndex: null, hideFocusRing: true, onClick: function () {}, onMouseDown: function () {}, onFocus: function () {}, onBlur: function () {}, className: "_5vwz _45hc", wrapper: function () {}, shouldWrapTab: true, mockSpacebarClick: true, role: "presentation" },
-        React.createElement(
-          "a",
-          { ref: "tab", ajaxify: undefined, href: "#", role: "tab", rel: undefined, target: undefined, tabIndex: -1, className: "", "aria-selected": false, onKeyDown: function () {} },
-          React.createElement(
-            "div",
-            { className: "_4jq5" },
-            "Audiences"
-          ),
-          React.createElement("span", { className: "_13xf" })
-        )
-      );
+      var props = this.props;
+      if (props.x === 40) {
+        return React.createElement(
+          "div",
+          { style: { "width": 1306 } },
+          React.createElement(AdsUnifiedNavigationLocalNav22, { x: 35 }),
+          React.createElement(AdsErrorBoundary10, { x: 39 })
+        );
+      }
     }
   });
 
-  var TabBarItem32 = React.createClass({
-    displayName: "TabBarItem32",
+  var FluxContainer_AdsPETopNavContainer_26 = React.createClass({
+    displayName: "FluxContainer_AdsPETopNavContainer_26",
 
     render: function () {
-      return React.createElement(_wrapper31, null);
+      var props = this.props;
+      if (props.x === 41) {
+        return React.createElement(AdsPETopNav25, { x: 40 });
+      }
     }
   });
 
-  var XUIPageNavigationItem33 = React.createClass({
-    displayName: "XUIPageNavigationItem33",
+  var XUIAbstractGlyphButton27 = React.createClass({
+    displayName: "XUIAbstractGlyphButton27",
 
     render: function () {
-      return React.createElement(TabBarItem32, null);
+      var props = this.props;
+      if (props.x === 46) {
+        return React.createElement(AbstractButton3, { x: 45 });
+      }
+      if (props.x === 150) {
+        return React.createElement(AbstractButton3, { x: 149 });
+      }
     }
   });
 
-  var TabBarItemWrapper34 = React.createClass({
-    displayName: "TabBarItemWrapper34",
+  var XUICloseButton28 = React.createClass({
+    displayName: "XUICloseButton28",
 
     render: function () {
-      return React.createElement(XUIPageNavigationItem33, { key: "AUDIENCES" });
+      var props = this.props;
+      if (props.x === 47) {
+        return React.createElement(XUIAbstractGlyphButton27, { x: 46 });
+      }
+      if (props.x === 151) {
+        return React.createElement(XUIAbstractGlyphButton27, { x: 150 });
+      }
     }
   });
 
-  var _wrapper35 = React.createClass({
-    displayName: "_wrapper35",
+  var XUIText29 = React.createClass({
+    displayName: "XUIText29",
 
     render: function () {
-      return React.createElement(
-        "li",
-        { selected: false, focused: false, tabIndex: null, hideFocusRing: true, onClick: function () {}, onMouseDown: function () {}, onFocus: function () {}, onBlur: function () {}, className: "_5vwz _45hc", wrapper: function () {}, shouldWrapTab: true, mockSpacebarClick: true, role: "presentation" },
-        React.createElement(
-          "a",
-          { ref: "tab", ajaxify: undefined, href: "#", role: "tab", rel: undefined, target: undefined, tabIndex: -1, className: "", "aria-selected": false, onKeyDown: function () {} },
-          React.createElement(
-            "div",
-            { className: "_4jq5" },
-            "Image Library"
-          ),
-          React.createElement("span", { className: "_13xf" })
-        )
-      );
+      var props = this.props;
+      if (props.x === 48) {
+        return React.createElement(
+          "span",
+          { display: "inline", className: " _50f7" },
+          "Ads Manager"
+        );
+      }
+      if (props.x === 205) {
+        return React.createElement(
+          "span",
+          { className: "_2x9f  _50f5 _50f7", display: "inline" },
+          "Editing Campaign"
+        );
+      }
+      if (props.x === 206) {
+        return React.createElement(
+          "span",
+          { display: "inline", className: " _50f5 _50f7" },
+          "Test Campaign"
+        );
+      }
     }
   });
 
-  var TabBarItem36 = React.createClass({
-    displayName: "TabBarItem36",
+  var XUINotice30 = React.createClass({
+    displayName: "XUINotice30",
 
     render: function () {
-      return React.createElement(_wrapper35, null);
+      var props = this.props;
+      if (props.x === 51) {
+        return React.createElement(
+          "div",
+          { size: "medium", className: "_585n _585o _2wdd" },
+          React.createElement(ReactImage0, { x: 42 }),
+          React.createElement(XUICloseButton28, { x: 47 }),
+          React.createElement(
+            "div",
+            { className: "_585r _2i-a _50f4" },
+            "Please go to ",
+            React.createElement(Link2, { x: 50 }),
+            " to set up a payment method for this ad account."
+          )
+        );
+      }
     }
   });
 
-  var XUIPageNavigationItem37 = React.createClass({
-    displayName: "XUIPageNavigationItem37",
+  var ReactCSSTransitionGroupChild31 = React.createClass({
+    displayName: "ReactCSSTransitionGroupChild31",
 
     render: function () {
-      return React.createElement(TabBarItem36, null);
+      var props = this.props;
+      if (props.x === 52) {
+        return React.createElement(XUINotice30, { x: 51 });
+      }
     }
   });
 
-  var TabBarItemWrapper38 = React.createClass({
-    displayName: "TabBarItemWrapper38",
+  var ReactTransitionGroup32 = React.createClass({
+    displayName: "ReactTransitionGroup32",
 
     render: function () {
-      return React.createElement(XUIPageNavigationItem37, { key: "IMAGES" });
+      var props = this.props;
+      if (props.x === 53) {
+        return React.createElement(
+          "span",
+          null,
+          React.createElement(ReactCSSTransitionGroupChild31, { x: 52, key: ".0", ref: ".0" })
+        );
+      }
     }
   });
 
-  var _wrapper39 = React.createClass({
-    displayName: "_wrapper39",
+  var ReactCSSTransitionGroup33 = React.createClass({
+    displayName: "ReactCSSTransitionGroup33",
 
     render: function () {
-      return React.createElement(
-        "li",
-        { selected: false, focused: false, tabIndex: null, hideFocusRing: true, onClick: function () {}, onMouseDown: function () {}, onFocus: function () {}, onBlur: function () {}, className: "_5vwz _45hc", wrapper: function () {}, shouldWrapTab: true, mockSpacebarClick: true, role: "presentation" },
-        React.createElement(
-          "a",
-          { ref: "tab", ajaxify: undefined, href: "#", role: "tab", rel: undefined, target: undefined, tabIndex: -1, className: "", "aria-selected": false, onKeyDown: function () {} },
-          React.createElement(
-            "div",
-            { className: "_4jq5" },
-            "Reporting",
-            null
-          ),
-          React.createElement("span", { className: "_13xf" })
-        )
-      );
+      var props = this.props;
+      if (props.x === 54) {
+        return React.createElement(ReactTransitionGroup32, { x: 53 });
+      }
     }
   });
 
-  var TabBarItem40 = React.createClass({
-    displayName: "TabBarItem40",
+  var AdsPETopError34 = React.createClass({
+    displayName: "AdsPETopError34",
 
     render: function () {
-      return React.createElement(_wrapper39, null);
+      var props = this.props;
+      if (props.x === 55) {
+        return React.createElement(
+          "div",
+          { className: "_2wdc" },
+          React.createElement(ReactCSSTransitionGroup33, { x: 54 })
+        );
+      }
     }
   });
 
-  var XUIPageNavigationItem41 = React.createClass({
-    displayName: "XUIPageNavigationItem41",
+  var FluxContainer_AdsPETopErrorContainer_35 = React.createClass({
+    displayName: "FluxContainer_AdsPETopErrorContainer_35",
 
     render: function () {
-      return React.createElement(TabBarItem40, null);
+      var props = this.props;
+      if (props.x === 56) {
+        return React.createElement(AdsPETopError34, { x: 55 });
+      }
     }
   });
 
-  var TabBarItemWrapper42 = React.createClass({
-    displayName: "TabBarItemWrapper42",
+  var FluxContainer_AdsGuidanceChannel_36 = React.createClass({
+    displayName: "FluxContainer_AdsGuidanceChannel_36",
 
     render: function () {
-      return React.createElement(XUIPageNavigationItem41, { key: "REPORTING" });
+      var props = this.props;
+      if (props.x === 59) {
+        return null;
+      }
     }
   });
 
-  var _wrapper43 = React.createClass({
-    displayName: "_wrapper43",
+  var ResponsiveBlock37 = React.createClass({
+    displayName: "ResponsiveBlock37",
 
     render: function () {
-      return React.createElement(
-        "li",
-        { selected: false, focused: false, tabIndex: null, hideFocusRing: true, onClick: function () {}, onMouseDown: function () {}, onFocus: function () {}, onBlur: function () {}, className: "_5vwz _45hc", wrapper: function () {}, shouldWrapTab: true, mockSpacebarClick: true, role: "presentation" },
-        React.createElement(
-          "a",
-          { ref: "tab", ajaxify: undefined, href: "#", role: "tab", rel: undefined, target: undefined, tabIndex: -1, className: "", "aria-selected": false, onKeyDown: function () {} },
+      var props = this.props;
+      if (props.x === 62) {
+        return React.createElement(
+          "div",
+          { onResize: function () {}, className: "_4u-c" },
+          [React.createElement(AdsErrorBoundary10, { x: 58 }), React.createElement(AdsErrorBoundary10, { x: 61 })],
           React.createElement(
             "div",
-            { className: "_4jq5" },
-            "Page Posts"
-          ),
-          React.createElement("span", { className: "_13xf" })
-        )
-      );
-    }
-  });
-
-  var TabBarItem44 = React.createClass({
-    displayName: "TabBarItem44",
-
-    render: function () {
-      return React.createElement(_wrapper43, null);
-    }
-  });
-
-  var XUIPageNavigationItem45 = React.createClass({
-    displayName: "XUIPageNavigationItem45",
-
-    render: function () {
-      return React.createElement(TabBarItem44, null);
+            { key: "sensor", className: "_4u-f" },
+            React.createElement("iframe", { ref: "sensorNode", "aria-hidden": "true", className: "_1_xb", tabIndex: "-1" })
+          )
+        );
+      }
+      if (props.x === 469) {
+        return React.createElement(
+          "div",
+          { onResize: function () {}, className: "_4u-c" },
+          React.createElement(AdsPEDataTableContainer158, { x: 468 }),
+          React.createElement(
+            "div",
+            { key: "sensor", className: "_4u-f" },
+            React.createElement("iframe", { ref: "sensorNode", "aria-hidden": "true", className: "_1_xb", tabIndex: "-1" })
+          )
+        );
+      }
     }
   });
 
-  var TabBarItemWrapper46 = React.createClass({
-    displayName: "TabBarItemWrapper46",
+  var FluxContainer_AdsBulkEditDialogContainer_38 = React.createClass({
+    displayName: "FluxContainer_AdsBulkEditDialogContainer_38",
 
     render: function () {
-      return React.createElement(XUIPageNavigationItem45, { key: "PAGES" });
+      var props = this.props;
+      if (props.x === 63) {
+        return null;
+      }
     }
   });
 
-  var TabBarItem47 = React.createClass({
-    displayName: "TabBarItem47",
+  var Column39 = React.createClass({
+    displayName: "Column39",
 
     render: function () {
-      return React.createElement(
-        "a",
-        { ref: "tab", menuClassName: undefined, selected: false, focused: false, hideFocusRing: true, onMouseDown: function () {}, onFocus: function () {}, onBlur: function () {}, label: "Tools", tabComponent: function () {}, shouldWrapTab: false, className: "_45hd _45hc _p _45hc", tabIndex: -1, mockSpacebarClick: false, wrapper: function () {}, href: "#", role: "tab", "aria-selected": false },
-        React.createElement(
-          "span",
-          { className: "_1b0" },
-          "Tools",
+      var props = this.props;
+      if (props.x === 66) {
+        return React.createElement(
+          "div",
+          { className: "_4bl8 _4bl7" },
           React.createElement(
-            "span",
-            { className: "accessible_elem" },
-            "additional tabs menu"
+            "div",
+            { className: "_3c5f" },
+            null,
+            null,
+            React.createElement("div", { className: "_3c5i" }),
+            null
           )
-        )
-      );
+        );
+      }
     }
   });
 
-  var InlineBlock48 = React.createClass({
-    displayName: "InlineBlock48",
+  var XUIButtonGroup40 = React.createClass({
+    displayName: "XUIButtonGroup40",
 
     render: function () {
-      return React.createElement(
-        "div",
-        { menu: {}, layerBehaviors: {}, alignv: "middle", className: "uiPopover _6a _6b", disabled: null, fullWidth: false },
-        React.createElement(TabBarItem47, { key: "/.0" })
-      );
+      var props = this.props;
+      if (props.x === 75) {
+        return React.createElement(
+          "div",
+          { className: "_5n7z _51xa" },
+          React.createElement(XUIButton4, { x: 69 }),
+          React.createElement(ReactPopoverMenu20, { x: 74 })
+        );
+      }
+      if (props.x === 84) {
+        return React.createElement(
+          "div",
+          { className: "_5n7z _51xa" },
+          React.createElement(XUIButton4, { x: 78, key: "edit" }),
+          React.createElement(ReactPopoverMenu20, { x: 83, key: "editMenu" })
+        );
+      }
+      if (props.x === 97) {
+        return React.createElement(
+          "div",
+          { className: "_5n7z _51xa" },
+          React.createElement(XUIButton4, { x: 90, key: "revert" }),
+          React.createElement(XUIButton4, { x: 93, key: "delete" }),
+          React.createElement(XUIButton4, { x: 96, key: "duplicate" })
+        );
+      }
+      if (props.x === 117) {
+        return React.createElement(
+          "div",
+          { className: "_5n7z _51xa" },
+          React.createElement(AdsPEExportImportMenuContainer48, { x: 107 }),
+          React.createElement(XUIButton4, { x: 110, key: "createReport", ref: "ads_create_report_button" }),
+          React.createElement(AdsPECampaignGroupTagContainer51, { x: 116, key: "tags" })
+        );
+      }
     }
   });
 
-  var ReactPopoverMenu49 = React.createClass({
-    displayName: "ReactPopoverMenu49",
+  var AdsPEEditToolbarButton41 = React.createClass({
+    displayName: "AdsPEEditToolbarButton41",
 
     render: function () {
-      return React.createElement(InlineBlock48, { ref: "root" });
+      var props = this.props;
+      if (props.x === 85) {
+        return React.createElement(XUIButtonGroup40, { x: 84 });
+      }
     }
   });
 
-  var TabBarDropdownItem50 = React.createClass({
-    displayName: "TabBarDropdownItem50",
+  var FluxContainer_AdsPEEditCampaignGroupToolbarButtonContainer_42 = React.createClass({
+    displayName: "FluxContainer_AdsPEEditCampaignGroupToolbarButtonContainer_42",
 
     render: function () {
-      return React.createElement(
-        "li",
-        { className: " _45hd", role: "tab" },
-        React.createElement(ReactPopoverMenu49, null)
-      );
+      var props = this.props;
+      if (props.x === 86) {
+        return React.createElement(AdsPEEditToolbarButton41, { x: 85 });
+      }
     }
   });
 
-  var TabBar51 = React.createClass({
-    displayName: "TabBar51",
+  var FluxContainer_AdsPEEditToolbarButtonContainer_43 = React.createClass({
+    displayName: "FluxContainer_AdsPEEditToolbarButtonContainer_43",
 
     render: function () {
-      return React.createElement(
-        "ul",
-        { onTabClick: function () {}, activeTabKey: "MANAGE_ADS", onWidthCalculated: function () {}, width: null, maxTabsVisible: 5, moreLabel: "Tools", alwaysShowActive: true, dropdownTabComponent: function () {}, shouldCalculateVisibleTabs: true, className: "_43o4", role: "tablist", onKeyDown: function () {}, onKeyUp: function () {} },
-        React.createElement(TabBarItemWrapper30, { key: "MANAGE_ADS" }),
-        React.createElement(TabBarItemWrapper34, { key: "AUDIENCES" }),
-        React.createElement(TabBarItemWrapper38, { key: "IMAGES" }),
-        React.createElement(TabBarItemWrapper42, { key: "REPORTING" }),
-        React.createElement(TabBarItemWrapper46, { key: "PAGES" }),
-        React.createElement(TabBarDropdownItem50, { key: "_dropdown", ref: "more" })
-      );
+      var props = this.props;
+      if (props.x === 87) {
+        return React.createElement(FluxContainer_AdsPEEditCampaignGroupToolbarButtonContainer_42, { x: 86 });
+      }
     }
   });
 
-  var XUIPageNavigationGroup52 = React.createClass({
-    displayName: "XUIPageNavigationGroup52",
+  var AdsPEExportImportMenu44 = React.createClass({
+    displayName: "AdsPEExportImportMenu44",
 
     render: function () {
-      return React.createElement(TabBar51, { ref: "bar" });
+      var props = this.props;
+      if (props.x === 103) {
+        return React.createElement(ReactPopoverMenu20, { x: 102, key: "export" });
+      }
     }
   });
 
-  var LeftRight53 = React.createClass({
-    displayName: "LeftRight53",
+  var FluxContainer_AdsPECustomizeExportContainer_45 = React.createClass({
+    displayName: "FluxContainer_AdsPECustomizeExportContainer_45",
 
     render: function () {
-      return React.createElement(
-        "div",
-        { className: "_5vx7 clearfix" },
-        React.createElement(
-          "div",
-          { key: "left", className: "_ohe lfloat" },
-          React.createElement(XUIPageNavigationGroup52, { key: "0", ref: "left" })
-        ),
-        null
-      );
+      var props = this.props;
+      if (props.x === 104) {
+        return null;
+      }
     }
   });
 
-  var XUIPageNavigation54 = React.createClass({
-    displayName: "XUIPageNavigation54",
+  var AdsPEExportAsTextDialog46 = React.createClass({
+    displayName: "AdsPEExportAsTextDialog46",
 
     render: function () {
-      return React.createElement(
-        "div",
-        { className: "_5vx2 _5vx4 _5vx6 _5kkt" },
-        React.createElement(LeftRight53, null)
-      );
+      var props = this.props;
+      if (props.x === 105) {
+        return null;
+      }
     }
   });
 
-  var AdsPENavigationBar55 = React.createClass({
-    displayName: "AdsPENavigationBar55",
+  var FluxContainer_AdsPEExportAsTextDialogContainer_47 = React.createClass({
+    displayName: "FluxContainer_AdsPEExportAsTextDialogContainer_47",
 
     render: function () {
-      return React.createElement(
-        "div",
-        { className: "_5_a", id: "ads_pe_navigation_bar" },
-        React.createElement(XUIPageNavigation54, null)
-      );
+      var props = this.props;
+      if (props.x === 106) {
+        return React.createElement(AdsPEExportAsTextDialog46, { x: 105 });
+      }
     }
   });
 
-  var FluxContainer_w_56 = React.createClass({
-    displayName: "FluxContainer_w_56",
+  var AdsPEExportImportMenuContainer48 = React.createClass({
+    displayName: "AdsPEExportImportMenuContainer48",
 
     render: function () {
-      return React.createElement(AdsPENavigationBar55, null);
+      var props = this.props;
+      if (props.x === 107) {
+        return React.createElement(
+          "span",
+          null,
+          React.createElement(AdsPEExportImportMenu44, { x: 103 }),
+          React.createElement(FluxContainer_AdsPECustomizeExportContainer_45, { x: 104 }),
+          React.createElement(FluxContainer_AdsPEExportAsTextDialogContainer_47, { x: 106 }),
+          null,
+          null
+        );
+      }
     }
   });
 
-  var ReactImage57 = React.createClass({
-    displayName: "ReactImage57",
+  var Constructor49 = React.createClass({
+    displayName: "Constructor49",
 
     render: function () {
-      return React.createElement(
-        "i",
-        { alt: "Warning", className: "_585p img sp_R48dKBxiJkP sx_aed870", src: null },
-        React.createElement(
-          "u",
-          null,
-          "Warning"
-        )
-      );
+      var props = this.props;
+      if (props.x === 114) {
+        return null;
+      }
+      if (props.x === 142) {
+        return null;
+      }
+      if (props.x === 143) {
+        return null;
+      }
+      if (props.x === 183) {
+        return null;
+      }
     }
   });
 
-  var Link58 = React.createClass({
-    displayName: "Link58",
+  var TagSelectorPopover50 = React.createClass({
+    displayName: "TagSelectorPopover50",
 
     render: function () {
-      return React.createElement(
-        "a",
-        { className: "_585q _50zy _50-0 _50z- _5upp _42ft", href: "#", onClick: function () {}, size: "medium", shade: "dark", type: null, label: null, title: "Remove", "aria-label": undefined, "data-hover": undefined, "data-tooltip-alignh": undefined, disabled: null, rel: undefined },
-        undefined,
-        "Remove",
-        undefined
-      );
+      var props = this.props;
+      if (props.x === 115) {
+        return React.createElement(
+          "span",
+          { className: " _3d6e" },
+          React.createElement(XUIButton4, { x: 113, ref: "button" }),
+          React.createElement(Constructor49, { x: 114, key: "layer", ref: "layer" })
+        );
+      }
     }
   });
 
-  var AbstractButton59 = React.createClass({
-    displayName: "AbstractButton59",
+  var AdsPECampaignGroupTagContainer51 = React.createClass({
+    displayName: "AdsPECampaignGroupTagContainer51",
 
     render: function () {
-      return React.createElement(Link58, null);
+      var props = this.props;
+      if (props.x === 116) {
+        return React.createElement(TagSelectorPopover50, { x: 115, key: "98010048849317" });
+      }
     }
   });
 
-  var XUIAbstractGlyphButton60 = React.createClass({
-    displayName: "XUIAbstractGlyphButton60",
+  var AdsRuleToolbarMenu52 = React.createClass({
+    displayName: "AdsRuleToolbarMenu52",
 
     render: function () {
-      return React.createElement(AbstractButton59, null);
+      var props = this.props;
+      if (props.x === 118) {
+        return null;
+      }
     }
   });
 
-  var XUICloseButton61 = React.createClass({
-    displayName: "XUICloseButton61",
+  var FluxContainer_AdsPERuleToolbarMenuContainer_53 = React.createClass({
+    displayName: "FluxContainer_AdsPERuleToolbarMenuContainer_53",
 
     render: function () {
-      return React.createElement(XUIAbstractGlyphButton60, null);
+      var props = this.props;
+      if (props.x === 119) {
+        return React.createElement(AdsRuleToolbarMenu52, { x: 118 });
+      }
     }
   });
 
-  var XUIText62 = React.createClass({
-    displayName: "XUIText62",
+  var FillColumn54 = React.createClass({
+    displayName: "FillColumn54",
 
     render: function () {
-      return React.createElement(
-        "span",
-        { weight: "bold", size: "inherit", display: "inline", className: " _50f7" },
-        "Ads Manager"
-      );
+      var props = this.props;
+      if (props.x === 120) {
+        return React.createElement(
+          "div",
+          { className: "_4bl9" },
+          React.createElement(
+            "span",
+            { className: "_3c5e" },
+            React.createElement(
+              "span",
+              null,
+              React.createElement(XUIButtonGroup40, { x: 75 }),
+              React.createElement(FluxContainer_AdsPEEditToolbarButtonContainer_43, { x: 87 }),
+              null,
+              React.createElement(XUIButtonGroup40, { x: 97 })
+            ),
+            React.createElement(XUIButtonGroup40, { x: 117 }),
+            React.createElement(FluxContainer_AdsPERuleToolbarMenuContainer_53, { x: 119 })
+          )
+        );
+      }
     }
   });
 
-  var Link63 = React.createClass({
-    displayName: "Link63",
+  var Layout55 = React.createClass({
+    displayName: "Layout55",
 
     render: function () {
-      return React.createElement(
-        "a",
-        { href: "/ads/manage/billing.php?act=10149999073643408", target: "_blank", rel: undefined, onClick: function () {} },
-        React.createElement(XUIText62, null)
-      );
+      var props = this.props;
+      if (props.x === 121) {
+        return React.createElement(
+          "div",
+          { className: "clearfix" },
+          React.createElement(Column39, { x: 66, key: "1" }),
+          React.createElement(FillColumn54, { x: 120, key: "0" })
+        );
+      }
     }
   });
 
-  var XUINotice64 = React.createClass({
-    displayName: "XUINotice64",
+  var AdsPEMainPaneToolbar56 = React.createClass({
+    displayName: "AdsPEMainPaneToolbar56",
 
     render: function () {
-      return React.createElement(
-        "div",
-        { size: "medium", className: "_585n _585o _2wdd" },
-        React.createElement(ReactImage57, null),
-        React.createElement(XUICloseButton61, null),
-        React.createElement(
+      var props = this.props;
+      if (props.x === 122) {
+        return React.createElement(
           "div",
-          { className: "_585r _2i-a _50f4" },
-          "Please go to ",
-          React.createElement(Link63, null),
-          " to set up a payment method for this ad account."
-        )
-      );
+          { className: "_3c5b clearfix" },
+          React.createElement(Layout55, { x: 121 })
+        );
+      }
     }
   });
 
-  var ReactCSSTransitionGroupChild65 = React.createClass({
-    displayName: "ReactCSSTransitionGroupChild65",
+  var AdsPECampaignGroupToolbarContainer57 = React.createClass({
+    displayName: "AdsPECampaignGroupToolbarContainer57",
 
     render: function () {
-      return React.createElement(XUINotice64, null);
+      var props = this.props;
+      if (props.x === 123) {
+        return React.createElement(AdsPEMainPaneToolbar56, { x: 122 });
+      }
     }
   });
 
-  var ReactTransitionGroup66 = React.createClass({
-    displayName: "ReactTransitionGroup66",
+  var AdsPEFiltersPopover58 = React.createClass({
+    displayName: "AdsPEFiltersPopover58",
 
     render: function () {
-      return React.createElement(
-        "span",
-        { transitionEnterTimeout: 500, transitionLeaveTimeout: 500, transitionName: {}, transitionAppear: false, transitionEnter: true, transitionLeave: true, childFactory: function () {}, component: "span" },
-        React.createElement(ReactCSSTransitionGroupChild65, { key: ".0", ref: ".0" })
-      );
+      var props = this.props;
+      if (props.x === 144) {
+        return React.createElement(
+          "span",
+          { className: "_5b-l  _5bbe" },
+          React.createElement(ReactXUIPopoverButton6, { x: 133, ref: "searchButton" }),
+          React.createElement(ReactXUIPopoverButton6, { x: 141, ref: "filterButton" }),
+          [React.createElement(Constructor49, { x: 142, key: "filterMenu/.0" }), React.createElement(Constructor49, { x: 143, key: "searchMenu/.0" })]
+        );
+      }
     }
   });
 
-  var ReactCSSTransitionGroup67 = React.createClass({
-    displayName: "ReactCSSTransitionGroup67",
+  var AbstractCheckboxInput59 = React.createClass({
+    displayName: "AbstractCheckboxInput59",
 
     render: function () {
-      return React.createElement(ReactTransitionGroup66, null);
+      var props = this.props;
+      if (props.x === 145) {
+        return React.createElement(
+          "label",
+          { className: "uiInputLabelInput _55sg _kv1" },
+          React.createElement("input", { checked: true, disabled: true, name: "filterUnpublished", value: "on", onClick: function () {}, className: null, id: "js_input_label_21", type: "checkbox" }),
+          React.createElement("span", { "data-hover": null, "data-tooltip-content": undefined })
+        );
+      }
+      if (props.x === 336) {
+        return React.createElement(
+          "label",
+          { className: "_4h2r _55sg _kv1" },
+          React.createElement("input", { checked: undefined, onChange: function () {}, className: null, type: "checkbox" }),
+          React.createElement("span", { "data-hover": null, "data-tooltip-content": undefined })
+        );
+      }
     }
   });
 
-  var AdsPETopError68 = React.createClass({
-    displayName: "AdsPETopError68",
+  var XUICheckboxInput60 = React.createClass({
+    displayName: "XUICheckboxInput60",
 
     render: function () {
-      return React.createElement(
-        "div",
-        { className: "_2wdc" },
-        React.createElement(ReactCSSTransitionGroup67, null)
-      );
+      var props = this.props;
+      if (props.x === 146) {
+        return React.createElement(AbstractCheckboxInput59, { x: 145 });
+      }
+      if (props.x === 337) {
+        return React.createElement(AbstractCheckboxInput59, { x: 336 });
+      }
     }
   });
 
-  var FluxContainer_r_69 = React.createClass({
-    displayName: "FluxContainer_r_69",
+  var InputLabel61 = React.createClass({
+    displayName: "InputLabel61",
 
     render: function () {
-      return React.createElement(AdsPETopError68, null);
+      var props = this.props;
+      if (props.x === 147) {
+        return React.createElement(
+          "div",
+          { display: "block", className: "uiInputLabel clearfix" },
+          React.createElement(XUICheckboxInput60, { x: 146 }),
+          React.createElement(
+            "label",
+            { className: "uiInputLabelLabel", htmlFor: "js_input_label_21" },
+            "Always show new items"
+          )
+        );
+      }
     }
   });
 
-  var ReactImage70 = React.createClass({
-    displayName: "ReactImage70",
+  var AdsPopoverLink62 = React.createClass({
+    displayName: "AdsPopoverLink62",
 
     render: function () {
-      return React.createElement("i", { className: "_3-8_ img sp_UuU9HmrQ397 sx_bae57d", src: null });
+      var props = this.props;
+      if (props.x === 154) {
+        return React.createElement(
+          "span",
+          null,
+          React.createElement(
+            "span",
+            { ref: "tipIcon", onMouseEnter: function () {}, onMouseLeave: function () {}, onMouseUp: undefined },
+            React.createElement("span", { className: "_3o_j" }),
+            React.createElement(ReactImage0, { x: 153 })
+          ),
+          null
+        );
+      }
+      if (props.x === 238) {
+        return React.createElement(
+          "span",
+          null,
+          React.createElement(
+            "span",
+            { ref: "tipIcon", onMouseEnter: function () {}, onMouseLeave: function () {}, onMouseUp: undefined },
+            React.createElement("span", { className: "_3o_j" }),
+            React.createElement(ReactImage0, { x: 237 })
+          ),
+          null
+        );
+      }
     }
   });
 
-  var ReactImage71 = React.createClass({
-    displayName: "ReactImage71",
+  var AdsHelpLink63 = React.createClass({
+    displayName: "AdsHelpLink63",
 
     render: function () {
-      return React.createElement("i", { alt: "", className: "_3-99 img sp_UuU9HmrQ397 sx_7e56e9", src: null });
+      var props = this.props;
+      if (props.x === 155) {
+        return React.createElement(AdsPopoverLink62, { x: 154 });
+      }
+      if (props.x === 239) {
+        return React.createElement(AdsPopoverLink62, { x: 238 });
+      }
     }
   });
 
-  var Link72 = React.createClass({
-    displayName: "Link72",
+  var BUIFilterTokenInput64 = React.createClass({
+    displayName: "BUIFilterTokenInput64",
 
     render: function () {
-      return React.createElement(
-        "a",
-        { style: { "maxWidth": "200px" }, image: null, label: null, imageRight: {}, className: " _5bbf _55pi _2agf  _5bbf _55pi _4jy0 _4jy4 _517h _51sy _42ft", href: "#", haschevron: true, onClick: function () {}, size: "large", use: "default", borderShade: "light", suppressed: false, disabled: null, rel: undefined },
-        null,
-        React.createElement(
-          "span",
-          { className: "_55pe", style: { "maxWidth": "186px" } },
-          React.createElement(ReactImage70, null),
-          "Search"
-        ),
-        React.createElement(ReactImage71, null)
-      );
+      var props = this.props;
+      if (props.x === 158) {
+        return React.createElement(
+          "div",
+          { className: "_5b5o _3yz3 _4cld" },
+          React.createElement(
+            "div",
+            { className: "_5b5t _2d2k" },
+            React.createElement(ReactImage0, { x: 152 }),
+            React.createElement(
+              "div",
+              { className: "_5b5r" },
+              "Campaigns: (1)",
+              React.createElement(AdsHelpLink63, { x: 155 })
+            )
+          ),
+          React.createElement(XUIButton4, { x: 157 })
+        );
+      }
     }
   });
 
-  var AbstractButton73 = React.createClass({
-    displayName: "AbstractButton73",
+  var BUIFilterToken65 = React.createClass({
+    displayName: "BUIFilterToken65",
 
     render: function () {
-      return React.createElement(Link72, null);
+      var props = this.props;
+      if (props.x === 159) {
+        return React.createElement(
+          "div",
+          { className: "_3yz1 _3yz2 _3dad" },
+          React.createElement(
+            "div",
+            { ref: "filterToken", className: "_3yz4", "aria-hidden": false },
+            React.createElement(
+              "div",
+              { onClick: function () {}, className: "_3yz5" },
+              React.createElement(ReactImage0, { x: 148 }),
+              React.createElement(
+                "div",
+                { className: "_3yz7" },
+                "Campaigns:"
+              ),
+              React.createElement(
+                "div",
+                { className: "ellipsis _3yz8", "data-hover": "tooltip", "data-tooltip-display": "overflow" },
+                "(1)"
+              )
+            ),
+            null,
+            React.createElement(XUICloseButton28, { x: 151 })
+          ),
+          React.createElement(BUIFilterTokenInput64, { x: 158, ref: "filterTokenInput" })
+        );
+      }
     }
   });
 
-  var XUIButton74 = React.createClass({
-    displayName: "XUIButton74",
+  var BUIFilterTokenCreateButton66 = React.createClass({
+    displayName: "BUIFilterTokenCreateButton66",
 
     render: function () {
-      return React.createElement(AbstractButton73, null);
+      var props = this.props;
+      if (props.x === 163) {
+        return React.createElement(
+          "div",
+          { className: "_1tc" },
+          React.createElement(XUIButton4, { x: 162 })
+        );
+      }
     }
   });
 
-  var AbstractPopoverButton75 = React.createClass({
-    displayName: "AbstractPopoverButton75",
+  var BUIFilterTokenizer67 = React.createClass({
+    displayName: "BUIFilterTokenizer67",
 
     render: function () {
-      return React.createElement(XUIButton74, null);
+      var props = this.props;
+      if (props.x === 164) {
+        return React.createElement(
+          "div",
+          { className: "_5b-m  clearfix" },
+          undefined,
+          [],
+          React.createElement(BUIFilterToken65, { x: 159, key: "token0" }),
+          React.createElement(BUIFilterTokenCreateButton66, { x: 163 }),
+          null,
+          React.createElement("div", { className: "_49u3" })
+        );
+      }
     }
   });
 
-  var ReactXUIPopoverButton76 = React.createClass({
-    displayName: "ReactXUIPopoverButton76",
+  var XUIAmbientNUX68 = React.createClass({
+    displayName: "XUIAmbientNUX68",
 
     render: function () {
-      return React.createElement(AbstractPopoverButton75, null);
+      var props = this.props;
+      if (props.x === 165) {
+        return null;
+      }
+      if (props.x === 189) {
+        return null;
+      }
+      if (props.x === 200) {
+        return null;
+      }
     }
   });
 
-  var ReactImage77 = React.createClass({
-    displayName: "ReactImage77",
+  var XUIAmbientNUX69 = React.createClass({
+    displayName: "XUIAmbientNUX69",
 
     render: function () {
-      return React.createElement("i", { className: "_3-8_ img sp_UuU9HmrQ397 sx_81d5f0", src: null });
+      var props = this.props;
+      if (props.x === 166) {
+        return React.createElement(XUIAmbientNUX68, { x: 165 });
+      }
+      if (props.x === 190) {
+        return React.createElement(XUIAmbientNUX68, { x: 189 });
+      }
+      if (props.x === 201) {
+        return React.createElement(XUIAmbientNUX68, { x: 200 });
+      }
     }
   });
 
-  var ReactImage78 = React.createClass({
-    displayName: "ReactImage78",
+  var AdsPEAmbientNUXMegaphone70 = React.createClass({
+    displayName: "AdsPEAmbientNUXMegaphone70",
 
     render: function () {
-      return React.createElement("i", { alt: "", className: "_3-99 img sp_UuU9HmrQ397 sx_7e56e9", src: null });
+      var props = this.props;
+      if (props.x === 167) {
+        return React.createElement(
+          "span",
+          null,
+          React.createElement("span", { ref: "mainChild" }),
+          React.createElement(XUIAmbientNUX69, { x: 166, key: "nux" })
+        );
+      }
     }
   });
 
-  var Link79 = React.createClass({
-    displayName: "Link79",
+  var AdsPEFilters71 = React.createClass({
+    displayName: "AdsPEFilters71",
 
     render: function () {
-      return React.createElement(
-        "a",
-        { style: { "maxWidth": "200px" }, image: null, label: null, imageRight: {}, className: " _5bbf _55pi _2agf  _5bbf _55pi _4jy0 _4jy4 _517h _51sy _42ft", href: "#", haschevron: true, onClick: function () {}, size: "large", use: "default", borderShade: "light", suppressed: false, disabled: null, rel: undefined },
-        null,
-        React.createElement(
-          "span",
-          { className: "_55pe", style: { "maxWidth": "186px" } },
-          React.createElement(ReactImage77, null),
-          "Filters"
-        ),
-        React.createElement(ReactImage78, null)
-      );
+      var props = this.props;
+      if (props.x === 168) {
+        return React.createElement(
+          "div",
+          { className: "_4rw_" },
+          React.createElement(AdsPEFiltersPopover58, { x: 144 }),
+          React.createElement(
+            "div",
+            { className: "_1eo" },
+            React.createElement(InputLabel61, { x: 147 })
+          ),
+          React.createElement(BUIFilterTokenizer67, { x: 164 }),
+          "",
+          React.createElement(AdsPEAmbientNUXMegaphone70, { x: 167 })
+        );
+      }
     }
   });
 
-  var AbstractButton80 = React.createClass({
-    displayName: "AbstractButton80",
+  var AdsPEFilterContainer72 = React.createClass({
+    displayName: "AdsPEFilterContainer72",
 
     render: function () {
-      return React.createElement(Link79, null);
+      var props = this.props;
+      if (props.x === 169) {
+        return React.createElement(AdsPEFilters71, { x: 168 });
+      }
     }
   });
 
-  var XUIButton81 = React.createClass({
-    displayName: "XUIButton81",
+  var AdsPETablePager73 = React.createClass({
+    displayName: "AdsPETablePager73",
 
     render: function () {
-      return React.createElement(AbstractButton80, null);
+      var props = this.props;
+      if (props.x === 172) {
+        return null;
+      }
     }
   });
 
-  var AbstractPopoverButton82 = React.createClass({
-    displayName: "AbstractPopoverButton82",
+  var AdsPECampaignGroupTablePagerContainer74 = React.createClass({
+    displayName: "AdsPECampaignGroupTablePagerContainer74",
 
     render: function () {
-      return React.createElement(XUIButton81, null);
+      var props = this.props;
+      if (props.x === 173) {
+        return React.createElement(AdsPETablePager73, { x: 172 });
+      }
     }
   });
 
-  var ReactXUIPopoverButton83 = React.createClass({
-    displayName: "ReactXUIPopoverButton83",
+  var AdsPETablePagerContainer75 = React.createClass({
+    displayName: "AdsPETablePagerContainer75",
 
     render: function () {
-      return React.createElement(AbstractPopoverButton82, null);
+      var props = this.props;
+      if (props.x === 174) {
+        return React.createElement(AdsPECampaignGroupTablePagerContainer74, { x: 173 });
+      }
     }
   });
 
-  var AdsPEFiltersPopover84 = React.createClass({
-    displayName: "AdsPEFiltersPopover84",
+  var ReactXUIError76 = React.createClass({
+    displayName: "ReactXUIError76",
 
     render: function () {
-      return React.createElement(
-        "span",
-        { className: "_5b-l  _5bbe" },
-        React.createElement(ReactXUIPopoverButton76, { ref: "searchButton" }),
-        React.createElement(ReactXUIPopoverButton83, { ref: "filterButton" })
-      );
+      var props = this.props;
+      if (props.x === 181) {
+        return React.createElement(AbstractButton3, { x: 180 });
+      }
+      if (props.x === 216) {
+        return React.createElement(
+          "div",
+          { className: "_40bf _2vl4 _1h18" },
+          null,
+          null,
+          React.createElement(
+            "div",
+            { className: "_2vl9 _1h1f", style: { "backgroundColor": "#fff" } },
+            React.createElement(
+              "div",
+              { className: "_2vla _1h1g" },
+              React.createElement(
+                "div",
+                null,
+                null,
+                React.createElement("textarea", { ref: "input", className: "_2vli _2vlj _1h26 _1h27", dir: "auto", disabled: undefined, id: undefined, maxLength: null, value: "Test Campaign", onBlur: function () {}, onChange: function () {}, onFocus: function () {}, onKeyDown: function () {} }),
+                null
+              ),
+              React.createElement("div", { ref: "shadowText", "aria-hidden": "true", className: "_2vlk" })
+            )
+          ),
+          null
+        );
+      }
+      if (props.x === 221) {
+        return React.createElement(XUICard94, { x: 220 });
+      }
+      if (props.x === 250) {
+        return React.createElement(XUICard94, { x: 249 });
+      }
+      if (props.x === 280) {
+        return React.createElement(XUICard94, { x: 279 });
+      }
     }
   });
 
-  var ReactImage85 = React.createClass({
-    displayName: "ReactImage85",
+  var BUIPopoverButton77 = React.createClass({
+    displayName: "BUIPopoverButton77",
 
     render: function () {
-      return React.createElement("i", { className: "_3yz6 _5whs img sp_UuU9HmrQ397 sx_5fe5c2", src: null });
+      var props = this.props;
+      if (props.x === 182) {
+        return React.createElement(ReactXUIError76, { x: 181 });
+      }
     }
   });
 
-  var AbstractButton86 = React.createClass({
-    displayName: "AbstractButton86",
+  var BUIDateRangePicker78 = React.createClass({
+    displayName: "BUIDateRangePicker78",
 
     render: function () {
-      return React.createElement(
-        "button",
-        { className: "_3yz9 _1t-2 _50z_ _50zy _50zz _50z- _5upp _42ft", size: "small", onClick: function () {}, shade: "dark", type: "button", label: null, title: "Remove", "aria-label": undefined, "data-hover": undefined, "data-tooltip-alignh": undefined },
-        undefined,
-        "Remove",
-        undefined
-      );
+      var props = this.props;
+      if (props.x === 184) {
+        return React.createElement(
+          "span",
+          null,
+          React.createElement(BUIPopoverButton77, { x: 182, ref: function () {} }),
+          [React.createElement(Constructor49, { x: 183, key: "layer/.0" })]
+        );
+      }
     }
   });
 
-  var XUIAbstractGlyphButton87 = React.createClass({
-    displayName: "XUIAbstractGlyphButton87",
+  var AdsPEStatsRangePicker79 = React.createClass({
+    displayName: "AdsPEStatsRangePicker79",
 
     render: function () {
-      return React.createElement(AbstractButton86, null);
+      var props = this.props;
+      if (props.x === 185) {
+        return React.createElement(BUIDateRangePicker78, { x: 184 });
+      }
     }
   });
 
-  var XUICloseButton88 = React.createClass({
-    displayName: "XUICloseButton88",
+  var AdsPEStatRange80 = React.createClass({
+    displayName: "AdsPEStatRange80",
 
     render: function () {
-      return React.createElement(XUIAbstractGlyphButton87, null);
+      var props = this.props;
+      if (props.x === 191) {
+        return React.createElement(
+          "div",
+          { className: "_3c5k" },
+          React.createElement(
+            "span",
+            { className: "_3c5j" },
+            "Stats:"
+          ),
+          React.createElement(
+            "span",
+            { className: "_3c5l" },
+            React.createElement(AdsPEStatsRangePicker79, { x: 185 }),
+            React.createElement(XUIButton4, { x: 188, key: "settings", ref: "PE_TABLE_LIST_SETTING" })
+          ),
+          [React.createElement(XUIAmbientNUX69, { x: 190, key: "roasNUX/.0" })]
+        );
+      }
     }
   });
 
-  var ReactImage89 = React.createClass({
-    displayName: "ReactImage89",
+  var AdsPEStatRangeContainer81 = React.createClass({
+    displayName: "AdsPEStatRangeContainer81",
 
     render: function () {
-      return React.createElement("i", { className: "_5b5p _4gem img sp_UuU9HmrQ397 sx_5fe5c2", src: null });
+      var props = this.props;
+      if (props.x === 192) {
+        return React.createElement(AdsPEStatRange80, { x: 191 });
+      }
     }
   });
 
-  var ReactImage90 = React.createClass({
-    displayName: "ReactImage90",
+  var AdsPESideTrayTabButton82 = React.createClass({
+    displayName: "AdsPESideTrayTabButton82",
 
     render: function () {
-      return React.createElement("i", { src: null, className: "_541d img sp_R48dKBxiJkP sx_dc2cdb" });
+      var props = this.props;
+      if (props.x === 196) {
+        return React.createElement(
+          "div",
+          { className: "_1-ly _59j9 _d9a", onClick: function () {} },
+          React.createElement(ReactImage0, { x: 195 }),
+          React.createElement("div", { className: "_vf7" }),
+          React.createElement("div", { className: "_vf8" })
+        );
+      }
+      if (props.x === 199) {
+        return React.createElement(
+          "div",
+          { className: " _1-lz _d9a", onClick: function () {} },
+          React.createElement(ReactImage0, { x: 198 }),
+          React.createElement("div", { className: "_vf7" }),
+          React.createElement("div", { className: "_vf8" })
+        );
+      }
+      if (props.x === 203) {
+        return null;
+      }
     }
   });
 
-  var AdsPopoverLink91 = React.createClass({
-    displayName: "AdsPopoverLink91",
+  var AdsPEEditorTrayTabButton83 = React.createClass({
+    displayName: "AdsPEEditorTrayTabButton83",
 
     render: function () {
-      return React.createElement(
-        "span",
-        { ref: "tipIcon", onMouseEnter: function () {}, onMouseLeave: function () {} },
-        React.createElement("span", { className: "_3o_j" }),
-        React.createElement(ReactImage90, null)
-      );
+      var props = this.props;
+      if (props.x === 197) {
+        return React.createElement(AdsPESideTrayTabButton82, { x: 196 });
+      }
     }
   });
 
-  var AdsHelpLink92 = React.createClass({
-    displayName: "AdsHelpLink92",
+  var AdsPEInsightsTrayTabButton84 = React.createClass({
+    displayName: "AdsPEInsightsTrayTabButton84",
 
     render: function () {
-      return React.createElement(AdsPopoverLink91, null);
+      var props = this.props;
+      if (props.x === 202) {
+        return React.createElement(
+          "span",
+          null,
+          React.createElement(AdsPESideTrayTabButton82, { x: 199, ref: "PE_INSIGHTS_TAB_ICON" }),
+          React.createElement(XUIAmbientNUX69, { x: 201, key: "roasNUX" })
+        );
+      }
     }
   });
 
-  var AbstractButton93 = React.createClass({
-    displayName: "AbstractButton93",
+  var AdsPENekoDebuggerTrayTabButton85 = React.createClass({
+    displayName: "AdsPENekoDebuggerTrayTabButton85",
 
     render: function () {
-      return React.createElement(
-        "button",
-        { className: "_5b5u _5b5v _4jy0 _4jy3 _517h _51sy _42ft", label: null, use: "default", onClick: function () {}, size: "medium", borderShade: "light", suppressed: false, type: "submit", value: "1" },
-        undefined,
-        "Apply",
-        undefined
-      );
+      var props = this.props;
+      if (props.x === 204) {
+        return React.createElement(AdsPESideTrayTabButton82, { x: 203 });
+      }
     }
   });
 
-  var XUIButton94 = React.createClass({
-    displayName: "XUIButton94",
+  var AdsPEEditorChildLink86 = React.createClass({
+    displayName: "AdsPEEditorChildLink86",
 
     render: function () {
-      return React.createElement(AbstractButton93, null);
+      var props = this.props;
+      if (props.x === 211) {
+        return React.createElement(
+          "div",
+          { className: "_3ywr" },
+          React.createElement(Link2, { x: 208 }),
+          React.createElement(
+            "span",
+            { className: "_3ywq" },
+            "|"
+          ),
+          React.createElement(Link2, { x: 210 })
+        );
+      }
     }
   });
 
-  var BUIFilterTokenInput95 = React.createClass({
-    displayName: "BUIFilterTokenInput95",
+  var AdsPEEditorChildLinkContainer87 = React.createClass({
+    displayName: "AdsPEEditorChildLinkContainer87",
 
     render: function () {
-      return React.createElement(
-        "div",
-        { className: "_5b5o _3yz3 _4cld" },
-        React.createElement(
-          "div",
-          { className: "_5b5t _2d2k" },
-          React.createElement(ReactImage89, null),
-          React.createElement(
-            "div",
-            { className: "_5b5r" },
-            "Ads: (1)",
-            React.createElement(AdsHelpLink92, null)
-          )
-        ),
-        React.createElement(XUIButton94, null)
-      );
+      var props = this.props;
+      if (props.x === 212) {
+        return React.createElement(AdsPEEditorChildLink86, { x: 211 });
+      }
     }
   });
 
-  var BUIFilterToken96 = React.createClass({
-    displayName: "BUIFilterToken96",
+  var AdsPEHeaderSection88 = React.createClass({
+    displayName: "AdsPEHeaderSection88",
 
     render: function () {
-      return React.createElement(
-        "div",
-        { className: "_3yz1 _3yz2 _3dad" },
-        React.createElement(
+      var props = this.props;
+      if (props.x === 213) {
+        return React.createElement(
           "div",
-          { ref: "filterToken", className: "_3yz4", "aria-hidden": false },
+          { className: "_yke" },
+          React.createElement("div", { className: "_2x9d _pr-" }),
+          React.createElement(XUIText29, { x: 205 }),
           React.createElement(
             "div",
-            { onClick: function () {}, className: "_3yz5" },
-            React.createElement(ReactImage85, null),
-            React.createElement(
-              "div",
-              { className: "_3yz7" },
-              "Ads:"
-            ),
+            { className: "_3a-a" },
             React.createElement(
               "div",
-              { className: "ellipsis _3yz8", "data-hover": "tooltip", "data-tooltip-display": "overflow" },
-              "(1)"
+              { className: "_3a-b" },
+              React.createElement(XUIText29, { x: 206 })
             )
           ),
-          React.createElement(XUICloseButton88, null)
-        ),
-        React.createElement(BUIFilterTokenInput95, { ref: "filterTokenInput" })
-      );
-    }
-  });
-
-  var ReactImage97 = React.createClass({
-    displayName: "ReactImage97",
-
-    render: function () {
-      return React.createElement("i", { src: null, className: "img sp_UuU9HmrQ397 sx_158e8d" });
-    }
-  });
-
-  var AbstractButton98 = React.createClass({
-    displayName: "AbstractButton98",
-
-    render: function () {
-      return React.createElement(
-        "button",
-        { className: "_1wdf _4jy0 _517i _517h _51sy _42ft", size: "small", onClick: function () {}, image: {}, use: "default", borderShade: "light", suppressed: false, label: null, type: "submit", value: "1" },
-        React.createElement(ReactImage97, null),
-        undefined,
-        undefined
-      );
-    }
-  });
-
-  var XUIButton99 = React.createClass({
-    displayName: "XUIButton99",
-
-    render: function () {
-      return React.createElement(AbstractButton98, null);
+          React.createElement(AdsPEEditorChildLinkContainer87, { x: 212 })
+        );
+      }
     }
   });
 
-  var BUIFilterTokenCreateButton100 = React.createClass({
-    displayName: "BUIFilterTokenCreateButton100",
+  var AdsPECampaignGroupHeaderSectionContainer89 = React.createClass({
+    displayName: "AdsPECampaignGroupHeaderSectionContainer89",
 
     render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1tc" },
-        React.createElement(XUIButton99, null)
-      );
+      var props = this.props;
+      if (props.x === 214) {
+        return React.createElement(AdsPEHeaderSection88, { x: 213 });
+      }
     }
   });
 
-  var BUIFilterTokenizer101 = React.createClass({
-    displayName: "BUIFilterTokenizer101",
+  var AdsEditorLoadingErrors90 = React.createClass({
+    displayName: "AdsEditorLoadingErrors90",
 
     render: function () {
-      return React.createElement(
-        "div",
-        { className: "_5b-m _3o1v clearfix" },
-        undefined,
-        [],
-        React.createElement(BUIFilterToken96, { key: "token0" }),
-        React.createElement(BUIFilterTokenCreateButton100, null),
-        null,
-        React.createElement("div", { className: "_49u3" })
-      );
+      var props = this.props;
+      if (props.x === 215) {
+        return null;
+      }
     }
   });
 
-  var AdsPEAmbientNUXMegaphone102 = React.createClass({
-    displayName: "AdsPEAmbientNUXMegaphone102",
+  var AdsTextInput91 = React.createClass({
+    displayName: "AdsTextInput91",
 
     render: function () {
-      return React.createElement("span", { ref: "mainChild" });
+      var props = this.props;
+      if (props.x === 217) {
+        return React.createElement(ReactXUIError76, { x: 216 });
+      }
     }
   });
 
-  var AdsPEFilters103 = React.createClass({
-    displayName: "AdsPEFilters103",
+  var BUIFormElement92 = React.createClass({
+    displayName: "BUIFormElement92",
 
     render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4rw_" },
-        React.createElement(AdsPEFiltersPopover84, null),
-        null,
-        React.createElement(BUIFilterTokenizer101, null),
-        "",
-        React.createElement(AdsPEAmbientNUXMegaphone102, null)
-      );
+      var props = this.props;
+      if (props.x === 218) {
+        return React.createElement(
+          "div",
+          { className: "_5521 clearfix" },
+          React.createElement(
+            "div",
+            { className: "_5522 _3w5q" },
+            React.createElement(
+              "label",
+              { onClick: undefined, htmlFor: "1467872040612:1961945894", className: "_5523 _3w5r" },
+              "Campaign Name",
+              null
+            )
+          ),
+          React.createElement(
+            "div",
+            { className: "_5527" },
+            React.createElement(
+              "div",
+              { className: "_5528" },
+              React.createElement(
+                "span",
+                { key: ".0", className: "_40bg", density: "snug", labelPosition: "left", id: "1467872040612:1961945894" },
+                React.createElement(AdsTextInput91, { x: 217, key: "nameEditor98010048849317", ref: "nameTextInput" }),
+                null
+              )
+            ),
+            null
+          )
+        );
+      }
     }
   });
 
-  var AdsPEFilterContainer104 = React.createClass({
-    displayName: "AdsPEFilterContainer104",
+  var BUIForm93 = React.createClass({
+    displayName: "BUIForm93",
 
     render: function () {
-      return React.createElement(AdsPEFilters103, null);
+      var props = this.props;
+      if (props.x === 219) {
+        return React.createElement(
+          "div",
+          { className: "_5ks1 _550r  _550t _550y _3w5n" },
+          React.createElement(BUIFormElement92, { x: 218, key: ".0" })
+        );
+      }
     }
   });
 
-  var AdsPECampaignTimeLimitNotice105 = React.createClass({
-    displayName: "AdsPECampaignTimeLimitNotice105",
+  var XUICard94 = React.createClass({
+    displayName: "XUICard94",
 
     render: function () {
-      return React.createElement("div", null);
+      var props = this.props;
+      if (props.x === 220) {
+        return React.createElement(
+          "div",
+          { className: "_40bc _12k2 _4-u2  _4-u8", xuiErrorPosition: "above", background: "white" },
+          React.createElement(BUIForm93, { x: 219 })
+        );
+      }
+      if (props.x === 249) {
+        return React.createElement(
+          "div",
+          { xuiErrorPosition: "above", className: "_12k2 _4-u2  _4-u8", background: "white" },
+          React.createElement(AdsCardHeader103, { x: 230 }),
+          React.createElement(AdsCardSection108, { x: 248 })
+        );
+      }
+      if (props.x === 279) {
+        return React.createElement(
+          "div",
+          { xuiErrorPosition: "above", className: "_12k2 _4-u2  _4-u8", background: "white" },
+          React.createElement(AdsCardLeftRightHeader122, { x: 278 })
+        );
+      }
     }
   });
 
-  var AdsPECampaignTimeLimitNoticeContainer106 = React.createClass({
-    displayName: "AdsPECampaignTimeLimitNoticeContainer106",
+  var AdsCard95 = React.createClass({
+    displayName: "AdsCard95",
 
     render: function () {
-      return React.createElement(AdsPECampaignTimeLimitNotice105, null);
+      var props = this.props;
+      if (props.x === 222) {
+        return React.createElement(ReactXUIError76, { x: 221 });
+      }
+      if (props.x === 251) {
+        return React.createElement(ReactXUIError76, { x: 250 });
+      }
+      if (props.x === 281) {
+        return React.createElement(ReactXUIError76, { x: 280 });
+      }
     }
   });
 
-  var AdsPETablePager107 = React.createClass({
-    displayName: "AdsPETablePager107",
+  var AdsEditorNameSection96 = React.createClass({
+    displayName: "AdsEditorNameSection96",
 
     render: function () {
-      return null;
+      var props = this.props;
+      if (props.x === 223) {
+        return React.createElement(AdsCard95, { x: 222 });
+      }
     }
   });
 
-  var AdsPEAdgroupTablePagerContainer108 = React.createClass({
-    displayName: "AdsPEAdgroupTablePagerContainer108",
+  var AdsCampaignGroupNameSectionContainer97 = React.createClass({
+    displayName: "AdsCampaignGroupNameSectionContainer97",
 
     render: function () {
-      return React.createElement(AdsPETablePager107, null);
+      var props = this.props;
+      if (props.x === 224) {
+        return React.createElement(AdsEditorNameSection96, { x: 223, key: "nameSection98010048849317" });
+      }
     }
   });
 
-  var AdsPETablePagerContainer109 = React.createClass({
-    displayName: "AdsPETablePagerContainer109",
+  var _render98 = React.createClass({
+    displayName: "_render98",
 
     render: function () {
-      return React.createElement(AdsPEAdgroupTablePagerContainer108, null);
+      var props = this.props;
+      if (props.x === 225) {
+        return React.createElement(AdsCampaignGroupNameSectionContainer97, { x: 224 });
+      }
     }
   });
 
-  var ReactImage110 = React.createClass({
-    displayName: "ReactImage110",
+  var AdsPluginWrapper99 = React.createClass({
+    displayName: "AdsPluginWrapper99",
 
     render: function () {
-      return React.createElement("i", { alt: "", className: "_3-99 img sp_UuU9HmrQ397 sx_132804", src: null });
+      var props = this.props;
+      if (props.x === 226) {
+        return React.createElement(_render98, { x: 225 });
+      }
+      if (props.x === 255) {
+        return React.createElement(_render111, { x: 254 });
+      }
+      if (props.x === 258) {
+        return React.createElement(_render113, { x: 257 });
+      }
+      if (props.x === 287) {
+        return React.createElement(_render127, { x: 286 });
+      }
+      if (props.x === 291) {
+        return React.createElement(_render130, { x: 290 });
+      }
     }
   });
 
-  var Link111 = React.createClass({
-    displayName: "Link111",
+  var XUICardHeaderTitle100 = React.createClass({
+    displayName: "XUICardHeaderTitle100",
 
     render: function () {
-      return React.createElement(
-        "a",
-        { style: { "maxWidth": "200px" }, image: null, label: null, imageRight: {}, className: "_55pi _2agf _55pi _4jy0 _4jy4 _517h _51sy _42ft", href: "#", disabled: null, maxwidth: undefined, size: "large", suppressed: false, chevron: {}, use: "default", borderShade: "light", onClick: function () {}, rel: undefined },
-        null,
-        React.createElement(
+      var props = this.props;
+      if (props.x === 227) {
+        return React.createElement(
           "span",
-          { className: "_55pe", style: { "maxWidth": "186px" } },
+          { itemComponent: "span", className: "_38my" },
+          "Campaign Details",
           null,
-          "Lifetime"
-        ),
-        React.createElement(ReactImage110, null)
-      );
-    }
-  });
-
-  var AbstractButton112 = React.createClass({
-    displayName: "AbstractButton112",
-
-    render: function () {
-      return React.createElement(Link111, null);
-    }
-  });
-
-  var XUIButton113 = React.createClass({
-    displayName: "XUIButton113",
-
-    render: function () {
-      return React.createElement(AbstractButton112, null);
+          React.createElement("span", { className: "_c1c" })
+        );
+      }
+      if (props.x === 265) {
+        return React.createElement(
+          "span",
+          { itemComponent: "span", className: "_38my" },
+          [React.createElement(
+            "span",
+            null,
+            "Campaign ID",
+            ": ",
+            "98010048849317"
+          ), React.createElement(
+            "div",
+            { className: "_5lh9" },
+            React.createElement(FluxContainer_AdsCampaignGroupStatusSwitchContainer_119, { x: 264 })
+          )],
+          null,
+          React.createElement("span", { className: "_c1c" })
+        );
+      }
     }
   });
 
-  var AbstractPopoverButton114 = React.createClass({
-    displayName: "AbstractPopoverButton114",
+  var XUICardSection101 = React.createClass({
+    displayName: "XUICardSection101",
 
     render: function () {
-      return React.createElement(XUIButton113, null);
+      var props = this.props;
+      if (props.x === 228) {
+        return React.createElement(
+          "div",
+          { className: "_5dw9 _5dwa _4-u3", background: "transparent" },
+          [React.createElement(XUICardHeaderTitle100, { x: 227, key: ".0" })],
+          undefined,
+          undefined,
+          React.createElement("div", { className: "_3s3-" })
+        );
+      }
+      if (props.x === 247) {
+        return React.createElement(
+          "div",
+          { className: "_12jy _4-u3", background: "transparent" },
+          React.createElement(
+            "div",
+            { className: "_3-8j" },
+            React.createElement(FlexibleBlock105, { x: 233 }),
+            React.createElement(FlexibleBlock105, { x: 236 }),
+            React.createElement(FlexibleBlock105, { x: 246 }),
+            null,
+            null
+          )
+        );
+      }
     }
   });
 
-  var ReactXUIPopoverButton115 = React.createClass({
-    displayName: "ReactXUIPopoverButton115",
+  var XUICardHeader102 = React.createClass({
+    displayName: "XUICardHeader102",
 
     render: function () {
-      return React.createElement(AbstractPopoverButton114, null);
+      var props = this.props;
+      if (props.x === 229) {
+        return React.createElement(XUICardSection101, { x: 228 });
+      }
     }
   });
 
-  var XUISingleSelectorButton116 = React.createClass({
-    displayName: "XUISingleSelectorButton116",
+  var AdsCardHeader103 = React.createClass({
+    displayName: "AdsCardHeader103",
 
     render: function () {
-      return React.createElement(ReactXUIPopoverButton115, null);
+      var props = this.props;
+      if (props.x === 230) {
+        return React.createElement(XUICardHeader102, { x: 229 });
+      }
     }
   });
 
-  var InlineBlock117 = React.createClass({
-    displayName: "InlineBlock117",
+  var AdsLabeledField104 = React.createClass({
+    displayName: "AdsLabeledField104",
 
     render: function () {
-      return React.createElement(
-        "div",
-        { className: "_3c5o _3c5p _6a _6b", defaultValue: "LIFETIME", size: "large", onChange: function () {}, disabled: false, alignv: "middle", fullWidth: false },
-        React.createElement("input", { type: "hidden", autoComplete: "off", name: undefined, value: "LIFETIME" }),
-        React.createElement(XUISingleSelectorButton116, { ref: "button" })
-      );
+      var props = this.props;
+      if (props.x === 231) {
+        return React.createElement(
+          "div",
+          { className: "_2oc6 _3bvz", label: "Objective", labelSize: "small", optionalText: "(optional)" },
+          React.createElement(
+            "label",
+            { className: "_4el4 _3qwj _3hy-", htmlFor: undefined },
+            "Objective "
+          ),
+          null,
+          React.createElement("div", { className: "_3bv-" })
+        );
+      }
+      if (props.x === 234) {
+        return React.createElement(
+          "div",
+          { className: "_2oc6 _3bvz", label: "Buying Type", labelSize: "small", optionalText: "(optional)" },
+          React.createElement(
+            "label",
+            { className: "_4el4 _3qwj _3hy-", htmlFor: undefined },
+            "Buying Type "
+          ),
+          null,
+          React.createElement("div", { className: "_3bv-" })
+        );
+      }
+      if (props.x === 240) {
+        return React.createElement(
+          "div",
+          { className: "_2oc6 _3bvz", helpText: "Set an overall spending limit for your ad campaign. This means your ad sets in the campaign will stop once you've reached your spending limit.", label: "Campaign Spending Limit", labelSize: "small", optionalText: "(optional)" },
+          React.createElement(
+            "label",
+            { className: "_4el4 _3qwj _3hy-", htmlFor: undefined },
+            "Campaign Spending Limit "
+          ),
+          React.createElement(AdsHelpLink63, { x: 239 }),
+          React.createElement("div", { className: "_3bv-" })
+        );
+      }
     }
   });
 
-  var XUISingleSelector118 = React.createClass({
-    displayName: "XUISingleSelector118",
+  var FlexibleBlock105 = React.createClass({
+    displayName: "FlexibleBlock105",
 
     render: function () {
-      return React.createElement(InlineBlock117, null);
+      var props = this.props;
+      if (props.x === 233) {
+        return React.createElement(LeftRight21, { x: 232 });
+      }
+      if (props.x === 236) {
+        return React.createElement(LeftRight21, { x: 235 });
+      }
+      if (props.x === 246) {
+        return React.createElement(LeftRight21, { x: 245 });
+      }
     }
   });
 
-  var ReactImage119 = React.createClass({
-    displayName: "ReactImage119",
+  var AdsBulkCampaignSpendCapField106 = React.createClass({
+    displayName: "AdsBulkCampaignSpendCapField106",
 
     render: function () {
-      return React.createElement("i", { src: null, className: "img sp_UuU9HmrQ397 sx_6c732d" });
+      var props = this.props;
+      if (props.x === 243) {
+        return React.createElement(
+          "div",
+          { className: "_33dv" },
+          "",
+          React.createElement(Link2, { x: 242 }),
+          " (optional)"
+        );
+      }
     }
   });
 
-  var AbstractButton120 = React.createClass({
-    displayName: "AbstractButton120",
+  var FluxContainer_AdsCampaignGroupSpendCapContainer_107 = React.createClass({
+    displayName: "FluxContainer_AdsCampaignGroupSpendCapContainer_107",
 
     render: function () {
-      return React.createElement(
-        "button",
-        { "aria-label": "List Settings", className: "_u_k _3c5o _1-r0 _4jy0 _4jy4 _517h _51sy _42ft", "data-hover": "tooltip", image: {}, size: "large", onClick: function () {}, use: "default", borderShade: "light", suppressed: false, label: null, type: "submit", value: "1" },
-        React.createElement(ReactImage119, null),
-        undefined,
-        undefined
-      );
+      var props = this.props;
+      if (props.x === 244) {
+        return React.createElement(AdsBulkCampaignSpendCapField106, { x: 243 });
+      }
     }
   });
 
-  var XUIButton121 = React.createClass({
-    displayName: "XUIButton121",
+  var AdsCardSection108 = React.createClass({
+    displayName: "AdsCardSection108",
 
     render: function () {
-      return React.createElement(AbstractButton120, null);
+      var props = this.props;
+      if (props.x === 248) {
+        return React.createElement(XUICardSection101, { x: 247 });
+      }
     }
   });
 
-  var AdsPEStatRange122 = React.createClass({
-    displayName: "AdsPEStatRange122",
+  var AdsEditorCampaignGroupDetailsSection109 = React.createClass({
+    displayName: "AdsEditorCampaignGroupDetailsSection109",
 
     render: function () {
-      return React.createElement(
-        "div",
-        { className: "_3c5k" },
-        React.createElement(
-          "span",
-          { className: "_3c5j" },
-          "Stats:"
-        ),
-        React.createElement(
-          "span",
-          { className: "_3c5l" },
-          React.createElement(XUISingleSelector118, { key: "range" }),
-          null,
-          React.createElement(XUIButton121, { key: "settings" })
-        )
-      );
+      var props = this.props;
+      if (props.x === 252) {
+        return React.createElement(AdsCard95, { x: 251 });
+      }
     }
   });
 
-  var AdsPEStatRangeContainer123 = React.createClass({
-    displayName: "AdsPEStatRangeContainer123",
+  var AdsEditorCampaignGroupDetailsSectionContainer110 = React.createClass({
+    displayName: "AdsEditorCampaignGroupDetailsSectionContainer110",
 
     render: function () {
-      return React.createElement(AdsPEStatRange122, null);
+      var props = this.props;
+      if (props.x === 253) {
+        return React.createElement(AdsEditorCampaignGroupDetailsSection109, { x: 252, key: "campaignGroupDetailsSection98010048849317" });
+      }
     }
   });
 
-  var Column124 = React.createClass({
-    displayName: "Column124",
+  var _render111 = React.createClass({
+    displayName: "_render111",
 
     render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4bl8 _4bl7" },
-        React.createElement(
-          "div",
-          { className: "_3c5f" },
-          null,
-          React.createElement(AdsPETablePagerContainer109, null),
-          React.createElement("div", { className: "_3c5i" }),
-          React.createElement(AdsPEStatRangeContainer123, null)
-        )
-      );
+      var props = this.props;
+      if (props.x === 254) {
+        return React.createElement(AdsEditorCampaignGroupDetailsSectionContainer110, { x: 253 });
+      }
     }
   });
 
-  var ReactImage125 = React.createClass({
-    displayName: "ReactImage125",
+  var FluxContainer_AdsEditorToplineDetailsSectionContainer_112 = React.createClass({
+    displayName: "FluxContainer_AdsEditorToplineDetailsSectionContainer_112",
 
     render: function () {
-      return React.createElement("i", { alt: "", className: "_3-8_ img sp_UuU9HmrQ397 sx_158e8d", src: null });
+      var props = this.props;
+      if (props.x === 256) {
+        return null;
+      }
     }
   });
 
-  var AbstractButton126 = React.createClass({
-    displayName: "AbstractButton126",
+  var _render113 = React.createClass({
+    displayName: "_render113",
 
     render: function () {
-      return React.createElement(
-        "button",
-        { className: "_u_k _4jy0 _4jy4 _517h _51sy _42ft", label: null, size: "large", onClick: function () {}, image: {}, use: "default", borderShade: "light", suppressed: false, type: "submit", value: "1" },
-        React.createElement(ReactImage125, null),
-        "Create Ad",
-        undefined
-      );
+      var props = this.props;
+      if (props.x === 257) {
+        return React.createElement(FluxContainer_AdsEditorToplineDetailsSectionContainer_112, { x: 256 });
+      }
     }
   });
 
-  var XUIButton127 = React.createClass({
-    displayName: "XUIButton127",
+  var AdsStickyArea114 = React.createClass({
+    displayName: "AdsStickyArea114",
 
     render: function () {
-      return React.createElement(AbstractButton126, null);
+      var props = this.props;
+      if (props.x === 259) {
+        return React.createElement(
+          "div",
+          { inContainingBlock: true },
+          React.createElement("div", { ref: "sticky", onWheel: function () {} })
+        );
+      }
+      if (props.x === 292) {
+        return React.createElement(
+          "div",
+          { inContainingBlock: true },
+          React.createElement(
+            "div",
+            { ref: "sticky", onWheel: function () {} },
+            [React.createElement(
+              "div",
+              { key: "campaign_group_errors_section98010048849317" },
+              React.createElement(AdsPluginWrapper99, { x: 291 })
+            )]
+          )
+        );
+      }
     }
   });
 
-  var ReactImage128 = React.createClass({
-    displayName: "ReactImage128",
+  var FluxContainer_AdsEditorColumnContainer_115 = React.createClass({
+    displayName: "FluxContainer_AdsEditorColumnContainer_115",
 
     render: function () {
-      return React.createElement("i", { src: null, className: "img sp_UuU9HmrQ397 sx_d5a685" });
+      var props = this.props;
+      if (props.x === 260) {
+        return React.createElement(
+          "div",
+          null,
+          [React.createElement(
+            "div",
+            { key: "campaign_group_name_section98010048849317" },
+            React.createElement(AdsPluginWrapper99, { x: 226 })
+          ), React.createElement(
+            "div",
+            { key: "campaign_group_basic_section98010048849317" },
+            React.createElement(AdsPluginWrapper99, { x: 255 })
+          ), React.createElement(
+            "div",
+            { key: "campaign_group_topline_section98010048849317" },
+            React.createElement(AdsPluginWrapper99, { x: 258 })
+          )],
+          React.createElement(AdsStickyArea114, { x: 259 })
+        );
+      }
+      if (props.x === 293) {
+        return React.createElement(
+          "div",
+          null,
+          [React.createElement(
+            "div",
+            { key: "campaign_group_navigation_section98010048849317" },
+            React.createElement(AdsPluginWrapper99, { x: 287 })
+          )],
+          React.createElement(AdsStickyArea114, { x: 292 })
+        );
+      }
     }
   });
 
-  var AbstractButton129 = React.createClass({
-    displayName: "AbstractButton129",
+  var BUISwitch116 = React.createClass({
+    displayName: "BUISwitch116",
 
     render: function () {
-      return React.createElement(
-        "button",
-        { className: "_u_k _p _4jy0 _4jy4 _517h _51sy _42ft", image: {}, size: "large", use: "default", borderShade: "light", suppressed: false, label: null, type: "submit", value: "1" },
-        React.createElement(ReactImage128, null),
-        undefined,
-        undefined
-      );
+      var props = this.props;
+      if (props.x === 261) {
+        return React.createElement(
+          "div",
+          { "data-hover": "tooltip", "data-tooltip-content": "Currently active. Click this switch to deactivate it.", "data-tooltip-position": "below", disabled: false, value: true, onToggle: function () {}, animate: true, className: "_128j _128k _128n", role: "checkbox", "aria-checked": "true" },
+          React.createElement(
+            "div",
+            { className: "_128o", onClick: function () {}, onKeyDown: function () {}, onMouseDown: function () {}, tabIndex: "0" },
+            React.createElement("div", { className: "_128p" })
+          ),
+          null
+        );
+      }
     }
   });
 
-  var XUIButton130 = React.createClass({
-    displayName: "XUIButton130",
+  var AdsStatusSwitchInternal117 = React.createClass({
+    displayName: "AdsStatusSwitchInternal117",
 
     render: function () {
-      return React.createElement(AbstractButton129, null);
+      var props = this.props;
+      if (props.x === 262) {
+        return React.createElement(BUISwitch116, { x: 261 });
+      }
     }
   });
 
-  var InlineBlock131 = React.createClass({
-    displayName: "InlineBlock131",
+  var AdsStatusSwitch118 = React.createClass({
+    displayName: "AdsStatusSwitch118",
 
     render: function () {
-      return React.createElement(
-        "div",
-        { menu: {}, alignh: "right", layerBehaviors: {}, alignv: "middle", className: "uiPopover _6a _6b", disabled: null, fullWidth: false },
-        React.createElement(XUIButton130, { key: "/.0" })
-      );
+      var props = this.props;
+      if (props.x === 263) {
+        return React.createElement(AdsStatusSwitchInternal117, { x: 262 });
+      }
     }
   });
 
-  var ReactPopoverMenu132 = React.createClass({
-    displayName: "ReactPopoverMenu132",
+  var FluxContainer_AdsCampaignGroupStatusSwitchContainer_119 = React.createClass({
+    displayName: "FluxContainer_AdsCampaignGroupStatusSwitchContainer_119",
 
     render: function () {
-      return React.createElement(InlineBlock131, { ref: "root" });
+      var props = this.props;
+      if (props.x === 264) {
+        return React.createElement(AdsStatusSwitch118, { x: 263, key: "status98010048849317" });
+      }
     }
   });
 
-  var XUIButtonGroup133 = React.createClass({
-    displayName: "XUIButtonGroup133",
+  var AdsLinksMenu120 = React.createClass({
+    displayName: "AdsLinksMenu120",
 
     render: function () {
-      return React.createElement(
-        "div",
-        { className: "_5n7z _51xa" },
-        React.createElement(XUIButton127, null),
-        React.createElement(ReactPopoverMenu132, null)
-      );
+      var props = this.props;
+      if (props.x === 275) {
+        return React.createElement(ReactPopoverMenu20, { x: 274 });
+      }
     }
   });
 
-  var ReactImage134 = React.createClass({
-    displayName: "ReactImage134",
+  var FluxContainer_AdsPluginizedLinksMenuContainer_121 = React.createClass({
+    displayName: "FluxContainer_AdsPluginizedLinksMenuContainer_121",
 
     render: function () {
-      return React.createElement("i", { alt: "", className: "_3-8_ img sp_UuU9HmrQ397 sx_990b54", src: null });
+      var props = this.props;
+      if (props.x === 276) {
+        return React.createElement(
+          "div",
+          null,
+          null,
+          React.createElement(AdsLinksMenu120, { x: 275 })
+        );
+      }
     }
   });
 
-  var AbstractButton135 = React.createClass({
-    displayName: "AbstractButton135",
+  var AdsCardLeftRightHeader122 = React.createClass({
+    displayName: "AdsCardLeftRightHeader122",
 
     render: function () {
-      return React.createElement(
-        "button",
-        { size: "large", disabled: false, className: "_d2_ _u_k _5n7z _4jy0 _4jy4 _517h _51sy _42ft", image: {}, "data-hover": "tooltip", "aria-label": "Edit Ads (Ctrl+U)", onClick: function () {}, use: "default", label: null, borderShade: "light", suppressed: false, type: "submit", value: "1" },
-        React.createElement(ReactImage134, null),
-        "Edit",
-        undefined
-      );
+      var props = this.props;
+      if (props.x === 278) {
+        return React.createElement(LeftRight21, { x: 277 });
+      }
     }
   });
 
-  var XUIButton136 = React.createClass({
-    displayName: "XUIButton136",
+  var AdsPEIDSection123 = React.createClass({
+    displayName: "AdsPEIDSection123",
 
     render: function () {
-      return React.createElement(AbstractButton135, null);
+      var props = this.props;
+      if (props.x === 282) {
+        return React.createElement(AdsCard95, { x: 281 });
+      }
     }
   });
 
-  var ReactImage137 = React.createClass({
-    displayName: "ReactImage137",
+  var FluxContainer_AdsPECampaignGroupIDSectionContainer_124 = React.createClass({
+    displayName: "FluxContainer_AdsPECampaignGroupIDSectionContainer_124",
 
     render: function () {
-      return React.createElement("i", { src: null, className: "img sp_UuU9HmrQ397 sx_203adb" });
+      var props = this.props;
+      if (props.x === 283) {
+        return React.createElement(AdsPEIDSection123, { x: 282 });
+      }
     }
   });
 
-  var AbstractButton138 = React.createClass({
-    displayName: "AbstractButton138",
+  var DeferredComponent125 = React.createClass({
+    displayName: "DeferredComponent125",
 
     render: function () {
-      return React.createElement(
-        "button",
-        { "aria-label": "Duplicate", className: "_u_k _4jy0 _4jy4 _517h _51sy _42ft", "data-hover": "tooltip", disabled: false, image: {}, size: "large", onClick: function () {}, use: "default", borderShade: "light", suppressed: false, label: null, type: "submit", value: "1" },
-        React.createElement(ReactImage137, null),
-        undefined,
-        undefined
-      );
+      var props = this.props;
+      if (props.x === 284) {
+        return React.createElement(FluxContainer_AdsPECampaignGroupIDSectionContainer_124, { x: 283 });
+      }
     }
   });
 
-  var XUIButton139 = React.createClass({
-    displayName: "XUIButton139",
+  var BootloadedComponent126 = React.createClass({
+    displayName: "BootloadedComponent126",
 
     render: function () {
-      return React.createElement(AbstractButton138, null);
+      var props = this.props;
+      if (props.x === 285) {
+        return React.createElement(DeferredComponent125, { x: 284 });
+      }
     }
   });
 
-  var ReactImage140 = React.createClass({
-    displayName: "ReactImage140",
+  var _render127 = React.createClass({
+    displayName: "_render127",
 
     render: function () {
-      return React.createElement("i", { src: null, className: "img sp_UuU9HmrQ397 sx_0c342e" });
+      var props = this.props;
+      if (props.x === 286) {
+        return React.createElement(BootloadedComponent126, { x: 285 });
+      }
     }
   });
 
-  var AbstractButton141 = React.createClass({
-    displayName: "AbstractButton141",
+  var AdsEditorErrorsCard128 = React.createClass({
+    displayName: "AdsEditorErrorsCard128",
 
     render: function () {
-      return React.createElement(
-        "button",
-        { "aria-label": "Revert", className: "_u_k _4jy0 _4jy4 _517h _51sy _42ft _42fr", "data-hover": "tooltip", disabled: true, image: {}, size: "large", onClick: function () {}, use: "default", borderShade: "light", suppressed: false, label: null, type: "submit", value: "1" },
-        React.createElement(ReactImage140, null),
-        undefined,
-        undefined
-      );
+      var props = this.props;
+      if (props.x === 288) {
+        return null;
+      }
     }
   });
 
-  var XUIButton142 = React.createClass({
-    displayName: "XUIButton142",
+  var FluxContainer_FunctionalContainer_129 = React.createClass({
+    displayName: "FluxContainer_FunctionalContainer_129",
 
     render: function () {
-      return React.createElement(AbstractButton141, null);
+      var props = this.props;
+      if (props.x === 289) {
+        return React.createElement(AdsEditorErrorsCard128, { x: 288 });
+      }
     }
   });
 
-  var ReactImage143 = React.createClass({
-    displayName: "ReactImage143",
+  var _render130 = React.createClass({
+    displayName: "_render130",
 
     render: function () {
-      return React.createElement("i", { src: null, className: "img sp_UuU9HmrQ397 sx_0e75f5" });
+      var props = this.props;
+      if (props.x === 290) {
+        return React.createElement(FluxContainer_FunctionalContainer_129, { x: 289 });
+      }
     }
   });
 
-  var AbstractButton144 = React.createClass({
-    displayName: "AbstractButton144",
+  var AdsEditorMultiColumnLayout131 = React.createClass({
+    displayName: "AdsEditorMultiColumnLayout131",
 
     render: function () {
-      return React.createElement(
-        "button",
-        { "aria-label": "Delete", className: "_u_k _4jy0 _4jy4 _517h _51sy _42ft", image: {}, "data-hover": "tooltip", disabled: false, size: "large", onClick: function () {}, use: "default", borderShade: "light", suppressed: false, label: null, type: "submit", value: "1" },
-        React.createElement(ReactImage143, null),
-        undefined,
-        undefined
-      );
+      var props = this.props;
+      if (props.x === 294) {
+        return React.createElement(
+          "div",
+          { className: "_psh" },
+          React.createElement(
+            "div",
+            { className: "_3cc0" },
+            React.createElement(
+              "div",
+              null,
+              React.createElement(AdsEditorLoadingErrors90, { x: 215, key: ".0" }),
+              React.createElement(
+                "div",
+                { className: "_3ms3" },
+                React.createElement(
+                  "div",
+                  { className: "_3ms4" },
+                  React.createElement(FluxContainer_AdsEditorColumnContainer_115, { x: 260, key: ".1" })
+                ),
+                React.createElement(
+                  "div",
+                  { className: "_3pvg" },
+                  React.createElement(FluxContainer_AdsEditorColumnContainer_115, { x: 293, key: ".2" })
+                )
+              )
+            )
+          )
+        );
+      }
     }
   });
 
-  var XUIButton145 = React.createClass({
-    displayName: "XUIButton145",
+  var AdsPECampaignGroupEditor132 = React.createClass({
+    displayName: "AdsPECampaignGroupEditor132",
 
     render: function () {
-      return React.createElement(AbstractButton144, null);
+      var props = this.props;
+      if (props.x === 295) {
+        return React.createElement(
+          "div",
+          null,
+          React.createElement(AdsPECampaignGroupHeaderSectionContainer89, { x: 214 }),
+          React.createElement(AdsEditorMultiColumnLayout131, { x: 294 })
+        );
+      }
     }
   });
 
-  var XUIButtonGroup146 = React.createClass({
-    displayName: "XUIButtonGroup146",
+  var AdsPECampaignGroupEditorContainer133 = React.createClass({
+    displayName: "AdsPECampaignGroupEditorContainer133",
 
     render: function () {
-      return React.createElement(
-        "div",
-        { className: "_5n7z _51xa" },
-        React.createElement(XUIButton139, { key: "duplicate" }),
-        React.createElement(XUIButton142, { key: "revert" }),
-        React.createElement(XUIButton145, { key: "delete" })
-      );
+      var props = this.props;
+      if (props.x === 296) {
+        return React.createElement(AdsPECampaignGroupEditor132, { x: 295 });
+      }
     }
   });
 
-  var ReactImage147 = React.createClass({
-    displayName: "ReactImage147",
+  var AdsPESideTrayTabContent134 = React.createClass({
+    displayName: "AdsPESideTrayTabContent134",
 
     render: function () {
-      return React.createElement("i", { src: null, className: "img sp_UuU9HmrQ397 sx_8c19ae" });
+      var props = this.props;
+      if (props.x === 297) {
+        return React.createElement(
+          "div",
+          { className: "_1o_8 _44ra _5cyn" },
+          React.createElement(AdsPECampaignGroupEditorContainer133, { x: 296 })
+        );
+      }
     }
   });
 
-  var AbstractButton148 = React.createClass({
-    displayName: "AbstractButton148",
+  var AdsPEEditorTrayTabContentContainer135 = React.createClass({
+    displayName: "AdsPEEditorTrayTabContentContainer135",
 
     render: function () {
-      return React.createElement(
-        "button",
-        { size: "large", disabled: false, className: "_u_k _4jy0 _4jy4 _517h _51sy _42ft", image: {}, "data-hover": "tooltip", "aria-label": "Save Audience", onClick: function () {}, use: "default", borderShade: "light", suppressed: false, label: null, type: "submit", value: "1" },
-        React.createElement(ReactImage147, null),
-        undefined,
-        undefined
-      );
+      var props = this.props;
+      if (props.x === 298) {
+        return React.createElement(AdsPESideTrayTabContent134, { x: 297 });
+      }
     }
   });
 
-  var XUIButton149 = React.createClass({
-    displayName: "XUIButton149",
+  var AdsPEMultiTabDrawer136 = React.createClass({
+    displayName: "AdsPEMultiTabDrawer136",
 
     render: function () {
-      return React.createElement(AbstractButton148, null);
+      var props = this.props;
+      if (props.x === 299) {
+        return React.createElement(
+          "div",
+          { className: "_2kev _2kex" },
+          React.createElement(
+            "div",
+            { className: "_5yno" },
+            React.createElement(AdsPEEditorTrayTabButton83, { x: 197, key: "editor_tray_button" }),
+            React.createElement(AdsPEInsightsTrayTabButton84, { x: 202, key: "insights_tray_button" }),
+            React.createElement(AdsPENekoDebuggerTrayTabButton85, { x: 204, key: "neko_debugger_tray_button" })
+          ),
+          React.createElement(
+            "div",
+            { className: "_5ynn" },
+            React.createElement(AdsPEEditorTrayTabContentContainer135, { x: 298, key: "EDITOR_DRAWER" }),
+            null
+          )
+        );
+      }
     }
   });
 
-  var ReactImage150 = React.createClass({
-    displayName: "ReactImage150",
+  var FluxContainer_AdsPEMultiTabDrawerContainer_137 = React.createClass({
+    displayName: "FluxContainer_AdsPEMultiTabDrawerContainer_137",
 
     render: function () {
-      return React.createElement("i", { src: null, className: "img sp_UuU9HmrQ397 sx_d2b33c" });
+      var props = this.props;
+      if (props.x === 300) {
+        return React.createElement(AdsPEMultiTabDrawer136, { x: 299 });
+      }
     }
   });
 
-  var AbstractButton151 = React.createClass({
-    displayName: "AbstractButton151",
+  var AdsPESimpleOrganizer138 = React.createClass({
+    displayName: "AdsPESimpleOrganizer138",
 
     render: function () {
-      return React.createElement(
-        "button",
-        { size: "large", className: "_u_k noMargin _p _4jy0 _4jy4 _517h _51sy _42ft", onClick: function () {}, image: {}, "data-hover": "tooltip", "aria-label": "Export & Import", use: "default", borderShade: "light", suppressed: false, label: null, type: "submit", value: "1" },
-        React.createElement(ReactImage150, null),
-        undefined,
-        undefined
-      );
+      var props = this.props;
+      if (props.x === 309) {
+        return React.createElement(
+          "div",
+          { className: "_tm2" },
+          React.createElement(XUIButton4, { x: 304 }),
+          React.createElement(XUIButton4, { x: 306 }),
+          React.createElement(XUIButton4, { x: 308 })
+        );
+      }
     }
   });
 
-  var XUIButton152 = React.createClass({
-    displayName: "XUIButton152",
+  var AdsPEOrganizerContainer139 = React.createClass({
+    displayName: "AdsPEOrganizerContainer139",
 
     render: function () {
-      return React.createElement(AbstractButton151, null);
+      var props = this.props;
+      if (props.x === 310) {
+        return React.createElement(
+          "div",
+          null,
+          React.createElement(AdsPESimpleOrganizer138, { x: 309 })
+        );
+      }
     }
   });
 
-  var InlineBlock153 = React.createClass({
-    displayName: "InlineBlock153",
+  var FixedDataTableColumnResizeHandle140 = React.createClass({
+    displayName: "FixedDataTableColumnResizeHandle140",
 
     render: function () {
-      return React.createElement(
-        "div",
-        { menu: {}, size: "large", alignv: "middle", className: "uiPopover _6a _6b", disabled: null, fullWidth: false },
-        React.createElement(XUIButton152, { key: "/.0" })
-      );
+      var props = this.props;
+      if (props.x === 313) {
+        return React.createElement(
+          "div",
+          { className: "_3487 _3488 _3489", style: { "width": 0, "height": 25, "left": 0 } },
+          React.createElement("div", { className: "_348a", style: { "height": 25 } })
+        );
+      }
     }
   });
 
-  var ReactPopoverMenu154 = React.createClass({
-    displayName: "ReactPopoverMenu154",
+  var AdsPETableHeader141 = React.createClass({
+    displayName: "AdsPETableHeader141",
 
     render: function () {
-      return React.createElement(InlineBlock153, { ref: "root" });
-    }
-  });
-
-  var AdsPEExportImportMenu155 = React.createClass({
-    displayName: "AdsPEExportImportMenu155",
-
-    render: function () {
-      return React.createElement(ReactPopoverMenu154, { key: "export" });
-    }
-  });
-
-  var FluxContainer_x_156 = React.createClass({
-    displayName: "FluxContainer_x_156",
-
-    render: function () {
-      return null;
-    }
-  });
-
-  var AdsPEExportAsTextDialog157 = React.createClass({
-    displayName: "AdsPEExportAsTextDialog157",
-
-    render: function () {
-      return null;
-    }
-  });
-
-  var FluxContainer_q_158 = React.createClass({
-    displayName: "FluxContainer_q_158",
-
-    render: function () {
-      return React.createElement(AdsPEExportAsTextDialog157, null);
-    }
-  });
-
-  var AdsPEExportImportMenuContainer159 = React.createClass({
-    displayName: "AdsPEExportImportMenuContainer159",
-
-    render: function () {
-      return React.createElement(
-        "span",
-        null,
-        React.createElement(AdsPEExportImportMenu155, null),
-        React.createElement(FluxContainer_x_156, null),
-        React.createElement(FluxContainer_q_158, null),
-        null
-      );
-    }
-  });
-
-  var ReactImage160 = React.createClass({
-    displayName: "ReactImage160",
-
-    render: function () {
-      return React.createElement("i", { src: null, className: "img sp_UuU9HmrQ397 sx_872db1" });
-    }
-  });
-
-  var AbstractButton161 = React.createClass({
-    displayName: "AbstractButton161",
-
-    render: function () {
-      return React.createElement(
-        "button",
-        { size: "large", disabled: false, onClick: function () {}, className: "_u_k _5n7z _4jy0 _4jy4 _517h _51sy _42ft", image: {}, style: { "boxSizing": "border-box", "height": "28px", "width": "48px" }, "data-hover": "tooltip", "aria-label": "Create Report", use: "default", borderShade: "light", suppressed: false, label: null, type: "submit", value: "1" },
-        React.createElement(ReactImage160, null),
-        undefined,
-        undefined
-      );
-    }
-  });
-
-  var XUIButton162 = React.createClass({
-    displayName: "XUIButton162",
-
-    render: function () {
-      return React.createElement(AbstractButton161, null);
-    }
-  });
-
-  var AbstractButton163 = React.createClass({
-    displayName: "AbstractButton163",
-
-    render: function () {
-      return React.createElement(
-        "button",
-        { size: "large", disabled: true, className: "hidden_elem _5n7z _4jy0 _4jy4 _517h _51sy _42ft _42fr", label: null, onClick: function () {}, use: "default", borderShade: "light", suppressed: false, type: "submit", value: "1" },
-        undefined,
-        "Generate Variations",
-        undefined
-      );
-    }
-  });
-
-  var XUIButton164 = React.createClass({
-    displayName: "XUIButton164",
-
-    render: function () {
-      return React.createElement(AbstractButton163, null);
-    }
-  });
-
-  var XUIButtonGroup165 = React.createClass({
-    displayName: "XUIButtonGroup165",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_5n7z _51xa" },
-        React.createElement(XUIButton149, { key: "saveAudience" }),
-        React.createElement(AdsPEExportImportMenuContainer159, null),
-        React.createElement(XUIButton162, { key: "createReport", ref: "ads_create_report_button" }),
-        React.createElement(XUIButton164, { key: "variations" })
-      );
-    }
-  });
-
-  var FillColumn166 = React.createClass({
-    displayName: "FillColumn166",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4bl9" },
-        React.createElement(
-          "span",
-          { className: "_3c5e" },
+      var props = this.props;
+      if (props.x === 315) {
+        return React.createElement(
+          "div",
+          { className: "_1cig _1ksv _1vd7 _4h2r", id: undefined },
+          React.createElement(ReactImage0, { x: 314 }),
           React.createElement(
             "span",
-            null,
-            React.createElement(XUIButtonGroup133, null),
-            React.createElement(XUIButton136, { key: "edit" }),
-            React.createElement(XUIButtonGroup146, null)
-          ),
-          React.createElement(XUIButtonGroup165, null)
-        )
-      );
-    }
-  });
-
-  var Layout167 = React.createClass({
-    displayName: "Layout167",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "clearfix" },
-        React.createElement(Column124, { key: "1" }),
-        React.createElement(FillColumn166, { key: "0" })
-      );
-    }
-  });
-
-  var AdsPEMainPaneToolbar168 = React.createClass({
-    displayName: "AdsPEMainPaneToolbar168",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_3c5b clearfix" },
-        React.createElement(Layout167, null)
-      );
-    }
-  });
-
-  var AdsPEAdgroupToolbarContainer169 = React.createClass({
-    displayName: "AdsPEAdgroupToolbarContainer169",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        null,
-        React.createElement(AdsPEMainPaneToolbar168, null),
-        null
-      );
-    }
-  });
-
-  var AbstractButton170 = React.createClass({
-    displayName: "AbstractButton170",
-
-    render: function () {
-      return React.createElement(
-        "button",
-        { className: "_tm3 _tm6 _4jy0 _4jy6 _517h _51sy _42ft", label: null, "data-tooltip-position": "right", "aria-label": "Campaigns", "data-hover": "tooltip", onClick: function () {}, size: "xxlarge", use: "default", borderShade: "light", suppressed: false, type: "submit", value: "1" },
-        undefined,
-        React.createElement(
+            { className: "_1cid" },
+            "Campaigns"
+          )
+        );
+      }
+      if (props.x === 320) {
+        return React.createElement(
           "div",
+          { className: "_1cig _1vd7 _4h2r", id: undefined },
           null,
-          React.createElement("div", { className: "_tma" }),
-          React.createElement("div", { className: "_tm8" }),
           React.createElement(
-            "div",
-            { className: "_tm9" },
-            1
+            "span",
+            { className: "_1cid" },
+            "Performance"
           )
-        ),
-        undefined
-      );
-    }
-  });
-
-  var XUIButton171 = React.createClass({
-    displayName: "XUIButton171",
-
-    render: function () {
-      return React.createElement(AbstractButton170, null);
-    }
-  });
-
-  var AbstractButton172 = React.createClass({
-    displayName: "AbstractButton172",
-
-    render: function () {
-      return React.createElement(
-        "button",
-        { className: "_tm4 _tm6 _4jy0 _4jy6 _517h _51sy _42ft", label: null, "data-tooltip-position": "right", "aria-label": "Ad Sets", "data-hover": "tooltip", onClick: function () {}, size: "xxlarge", use: "default", borderShade: "light", suppressed: false, type: "submit", value: "1" },
-        undefined,
-        React.createElement(
+        );
+      }
+      if (props.x === 323) {
+        return React.createElement(
           "div",
+          { className: "_1cig _1vd7 _4h2r", id: undefined },
           null,
-          React.createElement("div", { className: "_tma" }),
-          React.createElement("div", { className: "_tm8" }),
           React.createElement(
-            "div",
-            { className: "_tm9" },
-            1
+            "span",
+            { className: "_1cid" },
+            "Overview"
           )
-        ),
-        undefined
-      );
-    }
-  });
-
-  var XUIButton173 = React.createClass({
-    displayName: "XUIButton173",
-
-    render: function () {
-      return React.createElement(AbstractButton172, null);
-    }
-  });
-
-  var AbstractButton174 = React.createClass({
-    displayName: "AbstractButton174",
-
-    render: function () {
-      return React.createElement(
-        "button",
-        { className: "_tm5 _tm6 _tm7 _4jy0 _4jy6 _517h _51sy _42ft", label: null, "data-tooltip-position": "right", "aria-label": "Ads", "data-hover": "tooltip", onClick: function () {}, size: "xxlarge", use: "default", borderShade: "light", suppressed: false, type: "submit", value: "1" },
-        undefined,
-        React.createElement(
+        );
+      }
+      if (props.x === 326) {
+        return React.createElement(
           "div",
+          { className: "_1cig _1vd7 _4h2r", id: undefined },
           null,
-          React.createElement("div", { className: "_tma" }),
-          React.createElement("div", { className: "_tm8" }),
           React.createElement(
-            "div",
-            { className: "_tm9" },
-            1
+            "span",
+            { className: "_1cid" },
+            "Toplines"
           )
-        ),
-        undefined
-      );
-    }
-  });
-
-  var XUIButton175 = React.createClass({
-    displayName: "XUIButton175",
-
-    render: function () {
-      return React.createElement(AbstractButton174, null);
-    }
-  });
-
-  var AdsPESimpleOrganizer176 = React.createClass({
-    displayName: "AdsPESimpleOrganizer176",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_tm2" },
-        React.createElement(XUIButton171, null),
-        React.createElement(XUIButton173, null),
-        React.createElement(XUIButton175, null)
-      );
-    }
-  });
-
-  var AdsPEOrganizerContainer177 = React.createClass({
-    displayName: "AdsPEOrganizerContainer177",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        null,
-        React.createElement(AdsPESimpleOrganizer176, null)
-      );
-    }
-  });
-
-  var FixedDataTableColumnResizeHandle178 = React.createClass({
-    displayName: "FixedDataTableColumnResizeHandle178",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_3487 _3488 _3489", style: { "width": 0, "height": 532, "left": 0 } },
-        React.createElement("div", { className: "_348a", style: { "height": 532 } })
-      );
-    }
-  });
-
-  var ReactImage179 = React.createClass({
-    displayName: "ReactImage179",
-
-    render: function () {
-      return React.createElement("i", { className: "_1cie _1cif img sp_R48dKBxiJkP sx_dc0ad2", src: null });
-    }
-  });
-
-  var AdsPETableHeader180 = React.createClass({
-    displayName: "AdsPETableHeader180",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _1ksv _1vd7 _4h2r" },
-        React.createElement(ReactImage179, null),
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "Ads"
-        )
-      );
-    }
-  });
-
-  var TransitionCell181 = React.createClass({
-    displayName: "TransitionCell181",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "Ads", dataKey: 0, groupHeaderRenderer: function () {}, groupHeaderLabels: {}, groupHeaderData: {}, columnKey: undefined, height: 40, width: 521, rowIndex: 0, className: "_4lgc _4h2u", style: { "height": 40, "width": 521 } },
-        React.createElement(
+        );
+      }
+      if (props.x === 329) {
+        return React.createElement("div", { className: "_1cig _1vd7 _4h2r", id: undefined });
+      }
+      if (props.x === 340) {
+        return React.createElement(
+          "div",
+          { className: "_1cig _25fg", id: undefined },
+          null,
+          React.createElement(
+            "span",
+            { className: "_1cid" },
+            "Campaign Name"
+          )
+        );
+      }
+      if (props.x === 346) {
+        return React.createElement(
+          "div",
+          { className: "_1cig _25fg", id: undefined, "data-tooltip-content": "Changed", "data-hover": "tooltip" },
+          React.createElement(ReactImage0, { x: 345 }),
+          null
+        );
+      }
+      if (props.x === 352) {
+        return React.createElement(
+          "div",
+          { className: "_1cig _25fg", id: "ads_pe_table_error_header", "data-tooltip-content": "Errors", "data-hover": "tooltip" },
+          React.createElement(ReactImage0, { x: 351 }),
+          null
+        );
+      }
+      if (props.x === 357) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { className: "_1cig _25fg", id: undefined },
+          null,
           React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(AdsPETableHeader180, null)
+            "span",
+            { className: "_1cid" },
+            "Status"
           )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell182 = React.createClass({
-    displayName: "FixedDataTableCell182",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 40, "width": 521, "left": 0 } },
-        undefined,
-        React.createElement(TransitionCell181, null)
-      );
-    }
-  });
-
-  var FixedDataTableCellGroupImpl183 = React.createClass({
-    displayName: "FixedDataTableCellGroupImpl183",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_3pzj", style: { "height": 40, "position": "absolute", "width": 521, "zIndex": 2, "transform": "translate3d(0px,0px,0)", "backfaceVisibility": "hidden" } },
-        React.createElement(FixedDataTableCell182, { key: "cell_0" })
-      );
-    }
-  });
-
-  var FixedDataTableCellGroup184 = React.createClass({
-    displayName: "FixedDataTableCellGroup184",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { style: { "height": 40, "left": 0 }, className: "_3pzk" },
-        React.createElement(FixedDataTableCellGroupImpl183, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader185 = React.createClass({
-    displayName: "AdsPETableHeader185",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _1vd7 _4h2r" },
-        null,
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "Delivery"
-        )
-      );
-    }
-  });
-
-  var TransitionCell186 = React.createClass({
-    displayName: "TransitionCell186",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "Delivery", dataKey: 1, groupHeaderRenderer: function () {}, groupHeaderLabels: {}, groupHeaderData: {}, columnKey: undefined, height: 40, width: 298, rowIndex: 0, className: "_4lgc _4h2u", style: { "height": 40, "width": 298 } },
-        React.createElement(
+        );
+      }
+      if (props.x === 362) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { className: "_1cig _25fg", id: undefined },
+          null,
           React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(AdsPETableHeader185, null)
+            "span",
+            { className: "_1cid" },
+            "Delivery"
           )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell187 = React.createClass({
-    displayName: "FixedDataTableCell187",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 40, "width": 298, "left": 0 } },
-        undefined,
-        React.createElement(TransitionCell186, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader188 = React.createClass({
-    displayName: "AdsPETableHeader188",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _1vd7 _4h2r" },
-        null,
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "Performance"
-        )
-      );
-    }
-  });
-
-  var TransitionCell189 = React.createClass({
-    displayName: "TransitionCell189",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "Performance", dataKey: 2, groupHeaderRenderer: function () {}, groupHeaderLabels: {}, groupHeaderData: {}, columnKey: undefined, height: 40, width: 490, rowIndex: 0, className: "_4lgc _4h2u", style: { "height": 40, "width": 490 } },
-        React.createElement(
+        );
+      }
+      if (props.x === 369) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { className: "_1cig _25fg", id: undefined },
+          null,
           React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(AdsPETableHeader188, null)
+            "span",
+            { className: "_1cid" },
+            "Results"
           )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell190 = React.createClass({
-    displayName: "FixedDataTableCell190",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 40, "width": 490, "left": 298 } },
-        undefined,
-        React.createElement(TransitionCell189, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader191 = React.createClass({
-    displayName: "AdsPETableHeader191",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _1vd7 _4h2r" },
-        null,
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "Overview"
-        )
-      );
-    }
-  });
-
-  var TransitionCell192 = React.createClass({
-    displayName: "TransitionCell192",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "Overview", dataKey: 3, groupHeaderRenderer: function () {}, groupHeaderLabels: {}, groupHeaderData: {}, columnKey: undefined, height: 40, width: 972, rowIndex: 0, className: "_4lgc _4h2u", style: { "height": 40, "width": 972 } },
-        React.createElement(
+        );
+      }
+      if (props.x === 374) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { className: "_1cig _25fg", id: undefined },
+          null,
           React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(AdsPETableHeader191, null)
+            "span",
+            { className: "_1cid" },
+            "Cost"
           )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell193 = React.createClass({
-    displayName: "FixedDataTableCell193",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 40, "width": 972, "left": 788 } },
-        undefined,
-        React.createElement(TransitionCell192, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader194 = React.createClass({
-    displayName: "AdsPETableHeader194",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _1vd7 _4h2r" },
-        null,
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "Creative Assets"
-        )
-      );
-    }
-  });
-
-  var TransitionCell195 = React.createClass({
-    displayName: "TransitionCell195",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "Creative Assets", dataKey: 4, groupHeaderRenderer: function () {}, groupHeaderLabels: {}, groupHeaderData: {}, columnKey: undefined, height: 40, width: 514, rowIndex: 0, className: "_4lgc _4h2u", style: { "height": 40, "width": 514 } },
-        React.createElement(
+        );
+      }
+      if (props.x === 379) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { className: "_1cig _25fg", id: undefined },
+          null,
           React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(AdsPETableHeader194, null)
+            "span",
+            { className: "_1cid" },
+            "Reach"
           )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell196 = React.createClass({
-    displayName: "FixedDataTableCell196",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 40, "width": 514, "left": 1760 } },
-        undefined,
-        React.createElement(TransitionCell195, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader197 = React.createClass({
-    displayName: "AdsPETableHeader197",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _1vd7 _4h2r" },
-        null,
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "Toplines"
-        )
-      );
-    }
-  });
-
-  var TransitionCell198 = React.createClass({
-    displayName: "TransitionCell198",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "Toplines", dataKey: 5, groupHeaderRenderer: function () {}, groupHeaderLabels: {}, groupHeaderData: {}, columnKey: undefined, height: 40, width: 0, rowIndex: 0, className: "_4lgc _4h2u", style: { "height": 40, "width": 0 } },
-        React.createElement(
+        );
+      }
+      if (props.x === 384) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { className: "_1cig _25fg", id: undefined },
+          null,
           React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(AdsPETableHeader197, null)
+            "span",
+            { className: "_1cid" },
+            "Impressions"
           )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell199 = React.createClass({
-    displayName: "FixedDataTableCell199",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 40, "width": 0, "left": 2274 } },
-        undefined,
-        React.createElement(TransitionCell198, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader200 = React.createClass({
-    displayName: "AdsPETableHeader200",
-
-    render: function () {
-      return React.createElement("div", { className: "_1cig _1vd7 _4h2r" });
-    }
-  });
-
-  var TransitionCell201 = React.createClass({
-    displayName: "TransitionCell201",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "", dataKey: 6, groupHeaderRenderer: function () {}, groupHeaderLabels: {}, groupHeaderData: {}, columnKey: undefined, height: 40, width: 25, rowIndex: 0, className: "_4lgc _4h2u", style: { "height": 40, "width": 25 } },
-        React.createElement(
+        );
+      }
+      if (props.x === 389) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { className: "_1cig _25fg", id: undefined },
+          null,
           React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(AdsPETableHeader200, null)
+            "span",
+            { className: "_1cid" },
+            "Clicks"
           )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell202 = React.createClass({
-    displayName: "FixedDataTableCell202",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 40, "width": 25, "left": 2274 } },
-        undefined,
-        React.createElement(TransitionCell201, null)
-      );
-    }
-  });
-
-  var FixedDataTableCellGroupImpl203 = React.createClass({
-    displayName: "FixedDataTableCellGroupImpl203",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_3pzj", style: { "height": 40, "position": "absolute", "width": 2299, "zIndex": 0, "transform": "translate3d(0px,0px,0)", "backfaceVisibility": "hidden" } },
-        React.createElement(FixedDataTableCell187, { key: "cell_0" }),
-        React.createElement(FixedDataTableCell190, { key: "cell_1" }),
-        React.createElement(FixedDataTableCell193, { key: "cell_2" }),
-        React.createElement(FixedDataTableCell196, { key: "cell_3" }),
-        React.createElement(FixedDataTableCell199, { key: "cell_4" }),
-        React.createElement(FixedDataTableCell202, { key: "cell_5" })
-      );
-    }
-  });
-
-  var FixedDataTableCellGroup204 = React.createClass({
-    displayName: "FixedDataTableCellGroup204",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { style: { "height": 40, "left": 521 }, className: "_3pzk" },
-        React.createElement(FixedDataTableCellGroupImpl203, null)
-      );
-    }
-  });
-
-  var FixedDataTableRowImpl205 = React.createClass({
-    displayName: "FixedDataTableRowImpl205",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1gd4 _4li _52no _3h1a _1mib", onClick: null, onDoubleClick: null, onMouseDown: null, onMouseEnter: null, onMouseLeave: null, style: { "width": 1083, "height": 40 } },
-        React.createElement(
+        );
+      }
+      if (props.x === 394) {
+        return React.createElement(
           "div",
-          { className: "_1gd5" },
-          React.createElement(FixedDataTableCellGroup184, { key: "fixed_cells" }),
-          React.createElement(FixedDataTableCellGroup204, { key: "scrollable_cells" }),
-          React.createElement("div", { className: "_1gd6 _1gd8", style: { "left": 521, "height": 40 } })
-        )
-      );
-    }
-  });
-
-  var FixedDataTableRow206 = React.createClass({
-    displayName: "FixedDataTableRow206",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { style: { "width": 1083, "height": 40, "zIndex": 1, "transform": "translate3d(0px,0px,0)", "backfaceVisibility": "hidden" }, className: "_1gda" },
-        React.createElement(FixedDataTableRowImpl205, null)
-      );
-    }
-  });
-
-  var AbstractCheckboxInput207 = React.createClass({
-    displayName: "AbstractCheckboxInput207",
-
-    render: function () {
-      return React.createElement(
-        "label",
-        { className: "_4h2r _55sg _kv1" },
-        React.createElement("input", { checked: undefined, onChange: function () {}, className: null, type: "checkbox" }),
-        React.createElement("span", { "data-hover": null, "aria-label": undefined })
-      );
-    }
-  });
-
-  var XUICheckboxInput208 = React.createClass({
-    displayName: "XUICheckboxInput208",
-
-    render: function () {
-      return React.createElement(AbstractCheckboxInput207, null);
-    }
-  });
-
-  var TransitionCell209 = React.createClass({
-    displayName: "TransitionCell209",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: undefined, width: 42, dataKey: "common.id", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "common.id", height: 25, style: { "height": 25, "width": 42 } },
-        React.createElement(
+          { className: "_1cig _25fg", id: undefined },
+          null,
+          React.createElement(
+            "span",
+            { className: "_1cid" },
+            "Avg. CPM"
+          )
+        );
+      }
+      if (props.x === 399) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { className: "_1cig _25fg", id: undefined },
+          null,
           React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(XUICheckboxInput208, null)
+            "span",
+            { className: "_1cid" },
+            "Avg. CPC"
           )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell210 = React.createClass({
-    displayName: "FixedDataTableCell210",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4lg6 _4h2m", style: { "height": 25, "width": 42, "left": 0 } },
-        undefined,
-        React.createElement(TransitionCell209, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader211 = React.createClass({
-    displayName: "AdsPETableHeader211",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _25fg" },
-        null,
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "Ad Name"
-        )
-      );
-    }
-  });
-
-  var FixedDataTableAbstractSortableHeader212 = React.createClass({
-    displayName: "FixedDataTableAbstractSortableHeader212",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
-        React.createElement(
+        );
+      }
+      if (props.x === 404) {
+        return React.createElement(
           "div",
-          { className: "_2eq6" },
+          { className: "_1cig _25fg", id: undefined },
           null,
-          React.createElement(AdsPETableHeader211, null)
-        )
-      );
-    }
-  });
-
-  var FixedDataTableSortableHeader213 = React.createClass({
-    displayName: "FixedDataTableSortableHeader213",
-
-    render: function () {
-      return React.createElement(FixedDataTableAbstractSortableHeader212, null);
-    }
-  });
-
-  var TransitionCell214 = React.createClass({
-    displayName: "TransitionCell214",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "Ad Name", width: 200, dataKey: "ad.name", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "ad.name", height: 25, style: { "height": 25, "width": 200 } },
-        React.createElement(
+          React.createElement(
+            "span",
+            { className: "_1cid" },
+            "CTR %"
+          )
+        );
+      }
+      if (props.x === 409) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { className: "_1cig _25fg", id: undefined },
+          null,
           React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(FixedDataTableSortableHeader213, null)
+            "span",
+            { className: "_1cid" },
+            "Spent"
           )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell215 = React.createClass({
-    displayName: "FixedDataTableCell215",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 200, "left": 42 } },
-        React.createElement(
+        );
+      }
+      if (props.x === 414) {
+        return React.createElement(
           "div",
-          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
-          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
-        ),
-        React.createElement(TransitionCell214, null)
-      );
-    }
-  });
-
-  var ReactImage216 = React.createClass({
-    displayName: "ReactImage216",
-
-    render: function () {
-      return React.createElement("i", { className: "_1cie img sp_UuU9HmrQ397 sx_844e7d", src: null });
-    }
-  });
-
-  var AdsPETableHeader217 = React.createClass({
-    displayName: "AdsPETableHeader217",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _25fg" },
-        React.createElement(ReactImage216, null),
-        null
-      );
-    }
-  });
-
-  var FixedDataTableAbstractSortableHeader218 = React.createClass({
-    displayName: "FixedDataTableAbstractSortableHeader218",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { onClick: function () {}, className: "_54_8 _1kst _4h2r _2wzx" },
-        React.createElement(
+          { className: "_1cig _25fg", id: undefined },
+          null,
+          React.createElement(
+            "span",
+            { className: "_1cid" },
+            "Objective"
+          )
+        );
+      }
+      if (props.x === 419) {
+        return React.createElement(
           "div",
-          { className: "_2eq6" },
+          { className: "_1cig _25fg", id: undefined },
           null,
-          React.createElement(AdsPETableHeader217, null)
-        )
-      );
-    }
-  });
-
-  var FixedDataTableSortableHeader219 = React.createClass({
-    displayName: "FixedDataTableSortableHeader219",
-
-    render: function () {
-      return React.createElement(FixedDataTableAbstractSortableHeader218, null);
-    }
-  });
-
-  var TransitionCell220 = React.createClass({
-    displayName: "TransitionCell220",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: undefined, width: 33, dataKey: "edit_status", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "edit_status", height: 25, style: { "height": 25, "width": 33 } },
-        React.createElement(
+          React.createElement(
+            "span",
+            { className: "_1cid" },
+            "Buying Type"
+          )
+        );
+      }
+      if (props.x === 424) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { className: "_1cig _25fg", id: undefined },
+          null,
           React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(FixedDataTableSortableHeader219, null)
+            "span",
+            { className: "_1cid" },
+            "Campaign ID"
           )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell221 = React.createClass({
-    displayName: "FixedDataTableCell221",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 33, "left": 242 } },
-        undefined,
-        React.createElement(TransitionCell220, null)
-      );
-    }
-  });
-
-  var ReactImage222 = React.createClass({
-    displayName: "ReactImage222",
-
-    render: function () {
-      return React.createElement("i", { className: "_1cie img sp_UuU9HmrQ397 sx_36dc45", src: null });
-    }
-  });
-
-  var AdsPETableHeader223 = React.createClass({
-    displayName: "AdsPETableHeader223",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _25fg" },
-        React.createElement(ReactImage222, null),
-        null
-      );
-    }
-  });
-
-  var FixedDataTableAbstractSortableHeader224 = React.createClass({
-    displayName: "FixedDataTableAbstractSortableHeader224",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { onClick: function () {}, className: "_54_8 _1kst _4h2r _2wzx" },
-        React.createElement(
+        );
+      }
+      if (props.x === 429) {
+        return React.createElement(
           "div",
-          { className: "_2eq6" },
+          { className: "_1cig _25fg", id: undefined },
           null,
-          React.createElement(AdsPETableHeader223, null)
-        )
-      );
-    }
-  });
-
-  var FixedDataTableSortableHeader225 = React.createClass({
-    displayName: "FixedDataTableSortableHeader225",
-
-    render: function () {
-      return React.createElement(FixedDataTableAbstractSortableHeader224, null);
-    }
-  });
-
-  var TransitionCell226 = React.createClass({
-    displayName: "TransitionCell226",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: undefined, width: 36, dataKey: "errors", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "errors", height: 25, style: { "height": 25, "width": 36 } },
-        React.createElement(
+          React.createElement(
+            "span",
+            { className: "_1cid" },
+            "Start"
+          )
+        );
+      }
+      if (props.x === 434) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { className: "_1cig _25fg", id: undefined },
+          null,
           React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(FixedDataTableSortableHeader225, null)
+            "span",
+            { className: "_1cid" },
+            "End"
           )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell227 = React.createClass({
-    displayName: "FixedDataTableCell227",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 36, "left": 275 } },
-        undefined,
-        React.createElement(TransitionCell226, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader228 = React.createClass({
-    displayName: "AdsPETableHeader228",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _25fg" },
-        null,
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "Status"
-        )
-      );
-    }
-  });
-
-  var FixedDataTableAbstractSortableHeader229 = React.createClass({
-    displayName: "FixedDataTableAbstractSortableHeader229",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
-        React.createElement(
+        );
+      }
+      if (props.x === 439) {
+        return React.createElement(
           "div",
-          { className: "_2eq6" },
+          { className: "_1cig _25fg", id: undefined },
           null,
-          React.createElement(AdsPETableHeader228, null)
-        )
-      );
-    }
-  });
-
-  var FixedDataTableSortableHeader230 = React.createClass({
-    displayName: "FixedDataTableSortableHeader230",
-
-    render: function () {
-      return React.createElement(FixedDataTableAbstractSortableHeader229, null);
-    }
-  });
-
-  var TransitionCell231 = React.createClass({
-    displayName: "TransitionCell231",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "Status", width: 60, dataKey: "ad.adgroup_status", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "ad.adgroup_status", height: 25, style: { "height": 25, "width": 60 } },
-        React.createElement(
+          React.createElement(
+            "span",
+            { className: "_1cid" },
+            "Date created"
+          )
+        );
+      }
+      if (props.x === 444) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { className: "_1cig _25fg", id: undefined },
+          null,
           React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(FixedDataTableSortableHeader230, null)
+            "span",
+            { className: "_1cid" },
+            "Date last edited"
           )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell232 = React.createClass({
-    displayName: "FixedDataTableCell232",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 60, "left": 311 } },
-        undefined,
-        React.createElement(TransitionCell231, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader233 = React.createClass({
-    displayName: "AdsPETableHeader233",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _25fg" },
-        null,
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "Delivery"
-        )
-      );
-    }
-  });
-
-  var FixedDataTableAbstractSortableHeader234 = React.createClass({
-    displayName: "FixedDataTableAbstractSortableHeader234",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
-        React.createElement(
+        );
+      }
+      if (props.x === 449) {
+        return React.createElement(
           "div",
-          { className: "_2eq6" },
+          { className: "_1cig _25fg _4h2r", id: undefined },
           null,
-          React.createElement(AdsPETableHeader233, null)
-        )
-      );
-    }
-  });
-
-  var FixedDataTableSortableHeader235 = React.createClass({
-    displayName: "FixedDataTableSortableHeader235",
-
-    render: function () {
-      return React.createElement(FixedDataTableAbstractSortableHeader234, null);
+          React.createElement(
+            "span",
+            { className: "_1cid" },
+            "Tags"
+          )
+        );
+      }
+      if (props.x === 452) {
+        return React.createElement("div", { className: "_1cig _25fg _4h2r", id: undefined });
+      }
     }
   });
 
-  var TransitionCell236 = React.createClass({
-    displayName: "TransitionCell236",
+  var TransitionCell142 = React.createClass({
+    displayName: "TransitionCell142",
 
     render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "Delivery", width: 150, dataKey: "ukiAdData.computed_activity_status", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "ukiAdData.computed_activity_status", height: 25, style: { "height": 25, "width": 150 } },
-        React.createElement(
+      var props = this.props;
+      if (props.x === 316) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { isHeaderCell: true, label: "Campaigns", dataKey: 0, groupHeaderRenderer: function () {}, groupHeaderLabels: {}, groupHeaderData: {}, columnKey: undefined, height: 40, width: 721, rowIndex: 0, className: "_4lgc _4h2u", style: { "height": 40, "width": 721 } },
           React.createElement(
             "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(FixedDataTableSortableHeader235, null)
+            { className: "_4lgd _4h2w" },
+            React.createElement(
+              "div",
+              { className: "_4lge _4h2x" },
+              React.createElement(AdsPETableHeader141, { x: 315 })
+            )
           )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell237 = React.createClass({
-    displayName: "FixedDataTableCell237",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 150, "left": 371 } },
-        React.createElement(
+        );
+      }
+      if (props.x === 321) {
+        return React.createElement(
           "div",
-          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
-          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
-        ),
-        React.createElement(TransitionCell236, null)
-      );
-    }
-  });
-
-  var FixedDataTableCellGroupImpl238 = React.createClass({
-    displayName: "FixedDataTableCellGroupImpl238",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_3pzj", style: { "height": 25, "position": "absolute", "width": 521, "zIndex": 2, "transform": "translate3d(0px,0px,0)", "backfaceVisibility": "hidden" } },
-        React.createElement(FixedDataTableCell210, { key: "cell_0" }),
-        React.createElement(FixedDataTableCell215, { key: "cell_1" }),
-        React.createElement(FixedDataTableCell221, { key: "cell_2" }),
-        React.createElement(FixedDataTableCell227, { key: "cell_3" }),
-        React.createElement(FixedDataTableCell232, { key: "cell_4" }),
-        React.createElement(FixedDataTableCell237, { key: "cell_5" })
-      );
-    }
-  });
-
-  var FixedDataTableCellGroup239 = React.createClass({
-    displayName: "FixedDataTableCellGroup239",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { style: { "height": 25, "left": 0 }, className: "_3pzk" },
-        React.createElement(FixedDataTableCellGroupImpl238, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader240 = React.createClass({
-    displayName: "AdsPETableHeader240",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _25fg" },
-        null,
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "Reach"
-        )
-      );
-    }
-  });
-
-  var FixedDataTableAbstractSortableHeader241 = React.createClass({
-    displayName: "FixedDataTableAbstractSortableHeader241",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
-        React.createElement(
-          "div",
-          { className: "_2eq6" },
-          null,
-          React.createElement(AdsPETableHeader240, null)
-        )
-      );
-    }
-  });
-
-  var FixedDataTableSortableHeader242 = React.createClass({
-    displayName: "FixedDataTableSortableHeader242",
-
-    render: function () {
-      return React.createElement(FixedDataTableAbstractSortableHeader241, null);
-    }
-  });
-
-  var TransitionCell243 = React.createClass({
-    displayName: "TransitionCell243",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "Reach", width: 60, dataKey: "stats.unique_impressions", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "stats.unique_impressions", height: 25, style: { "height": 25, "width": 60 } },
-        React.createElement(
+          { isHeaderCell: true, label: "Performance", dataKey: 1, groupHeaderRenderer: function () {}, groupHeaderLabels: {}, groupHeaderData: {}, columnKey: undefined, height: 40, width: 798, rowIndex: 0, className: "_4lgc _4h2u", style: { "height": 40, "width": 798 } },
+          React.createElement(
+            "div",
+            { className: "_4lgd _4h2w" },
+            React.createElement(
+              "div",
+              { className: "_4lge _4h2x" },
+              React.createElement(AdsPETableHeader141, { x: 320 })
+            )
+          )
+        );
+      }
+      if (props.x === 324) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { isHeaderCell: true, label: "Overview", dataKey: 2, groupHeaderRenderer: function () {}, groupHeaderLabels: {}, groupHeaderData: {}, columnKey: undefined, height: 40, width: 1022, rowIndex: 0, className: "_4lgc _4h2u", style: { "height": 40, "width": 1022 } },
           React.createElement(
             "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(FixedDataTableSortableHeader242, null)
+            { className: "_4lgd _4h2w" },
+            React.createElement(
+              "div",
+              { className: "_4lge _4h2x" },
+              React.createElement(AdsPETableHeader141, { x: 323 })
+            )
           )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell244 = React.createClass({
-    displayName: "FixedDataTableCell244",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 25, "width": 60, "left": 0 } },
-        React.createElement(
+        );
+      }
+      if (props.x === 327) {
+        return React.createElement(
           "div",
-          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
-          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
-        ),
-        React.createElement(TransitionCell243, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader245 = React.createClass({
-    displayName: "AdsPETableHeader245",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _25fg" },
-        null,
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "Ad Impressions"
-        )
-      );
-    }
-  });
-
-  var FixedDataTableAbstractSortableHeader246 = React.createClass({
-    displayName: "FixedDataTableAbstractSortableHeader246",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
-        React.createElement(
+          { isHeaderCell: true, label: "Toplines", dataKey: 3, groupHeaderRenderer: function () {}, groupHeaderLabels: {}, groupHeaderData: {}, columnKey: undefined, height: 40, width: 0, rowIndex: 0, className: "_4lgc _4h2u", style: { "height": 40, "width": 0 } },
+          React.createElement(
+            "div",
+            { className: "_4lgd _4h2w" },
+            React.createElement(
+              "div",
+              { className: "_4lge _4h2x" },
+              React.createElement(AdsPETableHeader141, { x: 326 })
+            )
+          )
+        );
+      }
+      if (props.x === 330) {
+        return React.createElement(
           "div",
-          { className: "_2eq6" },
-          null,
-          React.createElement(AdsPETableHeader245, null)
-        )
-      );
-    }
-  });
-
-  var FixedDataTableSortableHeader247 = React.createClass({
-    displayName: "FixedDataTableSortableHeader247",
-
-    render: function () {
-      return React.createElement(FixedDataTableAbstractSortableHeader246, null);
-    }
-  });
-
-  var TransitionCell248 = React.createClass({
-    displayName: "TransitionCell248",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "Ad Impressions", width: 80, dataKey: "stats.impressions", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "stats.impressions", height: 25, style: { "height": 25, "width": 80 } },
-        React.createElement(
+          { isHeaderCell: true, label: "", dataKey: 4, groupHeaderRenderer: function () {}, groupHeaderLabels: {}, groupHeaderData: {}, columnKey: undefined, height: 40, width: 25, rowIndex: 0, className: "_4lgc _4h2u", style: { "height": 40, "width": 25 } },
+          React.createElement(
+            "div",
+            { className: "_4lgd _4h2w" },
+            React.createElement(
+              "div",
+              { className: "_4lge _4h2x" },
+              React.createElement(AdsPETableHeader141, { x: 329 })
+            )
+          )
+        );
+      }
+      if (props.x === 338) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { isHeaderCell: true, label: undefined, width: 42, dataKey: "common.id", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "common.id", height: 25, style: { "height": 25, "width": 42 } },
           React.createElement(
             "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(FixedDataTableSortableHeader247, null)
+            { className: "_4lgd _4h2w" },
+            React.createElement(
+              "div",
+              { className: "_4lge _4h2x" },
+              React.createElement(XUICheckboxInput60, { x: 337 })
+            )
           )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell249 = React.createClass({
-    displayName: "FixedDataTableCell249",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 25, "width": 80, "left": 60 } },
-        React.createElement(
+        );
+      }
+      if (props.x === 343) {
+        return React.createElement(
           "div",
-          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
-          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
-        ),
-        React.createElement(TransitionCell248, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader250 = React.createClass({
-    displayName: "AdsPETableHeader250",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _25fg" },
-        null,
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "Avg. CPM"
-        )
-      );
-    }
-  });
-
-  var FixedDataTableAbstractSortableHeader251 = React.createClass({
-    displayName: "FixedDataTableAbstractSortableHeader251",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
-        React.createElement(
+          { isHeaderCell: true, label: "Campaign Name", width: 400, dataKey: "campaignGroup.name", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "campaignGroup.name", height: 25, style: { "height": 25, "width": 400 } },
+          React.createElement(
+            "div",
+            { className: "_4lgd _4h2w" },
+            React.createElement(
+              "div",
+              { className: "_4lge _4h2x" },
+              React.createElement(FixedDataTableSortableHeader149, { x: 342 })
+            )
+          )
+        );
+      }
+      if (props.x === 349) {
+        return React.createElement(
           "div",
-          { className: "_2eq6" },
-          null,
-          React.createElement(AdsPETableHeader250, null)
-        )
-      );
-    }
-  });
-
-  var FixedDataTableSortableHeader252 = React.createClass({
-    displayName: "FixedDataTableSortableHeader252",
-
-    render: function () {
-      return React.createElement(FixedDataTableAbstractSortableHeader251, null);
-    }
-  });
-
-  var TransitionCell253 = React.createClass({
-    displayName: "TransitionCell253",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "Avg. CPM", width: 80, dataKey: "stats.avg_cpm", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "stats.avg_cpm", height: 25, style: { "height": 25, "width": 80 } },
-        React.createElement(
+          { isHeaderCell: true, label: undefined, width: 33, dataKey: "edit_status", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "edit_status", height: 25, style: { "height": 25, "width": 33 } },
+          React.createElement(
+            "div",
+            { className: "_4lgd _4h2w" },
+            React.createElement(
+              "div",
+              { className: "_4lge _4h2x" },
+              React.createElement(FixedDataTableSortableHeader149, { x: 348 })
+            )
+          )
+        );
+      }
+      if (props.x === 355) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { isHeaderCell: true, label: undefined, width: 36, dataKey: "errors", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "errors", height: 25, style: { "height": 25, "width": 36 } },
           React.createElement(
             "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(FixedDataTableSortableHeader252, null)
+            { className: "_4lgd _4h2w" },
+            React.createElement(
+              "div",
+              { className: "_4lge _4h2x" },
+              React.createElement(FixedDataTableSortableHeader149, { x: 354 })
+            )
           )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell254 = React.createClass({
-    displayName: "FixedDataTableCell254",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 25, "width": 80, "left": 140 } },
-        React.createElement(
+        );
+      }
+      if (props.x === 360) {
+        return React.createElement(
           "div",
-          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
-          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
-        ),
-        React.createElement(TransitionCell253, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader255 = React.createClass({
-    displayName: "AdsPETableHeader255",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _25fg" },
-        null,
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "Avg. CPC"
-        )
-      );
-    }
-  });
-
-  var FixedDataTableAbstractSortableHeader256 = React.createClass({
-    displayName: "FixedDataTableAbstractSortableHeader256",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
-        React.createElement(
+          { isHeaderCell: true, label: "Status", width: 60, dataKey: "campaignGroup.status", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "campaignGroup.status", height: 25, style: { "height": 25, "width": 60 } },
+          React.createElement(
+            "div",
+            { className: "_4lgd _4h2w" },
+            React.createElement(
+              "div",
+              { className: "_4lge _4h2x" },
+              React.createElement(FixedDataTableSortableHeader149, { x: 359 })
+            )
+          )
+        );
+      }
+      if (props.x === 365) {
+        return React.createElement(
           "div",
-          { className: "_2eq6" },
-          null,
-          React.createElement(AdsPETableHeader255, null)
-        )
-      );
-    }
-  });
-
-  var FixedDataTableSortableHeader257 = React.createClass({
-    displayName: "FixedDataTableSortableHeader257",
-
-    render: function () {
-      return React.createElement(FixedDataTableAbstractSortableHeader256, null);
-    }
-  });
-
-  var TransitionCell258 = React.createClass({
-    displayName: "TransitionCell258",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "Avg. CPC", width: 78, dataKey: "stats.avg_cpc", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "stats.avg_cpc", height: 25, style: { "height": 25, "width": 78 } },
-        React.createElement(
+          { isHeaderCell: true, label: "Delivery", width: 150, dataKey: "derivedCampaignGroup.activity_status", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "derivedCampaignGroup.activity_status", height: 25, style: { "height": 25, "width": 150 } },
+          React.createElement(
+            "div",
+            { className: "_4lgd _4h2w" },
+            React.createElement(
+              "div",
+              { className: "_4lge _4h2x" },
+              React.createElement(FixedDataTableSortableHeader149, { x: 364 })
+            )
+          )
+        );
+      }
+      if (props.x === 372) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { isHeaderCell: true, label: "Results", width: 140, dataKey: "stats.actions", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "stats.actions", height: 25, style: { "height": 25, "width": 140 } },
           React.createElement(
             "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(FixedDataTableSortableHeader257, null)
+            { className: "_4lgd _4h2w" },
+            React.createElement(
+              "div",
+              { className: "_4lge _4h2x" },
+              React.createElement(FixedDataTableSortableHeader149, { x: 371 })
+            )
           )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell259 = React.createClass({
-    displayName: "FixedDataTableCell259",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 25, "width": 78, "left": 220 } },
-        React.createElement(
+        );
+      }
+      if (props.x === 377) {
+        return React.createElement(
           "div",
-          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
-          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
-        ),
-        React.createElement(TransitionCell258, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader260 = React.createClass({
-    displayName: "AdsPETableHeader260",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _25fg _4h2r" },
-        null,
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "Results"
-        )
-      );
-    }
-  });
-
-  var TransitionCell261 = React.createClass({
-    displayName: "TransitionCell261",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "Results", width: 140, dataKey: "stats.actions", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "stats.actions", height: 25, style: { "height": 25, "width": 140 } },
-        React.createElement(
+          { isHeaderCell: true, label: "Cost", width: 140, dataKey: "stats.cpa", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "stats.cpa", height: 25, style: { "height": 25, "width": 140 } },
+          React.createElement(
+            "div",
+            { className: "_4lgd _4h2w" },
+            React.createElement(
+              "div",
+              { className: "_4lge _4h2x" },
+              React.createElement(FixedDataTableSortableHeader149, { x: 376 })
+            )
+          )
+        );
+      }
+      if (props.x === 382) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { isHeaderCell: true, label: "Reach", width: 80, dataKey: "stats.unique_impressions", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "stats.unique_impressions", height: 25, style: { "height": 25, "width": 80 } },
           React.createElement(
             "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(AdsPETableHeader260, null)
+            { className: "_4lgd _4h2w" },
+            React.createElement(
+              "div",
+              { className: "_4lge _4h2x" },
+              React.createElement(FixedDataTableSortableHeader149, { x: 381 })
+            )
           )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell262 = React.createClass({
-    displayName: "FixedDataTableCell262",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 25, "width": 140, "left": 298 } },
-        React.createElement(
+        );
+      }
+      if (props.x === 387) {
+        return React.createElement(
           "div",
-          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
-          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
-        ),
-        React.createElement(TransitionCell261, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader263 = React.createClass({
-    displayName: "AdsPETableHeader263",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _25fg _4h2r" },
-        null,
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "Cost"
-        )
-      );
-    }
-  });
-
-  var TransitionCell264 = React.createClass({
-    displayName: "TransitionCell264",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "Cost", width: 140, dataKey: "stats.cpa", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "stats.cpa", height: 25, style: { "height": 25, "width": 140 } },
-        React.createElement(
+          { isHeaderCell: true, label: "Impressions", width: 80, dataKey: "stats.impressions", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "stats.impressions", height: 25, style: { "height": 25, "width": 80 } },
+          React.createElement(
+            "div",
+            { className: "_4lgd _4h2w" },
+            React.createElement(
+              "div",
+              { className: "_4lge _4h2x" },
+              React.createElement(FixedDataTableSortableHeader149, { x: 386 })
+            )
+          )
+        );
+      }
+      if (props.x === 392) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { isHeaderCell: true, label: "Clicks", width: 60, dataKey: "stats.clicks", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "stats.clicks", height: 25, style: { "height": 25, "width": 60 } },
           React.createElement(
             "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(AdsPETableHeader263, null)
+            { className: "_4lgd _4h2w" },
+            React.createElement(
+              "div",
+              { className: "_4lge _4h2x" },
+              React.createElement(FixedDataTableSortableHeader149, { x: 391 })
+            )
           )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell265 = React.createClass({
-    displayName: "FixedDataTableCell265",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 25, "width": 140, "left": 438 } },
-        React.createElement(
+        );
+      }
+      if (props.x === 397) {
+        return React.createElement(
           "div",
-          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
-          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
-        ),
-        React.createElement(TransitionCell264, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader266 = React.createClass({
-    displayName: "AdsPETableHeader266",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _25fg" },
-        null,
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "Clicks"
-        )
-      );
-    }
-  });
-
-  var FixedDataTableAbstractSortableHeader267 = React.createClass({
-    displayName: "FixedDataTableAbstractSortableHeader267",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
-        React.createElement(
+          { isHeaderCell: true, label: "Avg. CPM", width: 80, dataKey: "stats.avg_cpm", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "stats.avg_cpm", height: 25, style: { "height": 25, "width": 80 } },
+          React.createElement(
+            "div",
+            { className: "_4lgd _4h2w" },
+            React.createElement(
+              "div",
+              { className: "_4lge _4h2x" },
+              React.createElement(FixedDataTableSortableHeader149, { x: 396 })
+            )
+          )
+        );
+      }
+      if (props.x === 402) {
+        return React.createElement(
           "div",
-          { className: "_2eq6" },
-          null,
-          React.createElement(AdsPETableHeader266, null)
-        )
-      );
-    }
-  });
-
-  var FixedDataTableSortableHeader268 = React.createClass({
-    displayName: "FixedDataTableSortableHeader268",
-
-    render: function () {
-      return React.createElement(FixedDataTableAbstractSortableHeader267, null);
-    }
-  });
-
-  var TransitionCell269 = React.createClass({
-    displayName: "TransitionCell269",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "Clicks", width: 60, dataKey: "stats.clicks", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "stats.clicks", height: 25, style: { "height": 25, "width": 60 } },
-        React.createElement(
+          { isHeaderCell: true, label: "Avg. CPC", width: 78, dataKey: "stats.avg_cpc", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "stats.avg_cpc", height: 25, style: { "height": 25, "width": 78 } },
+          React.createElement(
+            "div",
+            { className: "_4lgd _4h2w" },
+            React.createElement(
+              "div",
+              { className: "_4lge _4h2x" },
+              React.createElement(FixedDataTableSortableHeader149, { x: 401 })
+            )
+          )
+        );
+      }
+      if (props.x === 407) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { isHeaderCell: true, label: "CTR %", width: 70, dataKey: "stats.ctr", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "stats.ctr", height: 25, style: { "height": 25, "width": 70 } },
           React.createElement(
             "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(FixedDataTableSortableHeader268, null)
+            { className: "_4lgd _4h2w" },
+            React.createElement(
+              "div",
+              { className: "_4lge _4h2x" },
+              React.createElement(FixedDataTableSortableHeader149, { x: 406 })
+            )
           )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell270 = React.createClass({
-    displayName: "FixedDataTableCell270",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 25, "width": 60, "left": 578 } },
-        React.createElement(
+        );
+      }
+      if (props.x === 412) {
+        return React.createElement(
           "div",
-          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
-          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
-        ),
-        React.createElement(TransitionCell269, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader271 = React.createClass({
-    displayName: "AdsPETableHeader271",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _25fg" },
-        null,
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "CTR %"
-        )
-      );
-    }
-  });
-
-  var FixedDataTableAbstractSortableHeader272 = React.createClass({
-    displayName: "FixedDataTableAbstractSortableHeader272",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
-        React.createElement(
-          "div",
-          { className: "_2eq6" },
-          null,
-          React.createElement(AdsPETableHeader271, null)
-        )
-      );
-    }
-  });
-
-  var FixedDataTableSortableHeader273 = React.createClass({
-    displayName: "FixedDataTableSortableHeader273",
-
-    render: function () {
-      return React.createElement(FixedDataTableAbstractSortableHeader272, null);
-    }
-  });
-
-  var TransitionCell274 = React.createClass({
-    displayName: "TransitionCell274",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "CTR %", width: 70, dataKey: "stats.ctr", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "stats.ctr", height: 25, style: { "height": 25, "width": 70 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
+          { isHeaderCell: true, label: "Spent", width: 70, dataKey: "stats.spent_100", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "stats.spent_100", height: 25, style: { "height": 25, "width": 70 } },
           React.createElement(
             "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(FixedDataTableSortableHeader273, null)
+            { className: "_4lgd _4h2w" },
+            React.createElement(
+              "div",
+              { className: "_4lge _4h2x" },
+              React.createElement(FixedDataTableSortableHeader149, { x: 411 })
+            )
           )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell275 = React.createClass({
-    displayName: "FixedDataTableCell275",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 25, "width": 70, "left": 638 } },
-        React.createElement(
+        );
+      }
+      if (props.x === 417) {
+        return React.createElement(
           "div",
-          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
-          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
-        ),
-        React.createElement(TransitionCell274, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader276 = React.createClass({
-    displayName: "AdsPETableHeader276",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _25fg" },
-        null,
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "Social %"
-        )
-      );
-    }
-  });
-
-  var FixedDataTableAbstractSortableHeader277 = React.createClass({
-    displayName: "FixedDataTableAbstractSortableHeader277",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
-        React.createElement(
+          { isHeaderCell: true, label: "Objective", width: 200, dataKey: "campaignGroup.objective", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "campaignGroup.objective", height: 25, style: { "height": 25, "width": 200 } },
+          React.createElement(
+            "div",
+            { className: "_4lgd _4h2w" },
+            React.createElement(
+              "div",
+              { className: "_4lge _4h2x" },
+              React.createElement(FixedDataTableSortableHeader149, { x: 416 })
+            )
+          )
+        );
+      }
+      if (props.x === 422) {
+        return React.createElement(
           "div",
-          { className: "_2eq6" },
-          null,
-          React.createElement(AdsPETableHeader276, null)
-        )
-      );
-    }
-  });
-
-  var FixedDataTableSortableHeader278 = React.createClass({
-    displayName: "FixedDataTableSortableHeader278",
-
-    render: function () {
-      return React.createElement(FixedDataTableAbstractSortableHeader277, null);
-    }
-  });
-
-  var TransitionCell279 = React.createClass({
-    displayName: "TransitionCell279",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "Social %", width: 80, dataKey: "stats.social_percent", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "stats.social_percent", height: 25, style: { "height": 25, "width": 80 } },
-        React.createElement(
+          { isHeaderCell: true, label: "Buying Type", width: 100, dataKey: "campaignGroup.buying_type", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "campaignGroup.buying_type", height: 25, style: { "height": 25, "width": 100 } },
+          React.createElement(
+            "div",
+            { className: "_4lgd _4h2w" },
+            React.createElement(
+              "div",
+              { className: "_4lge _4h2x" },
+              React.createElement(FixedDataTableSortableHeader149, { x: 421 })
+            )
+          )
+        );
+      }
+      if (props.x === 427) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { isHeaderCell: true, label: "Campaign ID", width: 120, dataKey: "campaignGroup.id", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "campaignGroup.id", height: 25, style: { "height": 25, "width": 120 } },
           React.createElement(
             "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(FixedDataTableSortableHeader278, null)
+            { className: "_4lgd _4h2w" },
+            React.createElement(
+              "div",
+              { className: "_4lge _4h2x" },
+              React.createElement(FixedDataTableSortableHeader149, { x: 426 })
+            )
           )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell280 = React.createClass({
-    displayName: "FixedDataTableCell280",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 25, "width": 80, "left": 708 } },
-        React.createElement(
+        );
+      }
+      if (props.x === 432) {
+        return React.createElement(
           "div",
-          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
-          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
-        ),
-        React.createElement(TransitionCell279, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader281 = React.createClass({
-    displayName: "AdsPETableHeader281",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _25fg" },
-        null,
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "Ad Set Name"
-        )
-      );
-    }
-  });
-
-  var FixedDataTableAbstractSortableHeader282 = React.createClass({
-    displayName: "FixedDataTableAbstractSortableHeader282",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
-        React.createElement(
+          { isHeaderCell: true, label: "Start", width: 113, dataKey: "derivedCampaignGroup.startDate", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "derivedCampaignGroup.startDate", height: 25, style: { "height": 25, "width": 113 } },
+          React.createElement(
+            "div",
+            { className: "_4lgd _4h2w" },
+            React.createElement(
+              "div",
+              { className: "_4lge _4h2x" },
+              React.createElement(FixedDataTableSortableHeader149, { x: 431 })
+            )
+          )
+        );
+      }
+      if (props.x === 437) {
+        return React.createElement(
           "div",
-          { className: "_2eq6" },
-          null,
-          React.createElement(AdsPETableHeader281, null)
-        )
-      );
-    }
-  });
-
-  var FixedDataTableSortableHeader283 = React.createClass({
-    displayName: "FixedDataTableSortableHeader283",
-
-    render: function () {
-      return React.createElement(FixedDataTableAbstractSortableHeader282, null);
-    }
-  });
-
-  var TransitionCell284 = React.createClass({
-    displayName: "TransitionCell284",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "Ad Set Name", width: 100, dataKey: "campaign.name", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "campaign.name", height: 25, style: { "height": 25, "width": 100 } },
-        React.createElement(
+          { isHeaderCell: true, label: "End", width: 113, dataKey: "derivedCampaignGroup.stopDate", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "derivedCampaignGroup.stopDate", height: 25, style: { "height": 25, "width": 113 } },
+          React.createElement(
+            "div",
+            { className: "_4lgd _4h2w" },
+            React.createElement(
+              "div",
+              { className: "_4lge _4h2x" },
+              React.createElement(FixedDataTableSortableHeader149, { x: 436 })
+            )
+          )
+        );
+      }
+      if (props.x === 442) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { isHeaderCell: true, label: "Date created", width: 113, dataKey: "derivedCampaignGroup.createdDate", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "derivedCampaignGroup.createdDate", height: 25, style: { "height": 25, "width": 113 } },
           React.createElement(
             "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(FixedDataTableSortableHeader283, null)
+            { className: "_4lgd _4h2w" },
+            React.createElement(
+              "div",
+              { className: "_4lge _4h2x" },
+              React.createElement(FixedDataTableSortableHeader149, { x: 441 })
+            )
           )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell285 = React.createClass({
-    displayName: "FixedDataTableCell285",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 100, "left": 788 } },
-        React.createElement(
+        );
+      }
+      if (props.x === 447) {
+        return React.createElement(
           "div",
-          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
-          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
-        ),
-        React.createElement(TransitionCell284, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader286 = React.createClass({
-    displayName: "AdsPETableHeader286",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _25fg" },
-        null,
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "Campaign Name"
-        )
-      );
-    }
-  });
-
-  var FixedDataTableAbstractSortableHeader287 = React.createClass({
-    displayName: "FixedDataTableAbstractSortableHeader287",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
-        React.createElement(
+          { isHeaderCell: true, label: "Date last edited", width: 113, dataKey: "derivedCampaignGroup.updatedDate", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "derivedCampaignGroup.updatedDate", height: 25, style: { "height": 25, "width": 113 } },
+          React.createElement(
+            "div",
+            { className: "_4lgd _4h2w" },
+            React.createElement(
+              "div",
+              { className: "_4lge _4h2x" },
+              React.createElement(FixedDataTableSortableHeader149, { x: 446 })
+            )
+          )
+        );
+      }
+      if (props.x === 450) {
+        return React.createElement(
           "div",
-          { className: "_2eq6" },
-          null,
-          React.createElement(AdsPETableHeader286, null)
-        )
-      );
-    }
-  });
-
-  var FixedDataTableSortableHeader288 = React.createClass({
-    displayName: "FixedDataTableSortableHeader288",
-
-    render: function () {
-      return React.createElement(FixedDataTableAbstractSortableHeader287, null);
-    }
-  });
-
-  var TransitionCell289 = React.createClass({
-    displayName: "TransitionCell289",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "Campaign Name", width: 150, dataKey: "campaignGroup.name", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "campaignGroup.name", height: 25, style: { "height": 25, "width": 150 } },
-        React.createElement(
+          { isHeaderCell: true, label: "Tags", width: 150, dataKey: "labels", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "labels", height: 25, style: { "height": 25, "width": 150 } },
+          React.createElement(
+            "div",
+            { className: "_4lgd _4h2w" },
+            React.createElement(
+              "div",
+              { className: "_4lge _4h2x" },
+              React.createElement(AdsPETableHeader141, { x: 449 })
+            )
+          )
+        );
+      }
+      if (props.x === 453) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { isHeaderCell: true, label: "", width: 25, dataKey: "scrollbar_spacer", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "scrollbar_spacer", height: 25, style: { "height": 25, "width": 25 } },
           React.createElement(
             "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(FixedDataTableSortableHeader288, null)
+            { className: "_4lgd _4h2w" },
+            React.createElement(
+              "div",
+              { className: "_4lge _4h2x" },
+              React.createElement(AdsPETableHeader141, { x: 452 })
+            )
           )
-        )
-      );
+        );
+      }
     }
   });
 
-  var FixedDataTableCell290 = React.createClass({
-    displayName: "FixedDataTableCell290",
+  var FixedDataTableCell143 = React.createClass({
+    displayName: "FixedDataTableCell143",
 
     render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 150, "left": 888 } },
-        React.createElement(
+      var props = this.props;
+      if (props.x === 317) {
+        return React.createElement(
           "div",
-          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
-          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
-        ),
-        React.createElement(TransitionCell289, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader291 = React.createClass({
-    displayName: "AdsPETableHeader291",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _25fg" },
-        null,
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "Ad ID"
-        )
-      );
-    }
-  });
-
-  var FixedDataTableAbstractSortableHeader292 = React.createClass({
-    displayName: "FixedDataTableAbstractSortableHeader292",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
-        React.createElement(
+          { className: "_4lg0 _4h2m", style: { "height": 40, "width": 721, "left": 0 } },
+          undefined,
+          React.createElement(TransitionCell142, { x: 316 })
+        );
+      }
+      if (props.x === 322) {
+        return React.createElement(
           "div",
-          { className: "_2eq6" },
-          null,
-          React.createElement(AdsPETableHeader291, null)
-        )
-      );
-    }
-  });
-
-  var FixedDataTableSortableHeader293 = React.createClass({
-    displayName: "FixedDataTableSortableHeader293",
-
-    render: function () {
-      return React.createElement(FixedDataTableAbstractSortableHeader292, null);
-    }
-  });
-
-  var TransitionCell294 = React.createClass({
-    displayName: "TransitionCell294",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "Ad ID", width: 120, dataKey: "ad.id", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "ad.id", height: 25, style: { "height": 25, "width": 120 } },
-        React.createElement(
+          { className: "_4lg0 _4h2m", style: { "height": 40, "width": 798, "left": 0 } },
+          undefined,
+          React.createElement(TransitionCell142, { x: 321 })
+        );
+      }
+      if (props.x === 325) {
+        return React.createElement(
+          "div",
+          { className: "_4lg0 _4h2m", style: { "height": 40, "width": 1022, "left": 798 } },
+          undefined,
+          React.createElement(TransitionCell142, { x: 324 })
+        );
+      }
+      if (props.x === 328) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { className: "_4lg0 _4h2m", style: { "height": 40, "width": 0, "left": 1820 } },
+          undefined,
+          React.createElement(TransitionCell142, { x: 327 })
+        );
+      }
+      if (props.x === 331) {
+        return React.createElement(
+          "div",
+          { className: "_4lg0 _4h2m", style: { "height": 40, "width": 25, "left": 1820 } },
+          undefined,
+          React.createElement(TransitionCell142, { x: 330 })
+        );
+      }
+      if (props.x === 339) {
+        return React.createElement(
+          "div",
+          { className: "_4lg0 _4lg6 _4h2m", style: { "height": 25, "width": 42, "left": 0 } },
+          undefined,
+          React.createElement(TransitionCell142, { x: 338 })
+        );
+      }
+      if (props.x === 344) {
+        return React.createElement(
+          "div",
+          { className: "_4lg0 _4h2m", style: { "height": 25, "width": 400, "left": 42 } },
           React.createElement(
             "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(FixedDataTableSortableHeader293, null)
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell295 = React.createClass({
-    displayName: "FixedDataTableCell295",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 120, "left": 1038 } },
-        React.createElement(
+            { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+            React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+          ),
+          React.createElement(TransitionCell142, { x: 343 })
+        );
+      }
+      if (props.x === 350) {
+        return React.createElement(
           "div",
-          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
-          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
-        ),
-        React.createElement(TransitionCell294, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader296 = React.createClass({
-    displayName: "AdsPETableHeader296",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _25fg" },
-        null,
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "Objective"
-        )
-      );
-    }
-  });
-
-  var FixedDataTableAbstractSortableHeader297 = React.createClass({
-    displayName: "FixedDataTableAbstractSortableHeader297",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
-        React.createElement(
+          { className: "_4lg0 _4h2m", style: { "height": 25, "width": 33, "left": 442 } },
+          undefined,
+          React.createElement(TransitionCell142, { x: 349 })
+        );
+      }
+      if (props.x === 356) {
+        return React.createElement(
           "div",
-          { className: "_2eq6" },
-          null,
-          React.createElement(AdsPETableHeader296, null)
-        )
-      );
-    }
-  });
-
-  var FixedDataTableSortableHeader298 = React.createClass({
-    displayName: "FixedDataTableSortableHeader298",
-
-    render: function () {
-      return React.createElement(FixedDataTableAbstractSortableHeader297, null);
-    }
-  });
-
-  var TransitionCell299 = React.createClass({
-    displayName: "TransitionCell299",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "Objective", width: 80, dataKey: "campaignGroup.objective", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "campaignGroup.objective", height: 25, style: { "height": 25, "width": 80 } },
-        React.createElement(
+          { className: "_4lg0 _4h2m", style: { "height": 25, "width": 36, "left": 475 } },
+          undefined,
+          React.createElement(TransitionCell142, { x: 355 })
+        );
+      }
+      if (props.x === 361) {
+        return React.createElement(
+          "div",
+          { className: "_4lg0 _4h2m", style: { "height": 25, "width": 60, "left": 511 } },
+          undefined,
+          React.createElement(TransitionCell142, { x: 360 })
+        );
+      }
+      if (props.x === 366) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { className: "_4lg0 _4h2m", style: { "height": 25, "width": 150, "left": 571 } },
           React.createElement(
             "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(FixedDataTableSortableHeader298, null)
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell300 = React.createClass({
-    displayName: "FixedDataTableCell300",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 80, "left": 1158 } },
-        React.createElement(
-          "div",
-          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
-          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
-        ),
-        React.createElement(TransitionCell299, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader301 = React.createClass({
-    displayName: "AdsPETableHeader301",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _25fg" },
-        null,
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "Spent"
-        )
-      );
-    }
-  });
-
-  var FixedDataTableAbstractSortableHeader302 = React.createClass({
-    displayName: "FixedDataTableAbstractSortableHeader302",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
-        React.createElement(
+            { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+            React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+          ),
+          React.createElement(TransitionCell142, { x: 365 })
+        );
+      }
+      if (props.x === 373) {
+        return React.createElement(
           "div",
-          { className: "_2eq6" },
-          null,
-          React.createElement(AdsPETableHeader301, null)
-        )
-      );
-    }
-  });
-
-  var FixedDataTableSortableHeader303 = React.createClass({
-    displayName: "FixedDataTableSortableHeader303",
-
-    render: function () {
-      return React.createElement(FixedDataTableAbstractSortableHeader302, null);
-    }
-  });
-
-  var TransitionCell304 = React.createClass({
-    displayName: "TransitionCell304",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "Spent", width: 70, dataKey: "stats.spent_100", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "stats.spent_100", height: 25, style: { "height": 25, "width": 70 } },
-        React.createElement(
+          { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 25, "width": 140, "left": 0 } },
+          React.createElement(
+            "div",
+            { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+            React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+          ),
+          React.createElement(TransitionCell142, { x: 372 })
+        );
+      }
+      if (props.x === 378) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 25, "width": 140, "left": 140 } },
           React.createElement(
             "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(FixedDataTableSortableHeader303, null)
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell305 = React.createClass({
-    displayName: "FixedDataTableCell305",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 25, "width": 70, "left": 1238 } },
-        React.createElement(
+            { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+            React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+          ),
+          React.createElement(TransitionCell142, { x: 377 })
+        );
+      }
+      if (props.x === 383) {
+        return React.createElement(
           "div",
-          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
-          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
-        ),
-        React.createElement(TransitionCell304, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader306 = React.createClass({
-    displayName: "AdsPETableHeader306",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _25fg" },
-        null,
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "Start"
-        )
-      );
-    }
-  });
-
-  var FixedDataTableAbstractSortableHeader307 = React.createClass({
-    displayName: "FixedDataTableAbstractSortableHeader307",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
-        React.createElement(
-          "div",
-          { className: "_2eq6" },
-          null,
-          React.createElement(AdsPETableHeader306, null)
-        )
-      );
-    }
-  });
-
-  var FixedDataTableSortableHeader308 = React.createClass({
-    displayName: "FixedDataTableSortableHeader308",
-
-    render: function () {
-      return React.createElement(FixedDataTableAbstractSortableHeader307, null);
-    }
-  });
-
-  var TransitionCell309 = React.createClass({
-    displayName: "TransitionCell309",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "Start", width: 113, dataKey: "derivedCampaign.startDate", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "derivedCampaign.startDate", height: 25, style: { "height": 25, "width": 113 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
+          { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 25, "width": 80, "left": 280 } },
           React.createElement(
             "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(FixedDataTableSortableHeader308, null)
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell310 = React.createClass({
-    displayName: "FixedDataTableCell310",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 113, "left": 1308 } },
-        React.createElement(
-          "div",
-          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
-          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
-        ),
-        React.createElement(TransitionCell309, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader311 = React.createClass({
-    displayName: "AdsPETableHeader311",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _25fg" },
-        null,
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "End"
-        )
-      );
-    }
-  });
-
-  var FixedDataTableAbstractSortableHeader312 = React.createClass({
-    displayName: "FixedDataTableAbstractSortableHeader312",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
-        React.createElement(
-          "div",
-          { className: "_2eq6" },
-          null,
-          React.createElement(AdsPETableHeader311, null)
-        )
-      );
-    }
-  });
-
-  var FixedDataTableSortableHeader313 = React.createClass({
-    displayName: "FixedDataTableSortableHeader313",
-
-    render: function () {
-      return React.createElement(FixedDataTableAbstractSortableHeader312, null);
-    }
-  });
-
-  var TransitionCell314 = React.createClass({
-    displayName: "TransitionCell314",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "End", width: 113, dataKey: "derivedCampaign.endDate", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "derivedCampaign.endDate", height: 25, style: { "height": 25, "width": 113 } },
-        React.createElement(
+            { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+            React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+          ),
+          React.createElement(TransitionCell142, { x: 382 })
+        );
+      }
+      if (props.x === 388) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 25, "width": 80, "left": 360 } },
           React.createElement(
             "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(FixedDataTableSortableHeader313, null)
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell315 = React.createClass({
-    displayName: "FixedDataTableCell315",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 113, "left": 1421 } },
-        React.createElement(
-          "div",
-          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
-          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
-        ),
-        React.createElement(TransitionCell314, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader316 = React.createClass({
-    displayName: "AdsPETableHeader316",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _25fg" },
-        null,
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "Date created"
-        )
-      );
-    }
-  });
-
-  var FixedDataTableAbstractSortableHeader317 = React.createClass({
-    displayName: "FixedDataTableAbstractSortableHeader317",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
-        React.createElement(
-          "div",
-          { className: "_2eq6" },
-          null,
-          React.createElement(AdsPETableHeader316, null)
-        )
-      );
-    }
-  });
-
-  var FixedDataTableSortableHeader318 = React.createClass({
-    displayName: "FixedDataTableSortableHeader318",
-
-    render: function () {
-      return React.createElement(FixedDataTableAbstractSortableHeader317, null);
-    }
-  });
-
-  var TransitionCell319 = React.createClass({
-    displayName: "TransitionCell319",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "Date created", width: 113, dataKey: "ad.created_time", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "ad.created_time", height: 25, style: { "height": 25, "width": 113 } },
-        React.createElement(
+            { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+            React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+          ),
+          React.createElement(TransitionCell142, { x: 387 })
+        );
+      }
+      if (props.x === 393) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 25, "width": 60, "left": 440 } },
           React.createElement(
             "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(FixedDataTableSortableHeader318, null)
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell320 = React.createClass({
-    displayName: "FixedDataTableCell320",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 113, "left": 1534 } },
-        React.createElement(
-          "div",
-          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
-          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
-        ),
-        React.createElement(TransitionCell319, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader321 = React.createClass({
-    displayName: "AdsPETableHeader321",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _25fg" },
-        null,
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "Date last edited"
-        )
-      );
-    }
-  });
-
-  var FixedDataTableAbstractSortableHeader322 = React.createClass({
-    displayName: "FixedDataTableAbstractSortableHeader322",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
-        React.createElement(
-          "div",
-          { className: "_2eq6" },
-          null,
-          React.createElement(AdsPETableHeader321, null)
-        )
-      );
-    }
-  });
-
-  var FixedDataTableSortableHeader323 = React.createClass({
-    displayName: "FixedDataTableSortableHeader323",
-
-    render: function () {
-      return React.createElement(FixedDataTableAbstractSortableHeader322, null);
-    }
-  });
-
-  var TransitionCell324 = React.createClass({
-    displayName: "TransitionCell324",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "Date last edited", width: 113, dataKey: "ad.updated_time", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "ad.updated_time", height: 25, style: { "height": 25, "width": 113 } },
-        React.createElement(
+            { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+            React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+          ),
+          React.createElement(TransitionCell142, { x: 392 })
+        );
+      }
+      if (props.x === 398) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 25, "width": 80, "left": 500 } },
           React.createElement(
             "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(FixedDataTableSortableHeader323, null)
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell325 = React.createClass({
-    displayName: "FixedDataTableCell325",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 113, "left": 1647 } },
-        React.createElement(
-          "div",
-          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
-          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
-        ),
-        React.createElement(TransitionCell324, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader326 = React.createClass({
-    displayName: "AdsPETableHeader326",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _25fg" },
-        null,
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "Title"
-        )
-      );
-    }
-  });
-
-  var FixedDataTableAbstractSortableHeader327 = React.createClass({
-    displayName: "FixedDataTableAbstractSortableHeader327",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
-        React.createElement(
-          "div",
-          { className: "_2eq6" },
-          null,
-          React.createElement(AdsPETableHeader326, null)
-        )
-      );
-    }
-  });
-
-  var FixedDataTableSortableHeader328 = React.createClass({
-    displayName: "FixedDataTableSortableHeader328",
-
-    render: function () {
-      return React.createElement(FixedDataTableAbstractSortableHeader327, null);
-    }
-  });
-
-  var TransitionCell329 = React.createClass({
-    displayName: "TransitionCell329",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "Title", width: 80, dataKey: "ad.title", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "ad.title", height: 25, style: { "height": 25, "width": 80 } },
-        React.createElement(
+            { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+            React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+          ),
+          React.createElement(TransitionCell142, { x: 397 })
+        );
+      }
+      if (props.x === 403) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 25, "width": 78, "left": 580 } },
           React.createElement(
             "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(FixedDataTableSortableHeader328, null)
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell330 = React.createClass({
-    displayName: "FixedDataTableCell330",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 80, "left": 1760 } },
-        React.createElement(
-          "div",
-          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
-          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
-        ),
-        React.createElement(TransitionCell329, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader331 = React.createClass({
-    displayName: "AdsPETableHeader331",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _25fg" },
-        null,
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "Body"
-        )
-      );
-    }
-  });
-
-  var FixedDataTableAbstractSortableHeader332 = React.createClass({
-    displayName: "FixedDataTableAbstractSortableHeader332",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
-        React.createElement(
-          "div",
-          { className: "_2eq6" },
-          null,
-          React.createElement(AdsPETableHeader331, null)
-        )
-      );
-    }
-  });
-
-  var FixedDataTableSortableHeader333 = React.createClass({
-    displayName: "FixedDataTableSortableHeader333",
-
-    render: function () {
-      return React.createElement(FixedDataTableAbstractSortableHeader332, null);
-    }
-  });
-
-  var TransitionCell334 = React.createClass({
-    displayName: "TransitionCell334",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "Body", width: 80, dataKey: "ad.creative.body", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "ad.creative.body", height: 25, style: { "height": 25, "width": 80 } },
-        React.createElement(
+            { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+            React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+          ),
+          React.createElement(TransitionCell142, { x: 402 })
+        );
+      }
+      if (props.x === 408) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 25, "width": 70, "left": 658 } },
           React.createElement(
             "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(FixedDataTableSortableHeader333, null)
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell335 = React.createClass({
-    displayName: "FixedDataTableCell335",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 80, "left": 1840 } },
-        React.createElement(
-          "div",
-          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
-          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
-        ),
-        React.createElement(TransitionCell334, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader336 = React.createClass({
-    displayName: "AdsPETableHeader336",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _25fg" },
-        null,
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "Destination"
-        )
-      );
-    }
-  });
-
-  var FixedDataTableAbstractSortableHeader337 = React.createClass({
-    displayName: "FixedDataTableAbstractSortableHeader337",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
-        React.createElement(
+            { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+            React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+          ),
+          React.createElement(TransitionCell142, { x: 407 })
+        );
+      }
+      if (props.x === 413) {
+        return React.createElement(
           "div",
-          { className: "_2eq6" },
-          null,
-          React.createElement(AdsPETableHeader336, null)
-        )
-      );
-    }
-  });
-
-  var FixedDataTableSortableHeader338 = React.createClass({
-    displayName: "FixedDataTableSortableHeader338",
-
-    render: function () {
-      return React.createElement(FixedDataTableAbstractSortableHeader337, null);
-    }
-  });
-
-  var TransitionCell339 = React.createClass({
-    displayName: "TransitionCell339",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "Destination", width: 92, dataKey: "destination", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "destination", height: 25, style: { "height": 25, "width": 92 } },
-        React.createElement(
+          { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 25, "width": 70, "left": 728 } },
+          React.createElement(
+            "div",
+            { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+            React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+          ),
+          React.createElement(TransitionCell142, { x: 412 })
+        );
+      }
+      if (props.x === 418) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { className: "_4lg0 _4h2m", style: { "height": 25, "width": 200, "left": 798 } },
           React.createElement(
             "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(FixedDataTableSortableHeader338, null)
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell340 = React.createClass({
-    displayName: "FixedDataTableCell340",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 92, "left": 1920 } },
-        React.createElement(
+            { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+            React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+          ),
+          React.createElement(TransitionCell142, { x: 417 })
+        );
+      }
+      if (props.x === 423) {
+        return React.createElement(
           "div",
-          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
-          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
-        ),
-        React.createElement(TransitionCell339, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader341 = React.createClass({
-    displayName: "AdsPETableHeader341",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _25fg" },
-        null,
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "Link"
-        )
-      );
-    }
-  });
-
-  var FixedDataTableAbstractSortableHeader342 = React.createClass({
-    displayName: "FixedDataTableAbstractSortableHeader342",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
-        React.createElement(
+          { className: "_4lg0 _4h2m", style: { "height": 25, "width": 100, "left": 998 } },
+          React.createElement(
+            "div",
+            { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+            React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+          ),
+          React.createElement(TransitionCell142, { x: 422 })
+        );
+      }
+      if (props.x === 428) {
+        return React.createElement(
           "div",
-          { className: "_2eq6" },
-          null,
-          React.createElement(AdsPETableHeader341, null)
-        )
-      );
-    }
-  });
-
-  var FixedDataTableSortableHeader343 = React.createClass({
-    displayName: "FixedDataTableSortableHeader343",
-
-    render: function () {
-      return React.createElement(FixedDataTableAbstractSortableHeader342, null);
-    }
-  });
-
-  var TransitionCell344 = React.createClass({
-    displayName: "TransitionCell344",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "Link", width: 70, dataKey: "ad.creative.link_url", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "ad.creative.link_url", height: 25, style: { "height": 25, "width": 70 } },
-        React.createElement(
+          { className: "_4lg0 _4h2m", style: { "height": 25, "width": 120, "left": 1098 } },
+          React.createElement(
+            "div",
+            { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+            React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+          ),
+          React.createElement(TransitionCell142, { x: 427 })
+        );
+      }
+      if (props.x === 433) {
+        return React.createElement(
           "div",
-          { className: "_4lgd _4h2w" },
+          { className: "_4lg0 _4h2m", style: { "height": 25, "width": 113, "left": 1218 } },
           React.createElement(
             "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(FixedDataTableSortableHeader343, null)
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell345 = React.createClass({
-    displayName: "FixedDataTableCell345",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 70, "left": 2012 } },
-        React.createElement(
+            { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+            React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+          ),
+          React.createElement(TransitionCell142, { x: 432 })
+        );
+      }
+      if (props.x === 438) {
+        return React.createElement(
           "div",
-          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
-          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
-        ),
-        React.createElement(TransitionCell344, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader346 = React.createClass({
-    displayName: "AdsPETableHeader346",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _25fg" },
-        null,
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "Related Page"
-        )
-      );
-    }
-  });
-
-  var FixedDataTableAbstractSortableHeader347 = React.createClass({
-    displayName: "FixedDataTableAbstractSortableHeader347",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
-        React.createElement(
-          "div",
-          { className: "_2eq6" },
-          null,
-          React.createElement(AdsPETableHeader346, null)
-        )
-      );
-    }
-  });
-
-  var FixedDataTableSortableHeader348 = React.createClass({
-    displayName: "FixedDataTableSortableHeader348",
-
-    render: function () {
-      return React.createElement(FixedDataTableAbstractSortableHeader347, null);
-    }
-  });
-
-  var TransitionCell349 = React.createClass({
-    displayName: "TransitionCell349",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "Related Page", width: 92, dataKey: "page", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "page", height: 25, style: { "height": 25, "width": 92 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(FixedDataTableSortableHeader348, null)
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell350 = React.createClass({
-    displayName: "FixedDataTableCell350",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 92, "left": 2082 } },
-        React.createElement(
-          "div",
-          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
-          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
-        ),
-        React.createElement(TransitionCell349, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader351 = React.createClass({
-    displayName: "AdsPETableHeader351",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1cig _25fg _4h2r" },
-        null,
-        React.createElement(
-          "span",
-          { className: "_1cid" },
-          "Preview Link"
-        )
-      );
-    }
-  });
-
-  var TransitionCell352 = React.createClass({
-    displayName: "TransitionCell352",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "Preview Link", width: 100, dataKey: "ad.demolink_hash", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "ad.demolink_hash", height: 25, style: { "height": 25, "width": 100 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(AdsPETableHeader351, null)
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell353 = React.createClass({
-    displayName: "FixedDataTableCell353",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 100, "left": 2174 } },
-        React.createElement(
-          "div",
-          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
-          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
-        ),
-        React.createElement(TransitionCell352, null)
-      );
-    }
-  });
-
-  var AdsPETableHeader354 = React.createClass({
-    displayName: "AdsPETableHeader354",
-
-    render: function () {
-      return React.createElement("div", { className: "_1cig _25fg _4h2r" });
-    }
-  });
-
-  var TransitionCell355 = React.createClass({
-    displayName: "TransitionCell355",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { isHeaderCell: true, label: "", width: 25, dataKey: "scrollbar_spacer", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "scrollbar_spacer", height: 25, style: { "height": 25, "width": 25 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(AdsPETableHeader354, null)
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell356 = React.createClass({
-    displayName: "FixedDataTableCell356",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 25, "left": 2274 } },
-        undefined,
-        React.createElement(TransitionCell355, null)
-      );
-    }
-  });
-
-  var FixedDataTableCellGroupImpl357 = React.createClass({
-    displayName: "FixedDataTableCellGroupImpl357",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_3pzj", style: { "height": 25, "position": "absolute", "width": 2299, "zIndex": 0, "transform": "translate3d(0px,0px,0)", "backfaceVisibility": "hidden" } },
-        React.createElement(FixedDataTableCell244, { key: "cell_0" }),
-        React.createElement(FixedDataTableCell249, { key: "cell_1" }),
-        React.createElement(FixedDataTableCell254, { key: "cell_2" }),
-        React.createElement(FixedDataTableCell259, { key: "cell_3" }),
-        React.createElement(FixedDataTableCell262, { key: "cell_4" }),
-        React.createElement(FixedDataTableCell265, { key: "cell_5" }),
-        React.createElement(FixedDataTableCell270, { key: "cell_6" }),
-        React.createElement(FixedDataTableCell275, { key: "cell_7" }),
-        React.createElement(FixedDataTableCell280, { key: "cell_8" }),
-        React.createElement(FixedDataTableCell285, { key: "cell_9" }),
-        React.createElement(FixedDataTableCell290, { key: "cell_10" }),
-        React.createElement(FixedDataTableCell295, { key: "cell_11" }),
-        React.createElement(FixedDataTableCell300, { key: "cell_12" }),
-        React.createElement(FixedDataTableCell305, { key: "cell_13" }),
-        React.createElement(FixedDataTableCell310, { key: "cell_14" }),
-        React.createElement(FixedDataTableCell315, { key: "cell_15" }),
-        React.createElement(FixedDataTableCell320, { key: "cell_16" }),
-        React.createElement(FixedDataTableCell325, { key: "cell_17" }),
-        React.createElement(FixedDataTableCell330, { key: "cell_18" }),
-        React.createElement(FixedDataTableCell335, { key: "cell_19" }),
-        React.createElement(FixedDataTableCell340, { key: "cell_20" }),
-        React.createElement(FixedDataTableCell345, { key: "cell_21" }),
-        React.createElement(FixedDataTableCell350, { key: "cell_22" }),
-        React.createElement(FixedDataTableCell353, { key: "cell_23" }),
-        React.createElement(FixedDataTableCell356, { key: "cell_24" })
-      );
-    }
-  });
-
-  var FixedDataTableCellGroup358 = React.createClass({
-    displayName: "FixedDataTableCellGroup358",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { style: { "height": 25, "left": 521 }, className: "_3pzk" },
-        React.createElement(FixedDataTableCellGroupImpl357, null)
-      );
-    }
-  });
-
-  var FixedDataTableRowImpl359 = React.createClass({
-    displayName: "FixedDataTableRowImpl359",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1gd4 _4li _3h1a _1mib", onClick: null, onDoubleClick: null, onMouseDown: null, onMouseEnter: null, onMouseLeave: null, style: { "width": 1083, "height": 25 } },
-        React.createElement(
-          "div",
-          { className: "_1gd5" },
-          React.createElement(FixedDataTableCellGroup239, { key: "fixed_cells" }),
-          React.createElement(FixedDataTableCellGroup358, { key: "scrollable_cells" }),
-          React.createElement("div", { className: "_1gd6 _1gd8", style: { "left": 521, "height": 25 } })
-        )
-      );
-    }
-  });
-
-  var FixedDataTableRow360 = React.createClass({
-    displayName: "FixedDataTableRow360",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { style: { "width": 1083, "height": 25, "zIndex": 1, "transform": "translate3d(0px,40px,0)", "backfaceVisibility": "hidden" }, className: "_1gda" },
-        React.createElement(FixedDataTableRowImpl359, null)
-      );
-    }
-  });
-
-  var AbstractCheckboxInput361 = React.createClass({
-    displayName: "AbstractCheckboxInput361",
-
-    render: function () {
-      return React.createElement(
-        "label",
-        { className: "_5hhv _55sg _kv1" },
-        React.createElement("input", { className: null, disabled: false, inline: true, checked: true, value: undefined, onChange: function () {}, type: "checkbox" }),
-        React.createElement("span", { "data-hover": null, "aria-label": undefined })
-      );
-    }
-  });
-
-  var XUICheckboxInput362 = React.createClass({
-    displayName: "XUICheckboxInput362",
-
-    render: function () {
-      return React.createElement(AbstractCheckboxInput361, null);
-    }
-  });
-
-  var TransitionCell363 = React.createClass({
-    displayName: "TransitionCell363",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { dataKey: "common.id", className: "_4lgc _4h2u", rowGetter: function () {}, width: 42, columnData: {}, cellDataGetter: function () {}, cellRenderer: function () {}, columnKey: "common.id", height: 32, rowIndex: 0, style: { "height": 32, "width": 42 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(
-              "span",
-              { className: "_5hhu _4h2r", onMouseDown: function () {} },
-              React.createElement(XUICheckboxInput362, null)
-            )
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell364 = React.createClass({
-    displayName: "FixedDataTableCell364",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4lg6 _4h2m", style: { "height": 32, "width": 42, "left": 0 } },
-        undefined,
-        React.createElement(TransitionCell363, null)
-      );
-    }
-  });
-
-  var AdsEditableTextCellDisplay365 = React.createClass({
-    displayName: "AdsEditableTextCellDisplay365",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_vew", onDoubleClick: function () {}, onMouseEnter: function () {}, onMouseLeave: function () {} },
-        React.createElement(
-          "div",
-          { className: "_vex _5w6k" },
-          React.createElement(
-            "div",
-            { className: "_vey" },
-            "Test Ad"
-          ),
-          React.createElement("div", { className: "_5w6_" })
-        )
-      );
-    }
-  });
-
-  var AdsEditableCell366 = React.createClass({
-    displayName: "AdsEditableCell366",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_2d6h _2-ev _4h2r _5abb" },
-        React.createElement(AdsEditableTextCellDisplay365, null)
-      );
-    }
-  });
-
-  var TransitionCell367 = React.createClass({
-    displayName: "TransitionCell367",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { dataKey: "ad.name", className: "_4lgc _4h2u", rowGetter: function () {}, width: 200, columnData: {}, cellDataGetter: function () {}, cellRenderer: function () {}, columnKey: "ad.name", height: 32, rowIndex: 0, style: { "height": 32, "width": 200 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(AdsEditableCell366, null)
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell368 = React.createClass({
-    displayName: "FixedDataTableCell368",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 32, "width": 200, "left": 42 } },
-        undefined,
-        React.createElement(TransitionCell367, null)
-      );
-    }
-  });
-
-  var FixedDataTableCellDefault369 = React.createClass({
-    displayName: "FixedDataTableCellDefault369",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { dataKey: "edit_status", className: "_4lgc _4h2u", rowGetter: function () {}, width: 33, columnData: {}, cellDataGetter: function () {}, cellRenderer: function () {}, columnKey: "edit_status", height: 32, rowIndex: 0, style: { "height": 32, "width": 33 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(
-              "div",
-              { className: "_4h2r" },
-              ""
-            )
-          )
-        )
-      );
-    }
-  });
-
-  var TransitionCell370 = React.createClass({
-    displayName: "TransitionCell370",
-
-    render: function () {
-      return React.createElement(FixedDataTableCellDefault369, null);
-    }
-  });
-
-  var FixedDataTableCell371 = React.createClass({
-    displayName: "FixedDataTableCell371",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 32, "width": 33, "left": 242 } },
-        undefined,
-        React.createElement(TransitionCell370, null)
-      );
-    }
-  });
-
-  var FixedDataTableCellDefault372 = React.createClass({
-    displayName: "FixedDataTableCellDefault372",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { dataKey: "errors", className: "_4lgc _4h2u", rowGetter: function () {}, width: 36, columnData: {}, cellDataGetter: function () {}, cellRenderer: function () {}, columnKey: "errors", height: 32, rowIndex: 0, style: { "height": 32, "width": 36 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement("div", { className: "_4h2r" })
-          )
-        )
-      );
-    }
-  });
-
-  var TransitionCell373 = React.createClass({
-    displayName: "TransitionCell373",
-
-    render: function () {
-      return React.createElement(FixedDataTableCellDefault372, null);
-    }
-  });
-
-  var FixedDataTableCell374 = React.createClass({
-    displayName: "FixedDataTableCell374",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 32, "width": 36, "left": 275 } },
-        undefined,
-        React.createElement(TransitionCell373, null)
-      );
-    }
-  });
-
-  var BUISwitch375 = React.createClass({
-    displayName: "BUISwitch375",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { value: true, disabled: true, onToggle: function () {}, "data-hover": "tooltip", "data-tooltip-position": "below", "aria-label": "Currently active and you can not deactivate it.", animate: true, className: "_128j _128k _128m _128n", role: "checkbox", "aria-checked": "true" },
-        React.createElement(
-          "div",
-          { className: "_128o", onClick: function () {}, onKeyDown: function () {}, onMouseDown: function () {}, tabIndex: "-1" },
-          React.createElement("div", { className: "_128p" })
-        ),
-        null
-      );
-    }
-  });
-
-  var AdsStatusSwitchInternal376 = React.createClass({
-    displayName: "AdsStatusSwitchInternal376",
-
-    render: function () {
-      return React.createElement(BUISwitch375, null);
-    }
-  });
-
-  var AdsStatusSwitch377 = React.createClass({
-    displayName: "AdsStatusSwitch377",
-
-    render: function () {
-      return React.createElement(AdsStatusSwitchInternal376, null);
-    }
-  });
-
-  var TransitionCell378 = React.createClass({
-    displayName: "TransitionCell378",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { dataKey: "ad.adgroup_status", className: "_4lgc _4h2u", rowGetter: function () {}, width: 60, columnData: {}, cellDataGetter: function () {}, cellRenderer: function () {}, columnKey: "ad.adgroup_status", height: 32, rowIndex: 0, style: { "height": 32, "width": 60 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(
-              "div",
-              { className: "_15si _4h2r" },
-              React.createElement(AdsStatusSwitch377, null)
-            )
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell379 = React.createClass({
-    displayName: "FixedDataTableCell379",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 32, "width": 60, "left": 311 } },
-        undefined,
-        React.createElement(TransitionCell378, null)
-      );
-    }
-  });
-
-  var ReactImage380 = React.createClass({
-    displayName: "ReactImage380",
-
-    render: function () {
-      return React.createElement("i", { "aria-label": "Pending Review", "data-hover": "tooltip", className: "_4ms8 img sp_UuU9HmrQ397 sx_ced63f", src: null, width: "7", height: "7" });
-    }
-  });
-
-  var AdsPEActivityStatusIndicator381 = React.createClass({
-    displayName: "AdsPEActivityStatusIndicator381",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_k4-" },
-        React.createElement(ReactImage380, null),
-        "Pending Review",
-        undefined
-      );
-    }
-  });
-
-  var TransitionCell382 = React.createClass({
-    displayName: "TransitionCell382",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { dataKey: "ukiAdData.computed_activity_status", className: "_4lgc _4h2u", rowGetter: function () {}, width: 150, columnData: {}, cellDataGetter: function () {}, cellRenderer: function () {}, columnKey: "ukiAdData.computed_activity_status", height: 32, rowIndex: 0, style: { "height": 32, "width": 150 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(
-              "div",
-              { className: "_2d6h _4h2r" },
-              React.createElement(AdsPEActivityStatusIndicator381, null)
-            )
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell383 = React.createClass({
-    displayName: "FixedDataTableCell383",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 32, "width": 150, "left": 371 } },
-        undefined,
-        React.createElement(TransitionCell382, null)
-      );
-    }
-  });
-
-  var FixedDataTableCellGroupImpl384 = React.createClass({
-    displayName: "FixedDataTableCellGroupImpl384",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_3pzj", style: { "height": 32, "position": "absolute", "width": 521, "zIndex": 2, "transform": "translate3d(0px,0px,0)", "backfaceVisibility": "hidden" } },
-        React.createElement(FixedDataTableCell364, { key: "cell_0" }),
-        React.createElement(FixedDataTableCell368, { key: "cell_1" }),
-        React.createElement(FixedDataTableCell371, { key: "cell_2" }),
-        React.createElement(FixedDataTableCell374, { key: "cell_3" }),
-        React.createElement(FixedDataTableCell379, { key: "cell_4" }),
-        React.createElement(FixedDataTableCell383, { key: "cell_5" })
-      );
-    }
-  });
-
-  var FixedDataTableCellGroup385 = React.createClass({
-    displayName: "FixedDataTableCellGroup385",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { style: { "height": 32, "left": 0 }, className: "_3pzk" },
-        React.createElement(FixedDataTableCellGroupImpl384, null)
-      );
-    }
-  });
-
-  var TransitionCell386 = React.createClass({
-    displayName: "TransitionCell386",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { dataKey: "stats.unique_impressions", className: "_4lgc _4h2u", rowGetter: function () {}, width: 60, columnData: {}, cellDataGetter: function () {}, cellRenderer: function () {}, columnKey: "stats.unique_impressions", height: 32, rowIndex: 0, style: { "height": 32, "width": 60 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(
-              "div",
-              { className: "_2d6h _2g7x _4h2r" },
-              " — "
-            )
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell387 = React.createClass({
-    displayName: "FixedDataTableCell387",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 32, "width": 60, "left": 0 } },
-        undefined,
-        React.createElement(TransitionCell386, null)
-      );
-    }
-  });
-
-  var TransitionCell388 = React.createClass({
-    displayName: "TransitionCell388",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { dataKey: "stats.impressions", className: "_4lgc _4h2u", rowGetter: function () {}, width: 80, columnData: {}, cellDataGetter: function () {}, cellRenderer: function () {}, columnKey: "stats.impressions", height: 32, rowIndex: 0, style: { "height": 32, "width": 80 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(
-              "div",
-              { className: "_2d6h _2g7x _4h2r" },
-              " — "
-            )
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell389 = React.createClass({
-    displayName: "FixedDataTableCell389",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 32, "width": 80, "left": 60 } },
-        undefined,
-        React.createElement(TransitionCell388, null)
-      );
-    }
-  });
-
-  var TransitionCell390 = React.createClass({
-    displayName: "TransitionCell390",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { dataKey: "stats.avg_cpm", className: "_4lgc _4h2u", rowGetter: function () {}, width: 80, columnData: {}, cellDataGetter: function () {}, cellRenderer: function () {}, columnKey: "stats.avg_cpm", height: 32, rowIndex: 0, style: { "height": 32, "width": 80 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(
-              "div",
-              { className: "_2d6h _2g7x _4h2r" },
-              " — "
-            )
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell391 = React.createClass({
-    displayName: "FixedDataTableCell391",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 32, "width": 80, "left": 140 } },
-        undefined,
-        React.createElement(TransitionCell390, null)
-      );
-    }
-  });
-
-  var TransitionCell392 = React.createClass({
-    displayName: "TransitionCell392",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { dataKey: "stats.avg_cpc", className: "_4lgc _4h2u", rowGetter: function () {}, width: 78, columnData: {}, cellDataGetter: function () {}, cellRenderer: function () {}, columnKey: "stats.avg_cpc", height: 32, rowIndex: 0, style: { "height": 32, "width": 78 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(
-              "div",
-              { className: "_2d6h _2g7x _4h2r" },
-              " — "
-            )
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell393 = React.createClass({
-    displayName: "FixedDataTableCell393",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 32, "width": 78, "left": 220 } },
-        undefined,
-        React.createElement(TransitionCell392, null)
-      );
-    }
-  });
-
-  var TransitionCell394 = React.createClass({
-    displayName: "TransitionCell394",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { dataKey: "stats.actions", className: "_4lgc _4h2u", rowGetter: function () {}, width: 140, columnData: {}, cellDataGetter: function () {}, cellRenderer: function () {}, columnKey: "stats.actions", height: 32, rowIndex: 0, style: { "height": 32, "width": 140 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(
-              "div",
-              { className: "_2d6h _2g7x _4h2r" },
-              " — "
-            )
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell395 = React.createClass({
-    displayName: "FixedDataTableCell395",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 32, "width": 140, "left": 298 } },
-        undefined,
-        React.createElement(TransitionCell394, null)
-      );
-    }
-  });
-
-  var TransitionCell396 = React.createClass({
-    displayName: "TransitionCell396",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { dataKey: "stats.cpa", className: "_4lgc _4h2u", rowGetter: function () {}, width: 140, columnData: {}, cellDataGetter: function () {}, cellRenderer: function () {}, columnKey: "stats.cpa", height: 32, rowIndex: 0, style: { "height": 32, "width": 140 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(
-              "div",
-              { className: "_2d6h _2g7x _4h2r" },
-              " — "
-            )
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell397 = React.createClass({
-    displayName: "FixedDataTableCell397",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 32, "width": 140, "left": 438 } },
-        undefined,
-        React.createElement(TransitionCell396, null)
-      );
-    }
-  });
-
-  var TransitionCell398 = React.createClass({
-    displayName: "TransitionCell398",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { dataKey: "stats.clicks", className: "_4lgc _4h2u", rowGetter: function () {}, width: 60, columnData: {}, cellDataGetter: function () {}, cellRenderer: function () {}, columnKey: "stats.clicks", height: 32, rowIndex: 0, style: { "height": 32, "width": 60 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(
-              "div",
-              { className: "_2d6h _2g7x _4h2r" },
-              " — "
-            )
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell399 = React.createClass({
-    displayName: "FixedDataTableCell399",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 32, "width": 60, "left": 578 } },
-        undefined,
-        React.createElement(TransitionCell398, null)
-      );
-    }
-  });
-
-  var TransitionCell400 = React.createClass({
-    displayName: "TransitionCell400",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { dataKey: "stats.ctr", className: "_4lgc _4h2u", rowGetter: function () {}, width: 70, columnData: {}, cellDataGetter: function () {}, cellRenderer: function () {}, columnKey: "stats.ctr", height: 32, rowIndex: 0, style: { "height": 32, "width": 70 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(
-              "div",
-              { className: "_2d6h _2g7x _4h2r" },
-              " — "
-            )
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell401 = React.createClass({
-    displayName: "FixedDataTableCell401",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 32, "width": 70, "left": 638 } },
-        undefined,
-        React.createElement(TransitionCell400, null)
-      );
-    }
-  });
-
-  var TransitionCell402 = React.createClass({
-    displayName: "TransitionCell402",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { dataKey: "stats.social_percent", className: "_4lgc _4h2u", rowGetter: function () {}, width: 80, columnData: {}, cellDataGetter: function () {}, cellRenderer: function () {}, columnKey: "stats.social_percent", height: 32, rowIndex: 0, style: { "height": 32, "width": 80 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(
-              "div",
-              { className: "_2d6h _2g7x _4h2r" },
-              " — "
-            )
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell403 = React.createClass({
-    displayName: "FixedDataTableCell403",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 32, "width": 80, "left": 708 } },
-        undefined,
-        React.createElement(TransitionCell402, null)
-      );
-    }
-  });
-
-  var FixedDataTableCellDefault404 = React.createClass({
-    displayName: "FixedDataTableCellDefault404",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { dataKey: "campaign.name", className: "_4lgc _4h2u", rowGetter: function () {}, width: 100, columnData: {}, cellDataGetter: function () {}, cellRenderer: undefined, columnKey: "campaign.name", height: 32, rowIndex: 0, style: { "height": 32, "width": 100 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(
-              "div",
-              { className: "_4h2r" },
-              "Test Ad Set"
-            )
-          )
-        )
-      );
-    }
-  });
-
-  var TransitionCell405 = React.createClass({
-    displayName: "TransitionCell405",
-
-    render: function () {
-      return React.createElement(FixedDataTableCellDefault404, null);
-    }
-  });
-
-  var FixedDataTableCell406 = React.createClass({
-    displayName: "FixedDataTableCell406",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 32, "width": 100, "left": 788 } },
-        undefined,
-        React.createElement(TransitionCell405, null)
-      );
-    }
-  });
-
-  var FixedDataTableCellDefault407 = React.createClass({
-    displayName: "FixedDataTableCellDefault407",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { dataKey: "campaignGroup.name", className: "_4lgc _4h2u", rowGetter: function () {}, width: 150, columnData: {}, cellDataGetter: function () {}, cellRenderer: undefined, columnKey: "campaignGroup.name", height: 32, rowIndex: 0, style: { "height": 32, "width": 150 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(
-              "div",
-              { className: "_4h2r" },
-              "Test Campaign"
-            )
-          )
-        )
-      );
-    }
-  });
-
-  var TransitionCell408 = React.createClass({
-    displayName: "TransitionCell408",
-
-    render: function () {
-      return React.createElement(FixedDataTableCellDefault407, null);
-    }
-  });
-
-  var FixedDataTableCell409 = React.createClass({
-    displayName: "FixedDataTableCell409",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 32, "width": 150, "left": 888 } },
-        undefined,
-        React.createElement(TransitionCell408, null)
-      );
-    }
-  });
-
-  var TransitionCell410 = React.createClass({
-    displayName: "TransitionCell410",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { dataKey: "ad.id", className: "_4lgc _4h2u", rowGetter: function () {}, width: 120, columnData: {}, cellDataGetter: function () {}, cellRenderer: function () {}, columnKey: "ad.id", height: 32, rowIndex: 0, style: { "height": 32, "width": 120 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(
-              "div",
-              { className: "_2d6h _4h2r" },
-              "98010048849345"
-            )
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell411 = React.createClass({
-    displayName: "FixedDataTableCell411",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 32, "width": 120, "left": 1038 } },
-        undefined,
-        React.createElement(TransitionCell410, null)
-      );
-    }
-  });
-
-  var TransitionCell412 = React.createClass({
-    displayName: "TransitionCell412",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { dataKey: "campaignGroup.objective", className: "_4lgc _4h2u", rowGetter: function () {}, width: 80, columnData: {}, cellDataGetter: function () {}, cellRenderer: function () {}, columnKey: "campaignGroup.objective", height: 32, rowIndex: 0, style: { "height": 32, "width": 80 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(
-              "div",
-              { className: "_2d6h _4h2r" },
-              "Clicks to Website"
-            )
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell413 = React.createClass({
-    displayName: "FixedDataTableCell413",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 32, "width": 80, "left": 1158 } },
-        undefined,
-        React.createElement(TransitionCell412, null)
-      );
-    }
-  });
-
-  var TransitionCell414 = React.createClass({
-    displayName: "TransitionCell414",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { dataKey: "stats.spent_100", className: "_4lgc _4h2u", rowGetter: function () {}, width: 70, columnData: {}, cellDataGetter: function () {}, cellRenderer: function () {}, columnKey: "stats.spent_100", height: 32, rowIndex: 0, style: { "height": 32, "width": 70 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(
-              "div",
-              { className: "_2d6h _2g7x _4h2r" },
-              " — "
-            )
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell415 = React.createClass({
-    displayName: "FixedDataTableCell415",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 32, "width": 70, "left": 1238 } },
-        undefined,
-        React.createElement(TransitionCell414, null)
-      );
-    }
-  });
-
-  var ReactDate416 = React.createClass({
-    displayName: "ReactDate416",
-
-    render: function () {
-      return React.createElement(
-        "span",
-        null,
-        "10/24/2015"
-      );
-    }
-  });
-
-  var TransitionCell417 = React.createClass({
-    displayName: "TransitionCell417",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { dataKey: "derivedCampaign.startDate", className: "_4lgc _4h2u", rowGetter: function () {}, width: 113, columnData: {}, cellDataGetter: function () {}, cellRenderer: function () {}, columnKey: "derivedCampaign.startDate", height: 32, rowIndex: 0, style: { "height": 32, "width": 113 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(
-              "div",
-              { className: "_2d6h _4h2r" },
-              React.createElement(ReactDate416, null)
-            )
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell418 = React.createClass({
-    displayName: "FixedDataTableCell418",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 32, "width": 113, "left": 1308 } },
-        undefined,
-        React.createElement(TransitionCell417, null)
-      );
-    }
-  });
-
-  var TransitionCell419 = React.createClass({
-    displayName: "TransitionCell419",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { dataKey: "derivedCampaign.endDate", className: "_4lgc _4h2u", rowGetter: function () {}, width: 113, columnData: {}, cellDataGetter: function () {}, cellRenderer: function () {}, columnKey: "derivedCampaign.endDate", height: 32, rowIndex: 0, style: { "height": 32, "width": 113 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(
-              "div",
-              { className: "_2d6h _4h2r" },
-              "Ongoing"
-            )
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell420 = React.createClass({
-    displayName: "FixedDataTableCell420",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 32, "width": 113, "left": 1421 } },
-        undefined,
-        React.createElement(TransitionCell419, null)
-      );
-    }
-  });
-
-  var ReactDate421 = React.createClass({
-    displayName: "ReactDate421",
-
-    render: function () {
-      return React.createElement(
-        "span",
-        null,
-        "10/24/2015"
-      );
-    }
-  });
-
-  var TransitionCell422 = React.createClass({
-    displayName: "TransitionCell422",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { dataKey: "ad.created_time", className: "_4lgc _4h2u", rowGetter: function () {}, width: 113, columnData: {}, cellDataGetter: function () {}, cellRenderer: function () {}, columnKey: "ad.created_time", height: 32, rowIndex: 0, style: { "height": 32, "width": 113 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(
-              "div",
-              { className: "_2d6h _4h2r" },
-              React.createElement(ReactDate421, null)
-            )
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell423 = React.createClass({
-    displayName: "FixedDataTableCell423",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 32, "width": 113, "left": 1534 } },
-        undefined,
-        React.createElement(TransitionCell422, null)
-      );
-    }
-  });
-
-  var ReactDate424 = React.createClass({
-    displayName: "ReactDate424",
-
-    render: function () {
-      return React.createElement(
-        "span",
-        null,
-        "10/24/2015"
-      );
-    }
-  });
-
-  var TransitionCell425 = React.createClass({
-    displayName: "TransitionCell425",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { dataKey: "ad.updated_time", className: "_4lgc _4h2u", rowGetter: function () {}, width: 113, columnData: {}, cellDataGetter: function () {}, cellRenderer: function () {}, columnKey: "ad.updated_time", height: 32, rowIndex: 0, style: { "height": 32, "width": 113 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(
-              "div",
-              { className: "_2d6h _4h2r" },
-              React.createElement(ReactDate424, null)
-            )
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell426 = React.createClass({
-    displayName: "FixedDataTableCell426",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 32, "width": 113, "left": 1647 } },
-        undefined,
-        React.createElement(TransitionCell425, null)
-      );
-    }
-  });
-
-  var TransitionCell427 = React.createClass({
-    displayName: "TransitionCell427",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { dataKey: "ad.title", className: "_4lgc _4h2u", rowGetter: function () {}, width: 80, columnData: {}, cellDataGetter: function () {}, cellRenderer: function () {}, columnKey: "ad.title", height: 32, rowIndex: 0, style: { "height": 32, "width": 80 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(
-              "div",
-              { className: "_2d6h _4h2r" },
-              "Example"
-            )
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell428 = React.createClass({
-    displayName: "FixedDataTableCell428",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 32, "width": 80, "left": 1760 } },
-        undefined,
-        React.createElement(TransitionCell427, null)
-      );
-    }
-  });
-
-  var TransitionCell429 = React.createClass({
-    displayName: "TransitionCell429",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { dataKey: "ad.creative.body", className: "_4lgc _4h2u", rowGetter: function () {}, width: 80, columnData: {}, cellDataGetter: function () {}, cellRenderer: function () {}, columnKey: "ad.creative.body", height: 32, rowIndex: 0, style: { "height": 32, "width": 80 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(
-              "div",
-              { className: "_2d6h _4h2r" },
-              "It's an example."
-            )
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell430 = React.createClass({
-    displayName: "FixedDataTableCell430",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 32, "width": 80, "left": 1840 } },
-        undefined,
-        React.createElement(TransitionCell429, null)
-      );
-    }
-  });
-
-  var TransitionCell431 = React.createClass({
-    displayName: "TransitionCell431",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { dataKey: "destination", className: "_4lgc _4h2u", rowGetter: function () {}, width: 92, columnData: {}, cellDataGetter: function () {}, cellRenderer: function () {}, columnKey: "destination", height: 32, rowIndex: 0, style: { "height": 32, "width": 92 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement("div", { className: "_2d6h _4h2r" })
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell432 = React.createClass({
-    displayName: "FixedDataTableCell432",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 32, "width": 92, "left": 1920 } },
-        undefined,
-        React.createElement(TransitionCell431, null)
-      );
-    }
-  });
-
-  var TransitionCell433 = React.createClass({
-    displayName: "TransitionCell433",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { dataKey: "ad.creative.link_url", className: "_4lgc _4h2u", rowGetter: function () {}, width: 70, columnData: {}, cellDataGetter: function () {}, cellRenderer: function () {}, columnKey: "ad.creative.link_url", height: 32, rowIndex: 0, style: { "height": 32, "width": 70 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(
-              "div",
-              { className: "_2d6h _4h2r" },
-              "http://www.example.com/"
-            )
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell434 = React.createClass({
-    displayName: "FixedDataTableCell434",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 32, "width": 70, "left": 2012 } },
-        undefined,
-        React.createElement(TransitionCell433, null)
-      );
-    }
-  });
-
-  var FixedDataTableCellDefault435 = React.createClass({
-    displayName: "FixedDataTableCellDefault435",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { dataKey: "page", className: "_4lgc _4h2u", rowGetter: function () {}, width: 92, columnData: {}, cellDataGetter: function () {}, cellRenderer: function () {}, columnKey: "page", height: 32, rowIndex: 0, style: { "height": 32, "width": 92 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement("div", { className: "_4h2r" })
-          )
-        )
-      );
-    }
-  });
-
-  var TransitionCell436 = React.createClass({
-    displayName: "TransitionCell436",
-
-    render: function () {
-      return React.createElement(FixedDataTableCellDefault435, null);
-    }
-  });
-
-  var FixedDataTableCell437 = React.createClass({
-    displayName: "FixedDataTableCell437",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 32, "width": 92, "left": 2082 } },
-        undefined,
-        React.createElement(TransitionCell436, null)
-      );
-    }
-  });
-
-  var Link438 = React.createClass({
-    displayName: "Link438",
-
-    render: function () {
-      return React.createElement(
-        "a",
-        { href: "https://www.facebook.com/?demo_ad=98010048849345&h=AQA24w3temAtB-5f#pagelet_ego_pane", target: "_blank", rel: undefined, onClick: function () {} },
-        "Preview Ad"
-      );
-    }
-  });
-
-  var ReactImage439 = React.createClass({
-    displayName: "ReactImage439",
-
-    render: function () {
-      return React.createElement("i", { src: null, className: "_541d img sp_R48dKBxiJkP sx_dc2cdb" });
-    }
-  });
-
-  var AdsPopoverLink440 = React.createClass({
-    displayName: "AdsPopoverLink440",
-
-    render: function () {
-      return React.createElement(
-        "span",
-        { ref: "tipIcon", onMouseEnter: function () {}, onMouseLeave: function () {} },
-        React.createElement("span", { className: "_3o_j" }),
-        React.createElement(ReactImage439, null)
-      );
-    }
-  });
-
-  var AdsHelpLink441 = React.createClass({
-    displayName: "AdsHelpLink441",
-
-    render: function () {
-      return React.createElement(AdsPopoverLink440, null);
-    }
-  });
-
-  var TransitionCell442 = React.createClass({
-    displayName: "TransitionCell442",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { dataKey: "ad.demolink_hash", className: "_4lgc _4h2u", rowGetter: function () {}, width: 100, columnData: {}, cellDataGetter: function () {}, cellRenderer: function () {}, columnKey: "ad.demolink_hash", height: 32, rowIndex: 0, style: { "height": 32, "width": 100 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement(
-              "div",
-              { className: "_4h2r" },
-              React.createElement(Link438, null),
-              React.createElement(AdsHelpLink441, null)
-            )
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell443 = React.createClass({
-    displayName: "FixedDataTableCell443",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 32, "width": 100, "left": 2174 } },
-        undefined,
-        React.createElement(TransitionCell442, null)
-      );
-    }
-  });
-
-  var TransitionCell444 = React.createClass({
-    displayName: "TransitionCell444",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { dataKey: "scrollbar_spacer", className: "_4lgc _4h2u", rowGetter: function () {}, width: 25, columnData: {}, cellDataGetter: function () {}, cellRenderer: function () {}, columnKey: "scrollbar_spacer", height: 32, rowIndex: 0, style: { "height": 32, "width": 25 } },
-        React.createElement(
-          "div",
-          { className: "_4lgd _4h2w" },
-          React.createElement(
-            "div",
-            { className: "_4lge _4h2x" },
-            React.createElement("div", { className: "_2d6h _4h2r" })
-          )
-        )
-      );
-    }
-  });
-
-  var FixedDataTableCell445 = React.createClass({
-    displayName: "FixedDataTableCell445",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_4lg0 _4h2m", style: { "height": 32, "width": 25, "left": 2274 } },
-        undefined,
-        React.createElement(TransitionCell444, null)
-      );
-    }
-  });
-
-  var FixedDataTableCellGroupImpl446 = React.createClass({
-    displayName: "FixedDataTableCellGroupImpl446",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_3pzj", style: { "height": 32, "position": "absolute", "width": 2299, "zIndex": 0, "transform": "translate3d(0px,0px,0)", "backfaceVisibility": "hidden" } },
-        React.createElement(FixedDataTableCell387, { key: "cell_0" }),
-        React.createElement(FixedDataTableCell389, { key: "cell_1" }),
-        React.createElement(FixedDataTableCell391, { key: "cell_2" }),
-        React.createElement(FixedDataTableCell393, { key: "cell_3" }),
-        React.createElement(FixedDataTableCell395, { key: "cell_4" }),
-        React.createElement(FixedDataTableCell397, { key: "cell_5" }),
-        React.createElement(FixedDataTableCell399, { key: "cell_6" }),
-        React.createElement(FixedDataTableCell401, { key: "cell_7" }),
-        React.createElement(FixedDataTableCell403, { key: "cell_8" }),
-        React.createElement(FixedDataTableCell406, { key: "cell_9" }),
-        React.createElement(FixedDataTableCell409, { key: "cell_10" }),
-        React.createElement(FixedDataTableCell411, { key: "cell_11" }),
-        React.createElement(FixedDataTableCell413, { key: "cell_12" }),
-        React.createElement(FixedDataTableCell415, { key: "cell_13" }),
-        React.createElement(FixedDataTableCell418, { key: "cell_14" }),
-        React.createElement(FixedDataTableCell420, { key: "cell_15" }),
-        React.createElement(FixedDataTableCell423, { key: "cell_16" }),
-        React.createElement(FixedDataTableCell426, { key: "cell_17" }),
-        React.createElement(FixedDataTableCell428, { key: "cell_18" }),
-        React.createElement(FixedDataTableCell430, { key: "cell_19" }),
-        React.createElement(FixedDataTableCell432, { key: "cell_20" }),
-        React.createElement(FixedDataTableCell434, { key: "cell_21" }),
-        React.createElement(FixedDataTableCell437, { key: "cell_22" }),
-        React.createElement(FixedDataTableCell443, { key: "cell_23" }),
-        React.createElement(FixedDataTableCell445, { key: "cell_24" })
-      );
-    }
-  });
-
-  var FixedDataTableCellGroup447 = React.createClass({
-    displayName: "FixedDataTableCellGroup447",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { style: { "height": 32, "left": 521 }, className: "_3pzk" },
-        React.createElement(FixedDataTableCellGroupImpl446, null)
-      );
-    }
-  });
-
-  var FixedDataTableRowImpl448 = React.createClass({
-    displayName: "FixedDataTableRowImpl448",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1gd4 _4li _52no _35m0 _35m1 _3c7k _4efq _4efs", onClick: null, onDoubleClick: null, onMouseDown: function () {}, onMouseEnter: null, onMouseLeave: null, style: { "width": 1083, "height": 32 } },
-        React.createElement(
-          "div",
-          { className: "_1gd5" },
-          React.createElement(FixedDataTableCellGroup385, { key: "fixed_cells" }),
-          React.createElement(FixedDataTableCellGroup447, { key: "scrollable_cells" }),
-          React.createElement("div", { className: "_1gd6 _1gd8", style: { "left": 521, "height": 32 } })
-        )
-      );
-    }
-  });
-
-  var FixedDataTableRow449 = React.createClass({
-    displayName: "FixedDataTableRow449",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { style: { "width": 1083, "height": 32, "zIndex": 0, "transform": "translate3d(0px,0px,0)", "backfaceVisibility": "hidden" }, className: "_1gda" },
-        React.createElement(FixedDataTableRowImpl448, null)
-      );
-    }
-  });
-
-  var FixedDataTableBufferedRows450 = React.createClass({
-    displayName: "FixedDataTableBufferedRows450",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { style: { "position": "absolute", "pointerEvents": "auto", "transform": "translate3d(0px,65px,0)", "backfaceVisibility": "hidden" } },
-        React.createElement(FixedDataTableRow449, { key: "0" })
-      );
-    }
-  });
-
-  var Scrollbar451 = React.createClass({
-    displayName: "Scrollbar451",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { onFocus: function () {}, onBlur: function () {}, onKeyDown: function () {}, onMouseDown: function () {}, onWheel: function () {}, className: "_1t0r _1t0t _4jdr _1t0u", style: { "width": 1083, "zIndex": 99 }, tabIndex: 0 },
-        React.createElement("div", { ref: "face", className: "_1t0w _1t0y _1t0_", style: { "width": 407.918085106383, "transform": "translate3d(4px,0px,0)", "backfaceVisibility": "hidden" } })
-      );
-    }
-  });
-
-  var HorizontalScrollbar452 = React.createClass({
-    displayName: "HorizontalScrollbar452",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_3h1k _3h1m", style: { "height": 15, "width": 1083 } },
-        React.createElement(
-          "div",
-          { style: { "height": 15, "position": "absolute", "overflow": "hidden", "width": 1083, "transform": "translate3d(0px,0px,0)", "backfaceVisibility": "hidden" } },
-          React.createElement(Scrollbar451, null)
-        )
-      );
-    }
-  });
-
-  var FixedDataTable453 = React.createClass({
-    displayName: "FixedDataTable453",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_3h1i _1mie", onWheel: function () {}, style: { "height": 532, "width": 1083 } },
-        React.createElement(
-          "div",
-          { className: "_3h1j", style: { "height": 515, "width": 1083 } },
-          React.createElement(FixedDataTableColumnResizeHandle178, null),
-          React.createElement(FixedDataTableRow206, { key: "group_header" }),
-          React.createElement(FixedDataTableRow360, { key: "header" }),
-          React.createElement(FixedDataTableBufferedRows450, null),
-          null,
-          undefined,
-          undefined
-        ),
-        undefined,
-        React.createElement(HorizontalScrollbar452, null)
-      );
-    }
-  });
-
-  var TransitionTable454 = React.createClass({
-    displayName: "TransitionTable454",
-
-    render: function () {
-      return React.createElement(FixedDataTable453, null);
-    }
-  });
-
-  var AdsSelectableFixedDataTable455 = React.createClass({
-    displayName: "AdsSelectableFixedDataTable455",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_5hht" },
-        React.createElement(TransitionTable454, null)
-      );
-    }
-  });
-
-  var AdsDataTableKeyboardSupportDecorator456 = React.createClass({
-    displayName: "AdsDataTableKeyboardSupportDecorator456",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { ref: "tableContainer", className: "_5d6f", tabIndex: "0", onKeyDown: function () {} },
-        React.createElement(AdsSelectableFixedDataTable455, null)
-      );
-    }
-  });
-
-  var AdsEditableDataTableDecorator457 = React.createClass({
-    displayName: "AdsEditableDataTableDecorator457",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { onCopy: function () {} },
-        React.createElement(AdsDataTableKeyboardSupportDecorator456, { ref: "decoratedTable" })
-      );
-    }
-  });
-
-  var AdsPEDataTableContainer458 = React.createClass({
-    displayName: "AdsPEDataTableContainer458",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_35l_" },
-        null,
-        null,
-        React.createElement(AdsEditableDataTableDecorator457, null)
-      );
-    }
-  });
-
-  var ResponsiveBlock459 = React.createClass({
-    displayName: "ResponsiveBlock459",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { onResize: function () {}, className: "_4u-c" },
-        React.createElement(AdsPEDataTableContainer458, null),
-        React.createElement(
-          "div",
-          { key: "sensor", className: "_4u-f" },
-          React.createElement("iframe", { ref: "sensorNode", "aria-hidden": "true", className: "_4u-g", tabIndex: "-1" })
-        )
-      );
-    }
-  });
-
-  var AdsPEAdTableContainer460 = React.createClass({
-    displayName: "AdsPEAdTableContainer460",
-
-    render: function () {
-      return React.createElement(ResponsiveBlock459, null);
-    }
-  });
-
-  var AdsPEManageAdsPaneContainer461 = React.createClass({
-    displayName: "AdsPEManageAdsPaneContainer461",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_2utw" },
-        null,
-        React.createElement(
-          "div",
-          { className: "_2utx _41tt" },
-          React.createElement(AdsPEFilterContainer104, null),
-          React.createElement(AdsPECampaignTimeLimitNoticeContainer106, null),
-          null
-        ),
-        React.createElement(
-          "div",
-          { className: " _41ts" },
-          React.createElement(AdsPEAdgroupToolbarContainer169, null)
-        ),
-        React.createElement(
-          "div",
-          { className: "_2utz" },
-          React.createElement(
-            "div",
-            { className: "_2ut-" },
-            React.createElement(AdsPEOrganizerContainer177, null)
-          ),
-          React.createElement(
-            "div",
-            { className: "_2ut_" },
-            React.createElement(AdsPEAdTableContainer460, null)
-          )
-        )
-      );
-    }
-  });
-
-  var AdsPEContentContainer462 = React.createClass({
-    displayName: "AdsPEContentContainer462",
-
-    render: function () {
-      return React.createElement(AdsPEManageAdsPaneContainer461, null);
-    }
-  });
-
-  var FluxContainer_r_463 = React.createClass({
-    displayName: "FluxContainer_r_463",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "mainWrapper", style: { "width": 1192 } },
-        React.createElement(FluxContainer_r_69, null),
-        React.createElement(AdsPEContentContainer462, null),
-        null
-      );
-    }
-  });
-
-  var FluxContainer_q_464 = React.createClass({
-    displayName: "FluxContainer_q_464",
-
-    render: function () {
-      return null;
-    }
-  });
-
-  var AdsPEUploadDialog465 = React.createClass({
-    displayName: "AdsPEUploadDialog465",
-
-    render: function () {
-      return null;
-    }
-  });
-
-  var FluxContainer_y_466 = React.createClass({
-    displayName: "FluxContainer_y_466",
-
-    render: function () {
-      return React.createElement(AdsPEUploadDialog465, null);
-    }
-  });
-
-  var ReactImage467 = React.createClass({
-    displayName: "ReactImage467",
-
-    render: function () {
-      return React.createElement("i", { className: "_1-lx img sp_UuU9HmrQ397 sx_990b54", src: null });
-    }
-  });
-
-  var AdsPESideTrayTabButton468 = React.createClass({
-    displayName: "AdsPESideTrayTabButton468",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { onClick: function () {}, className: "_1-ly _59j9 _d9a" },
-        React.createElement(ReactImage467, null),
-        React.createElement("div", { className: "_vf7" }),
-        React.createElement("div", { className: "_vf8" })
-      );
-    }
-  });
-
-  var AdsPEEditorTrayTabButton469 = React.createClass({
-    displayName: "AdsPEEditorTrayTabButton469",
-
-    render: function () {
-      return React.createElement(AdsPESideTrayTabButton468, null);
-    }
-  });
-
-  var ReactImage470 = React.createClass({
-    displayName: "ReactImage470",
-
-    render: function () {
-      return React.createElement("i", { className: "_1-lx img sp_UuU9HmrQ397 sx_94017f", src: null });
-    }
-  });
-
-  var AdsPESideTrayTabButton471 = React.createClass({
-    displayName: "AdsPESideTrayTabButton471",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { onClick: function () {}, className: " _1-lz _d9a" },
-        React.createElement(ReactImage470, null),
-        React.createElement("div", { className: "_vf7" }),
-        React.createElement("div", { className: "_vf8" })
-      );
-    }
-  });
-
-  var AdsPEInsightsTrayTabButton472 = React.createClass({
-    displayName: "AdsPEInsightsTrayTabButton472",
-
-    render: function () {
-      return React.createElement(AdsPESideTrayTabButton471, null);
-    }
-  });
-
-  var AdsPESideTrayTabButton473 = React.createClass({
-    displayName: "AdsPESideTrayTabButton473",
-
-    render: function () {
-      return null;
-    }
-  });
-
-  var AdsPENekoDebuggerTrayTabButton474 = React.createClass({
-    displayName: "AdsPENekoDebuggerTrayTabButton474",
-
-    render: function () {
-      return React.createElement(AdsPESideTrayTabButton473, null);
-    }
-  });
-
-  var FBDragHandle475 = React.createClass({
-    displayName: "FBDragHandle475",
-
-    render: function () {
-      return React.createElement("div", { style: { "height": 550 }, className: "_4a2j _2ciy _2ciz", horizontal: true, onStart: function () {}, onEnd: function () {}, onChange: function () {}, initialData: function () {}, vertical: false, throttle: 25, delay: 0, threshold: 0, onMouseDown: function () {}, onMouseUp: function () {}, onMouseLeave: function () {} });
-    }
-  });
-
-  var XUIText476 = React.createClass({
-    displayName: "XUIText476",
-
-    render: function () {
-      return React.createElement(
-        "span",
-        { size: "large", weight: "bold", className: "_2x9f  _50f5 _50f7", display: "inline" },
-        "Editing Ad"
-      );
-    }
-  });
-
-  var XUIText477 = React.createClass({
-    displayName: "XUIText477",
-
-    render: function () {
-      return React.createElement(
-        "span",
-        { size: "large", weight: "bold", display: "inline", className: " _50f5 _50f7" },
-        "Test Ad"
-      );
-    }
-  });
-
-  var AdsPEEditorChildLink478 = React.createClass({
-    displayName: "AdsPEEditorChildLink478",
-
-    render: function () {
-      return null;
-    }
-  });
-
-  var AdsPEEditorChildLinkContainer479 = React.createClass({
-    displayName: "AdsPEEditorChildLinkContainer479",
-
-    render: function () {
-      return React.createElement(AdsPEEditorChildLink478, null);
-    }
-  });
-
-  var AdsPEHeaderSection480 = React.createClass({
-    displayName: "AdsPEHeaderSection480",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_yke" },
-        React.createElement("div", { className: "_2x9d _pry" }),
-        React.createElement(XUIText476, null),
-        React.createElement(
-          "div",
-          { className: "_3a-a" },
-          React.createElement(
-            "div",
-            { className: "_3a-b" },
-            React.createElement(XUIText477, null)
-          )
-        ),
-        null,
-        React.createElement(AdsPEEditorChildLinkContainer479, null)
-      );
-    }
-  });
-
-  var AdsPEAdgroupHeaderSectionContainer481 = React.createClass({
-    displayName: "AdsPEAdgroupHeaderSectionContainer481",
-
-    render: function () {
-      return React.createElement(AdsPEHeaderSection480, null);
-    }
-  });
-
-  var AdsPEAdgroupDisapprovalMessage482 = React.createClass({
-    displayName: "AdsPEAdgroupDisapprovalMessage482",
-
-    render: function () {
-      return null;
-    }
-  });
-
-  var FluxContainer_r_483 = React.createClass({
-    displayName: "FluxContainer_r_483",
-
-    render: function () {
-      return React.createElement(AdsPEAdgroupDisapprovalMessage482, null);
-    }
-  });
-
-  var AdsPEAdgroupAutoNamingConfirmationContainer484 = React.createClass({
-    displayName: "AdsPEAdgroupAutoNamingConfirmationContainer484",
-
-    render: function () {
-      return null;
-    }
-  });
-
-  var AdsLabeledField485 = React.createClass({
-    displayName: "AdsLabeledField485",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_5ir9 _3bvz", label: "Ad Name", labelSize: "small" },
-        React.createElement(
-          "label",
-          { className: "_4el4 _3qwj _3hy-", htmlFor: undefined },
-          "Ad Name",
-          " ",
-          undefined
-        ),
-        null,
-        React.createElement("div", { className: "_3bv-" })
-      );
-    }
-  });
-
-  var ReactXUIError486 = React.createClass({
-    displayName: "ReactXUIError486",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_5ira _2vl4 _1h18" },
-        null,
-        null,
-        React.createElement(
-          "div",
-          { className: "_2vl9 _1h1f", style: { "backgroundColor": "#fff" } },
-          React.createElement(
-            "div",
-            { className: "_2vla _1h1g" },
-            React.createElement(
-              "div",
-              null,
-              null,
-              React.createElement("textarea", { ref: "input", id: undefined, disabled: undefined, onKeyDown: function () {}, onFocus: function () {}, onBlur: function () {}, onChange: function () {}, dir: "auto", maxLength: null, className: "_2vli _2vlj _1h26 _1h27", value: "Test Ad" }),
-              null
-            ),
-            React.createElement("div", { ref: "shadowText", "aria-hidden": "true", className: "_2vlk" })
-          )
-        ),
-        null
-      );
-    }
-  });
-
-  var AdsTextInput487 = React.createClass({
-    displayName: "AdsTextInput487",
-
-    render: function () {
-      return React.createElement(ReactXUIError486, null);
-    }
-  });
-
-  var Link488 = React.createClass({
-    displayName: "Link488",
-
-    render: function () {
-      return React.createElement(
-        "a",
-        { className: "_5ir9", label: "Rename using available fields", onMouseDown: function () {}, href: "#", rel: undefined, onClick: function () {} },
-        "Rename using available fields"
-      );
-    }
-  });
-
-  var AdsAutoNamingTemplateDialog489 = React.createClass({
-    displayName: "AdsAutoNamingTemplateDialog489",
-
-    render: function () {
-      return React.createElement(Link488, { ref: "link" });
-    }
-  });
-
-  var AdsPEAmbientNUXMegaphone490 = React.createClass({
-    displayName: "AdsPEAmbientNUXMegaphone490",
-
-    render: function () {
-      return React.createElement(
-        "span",
-        { ref: "mainChild" },
-        React.createElement(AdsAutoNamingTemplateDialog489, null)
-      );
-    }
-  });
-
-  var AdsLabeledField491 = React.createClass({
-    displayName: "AdsLabeledField491",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_5ir9 _3bvz", label: "Status", labelSize: "small" },
-        React.createElement(
-          "label",
-          { className: "_4el4 _3qwj _3hy-", htmlFor: undefined },
-          "Status",
-          " ",
-          undefined
-        ),
-        null,
-        React.createElement("div", { className: "_3bv-" })
-      );
-    }
-  });
-
-  var BUISwitch492 = React.createClass({
-    displayName: "BUISwitch492",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { value: true, disabled: true, onToggle: function () {}, "data-hover": "tooltip", "data-tooltip-position": "below", "aria-label": "Currently active and you can not deactivate it.", animate: true, className: "_128j _128k _128m _128n", role: "checkbox", "aria-checked": "true" },
-        React.createElement(
-          "div",
-          { className: "_128o", onClick: function () {}, onKeyDown: function () {}, onMouseDown: function () {}, tabIndex: "-1" },
-          React.createElement("div", { className: "_128p" })
-        ),
-        null
-      );
-    }
-  });
-
-  var AdsStatusSwitchInternal493 = React.createClass({
-    displayName: "AdsStatusSwitchInternal493",
-
-    render: function () {
-      return React.createElement(BUISwitch492, null);
-    }
-  });
-
-  var AdsStatusSwitch494 = React.createClass({
-    displayName: "AdsStatusSwitch494",
-
-    render: function () {
-      return React.createElement(AdsStatusSwitchInternal493, null);
-    }
-  });
-
-  var LeftRight495 = React.createClass({
-    displayName: "LeftRight495",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "clearfix" },
-        React.createElement(
-          "div",
-          { key: "left", className: "_ohe lfloat" },
-          React.createElement(
-            "div",
-            null,
-            React.createElement(AdsLabeledField485, null),
-            React.createElement(
-              "span",
-              { className: "_5irl" },
-              React.createElement(AdsTextInput487, { key: "nameEditor98010048849345", ref: "nameTextInput" }),
-              React.createElement(AdsPEAmbientNUXMegaphone490, null)
-            )
-          )
-        ),
-        React.createElement(
-          "div",
-          { key: "right", className: "_ohf rfloat" },
-          React.createElement(
-            "div",
-            null,
-            React.createElement(AdsLabeledField491, null),
-            React.createElement(
-              "div",
-              { className: "_5irp" },
-              React.createElement(AdsStatusSwitch494, null)
-            )
-          )
-        )
-      );
-    }
-  });
-
-  var XUICard496 = React.createClass({
-    displayName: "XUICard496",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_5ir8 _12k2 _4-u2  _4-u8", xuiErrorPosition: "above", background: "white" },
-        React.createElement(LeftRight495, null)
-      );
-    }
-  });
-
-  var ReactXUIError497 = React.createClass({
-    displayName: "ReactXUIError497",
-
-    render: function () {
-      return React.createElement(XUICard496, null);
-    }
-  });
-
-  var AdsCard498 = React.createClass({
-    displayName: "AdsCard498",
-
-    render: function () {
-      return React.createElement(ReactXUIError497, null);
-    }
-  });
-
-  var AdsPENameSection499 = React.createClass({
-    displayName: "AdsPENameSection499",
-
-    render: function () {
-      return React.createElement(AdsCard498, null);
-    }
-  });
-
-  var AdsPEAdgroupNameSectionContainer500 = React.createClass({
-    displayName: "AdsPEAdgroupNameSectionContainer500",
-
-    render: function () {
-      return React.createElement(AdsPENameSection499, null);
-    }
-  });
-
-  var XUICardHeaderTitle501 = React.createClass({
-    displayName: "XUICardHeaderTitle501",
-
-    render: function () {
-      return React.createElement(
-        "span",
-        { itemComponent: "span", className: "_38my" },
-        "Ad Links",
-        null,
-        React.createElement("span", { className: "_c1c" })
-      );
-    }
-  });
-
-  var XUICardSection502 = React.createClass({
-    displayName: "XUICardSection502",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_5dw9 _5dwa _4-u3", background: "transparent" },
-        [React.createElement(XUICardHeaderTitle501, { key: "/.0" })],
-        undefined,
-        undefined,
-        React.createElement("div", { className: "_3s3-" })
-      );
-    }
-  });
-
-  var XUICardHeader503 = React.createClass({
-    displayName: "XUICardHeader503",
-
-    render: function () {
-      return React.createElement(XUICardSection502, null);
-    }
-  });
-
-  var AdsCardHeader504 = React.createClass({
-    displayName: "AdsCardHeader504",
-
-    render: function () {
-      return React.createElement(XUICardHeader503, null);
-    }
-  });
-
-  var XUIText505 = React.createClass({
-    displayName: "XUIText505",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_502s", display: "block", size: "inherit", weight: "inherit" },
-        "Ad ID 98010048849345"
-      );
-    }
-  });
-
-  var Link506 = React.createClass({
-    displayName: "Link506",
-
-    render: function () {
-      return React.createElement(
-        "a",
-        { target: "_blank", href: "/ads/manager/ad/?ids=98010048849345", onClick: function () {}, rel: undefined },
-        "Open in Ads Manager"
-      );
-    }
-  });
-
-  var Link507 = React.createClass({
-    displayName: "Link507",
-
-    render: function () {
-      return React.createElement(
-        "a",
-        { target: "_blank", href: "#", onClick: function () {}, rel: undefined },
-        "Open in Ads Reporting"
-      );
-    }
-  });
-
-  var Link508 = React.createClass({
-    displayName: "Link508",
-
-    render: function () {
-      return React.createElement(
-        "a",
-        { target: "_blank", href: "https://www.facebook.com/?demo_ad=98010048849345&h=AQA24w3temAtB-5f#pagelet_ego_pane", onClick: function () {}, rel: undefined },
-        "View on Desktop Right Column"
-      );
-    }
-  });
-
-  var Link509 = React.createClass({
-    displayName: "Link509",
-
-    render: function () {
-      return React.createElement(
-        "a",
-        { target: "_blank", href: "/ads/manage/powereditor/?act=10149999073643408&adgroup=98010048849345", onClick: function () {}, rel: undefined },
-        "Open Power Editor with this ad selected"
-      );
-    }
-  });
-
-  var List510 = React.createClass({
-    displayName: "List510",
-
-    render: function () {
-      return React.createElement(
-        "ul",
-        { spacing: "small", border: "none", direction: "vertical", valign: "top", className: "uiList _4kg _6-i _6-h _704" },
-        null,
-        React.createElement(
-          "li",
-          { key: "/ads/manager/ad/?ids=98010048849345" },
-          React.createElement(Link506, null)
-        ),
-        React.createElement(
-          "li",
-          { key: "#" },
-          React.createElement(Link507, null)
-        ),
-        null,
-        React.createElement(
-          "li",
-          { key: "https://www.facebook.com/?demo_ad=98010048849345&h=AQA24w3temAtB-5f#pagelet_ego_pane" },
-          React.createElement(Link508, null)
-        ),
-        null,
-        null,
-        null,
-        React.createElement(
-          "li",
-          { key: "/ads/manage/powereditor/?act=10149999073643408&adgroup=98010048849345" },
-          React.createElement(Link509, null)
-        ),
-        null
-      );
-    }
-  });
-
-  var XUICardSection511 = React.createClass({
-    displayName: "XUICardSection511",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_12jy _4-u3", background: "transparent" },
-        React.createElement(
-          "div",
-          { className: "_3-8j" },
-          React.createElement(XUIText505, null),
-          React.createElement(List510, null)
-        )
-      );
-    }
-  });
-
-  var AdsCardSection512 = React.createClass({
-    displayName: "AdsCardSection512",
-
-    render: function () {
-      return React.createElement(XUICardSection511, null);
-    }
-  });
-
-  var XUICard513 = React.createClass({
-    displayName: "XUICard513",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { xuiErrorPosition: "above", className: "_12k2 _4-u2  _4-u8", background: "white" },
-        React.createElement(AdsCardHeader504, null),
-        React.createElement(AdsCardSection512, null)
-      );
-    }
-  });
-
-  var ReactXUIError514 = React.createClass({
-    displayName: "ReactXUIError514",
-
-    render: function () {
-      return React.createElement(XUICard513, null);
-    }
-  });
-
-  var AdsCard515 = React.createClass({
-    displayName: "AdsCard515",
-
-    render: function () {
-      return React.createElement(ReactXUIError514, null);
-    }
-  });
-
-  var AdsPELinkList516 = React.createClass({
-    displayName: "AdsPELinkList516",
-
-    render: function () {
-      return React.createElement(AdsCard515, null);
-    }
-  });
-
-  var AdsPEAdgroupLinksSection517 = React.createClass({
-    displayName: "AdsPEAdgroupLinksSection517",
-
-    render: function () {
-      return React.createElement(AdsPELinkList516, null);
-    }
-  });
-
-  var AdsPEAdgroupLinksSectionContainer518 = React.createClass({
-    displayName: "AdsPEAdgroupLinksSectionContainer518",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        null,
-        React.createElement(AdsPEAdgroupLinksSection517, null),
-        null
-      );
-    }
-  });
-
-  var XUICardHeaderTitle519 = React.createClass({
-    displayName: "XUICardHeaderTitle519",
-
-    render: function () {
-      return React.createElement(
-        "span",
-        { itemComponent: "span", className: "_38my" },
-        "Preview",
-        null,
-        React.createElement("span", { className: "_c1c" })
-      );
-    }
-  });
-
-  var XUICardSection520 = React.createClass({
-    displayName: "XUICardSection520",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_5dw9 _5dwa _4-u3", background: "transparent" },
-        [React.createElement(XUICardHeaderTitle519, { key: "/.0" })],
-        undefined,
-        undefined,
-        React.createElement("div", { className: "_3s3-" })
-      );
-    }
-  });
-
-  var XUICardHeader521 = React.createClass({
-    displayName: "XUICardHeader521",
-
-    render: function () {
-      return React.createElement(XUICardSection520, null);
-    }
-  });
-
-  var AdsCardHeader522 = React.createClass({
-    displayName: "AdsCardHeader522",
-
-    render: function () {
-      return React.createElement(XUICardHeader521, null);
-    }
-  });
-
-  var PillButton523 = React.createClass({
-    displayName: "PillButton523",
-
-    render: function () {
-      return React.createElement(
-        "a",
-        { label: null, selected: true, onClick: function () {}, href: "#", className: "uiPillButton uiPillButtonSelected" },
-        "Desktop Right Column"
-      );
-    }
-  });
-
-  var List524 = React.createClass({
-    displayName: "List524",
-
-    render: function () {
-      return React.createElement(
-        "ul",
-        { className: "uiList  _4ki _509- _6-i _6-h _704", border: "none", direction: "horizontal", spacing: "small", valign: "top" },
-        React.createElement(
-          "li",
-          { key: "0/.$RIGHT_COLUMN_STANDARD" },
-          React.createElement(PillButton523, { key: "RIGHT_COLUMN_STANDARD" })
-        )
-      );
-    }
-  });
-
-  var PillList525 = React.createClass({
-    displayName: "PillList525",
-
-    render: function () {
-      return React.createElement(List524, null);
-    }
-  });
-
-  var XUICardSection526 = React.createClass({
-    displayName: "XUICardSection526",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { background: "light-wash", className: "_14p9 _12jy _4-u3  _57d8" },
-        React.createElement(
-          "div",
-          { className: "_3-8j" },
-          React.createElement(PillList525, null)
-        )
-      );
-    }
-  });
-
-  var AdsCardSection527 = React.createClass({
-    displayName: "AdsCardSection527",
-
-    render: function () {
-      return React.createElement(XUICardSection526, null);
-    }
-  });
-
-  var AdsPEPreviewPillList528 = React.createClass({
-    displayName: "AdsPEPreviewPillList528",
-
-    render: function () {
-      return React.createElement(AdsCardSection527, null);
-    }
-  });
-
-  var XUISpinner529 = React.createClass({
-    displayName: "XUISpinner529",
-
-    render: function () {
-      return React.createElement("span", { size: "large", className: "hidden_elem img _55ym _55yq _55yo", showOnAsync: false, background: "light", "aria-label": "Loading...", "aria-busy": true });
-    }
-  });
-
-  var ReactImage530 = React.createClass({
-    displayName: "ReactImage530",
-
-    render: function () {
-      return React.createElement(
-        "i",
-        { alt: "Warning", className: "_585p img sp_R48dKBxiJkP sx_aed870", src: null },
-        React.createElement(
-          "u",
-          null,
-          "Warning"
-        )
-      );
-    }
-  });
-
-  var XUINotice531 = React.createClass({
-    displayName: "XUINotice531",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { size: "medium", className: "_585n _585o" },
-        React.createElement(ReactImage530, null),
-        null,
-        React.createElement(
-          "div",
-          { className: "_585r _50f4" },
-          "Unable to display a preview for this ad."
-        )
-      );
-    }
-  });
-
-  var AdPreview532 = React.createClass({
-    displayName: "AdPreview532",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_2hm6" },
-        React.createElement(
-          "div",
-          { className: undefined },
-          React.createElement(
-            "div",
-            { className: "_3akw" },
-            React.createElement(XUISpinner529, null)
-          ),
-          React.createElement(
-            "div",
-            { className: "hidden_elem" },
-            React.createElement(XUINotice531, null)
-          ),
-          React.createElement("div", { ref: "pageletContainer", className: "" })
-        )
-      );
-    }
-  });
-
-  var XUICardSection533 = React.createClass({
-    displayName: "XUICardSection533",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_3m4g _12jy _4-u3", style: { "maxHeight": "425px" }, background: "transparent" },
-        React.createElement(
-          "div",
-          { className: "_3-8j" },
-          React.createElement(
-            "div",
-            { className: "_14p7" },
-            React.createElement(
-              "div",
-              { className: "_14p8" },
-              React.createElement(AdPreview532, null)
-            )
-          )
-        )
-      );
-    }
-  });
-
-  var AdsCardSection534 = React.createClass({
-    displayName: "AdsCardSection534",
-
-    render: function () {
-      return React.createElement(XUICardSection533, null);
-    }
-  });
-
-  var AdsPEPreview535 = React.createClass({
-    displayName: "AdsPEPreview535",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        null,
-        React.createElement(AdsPEPreviewPillList528, { ref: "pillList" }),
-        undefined,
-        React.createElement(AdsCardSection534, null)
-      );
-    }
-  });
-
-  var AdsPEStandardPreview536 = React.createClass({
-    displayName: "AdsPEStandardPreview536",
-
-    render: function () {
-      return React.createElement(AdsPEPreview535, null);
-    }
-  });
-
-  var AdsPEStandardPreviewContainer537 = React.createClass({
-    displayName: "AdsPEStandardPreviewContainer537",
-
-    render: function () {
-      return React.createElement(AdsPEStandardPreview536, null);
-    }
-  });
-
-  var XUICard538 = React.createClass({
-    displayName: "XUICard538",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { xuiErrorPosition: "above", className: "_12k2 _4-u2  _4-u8", background: "white" },
-        React.createElement(AdsCardHeader522, null),
-        null,
-        React.createElement(AdsPEStandardPreviewContainer537, null)
-      );
-    }
-  });
-
-  var ReactXUIError539 = React.createClass({
-    displayName: "ReactXUIError539",
-
-    render: function () {
-      return React.createElement(XUICard538, null);
-    }
-  });
-
-  var AdsCard540 = React.createClass({
-    displayName: "AdsCard540",
-
-    render: function () {
-      return React.createElement(ReactXUIError539, null);
-    }
-  });
-
-  var AdsPEAdgroupPreviewSection541 = React.createClass({
-    displayName: "AdsPEAdgroupPreviewSection541",
-
-    render: function () {
-      return React.createElement(AdsCard540, null);
-    }
-  });
-
-  var AdsPEAdgroupPreviewSectionContainer542 = React.createClass({
-    displayName: "AdsPEAdgroupPreviewSectionContainer542",
-
-    render: function () {
-      return React.createElement(AdsPEAdgroupPreviewSection541, null);
-    }
-  });
-
-  var AdsPEStickyArea543 = React.createClass({
-    displayName: "AdsPEStickyArea543",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        null,
-        null,
-        React.createElement(
-          "div",
-          { ref: "sticky" },
-          React.createElement(AdsPEAdgroupPreviewSectionContainer542, null)
-        )
-      );
-    }
-  });
-
-  var XUICardHeaderTitle544 = React.createClass({
-    displayName: "XUICardHeaderTitle544",
-
-    render: function () {
-      return React.createElement(
-        "span",
-        { itemComponent: "span", className: "_38my" },
-        "Facebook Page",
-        null,
-        React.createElement("span", { className: "_c1c" })
-      );
-    }
-  });
-
-  var XUICardSection545 = React.createClass({
-    displayName: "XUICardSection545",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_5dw9 _5dwa _4-u3", background: "transparent" },
-        [React.createElement(XUICardHeaderTitle544, { key: "/.0" })],
-        undefined,
-        undefined,
-        React.createElement("div", { className: "_3s3-" })
-      );
-    }
-  });
-
-  var XUICardHeader546 = React.createClass({
-    displayName: "XUICardHeader546",
-
-    render: function () {
-      return React.createElement(XUICardSection545, null);
-    }
-  });
-
-  var AdsCardHeader547 = React.createClass({
-    displayName: "AdsCardHeader547",
-
-    render: function () {
-      return React.createElement(XUICardHeader546, null);
-    }
-  });
-
-  var Link548 = React.createClass({
-    displayName: "Link548",
-
-    render: function () {
-      return React.createElement(
-        "a",
-        { className: "fwb", onClick: function () {}, href: "#", rel: undefined },
-        "Connect a Facebook Page"
-      );
-    }
-  });
-
-  var AdsPEWebsiteNoPageDestinationSection549 = React.createClass({
-    displayName: "AdsPEWebsiteNoPageDestinationSection549",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        null,
-        React.createElement(
-          "div",
-          { className: "_3-95" },
-          "This ad is not connected to a Facebook Page. It will not show in News Feed."
-        ),
-        React.createElement(Link548, null)
-      );
-    }
-  });
-
-  var AdsPEWebsiteNoPageDestinationSectionContainer550 = React.createClass({
-    displayName: "AdsPEWebsiteNoPageDestinationSectionContainer550",
-
-    render: function () {
-      return React.createElement(AdsPEWebsiteNoPageDestinationSection549, null);
-    }
-  });
-
-  var XUICardSection551 = React.createClass({
-    displayName: "XUICardSection551",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_12jy _4-u3", background: "transparent" },
-        React.createElement(
-          "div",
-          { className: "_3-8j" },
-          React.createElement(AdsPEWebsiteNoPageDestinationSectionContainer550, null)
-        )
-      );
-    }
-  });
-
-  var AdsCardSection552 = React.createClass({
-    displayName: "AdsCardSection552",
-
-    render: function () {
-      return React.createElement(XUICardSection551, null);
-    }
-  });
-
-  var XUICard553 = React.createClass({
-    displayName: "XUICard553",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { xuiErrorPosition: "above", className: "_12k2 _4-u2  _4-u8", background: "white" },
-        React.createElement(AdsCardHeader547, null),
-        React.createElement(AdsCardSection552, null)
-      );
-    }
-  });
-
-  var ReactXUIError554 = React.createClass({
-    displayName: "ReactXUIError554",
-
-    render: function () {
-      return React.createElement(XUICard553, null);
-    }
-  });
-
-  var AdsCard555 = React.createClass({
-    displayName: "AdsCard555",
-
-    render: function () {
-      return React.createElement(ReactXUIError554, null);
-    }
-  });
-
-  var AdsPEAdgroupDestinationSection556 = React.createClass({
-    displayName: "AdsPEAdgroupDestinationSection556",
-
-    render: function () {
-      return React.createElement(AdsCard555, null);
-    }
-  });
-
-  var AdsPEAdgroupDestinationSectionContainer557 = React.createClass({
-    displayName: "AdsPEAdgroupDestinationSectionContainer557",
-
-    render: function () {
-      return React.createElement(AdsPEAdgroupDestinationSection556, null);
-    }
-  });
-
-  var XUICardHeaderTitle558 = React.createClass({
-    displayName: "XUICardHeaderTitle558",
-
-    render: function () {
-      return React.createElement(
-        "span",
-        { itemComponent: "span", className: "_38my" },
-        "Creative",
-        null,
-        React.createElement("span", { className: "_c1c" })
-      );
-    }
-  });
-
-  var XUICardSection559 = React.createClass({
-    displayName: "XUICardSection559",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_5dw9 _5dwa _4-u3", background: "transparent" },
-        [React.createElement(XUICardHeaderTitle558, { key: "/.0" })],
-        undefined,
-        undefined,
-        React.createElement("div", { className: "_3s3-" })
-      );
-    }
-  });
-
-  var XUICardHeader560 = React.createClass({
-    displayName: "XUICardHeader560",
-
-    render: function () {
-      return React.createElement(XUICardSection559, null);
-    }
-  });
-
-  var AdsCardHeader561 = React.createClass({
-    displayName: "AdsCardHeader561",
-
-    render: function () {
-      return React.createElement(XUICardHeader560, null);
-    }
-  });
-
-  var ReactImage562 = React.createClass({
-    displayName: "ReactImage562",
-
-    render: function () {
-      return React.createElement("i", { src: null, className: "_541d img sp_R48dKBxiJkP sx_dc2cdb" });
-    }
-  });
-
-  var AdsPopoverLink563 = React.createClass({
-    displayName: "AdsPopoverLink563",
-
-    render: function () {
-      return React.createElement(
-        "span",
-        { ref: "tipIcon", onMouseEnter: function () {}, onMouseLeave: function () {} },
-        React.createElement("span", { className: "_3o_j" }),
-        React.createElement(ReactImage562, null)
-      );
-    }
-  });
-
-  var AdsHelpLink564 = React.createClass({
-    displayName: "AdsHelpLink564",
-
-    render: function () {
-      return React.createElement(AdsPopoverLink563, null);
-    }
-  });
-
-  var AdsLabeledField565 = React.createClass({
-    displayName: "AdsLabeledField565",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { htmlFor: undefined, label: "Website URL", helpText: "Enter the website URL you want to promote. Ex: http://www.example.com/page", helpLinger: undefined, optional: undefined, labelSize: "small", className: "_3bvz" },
-        React.createElement(
-          "label",
-          { className: "_4el4 _3qwj _3hy-", htmlFor: undefined },
-          "Website URL",
-          " ",
-          undefined
-        ),
-        React.createElement(AdsHelpLink564, null),
-        React.createElement("div", { className: "_3bv-" })
-      );
-    }
-  });
-
-  var ReactXUIError566 = React.createClass({
-    displayName: "ReactXUIError566",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_gon _2vl4 _1h18" },
-        React.createElement(
-          "div",
-          { className: "_2vln" },
-          1001
-        ),
-        React.createElement(AdsLabeledField565, null),
-        React.createElement(
-          "div",
-          { className: "_2vl9 _1h1f", style: { "backgroundColor": "#fff" } },
-          React.createElement(
-            "div",
-            { className: "_2vla _1h1g" },
-            React.createElement(
-              "div",
-              null,
-              null,
-              React.createElement("textarea", { ref: "input", id: undefined, disabled: undefined, onKeyDown: function () {}, onFocus: function () {}, onBlur: function () {}, onChange: function () {}, dir: "auto", maxLength: null, className: "_2vli _2vlj _1h26 _1h27", value: "http://www.example.com/" }),
-              null
-            ),
-            React.createElement("div", { ref: "shadowText", "aria-hidden": "true", className: "_2vlk" })
-          )
-        ),
-        null
-      );
-    }
-  });
-
-  var AdsTextInput567 = React.createClass({
-    displayName: "AdsTextInput567",
-
-    render: function () {
-      return React.createElement(ReactXUIError566, null);
-    }
-  });
-
-  var AdsBulkTextInput568 = React.createClass({
-    displayName: "AdsBulkTextInput568",
-
-    render: function () {
-      return React.createElement(AdsTextInput567, null);
-    }
-  });
-
-  var AdsPEWebsiteURLField569 = React.createClass({
-    displayName: "AdsPEWebsiteURLField569",
-
-    render: function () {
-      return React.createElement(AdsBulkTextInput568, null);
-    }
-  });
-
-  var ReactImage570 = React.createClass({
-    displayName: "ReactImage570",
-
-    render: function () {
-      return React.createElement("i", { src: null, className: "_541d img sp_R48dKBxiJkP sx_dc2cdb" });
-    }
-  });
-
-  var AdsPopoverLink571 = React.createClass({
-    displayName: "AdsPopoverLink571",
-
-    render: function () {
-      return React.createElement(
-        "span",
-        { ref: "tipIcon", onMouseEnter: function () {}, onMouseLeave: function () {} },
-        React.createElement("span", { className: "_3o_j" }),
-        React.createElement(ReactImage570, null)
-      );
-    }
-  });
-
-  var AdsHelpLink572 = React.createClass({
-    displayName: "AdsHelpLink572",
-
-    render: function () {
-      return React.createElement(AdsPopoverLink571, null);
-    }
-  });
-
-  var AdsLabeledField573 = React.createClass({
-    displayName: "AdsLabeledField573",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { htmlFor: undefined, label: "Headline", helpText: "Your headline text will appear differently depending on the placement of your ad. Check the previews to make sure your headline looks the way you want in the placements it appears in.", helpLinger: undefined, optional: undefined, labelSize: "small", className: "_3bvz" },
-        React.createElement(
-          "label",
-          { className: "_4el4 _3qwj _3hy-", htmlFor: undefined },
-          "Headline",
-          " ",
-          undefined
-        ),
-        React.createElement(AdsHelpLink572, null),
-        React.createElement("div", { className: "_3bv-" })
-      );
-    }
-  });
-
-  var ReactXUIError574 = React.createClass({
-    displayName: "ReactXUIError574",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_gon _2vl4 _1h18" },
-        React.createElement(
-          "div",
-          { className: "_2vln" },
-          18
-        ),
-        React.createElement(AdsLabeledField573, null),
-        React.createElement(
-          "div",
-          { className: "_2vl9 _1h1f", style: { "backgroundColor": "#fff" } },
-          React.createElement(
-            "div",
-            { className: "_2vla _1h1g" },
-            React.createElement(
-              "div",
-              null,
-              null,
-              React.createElement("textarea", { ref: "input", id: undefined, disabled: undefined, onKeyDown: function () {}, onFocus: function () {}, onBlur: function () {}, onChange: function () {}, dir: "auto", maxLength: null, className: "_2vli _2vlj _1h26 _1h27", value: "Example" }),
-              null
-            ),
-            React.createElement("div", { ref: "shadowText", "aria-hidden": "true", className: "_2vlk" })
-          )
-        ),
-        null
-      );
-    }
-  });
-
-  var AdsTextInput575 = React.createClass({
-    displayName: "AdsTextInput575",
-
-    render: function () {
-      return React.createElement(ReactXUIError574, null);
-    }
-  });
-
-  var AdsBulkTextInput576 = React.createClass({
-    displayName: "AdsBulkTextInput576",
-
-    render: function () {
-      return React.createElement(AdsTextInput575, null);
-    }
-  });
-
-  var AdsPEHeadlineField577 = React.createClass({
-    displayName: "AdsPEHeadlineField577",
-
-    render: function () {
-      return React.createElement(AdsBulkTextInput576, null);
-    }
-  });
-
-  var AdsLabeledField578 = React.createClass({
-    displayName: "AdsLabeledField578",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { htmlFor: undefined, label: "Text", helpText: undefined, helpLinger: undefined, optional: undefined, labelSize: "small", className: "_3bvz" },
-        React.createElement(
-          "label",
-          { className: "_4el4 _3qwj _3hy-", htmlFor: undefined },
-          "Text",
-          " ",
-          undefined
-        ),
-        null,
-        React.createElement("div", { className: "_3bv-" })
-      );
-    }
-  });
-
-  var ReactXUIError579 = React.createClass({
-    displayName: "ReactXUIError579",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_gon _2vl4 _2vl6 _1h18 _1h1a" },
-        React.createElement(
-          "div",
-          { className: "_2vln" },
-          74
-        ),
-        React.createElement(AdsLabeledField578, null),
-        React.createElement(
-          "div",
-          { className: "_2vl9 _1h1f", style: { "backgroundColor": "#fff" } },
-          React.createElement(
-            "div",
-            { className: "_2vla _1h1g" },
-            React.createElement(
-              "div",
-              null,
-              null,
-              React.createElement("textarea", { ref: "input", id: undefined, disabled: undefined, onKeyDown: function () {}, onFocus: function () {}, onBlur: function () {}, onChange: function () {}, dir: "auto", maxLength: null, className: "_2vli _2vlj _1h26 _1h27", value: "It's an example." }),
-              null
-            ),
-            React.createElement("div", { ref: "shadowText", "aria-hidden": "true", className: "_2vlk" })
-          )
-        ),
-        null
-      );
-    }
-  });
-
-  var AdsTextInput580 = React.createClass({
-    displayName: "AdsTextInput580",
-
-    render: function () {
-      return React.createElement(ReactXUIError579, null);
-    }
-  });
-
-  var AdsBulkTextInput581 = React.createClass({
-    displayName: "AdsBulkTextInput581",
-
-    render: function () {
-      return React.createElement(AdsTextInput580, null);
-    }
-  });
-
-  var AdsPEMessageField582 = React.createClass({
-    displayName: "AdsPEMessageField582",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        null,
-        React.createElement(AdsBulkTextInput581, null),
-        null
-      );
-    }
-  });
-
-  var AbstractButton583 = React.createClass({
-    displayName: "AbstractButton583",
-
-    render: function () {
-      return React.createElement(
-        "button",
-        { label: null, onClick: function () {}, size: "large", use: "default", borderShade: "light", suppressed: false, className: "_4jy0 _4jy4 _517h _51sy _42ft", type: "submit", value: "1" },
-        undefined,
-        "Change Image",
-        undefined
-      );
-    }
-  });
-
-  var XUIButton584 = React.createClass({
-    displayName: "XUIButton584",
-
-    render: function () {
-      return React.createElement(AbstractButton583, null);
-    }
-  });
-
-  var BackgroundImage585 = React.createClass({
-    displayName: "BackgroundImage585",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { src: "https://scontent.xx.fbcdn.net/hads-xap1/t45.1600-4/12124737_98010048849339_1665004369_n.png", width: 114.6, height: 60, backgroundSize: "contain", optimizeResizeSpeed: false, loadingIndicatorStyle: "none", className: "_5f0d", style: { "width": "114.6px", "height": "60px" }, onContextMenu: undefined },
-        React.createElement("img", { alt: "", className: "_5i4g", style: { "width": "90px", "height": "60px", "left": "12px", "top": "0px" }, src: "https://scontent.xx.fbcdn.net/hads-xap1/t45.1600-4/12124737_98010048849339_1665004369_n.png" }),
-        undefined,
-        null
-      );
-    }
-  });
-
-  var XUIText586 = React.createClass({
-    displayName: "XUIText586",
-
-    render: function () {
-      return React.createElement(
-        "span",
-        { shade: "light", className: "_50f8", size: "inherit", weight: "inherit", display: "inline" },
-        "1000 × 667"
-      );
-    }
-  });
-
-  var XUIGrayText587 = React.createClass({
-    displayName: "XUIGrayText587",
-
-    render: function () {
-      return React.createElement(XUIText586, null);
-    }
-  });
-
-  var XUIText588 = React.createClass({
-    displayName: "XUIText588",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_3-95  _50f7", display: "block", weight: "bold", size: "inherit" },
-        "untitled – ",
-        React.createElement(XUIGrayText587, null),
-        ""
-      );
-    }
-  });
-
-  var CenteredContainer589 = React.createClass({
-    displayName: "CenteredContainer589",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_50vi", horizontal: false, vertical: true, fullHeight: false },
-        React.createElement(
-          "div",
-          { className: "_3bwv" },
-          React.createElement(
-            "div",
-            { className: "_3bwy" },
-            React.createElement(
-              "div",
-              { key: "/.0", className: "_3bwx" },
-              React.createElement(XUIText588, null)
-            ),
-            React.createElement("div", { key: "/.1", className: "_3bwx" })
-          )
-        )
-      );
-    }
-  });
-
-  var Link590 = React.createClass({
-    displayName: "Link590",
-
-    render: function () {
-      return React.createElement(
-        "a",
-        { href: "/business/ads-guide/", target: "_blank", rel: undefined, onClick: function () {} },
-        "Facebook Ad Guidelines"
-      );
-    }
-  });
-
-  var XUIText591 = React.createClass({
-    displayName: "XUIText591",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_3-96", display: "block", size: "inherit", weight: "inherit" },
-        "For questions and more information, see the ",
-        React.createElement(Link590, null),
-        "."
-      );
-    }
-  });
-
-  var AdsImageInput592 = React.createClass({
-    displayName: "AdsImageInput592",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        null,
-        React.createElement(
-          "div",
-          null,
-          React.createElement(XUIButton584, null),
-          undefined
-        ),
-        null,
-        React.createElement(
-          "div",
-          { className: "_50vh _3-8n _2ph_" },
-          React.createElement(
-            "div",
-            { className: "_37xq" },
-            React.createElement(
-              "div",
-              { className: "_3-90" },
-              React.createElement(
-                "div",
-                { className: " _1yi2", onContextMenu: undefined },
-                React.createElement(BackgroundImage585, null)
-              )
-            ),
-            React.createElement(CenteredContainer589, null)
-          ),
-          null
-        ),
-        React.createElement(XUIText591, null),
-        null
-      );
-    }
-  });
-
-  var AdsBulkImageInput593 = React.createClass({
-    displayName: "AdsBulkImageInput593",
-
-    render: function () {
-      return React.createElement(AdsImageInput592, null);
-    }
-  });
-
-  var AdsLabeledField594 = React.createClass({
-    displayName: "AdsLabeledField594",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_3-96 _3bvz", label: "Image", labelSize: "small" },
-        React.createElement(
-          "label",
-          { className: "_4el4 _3qwj _3hy-", htmlFor: undefined },
-          "Image",
-          " ",
-          undefined
-        ),
-        null,
-        React.createElement(
-          "div",
-          { className: "_3bv-" },
-          React.createElement(AdsBulkImageInput593, null)
-        )
-      );
-    }
-  });
-
-  var AdsPEImageSelector595 = React.createClass({
-    displayName: "AdsPEImageSelector595",
-
-    render: function () {
-      return React.createElement(AdsLabeledField594, null);
-    }
-  });
-
-  var AdsPEImageSelectorContainer596 = React.createClass({
-    displayName: "AdsPEImageSelectorContainer596",
-
-    render: function () {
-      return React.createElement(AdsPEImageSelector595, null);
-    }
-  });
-
-  var AdsPEWebsiteNoPageCreative597 = React.createClass({
-    displayName: "AdsPEWebsiteNoPageCreative597",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        null,
-        React.createElement(AdsPEWebsiteURLField569, null),
-        React.createElement(AdsPEHeadlineField577, null),
-        React.createElement(AdsPEMessageField582, null),
-        React.createElement(AdsPEImageSelectorContainer596, null)
-      );
-    }
-  });
-
-  var AdsPEWebsiteNoPageCreativeContainer598 = React.createClass({
-    displayName: "AdsPEWebsiteNoPageCreativeContainer598",
-
-    render: function () {
-      return React.createElement(AdsPEWebsiteNoPageCreative597, null);
-    }
-  });
-
-  var XUICardSection599 = React.createClass({
-    displayName: "XUICardSection599",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_12jy _4-u3", background: "transparent" },
-        React.createElement(
-          "div",
-          { className: "_3-8j" },
-          React.createElement("div", null),
-          React.createElement(AdsPEWebsiteNoPageCreativeContainer598, null)
-        )
-      );
-    }
-  });
-
-  var AdsCardSection600 = React.createClass({
-    displayName: "AdsCardSection600",
-
-    render: function () {
-      return React.createElement(XUICardSection599, null);
-    }
-  });
-
-  var XUICard601 = React.createClass({
-    displayName: "XUICard601",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { xuiErrorPosition: "above", className: "_12k2 _4-u2  _4-u8", background: "white" },
-        React.createElement(AdsCardHeader561, null),
-        React.createElement(AdsCardSection600, null)
-      );
-    }
-  });
-
-  var ReactXUIError602 = React.createClass({
-    displayName: "ReactXUIError602",
-
-    render: function () {
-      return React.createElement(XUICard601, null);
-    }
-  });
-
-  var AdsCard603 = React.createClass({
-    displayName: "AdsCard603",
-
-    render: function () {
-      return React.createElement(ReactXUIError602, null);
-    }
-  });
-
-  var AdsPEAdgroupCreativeSection604 = React.createClass({
-    displayName: "AdsPEAdgroupCreativeSection604",
-
-    render: function () {
-      return React.createElement(AdsCard603, null);
-    }
-  });
-
-  var AdsPEAdgroupCreativeSectionContainer605 = React.createClass({
-    displayName: "AdsPEAdgroupCreativeSectionContainer605",
-
-    render: function () {
-      return React.createElement(AdsPEAdgroupCreativeSection604, null);
-    }
-  });
-
-  var AdsPELeadGenFormSection606 = React.createClass({
-    displayName: "AdsPELeadGenFormSection606",
-
-    render: function () {
-      return null;
-    }
-  });
-
-  var AdsPELeadGenFormContainer607 = React.createClass({
-    displayName: "AdsPELeadGenFormContainer607",
-
-    render: function () {
-      return React.createElement(AdsPELeadGenFormSection606, null);
-    }
-  });
-
-  var XUICardHeaderTitle608 = React.createClass({
-    displayName: "XUICardHeaderTitle608",
-
-    render: function () {
-      return React.createElement(
-        "span",
-        { itemComponent: "span", className: "_38my" },
-        "Tracking",
-        null,
-        React.createElement("span", { className: "_c1c" })
-      );
-    }
-  });
-
-  var XUICardSection609 = React.createClass({
-    displayName: "XUICardSection609",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_5dw9 _5dwa _4-u3", background: "transparent" },
-        [React.createElement(XUICardHeaderTitle608, { key: "/.0" })],
-        undefined,
-        undefined,
-        React.createElement("div", { className: "_3s3-" })
-      );
-    }
-  });
-
-  var XUICardHeader610 = React.createClass({
-    displayName: "XUICardHeader610",
-
-    render: function () {
-      return React.createElement(XUICardSection609, null);
-    }
-  });
-
-  var AdsCardHeader611 = React.createClass({
-    displayName: "AdsCardHeader611",
-
-    render: function () {
-      return React.createElement(XUICardHeader610, null);
-    }
-  });
-
-  var XUIText612 = React.createClass({
-    displayName: "XUIText612",
-
-    render: function () {
-      return React.createElement(
-        "span",
-        { weight: "bold", className: "_3ga-  _50f7", size: "inherit", display: "inline" },
-        "Conversion Tracking"
-      );
-    }
-  });
-
-  var ReactImage613 = React.createClass({
-    displayName: "ReactImage613",
-
-    render: function () {
-      return React.createElement("i", { src: null, className: "_5s_w _541d img sp_R48dKBxiJkP sx_dc2cdb" });
-    }
-  });
-
-  var AdsPopoverLink614 = React.createClass({
-    displayName: "AdsPopoverLink614",
-
-    render: function () {
-      return React.createElement(
-        "span",
-        { ref: "tipIcon", onMouseEnter: function () {}, onMouseLeave: function () {} },
-        React.createElement("span", { className: "_3o_j" }),
-        React.createElement(ReactImage613, null)
-      );
-    }
-  });
-
-  var AdsHelpLink615 = React.createClass({
-    displayName: "AdsHelpLink615",
-
-    render: function () {
-      return React.createElement(AdsPopoverLink614, null);
-    }
-  });
-
-  var AdsCFHelpLink616 = React.createClass({
-    displayName: "AdsCFHelpLink616",
-
-    render: function () {
-      return React.createElement(AdsHelpLink615, null);
-    }
-  });
-
-  var AdsPixelTrackingLabel617 = React.createClass({
-    displayName: "AdsPixelTrackingLabel617",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_3gay" },
-        React.createElement(XUIText612, null),
-        React.createElement(AdsCFHelpLink616, null)
-      );
-    }
-  });
-
-  var ReactImage618 = React.createClass({
-    displayName: "ReactImage618",
-
-    render: function () {
-      return React.createElement("i", { src: null, className: "img _8o _8r img sp_UuU9HmrQ397 sx_ad67ef" });
+          { className: "_4lg0 _4h2m", style: { "height": 25, "width": 113, "left": 1331 } },
+          React.createElement(
+            "div",
+            { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+            React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+          ),
+          React.createElement(TransitionCell142, { x: 437 })
+        );
+      }
+      if (props.x === 443) {
+        return React.createElement(
+          "div",
+          { className: "_4lg0 _4h2m", style: { "height": 25, "width": 113, "left": 1444 } },
+          React.createElement(
+            "div",
+            { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+            React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+          ),
+          React.createElement(TransitionCell142, { x: 442 })
+        );
+      }
+      if (props.x === 448) {
+        return React.createElement(
+          "div",
+          { className: "_4lg0 _4h2m", style: { "height": 25, "width": 113, "left": 1557 } },
+          React.createElement(
+            "div",
+            { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+            React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+          ),
+          React.createElement(TransitionCell142, { x: 447 })
+        );
+      }
+      if (props.x === 451) {
+        return React.createElement(
+          "div",
+          { className: "_4lg0 _4h2m", style: { "height": 25, "width": 150, "left": 1670 } },
+          React.createElement(
+            "div",
+            { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+            React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+          ),
+          React.createElement(TransitionCell142, { x: 450 })
+        );
+      }
+      if (props.x === 454) {
+        return React.createElement(
+          "div",
+          { className: "_4lg0 _4h2m", style: { "height": 25, "width": 25, "left": 1820 } },
+          undefined,
+          React.createElement(TransitionCell142, { x: 453 })
+        );
+      }
+    }
+  });
+
+  var FixedDataTableCellGroupImpl144 = React.createClass({
+    displayName: "FixedDataTableCellGroupImpl144",
+
+    render: function () {
+      var props = this.props;
+      if (props.x === 318) {
+        return React.createElement(
+          "div",
+          { className: "_3pzj", style: { "height": 40, "position": "absolute", "width": 721, "zIndex": 2, "transform": "translate3d(0px,0px,0)", "backfaceVisibility": "hidden" } },
+          React.createElement(FixedDataTableCell143, { x: 317, key: "cell_0" })
+        );
+      }
+      if (props.x === 332) {
+        return React.createElement(
+          "div",
+          { className: "_3pzj", style: { "height": 40, "position": "absolute", "width": 1845, "zIndex": 0, "transform": "translate3d(0px,0px,0)", "backfaceVisibility": "hidden" } },
+          React.createElement(FixedDataTableCell143, { x: 322, key: "cell_0" }),
+          React.createElement(FixedDataTableCell143, { x: 325, key: "cell_1" }),
+          React.createElement(FixedDataTableCell143, { x: 328, key: "cell_2" }),
+          React.createElement(FixedDataTableCell143, { x: 331, key: "cell_3" })
+        );
+      }
+      if (props.x === 367) {
+        return React.createElement(
+          "div",
+          { className: "_3pzj", style: { "height": 25, "position": "absolute", "width": 721, "zIndex": 2, "transform": "translate3d(0px,0px,0)", "backfaceVisibility": "hidden" } },
+          React.createElement(FixedDataTableCell143, { x: 339, key: "cell_0" }),
+          React.createElement(FixedDataTableCell143, { x: 344, key: "cell_1" }),
+          React.createElement(FixedDataTableCell143, { x: 350, key: "cell_2" }),
+          React.createElement(FixedDataTableCell143, { x: 356, key: "cell_3" }),
+          React.createElement(FixedDataTableCell143, { x: 361, key: "cell_4" }),
+          React.createElement(FixedDataTableCell143, { x: 366, key: "cell_5" })
+        );
+      }
+      if (props.x === 455) {
+        return React.createElement(
+          "div",
+          { className: "_3pzj", style: { "height": 25, "position": "absolute", "width": 1845, "zIndex": 0, "transform": "translate3d(0px,0px,0)", "backfaceVisibility": "hidden" } },
+          React.createElement(FixedDataTableCell143, { x: 373, key: "cell_0" }),
+          React.createElement(FixedDataTableCell143, { x: 378, key: "cell_1" }),
+          React.createElement(FixedDataTableCell143, { x: 383, key: "cell_2" }),
+          React.createElement(FixedDataTableCell143, { x: 388, key: "cell_3" }),
+          React.createElement(FixedDataTableCell143, { x: 393, key: "cell_4" }),
+          React.createElement(FixedDataTableCell143, { x: 398, key: "cell_5" }),
+          React.createElement(FixedDataTableCell143, { x: 403, key: "cell_6" }),
+          React.createElement(FixedDataTableCell143, { x: 408, key: "cell_7" }),
+          React.createElement(FixedDataTableCell143, { x: 413, key: "cell_8" }),
+          React.createElement(FixedDataTableCell143, { x: 418, key: "cell_9" }),
+          React.createElement(FixedDataTableCell143, { x: 423, key: "cell_10" }),
+          React.createElement(FixedDataTableCell143, { x: 428, key: "cell_11" }),
+          React.createElement(FixedDataTableCell143, { x: 433, key: "cell_12" }),
+          React.createElement(FixedDataTableCell143, { x: 438, key: "cell_13" }),
+          React.createElement(FixedDataTableCell143, { x: 443, key: "cell_14" }),
+          React.createElement(FixedDataTableCell143, { x: 448, key: "cell_15" }),
+          React.createElement(FixedDataTableCell143, { x: 451, key: "cell_16" }),
+          React.createElement(FixedDataTableCell143, { x: 454, key: "cell_17" })
+        );
+      }
+    }
+  });
+
+  var FixedDataTableCellGroup145 = React.createClass({
+    displayName: "FixedDataTableCellGroup145",
+
+    render: function () {
+      var props = this.props;
+      if (props.x === 319) {
+        return React.createElement(
+          "div",
+          { style: { "height": 40, "left": 0 }, className: "_3pzk" },
+          React.createElement(FixedDataTableCellGroupImpl144, { x: 318 })
+        );
+      }
+      if (props.x === 333) {
+        return React.createElement(
+          "div",
+          { style: { "height": 40, "left": 721 }, className: "_3pzk" },
+          React.createElement(FixedDataTableCellGroupImpl144, { x: 332 })
+        );
+      }
+      if (props.x === 368) {
+        return React.createElement(
+          "div",
+          { style: { "height": 25, "left": 0 }, className: "_3pzk" },
+          React.createElement(FixedDataTableCellGroupImpl144, { x: 367 })
+        );
+      }
+      if (props.x === 456) {
+        return React.createElement(
+          "div",
+          { style: { "height": 25, "left": 721 }, className: "_3pzk" },
+          React.createElement(FixedDataTableCellGroupImpl144, { x: 455 })
+        );
+      }
+    }
+  });
+
+  var FixedDataTableRowImpl146 = React.createClass({
+    displayName: "FixedDataTableRowImpl146",
+
+    render: function () {
+      var props = this.props;
+      if (props.x === 334) {
+        return React.createElement(
+          "div",
+          { className: "_1gd4 _4li _52no _3h1a _1mib", onClick: null, onDoubleClick: null, onMouseDown: null, onMouseEnter: null, onMouseLeave: null, style: { "width": 1209, "height": 40 } },
+          React.createElement(
+            "div",
+            { className: "_1gd5" },
+            React.createElement(FixedDataTableCellGroup145, { x: 319, key: "fixed_cells" }),
+            React.createElement(FixedDataTableCellGroup145, { x: 333, key: "scrollable_cells" }),
+            React.createElement("div", { className: "_1gd6 _1gd8", style: { "left": 721, "height": 40 } })
+          )
+        );
+      }
+      if (props.x === 457) {
+        return React.createElement(
+          "div",
+          { className: "_1gd4 _4li _3h1a _1mib", onClick: null, onDoubleClick: null, onMouseDown: null, onMouseEnter: null, onMouseLeave: null, style: { "width": 1209, "height": 25 } },
+          React.createElement(
+            "div",
+            { className: "_1gd5" },
+            React.createElement(FixedDataTableCellGroup145, { x: 368, key: "fixed_cells" }),
+            React.createElement(FixedDataTableCellGroup145, { x: 456, key: "scrollable_cells" }),
+            React.createElement("div", { className: "_1gd6 _1gd8", style: { "left": 721, "height": 25 } })
+          )
+        );
+      }
     }
   });
 
-  var XUIText619 = React.createClass({
-    displayName: "XUIText619",
+  var FixedDataTableRow147 = React.createClass({
+    displayName: "FixedDataTableRow147",
 
     render: function () {
-      return React.createElement(
-        "div",
-        { size: "medium", weight: "bold", shade: "medium", display: "block", className: "_3-8m  _c24  _50f4 _50f7" },
-        "Facebook Pixel"
-      );
+      var props = this.props;
+      if (props.x === 335) {
+        return React.createElement(
+          "div",
+          { style: { "width": 1209, "height": 40, "zIndex": 1, "transform": "translate3d(0px,0px,0)", "backfaceVisibility": "hidden" }, className: "_1gda" },
+          React.createElement(FixedDataTableRowImpl146, { x: 334 })
+        );
+      }
+      if (props.x === 458) {
+        return React.createElement(
+          "div",
+          { style: { "width": 1209, "height": 25, "zIndex": 1, "transform": "translate3d(0px,40px,0)", "backfaceVisibility": "hidden" }, className: "_1gda" },
+          React.createElement(FixedDataTableRowImpl146, { x: 457 })
+        );
+      }
     }
   });
 
-  var XUIGrayText620 = React.createClass({
-    displayName: "XUIGrayText620",
+  var FixedDataTableAbstractSortableHeader148 = React.createClass({
+    displayName: "FixedDataTableAbstractSortableHeader148",
 
     render: function () {
-      return React.createElement(XUIText619, null);
+      var props = this.props;
+      if (props.x === 341) {
+        return React.createElement(
+          "div",
+          { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+          React.createElement(
+            "div",
+            { className: "_2eq6" },
+            null,
+            React.createElement(AdsPETableHeader141, { x: 340 })
+          )
+        );
+      }
+      if (props.x === 347) {
+        return React.createElement(
+          "div",
+          { onClick: function () {}, className: "_54_8 _1kst _4h2r _2wzx" },
+          React.createElement(
+            "div",
+            { className: "_2eq6" },
+            null,
+            React.createElement(AdsPETableHeader141, { x: 346 })
+          )
+        );
+      }
+      if (props.x === 353) {
+        return React.createElement(
+          "div",
+          { onClick: function () {}, className: "_54_8 _1kst _4h2r _2wzx" },
+          React.createElement(
+            "div",
+            { className: "_2eq6" },
+            null,
+            React.createElement(AdsPETableHeader141, { x: 352 })
+          )
+        );
+      }
+      if (props.x === 358) {
+        return React.createElement(
+          "div",
+          { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+          React.createElement(
+            "div",
+            { className: "_2eq6" },
+            null,
+            React.createElement(AdsPETableHeader141, { x: 357 })
+          )
+        );
+      }
+      if (props.x === 363) {
+        return React.createElement(
+          "div",
+          { onClick: function () {}, className: "_54_8 _54_9 _4h2r _2wzx" },
+          React.createElement(
+            "div",
+            { className: "_2eq6" },
+            null,
+            React.createElement(AdsPETableHeader141, { x: 362 })
+          )
+        );
+      }
+      if (props.x === 370) {
+        return React.createElement(
+          "div",
+          { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+          React.createElement(
+            "div",
+            { className: "_2eq6" },
+            null,
+            React.createElement(AdsPETableHeader141, { x: 369 })
+          )
+        );
+      }
+      if (props.x === 375) {
+        return React.createElement(
+          "div",
+          { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+          React.createElement(
+            "div",
+            { className: "_2eq6" },
+            null,
+            React.createElement(AdsPETableHeader141, { x: 374 })
+          )
+        );
+      }
+      if (props.x === 380) {
+        return React.createElement(
+          "div",
+          { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+          React.createElement(
+            "div",
+            { className: "_2eq6" },
+            null,
+            React.createElement(AdsPETableHeader141, { x: 379 })
+          )
+        );
+      }
+      if (props.x === 385) {
+        return React.createElement(
+          "div",
+          { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+          React.createElement(
+            "div",
+            { className: "_2eq6" },
+            null,
+            React.createElement(AdsPETableHeader141, { x: 384 })
+          )
+        );
+      }
+      if (props.x === 390) {
+        return React.createElement(
+          "div",
+          { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+          React.createElement(
+            "div",
+            { className: "_2eq6" },
+            null,
+            React.createElement(AdsPETableHeader141, { x: 389 })
+          )
+        );
+      }
+      if (props.x === 395) {
+        return React.createElement(
+          "div",
+          { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+          React.createElement(
+            "div",
+            { className: "_2eq6" },
+            null,
+            React.createElement(AdsPETableHeader141, { x: 394 })
+          )
+        );
+      }
+      if (props.x === 400) {
+        return React.createElement(
+          "div",
+          { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+          React.createElement(
+            "div",
+            { className: "_2eq6" },
+            null,
+            React.createElement(AdsPETableHeader141, { x: 399 })
+          )
+        );
+      }
+      if (props.x === 405) {
+        return React.createElement(
+          "div",
+          { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+          React.createElement(
+            "div",
+            { className: "_2eq6" },
+            null,
+            React.createElement(AdsPETableHeader141, { x: 404 })
+          )
+        );
+      }
+      if (props.x === 410) {
+        return React.createElement(
+          "div",
+          { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+          React.createElement(
+            "div",
+            { className: "_2eq6" },
+            null,
+            React.createElement(AdsPETableHeader141, { x: 409 })
+          )
+        );
+      }
+      if (props.x === 415) {
+        return React.createElement(
+          "div",
+          { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+          React.createElement(
+            "div",
+            { className: "_2eq6" },
+            null,
+            React.createElement(AdsPETableHeader141, { x: 414 })
+          )
+        );
+      }
+      if (props.x === 420) {
+        return React.createElement(
+          "div",
+          { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+          React.createElement(
+            "div",
+            { className: "_2eq6" },
+            null,
+            React.createElement(AdsPETableHeader141, { x: 419 })
+          )
+        );
+      }
+      if (props.x === 425) {
+        return React.createElement(
+          "div",
+          { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+          React.createElement(
+            "div",
+            { className: "_2eq6" },
+            null,
+            React.createElement(AdsPETableHeader141, { x: 424 })
+          )
+        );
+      }
+      if (props.x === 430) {
+        return React.createElement(
+          "div",
+          { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+          React.createElement(
+            "div",
+            { className: "_2eq6" },
+            null,
+            React.createElement(AdsPETableHeader141, { x: 429 })
+          )
+        );
+      }
+      if (props.x === 435) {
+        return React.createElement(
+          "div",
+          { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+          React.createElement(
+            "div",
+            { className: "_2eq6" },
+            null,
+            React.createElement(AdsPETableHeader141, { x: 434 })
+          )
+        );
+      }
+      if (props.x === 440) {
+        return React.createElement(
+          "div",
+          { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+          React.createElement(
+            "div",
+            { className: "_2eq6" },
+            null,
+            React.createElement(AdsPETableHeader141, { x: 439 })
+          )
+        );
+      }
+      if (props.x === 445) {
+        return React.createElement(
+          "div",
+          { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+          React.createElement(
+            "div",
+            { className: "_2eq6" },
+            null,
+            React.createElement(AdsPETableHeader141, { x: 444 })
+          )
+        );
+      }
+    }
+  });
+
+  var FixedDataTableSortableHeader149 = React.createClass({
+    displayName: "FixedDataTableSortableHeader149",
+
+    render: function () {
+      var props = this.props;
+      if (props.x === 342) {
+        return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 341 });
+      }
+      if (props.x === 348) {
+        return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 347 });
+      }
+      if (props.x === 354) {
+        return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 353 });
+      }
+      if (props.x === 359) {
+        return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 358 });
+      }
+      if (props.x === 364) {
+        return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 363 });
+      }
+      if (props.x === 371) {
+        return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 370 });
+      }
+      if (props.x === 376) {
+        return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 375 });
+      }
+      if (props.x === 381) {
+        return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 380 });
+      }
+      if (props.x === 386) {
+        return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 385 });
+      }
+      if (props.x === 391) {
+        return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 390 });
+      }
+      if (props.x === 396) {
+        return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 395 });
+      }
+      if (props.x === 401) {
+        return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 400 });
+      }
+      if (props.x === 406) {
+        return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 405 });
+      }
+      if (props.x === 411) {
+        return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 410 });
+      }
+      if (props.x === 416) {
+        return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 415 });
+      }
+      if (props.x === 421) {
+        return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 420 });
+      }
+      if (props.x === 426) {
+        return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 425 });
+      }
+      if (props.x === 431) {
+        return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 430 });
+      }
+      if (props.x === 436) {
+        return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 435 });
+      }
+      if (props.x === 441) {
+        return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 440 });
+      }
+      if (props.x === 446) {
+        return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 445 });
+      }
+    }
+  });
+
+  var FixedDataTableBufferedRows150 = React.createClass({
+    displayName: "FixedDataTableBufferedRows150",
+
+    render: function () {
+      var props = this.props;
+      if (props.x === 459) {
+        return React.createElement("div", { style: { "position": "absolute", "pointerEvents": "auto", "transform": "translate3d(0px,65px,0)", "backfaceVisibility": "hidden" } });
+      }
+    }
+  });
+
+  var Scrollbar151 = React.createClass({
+    displayName: "Scrollbar151",
+
+    render: function () {
+      var props = this.props;
+      if (props.x === 460) {
+        return null;
+      }
+      if (props.x === 461) {
+        return React.createElement(
+          "div",
+          { onFocus: function () {}, onBlur: function () {}, onKeyDown: function () {}, onMouseDown: function () {}, onWheel: function () {}, className: "_1t0r _1t0t _4jdr _1t0u", style: { "width": 1209, "zIndex": 99 }, tabIndex: 0 },
+          React.createElement("div", { ref: "face", className: "_1t0w _1t0y _1t0_", style: { "width": 561.6340607950117, "transform": "translate3d(4px,0px,0)", "backfaceVisibility": "hidden" } })
+        );
+      }
+    }
+  });
+
+  var HorizontalScrollbar152 = React.createClass({
+    displayName: "HorizontalScrollbar152",
+
+    render: function () {
+      var props = this.props;
+      if (props.x === 462) {
+        return React.createElement(
+          "div",
+          { className: "_3h1k _3h1m", style: { "height": 15, "width": 1209 } },
+          React.createElement(
+            "div",
+            { style: { "height": 15, "position": "absolute", "overflow": "hidden", "width": 1209, "transform": "translate3d(0px,0px,0)", "backfaceVisibility": "hidden" } },
+            React.createElement(Scrollbar151, { x: 461 })
+          )
+        );
+      }
     }
   });
 
-  var XUIText621 = React.createClass({
-    displayName: "XUIText621",
+  var FixedDataTable153 = React.createClass({
+    displayName: "FixedDataTable153",
 
     render: function () {
-      return React.createElement(
-        "span",
-        { size: "medium", weight: "inherit", display: "inline", className: " _50f4" },
-        "Learn More"
-      );
+      var props = this.props;
+      if (props.x === 463) {
+        return React.createElement(
+          "div",
+          { className: "_3h1i _1mie", onWheel: function () {}, style: { "height": 25, "width": 1209 } },
+          React.createElement(
+            "div",
+            { className: "_3h1j", style: { "height": 8, "width": 1209 } },
+            React.createElement(FixedDataTableColumnResizeHandle140, { x: 313 }),
+            React.createElement(FixedDataTableRow147, { x: 335, key: "group_header" }),
+            React.createElement(FixedDataTableRow147, { x: 458, key: "header" }),
+            React.createElement(FixedDataTableBufferedRows150, { x: 459 }),
+            null,
+            undefined,
+            React.createElement("div", { className: "_3h1e _3h1h", style: { "top": 8 } })
+          ),
+          React.createElement(Scrollbar151, { x: 460 }),
+          React.createElement(HorizontalScrollbar152, { x: 462 })
+        );
+      }
     }
   });
 
-  var Link622 = React.createClass({
-    displayName: "Link622",
+  var TransitionTable154 = React.createClass({
+    displayName: "TransitionTable154",
 
     render: function () {
-      return React.createElement(
-        "a",
-        { href: "/help/336923339852238", target: "_blank", rel: undefined, onClick: function () {} },
-        React.createElement(XUIText621, null)
-      );
+      var props = this.props;
+      if (props.x === 464) {
+        return React.createElement(FixedDataTable153, { x: 463, ref: "fixedDataTable" });
+      }
     }
   });
 
-  var XUIText623 = React.createClass({
-    displayName: "XUIText623",
+  var AdsSelectableFixedDataTable155 = React.createClass({
+    displayName: "AdsSelectableFixedDataTable155",
 
     render: function () {
-      return React.createElement(
-        "span",
-        { shade: "medium", size: "medium", className: " _c24  _50f4", weight: "inherit", display: "inline" },
-        "You can now create one pixel for tracking, optimization and remarketing.",
-        React.createElement(
-          "span",
-          { className: "_3-99" },
-          React.createElement(Link622, null)
-        )
-      );
+      var props = this.props;
+      if (props.x === 465) {
+        return React.createElement(
+          "div",
+          { className: "_5hht" },
+          React.createElement(TransitionTable154, { x: 464 })
+        );
+      }
     }
   });
 
-  var XUIGrayText624 = React.createClass({
-    displayName: "XUIGrayText624",
+  var AdsDataTableKeyboardSupportDecorator156 = React.createClass({
+    displayName: "AdsDataTableKeyboardSupportDecorator156",
 
     render: function () {
-      return React.createElement(XUIText623, null);
+      var props = this.props;
+      if (props.x === 466) {
+        return React.createElement(
+          "div",
+          { ref: "tableContainer", className: "_5d6f", tabIndex: "0", onKeyDown: function () {} },
+          React.createElement(AdsSelectableFixedDataTable155, { x: 465 })
+        );
+      }
     }
   });
 
-  var AbstractButton625 = React.createClass({
-    displayName: "AbstractButton625",
+  var AdsEditableDataTableDecorator157 = React.createClass({
+    displayName: "AdsEditableDataTableDecorator157",
 
     render: function () {
-      return React.createElement(
-        "button",
-        { className: "_23ng _4jy0 _4jy4 _4jy1 _51sy selected _42ft", label: null, onClick: function () {}, size: "large", use: "confirm", borderShade: "light", suppressed: false, type: "submit", value: "1" },
-        undefined,
-        "Create a Pixel",
-        undefined
-      );
+      var props = this.props;
+      if (props.x === 467) {
+        return React.createElement(
+          "div",
+          { onCopy: function () {} },
+          React.createElement(AdsDataTableKeyboardSupportDecorator156, { x: 466, ref: "decoratedTable" })
+        );
+      }
     }
   });
 
-  var XUIButton626 = React.createClass({
-    displayName: "XUIButton626",
+  var AdsPEDataTableContainer158 = React.createClass({
+    displayName: "AdsPEDataTableContainer158",
 
     render: function () {
-      return React.createElement(AbstractButton625, null);
+      var props = this.props;
+      if (props.x === 468) {
+        return React.createElement(
+          "div",
+          { className: "_35l_ _1hr clearfix" },
+          null,
+          null,
+          null,
+          React.createElement(AdsEditableDataTableDecorator157, { x: 467 })
+        );
+      }
     }
   });
 
-  var AdsPixelCreateButton627 = React.createClass({
-    displayName: "AdsPixelCreateButton627",
+  var AdsPECampaignGroupTableContainer159 = React.createClass({
+    displayName: "AdsPECampaignGroupTableContainer159",
 
     render: function () {
-      return React.createElement(XUIButton626, null);
+      var props = this.props;
+      if (props.x === 470) {
+        return React.createElement(ResponsiveBlock37, { x: 469 });
+      }
     }
   });
 
-  var LeftRight628 = React.createClass({
-    displayName: "LeftRight628",
+  var AdsPEManageAdsPaneContainer160 = React.createClass({
+    displayName: "AdsPEManageAdsPaneContainer160",
 
     render: function () {
-      return React.createElement(
-        "div",
-        { className: "_23nf clearfix", direction: "left" },
-        React.createElement(
-          "div",
-          { key: "left", className: "_ohe lfloat" },
-          React.createElement(ReactImage618, null)
-        ),
-        React.createElement(
+      var props = this.props;
+      if (props.x === 473) {
+        return React.createElement(
           "div",
-          { key: "right", className: "" },
+          null,
+          React.createElement(AdsErrorBoundary10, { x: 65 }),
+          React.createElement(
+            "div",
+            { className: "_2uty" },
+            React.createElement(AdsErrorBoundary10, { x: 125 })
+          ),
           React.createElement(
             "div",
-            { className: "_42ef _8u" },
+            { className: "_2utx _21oc" },
+            React.createElement(AdsErrorBoundary10, { x: 171 }),
             React.createElement(
               "div",
-              null,
-              React.createElement(XUIGrayText620, null),
-              React.createElement(XUIGrayText624, null),
-              React.createElement(
-                "div",
-                { className: "_3-8x" },
-                React.createElement(AdsPixelCreateButton627, null)
-              )
+              { className: "_41tu" },
+              React.createElement(AdsErrorBoundary10, { x: 176 }),
+              React.createElement(AdsErrorBoundary10, { x: 194 })
+            )
+          ),
+          React.createElement(
+            "div",
+            { className: "_2utz", style: { "height": 25 } },
+            React.createElement(AdsErrorBoundary10, { x: 302 }),
+            React.createElement(
+              "div",
+              { className: "_2ut-" },
+              React.createElement(AdsErrorBoundary10, { x: 312 })
+            ),
+            React.createElement(
+              "div",
+              { className: "_2ut_" },
+              React.createElement(AdsErrorBoundary10, { x: 472 })
             )
           )
-        )
-      );
+        );
+      }
     }
   });
 
-  var ImageBlock629 = React.createClass({
-    displayName: "ImageBlock629",
+  var AdsPEContentContainer161 = React.createClass({
+    displayName: "AdsPEContentContainer161",
 
     render: function () {
-      return React.createElement(LeftRight628, null);
+      var props = this.props;
+      if (props.x === 474) {
+        return React.createElement(AdsPEManageAdsPaneContainer160, { x: 473 });
+      }
     }
   });
 
-  var AdsPixelCreationCard630 = React.createClass({
-    displayName: "AdsPixelCreationCard630",
+  var FluxContainer_AdsPEWorkspaceContainer_162 = React.createClass({
+    displayName: "FluxContainer_AdsPEWorkspaceContainer_162",
 
     render: function () {
-      return React.createElement(
-        "div",
-        { className: "_2pie", horizontal: true },
-        React.createElement(
+      var props = this.props;
+      if (props.x === 477) {
+        return React.createElement(
           "div",
-          { className: "_23ne _4fsl" },
-          React.createElement(ImageBlock629, null)
-        )
-      );
+          { className: "_49wu", style: { "height": 177, "top": 43, "width": 1306 } },
+          React.createElement(ResponsiveBlock37, { x: 62 }),
+          React.createElement(AdsErrorBoundary10, { x: 476 }),
+          null
+        );
+      }
     }
   });
 
-  var AdsPixelTrackingSelector631 = React.createClass({
-    displayName: "AdsPixelTrackingSelector631",
+  var FluxContainer_AdsSessionExpiredDialogContainer_163 = React.createClass({
+    displayName: "FluxContainer_AdsSessionExpiredDialogContainer_163",
 
     render: function () {
-      return React.createElement(
-        "div",
-        { className: "_3-8x _4fsk" },
-        React.createElement(AdsPixelCreationCard630, { key: "FacebookPixelNUX" })
-      );
+      var props = this.props;
+      if (props.x === 478) {
+        return null;
+      }
     }
   });
 
-  var AdsPixelTracking632 = React.createClass({
-    displayName: "AdsPixelTracking632",
+  var FluxContainer_AdsPEUploadDialogLazyContainer_164 = React.createClass({
+    displayName: "FluxContainer_AdsPEUploadDialogLazyContainer_164",
 
     render: function () {
-      return React.createElement(
-        "div",
-        { className: undefined },
-        React.createElement(AdsPixelTrackingLabel617, null),
-        React.createElement(
-          "div",
-          { className: "_3-8x" },
-          React.createElement("div", null)
-        ),
-        React.createElement(AdsPixelTrackingSelector631, null)
-      );
+      var props = this.props;
+      if (props.x === 479) {
+        return null;
+      }
     }
   });
 
-  var AdsPEPixelTracking633 = React.createClass({
-    displayName: "AdsPEPixelTracking633",
+  var FluxContainer_DialogContainer_165 = React.createClass({
+    displayName: "FluxContainer_DialogContainer_165",
 
     render: function () {
-      return React.createElement(AdsPixelTracking632, { key: "tracking" });
+      var props = this.props;
+      if (props.x === 480) {
+        return null;
+      }
     }
   });
 
-  var AdsPEPixelTrackingContainer634 = React.createClass({
-    displayName: "AdsPEPixelTrackingContainer634",
+  var AdsBugReportContainer166 = React.createClass({
+    displayName: "AdsBugReportContainer166",
 
     render: function () {
-      return React.createElement(AdsPEPixelTracking633, null);
+      var props = this.props;
+      if (props.x === 481) {
+        return React.createElement("span", null);
+      }
     }
   });
 
-  var AdsPEAdgroupAppTrackingSelectorContainer635 = React.createClass({
-    displayName: "AdsPEAdgroupAppTrackingSelectorContainer635",
+  var AdsPEAudienceSplittingDialog167 = React.createClass({
+    displayName: "AdsPEAudienceSplittingDialog167",
 
     render: function () {
-      return null;
+      var props = this.props;
+      if (props.x === 482) {
+        return null;
+      }
     }
   });
 
-  var AdsPEStandardTrackingSection636 = React.createClass({
-    displayName: "AdsPEStandardTrackingSection636",
+  var AdsPEAudienceSplittingDialogContainer168 = React.createClass({
+    displayName: "AdsPEAudienceSplittingDialogContainer168",
 
     render: function () {
-      return React.createElement(
-        "div",
-        null,
-        null,
-        React.createElement(
-          "div",
-          { className: "_3-96" },
-          React.createElement(AdsPEPixelTrackingContainer634, null)
-        ),
-        React.createElement(
+      var props = this.props;
+      if (props.x === 483) {
+        return React.createElement(
           "div",
-          { className: "_3-96" },
-          React.createElement(AdsPEAdgroupAppTrackingSelectorContainer635, null)
-        ),
-        null
-      );
+          null,
+          React.createElement(AdsPEAudienceSplittingDialog167, { x: 482 })
+        );
+      }
     }
   });
 
-  var AdsPEStandardTrackingContainer637 = React.createClass({
-    displayName: "AdsPEStandardTrackingContainer637",
+  var FluxContainer_AdsRuleDialogBootloadContainer_169 = React.createClass({
+    displayName: "FluxContainer_AdsRuleDialogBootloadContainer_169",
 
     render: function () {
-      return React.createElement(AdsPEStandardTrackingSection636, null);
+      var props = this.props;
+      if (props.x === 484) {
+        return null;
+      }
     }
   });
 
-  var XUICardSection638 = React.createClass({
-    displayName: "XUICardSection638",
+  var FluxContainer_AdsPECFTrayContainer_170 = React.createClass({
+    displayName: "FluxContainer_AdsPECFTrayContainer_170",
 
     render: function () {
-      return React.createElement(
-        "div",
-        { className: "_12jy _4-u3", background: "transparent" },
-        React.createElement(
-          "div",
-          { className: "_3-8j" },
-          React.createElement(AdsPEStandardTrackingContainer637, null)
-        )
-      );
+      var props = this.props;
+      if (props.x === 485) {
+        return null;
+      }
     }
   });
 
-  var AdsCardSection639 = React.createClass({
-    displayName: "AdsCardSection639",
+  var FluxContainer_AdsPEDeleteDraftContainer_171 = React.createClass({
+    displayName: "FluxContainer_AdsPEDeleteDraftContainer_171",
 
     render: function () {
-      return React.createElement(XUICardSection638, null);
+      var props = this.props;
+      if (props.x === 486) {
+        return null;
+      }
     }
   });
 
-  var XUICard640 = React.createClass({
-    displayName: "XUICard640",
+  var FluxContainer_AdsPEInitialDraftPublishDialogContainer_172 = React.createClass({
+    displayName: "FluxContainer_AdsPEInitialDraftPublishDialogContainer_172",
 
     render: function () {
-      return React.createElement(
-        "div",
-        { xuiErrorPosition: "above", className: "_12k2 _4-u2  _4-u8", background: "white" },
-        React.createElement(AdsCardHeader611, null),
-        React.createElement(AdsCardSection639, null)
-      );
+      var props = this.props;
+      if (props.x === 487) {
+        return null;
+      }
     }
   });
 
-  var ReactXUIError641 = React.createClass({
-    displayName: "ReactXUIError641",
+  var FluxContainer_AdsPEReachFrequencyStatusTransitionDialogBootloadContainer_173 = React.createClass({
+    displayName: "FluxContainer_AdsPEReachFrequencyStatusTransitionDialogBootloadContainer_173",
 
     render: function () {
-      return React.createElement(XUICard640, null);
+      var props = this.props;
+      if (props.x === 488) {
+        return null;
+      }
     }
   });
 
-  var AdsCard642 = React.createClass({
-    displayName: "AdsCard642",
+  var FluxContainer_AdsPEPurgeArchiveDialogContainer_174 = React.createClass({
+    displayName: "FluxContainer_AdsPEPurgeArchiveDialogContainer_174",
 
     render: function () {
-      return React.createElement(ReactXUIError641, null);
+      var props = this.props;
+      if (props.x === 489) {
+        return null;
+      }
     }
   });
 
-  var AdsPEAdgroupTrackingSection643 = React.createClass({
-    displayName: "AdsPEAdgroupTrackingSection643",
+  var AdsPECreateDialogContainer175 = React.createClass({
+    displayName: "AdsPECreateDialogContainer175",
 
     render: function () {
-      return React.createElement(AdsCard642, null);
+      var props = this.props;
+      if (props.x === 490) {
+        return React.createElement("span", null);
+      }
     }
   });
 
-  var AdsPEAdgroupTrackingSectionContainer644 = React.createClass({
-    displayName: "AdsPEAdgroupTrackingSectionContainer644",
+  var FluxContainer_AdsPEModalStatusContainer_176 = React.createClass({
+    displayName: "FluxContainer_AdsPEModalStatusContainer_176",
 
     render: function () {
-      return React.createElement(AdsPEAdgroupTrackingSection643, null);
+      var props = this.props;
+      if (props.x === 491) {
+        return null;
+      }
     }
   });
 
-  var AdsPEAdgroupIOSection645 = React.createClass({
-    displayName: "AdsPEAdgroupIOSection645",
+  var FluxContainer_AdsBrowserExtensionErrorDialogContainer_177 = React.createClass({
+    displayName: "FluxContainer_AdsBrowserExtensionErrorDialogContainer_177",
 
     render: function () {
-      return null;
+      var props = this.props;
+      if (props.x === 492) {
+        return null;
+      }
     }
   });
 
-  var AdsPEAdgroupIOSectionContainer646 = React.createClass({
-    displayName: "AdsPEAdgroupIOSectionContainer646",
+  var FluxContainer_AdsPESortByErrorTipContainer_178 = React.createClass({
+    displayName: "FluxContainer_AdsPESortByErrorTipContainer_178",
 
     render: function () {
-      return React.createElement(AdsPEAdgroupIOSection645, null);
+      var props = this.props;
+      if (props.x === 493) {
+        return null;
+      }
     }
   });
 
-  var LeftRight647 = React.createClass({
-    displayName: "LeftRight647",
+  var LeadDownloadDialogSelector179 = React.createClass({
+    displayName: "LeadDownloadDialogSelector179",
 
     render: function () {
-      return React.createElement(
-        "div",
-        { flex: "left", direction: "right", className: "clearfix" },
-        React.createElement(
-          "div",
-          { key: "right", className: "_ohf rfloat" },
-          React.createElement(
-            "div",
-            { className: "_20ro _20rp" },
-            React.createElement(
-              "div",
-              null,
-              null,
-              React.createElement(AdsPEAdgroupLinksSectionContainer518, null),
-              React.createElement(AdsPEStickyArea543, null)
-            )
-          )
-        ),
-        React.createElement(
-          "div",
-          { key: "left", className: "" },
-          React.createElement(
-            "div",
-            { className: "_42ef" },
-            React.createElement(
-              "div",
-              null,
-              React.createElement(AdsPEAdgroupDestinationSectionContainer557, null),
-              React.createElement(AdsPEAdgroupCreativeSectionContainer605, null),
-              React.createElement(AdsPELeadGenFormContainer607, null),
-              React.createElement(AdsPEAdgroupTrackingSectionContainer644, null),
-              React.createElement(AdsPEAdgroupIOSectionContainer646, null)
-            )
-          )
-        )
-      );
+      var props = this.props;
+      if (props.x === 494) {
+        return null;
+      }
     }
   });
 
-  var FlexibleBlock648 = React.createClass({
-    displayName: "FlexibleBlock648",
+  var FluxContainer_AdsPELeadDownloadDialogContainerClass_180 = React.createClass({
+    displayName: "FluxContainer_AdsPELeadDownloadDialogContainerClass_180",
 
     render: function () {
-      return React.createElement(LeftRight647, null);
+      var props = this.props;
+      if (props.x === 495) {
+        return React.createElement(LeadDownloadDialogSelector179, { x: 494 });
+      }
     }
   });
 
-  var AdsPEMultiColumnEditor649 = React.createClass({
-    displayName: "AdsPEMultiColumnEditor649",
+  var AdsPEContainer181 = React.createClass({
+    displayName: "AdsPEContainer181",
 
     render: function () {
-      return React.createElement(
-        "div",
-        { className: "_2j_c _ykd" },
-        React.createElement(
+      var props = this.props;
+      if (props.x === 496) {
+        return React.createElement(
           "div",
+          { id: "ads_pe_container" },
+          React.createElement(FluxContainer_AdsPETopNavContainer_26, { x: 41 }),
           null,
-          React.createElement(FluxContainer_r_483, null),
-          null,
-          React.createElement(AdsPEAdgroupAutoNamingConfirmationContainer484, null),
-          React.createElement(AdsPEAdgroupNameSectionContainer500, null)
-        ),
-        React.createElement(FlexibleBlock648, null)
-      );
-    }
-  });
-
-  var AdsPEAdgroupEditor650 = React.createClass({
-    displayName: "AdsPEAdgroupEditor650",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        null,
-        React.createElement(AdsPEAdgroupHeaderSectionContainer481, null),
-        React.createElement(AdsPEMultiColumnEditor649, null)
-      );
-    }
-  });
-
-  var AdsPEAdgroupEditorContainer651 = React.createClass({
-    displayName: "AdsPEAdgroupEditorContainer651",
-
-    render: function () {
-      return React.createElement(AdsPEAdgroupEditor650, { key: "98010048849345" });
-    }
-  });
-
-  var AdsPESideTrayTabContent652 = React.createClass({
-    displayName: "AdsPESideTrayTabContent652",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { className: "_1o_8 _44ra _5cyn" },
-        React.createElement(AdsPEAdgroupEditorContainer651, null)
-      );
-    }
-  });
-
-  var AdsPEEditorTrayTabContent653 = React.createClass({
-    displayName: "AdsPEEditorTrayTabContent653",
-
-    render: function () {
-      return React.createElement(AdsPESideTrayTabContent652, null);
-    }
-  });
-
-  var AdsPEMultiTabDrawer654 = React.createClass({
-    displayName: "AdsPEMultiTabDrawer654",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { style: { "height": 550, "width": 1027 }, tabButtons: {}, tabContentPanes: {}, enableAnimation: true, showButton: true, className: "_2kev _2kew _2kex" },
-        React.createElement(
-          "div",
-          { className: "_2kf0" },
-          React.createElement(AdsPEEditorTrayTabButton469, { key: "editor_tray_button" }),
-          React.createElement(AdsPEInsightsTrayTabButton472, { key: "insights_tray_button" }),
-          React.createElement(AdsPENekoDebuggerTrayTabButton474, { key: "neko_debugger_tray_button" })
-        ),
-        React.createElement(
-          "div",
-          { className: "_2kf1" },
-          React.createElement(FBDragHandle475, null),
-          React.createElement(AdsPEEditorTrayTabContent653, { key: "EDITOR_DRAWER" }),
-          null
-        )
-      );
-    }
-  });
-
-  var FluxContainer_x_655 = React.createClass({
-    displayName: "FluxContainer_x_655",
-
-    render: function () {
-      return React.createElement(AdsPEMultiTabDrawer654, null);
-    }
-  });
-
-  var AdsBugReportContainer656 = React.createClass({
-    displayName: "AdsBugReportContainer656",
-
-    render: function () {
-      return null;
-    }
-  });
-
-  var AdsPEAudienceSplittingDialog657 = React.createClass({
-    displayName: "AdsPEAudienceSplittingDialog657",
-
-    render: function () {
-      return null;
-    }
-  });
-
-  var AdsPEAudienceSplittingDialogContainer658 = React.createClass({
-    displayName: "AdsPEAudienceSplittingDialogContainer658",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        null,
-        React.createElement(AdsPEAudienceSplittingDialog657, null)
-      );
-    }
-  });
-
-  var FluxContainer_p_659 = React.createClass({
-    displayName: "FluxContainer_p_659",
-
-    render: function () {
-      return null;
-    }
-  });
-
-  var AdsPECreateDialogContainer660 = React.createClass({
-    displayName: "AdsPECreateDialogContainer660",
-
-    render: function () {
-      return null;
-    }
-  });
-
-  var AdsPEContainer661 = React.createClass({
-    displayName: "AdsPEContainer661",
-
-    render: function () {
-      return React.createElement(
-        "div",
-        { id: "ads_pe_container" },
-        null,
-        React.createElement(FluxContainer_ja_26, null),
-        React.createElement(FluxContainer_w_56, null),
-        React.createElement(FluxContainer_r_463, null),
-        React.createElement(FluxContainer_q_464, null),
-        React.createElement(FluxContainer_y_466, null),
-        null,
-        React.createElement(FluxContainer_x_655, null),
-        React.createElement(AdsBugReportContainer656, null),
-        null,
-        React.createElement(AdsPEAudienceSplittingDialogContainer658, null),
-        null,
-        null,
-        null,
-        React.createElement(FluxContainer_p_659, null),
-        React.createElement(AdsPECreateDialogContainer660, null)
-      );
+          React.createElement(FluxContainer_AdsPEWorkspaceContainer_162, { x: 477 }),
+          React.createElement(FluxContainer_AdsSessionExpiredDialogContainer_163, { x: 478 }),
+          React.createElement(FluxContainer_AdsPEUploadDialogLazyContainer_164, { x: 479 }),
+          React.createElement(FluxContainer_DialogContainer_165, { x: 480 }),
+          React.createElement(AdsBugReportContainer166, { x: 481 }),
+          React.createElement(AdsPEAudienceSplittingDialogContainer168, { x: 483 }),
+          React.createElement(FluxContainer_AdsRuleDialogBootloadContainer_169, { x: 484 }),
+          React.createElement(FluxContainer_AdsPECFTrayContainer_170, { x: 485 }),
+          React.createElement(
+            "span",
+            null,
+            React.createElement(FluxContainer_AdsPEDeleteDraftContainer_171, { x: 486 }),
+            React.createElement(FluxContainer_AdsPEInitialDraftPublishDialogContainer_172, { x: 487 }),
+            React.createElement(FluxContainer_AdsPEReachFrequencyStatusTransitionDialogBootloadContainer_173, { x: 488 })
+          ),
+          React.createElement(FluxContainer_AdsPEPurgeArchiveDialogContainer_174, { x: 489 }),
+          React.createElement(AdsPECreateDialogContainer175, { x: 490 }),
+          React.createElement(FluxContainer_AdsPEModalStatusContainer_176, { x: 491 }),
+          React.createElement(FluxContainer_AdsBrowserExtensionErrorDialogContainer_177, { x: 492 }),
+          React.createElement(FluxContainer_AdsPESortByErrorTipContainer_178, { x: 493 }),
+          React.createElement(FluxContainer_AdsPELeadDownloadDialogContainerClass_180, { x: 495 }),
+          React.createElement("div", { id: "web_ads_guidance_tips" })
+        );
+      }
     }
   });
 
@@ -9002,10 +5102,12 @@
     displayName: "Benchmark",
 
     render: function () {
-      return React.createElement(AdsPEContainer661, null);
+      var props = this.props;
+      if (props.x === undefined) {
+        return React.createElement(AdsPEContainer181, { x: 496 });
+      }
     }
   });
 
   this.Benchmark = Benchmark;
 })(this);
-
diff --git a/scripts/bench/bench-pe-sfc-es5.js b/scripts/bench/bench-pe-sfc-es5.js
new file mode 100644
index 000000000000..787c0f21d97e
--- /dev/null
+++ b/scripts/bench/bench-pe-sfc-es5.js
@@ -0,0 +1,4198 @@
+(function () {
+
+  var ReactImage0 = function (props) {
+    if (props.x === 0) {
+      return React.createElement("i", { alt: "", className: "_3-99 img sp_i534r85sjIn sx_538591", src: null });
+    }
+    if (props.x === 15) {
+      return React.createElement("i", { className: "_3ut_ img sp_i534r85sjIn sx_e8ac93", src: null, alt: "" });
+    }
+    if (props.x === 22) {
+      return React.createElement("i", { alt: "", className: "_3-8_ img sp_i534r85sjIn sx_7b15bc", src: null });
+    }
+    if (props.x === 29) {
+      return React.createElement("i", { className: "_1m1s _4540 _p img sp_i534r85sjIn sx_f40b1c", src: null, alt: "" });
+    }
+    if (props.x === 42) {
+      return React.createElement(
+        "i",
+        { alt: "Warning", className: "_585p img sp_i534r85sjIn sx_20273d", src: null },
+        React.createElement(
+          "u",
+          null,
+          "Warning"
+        )
+      );
+    }
+    if (props.x === 67) {
+      return React.createElement("i", { alt: "", className: "_3-8_ img sp_i534r85sjIn sx_b5d079", src: null });
+    }
+    if (props.x === 70) {
+      return React.createElement("i", { src: null, alt: "", className: "img sp_i534r85sjIn sx_29f8c9" });
+    }
+    if (props.x === 76) {
+      return React.createElement("i", { alt: "", className: "_3-8_ img sp_i534r85sjIn sx_ef6a9c", src: null });
+    }
+    if (props.x === 79) {
+      return React.createElement("i", { src: null, alt: "", className: "img sp_i534r85sjIn sx_6f8c43" });
+    }
+    if (props.x === 88) {
+      return React.createElement("i", { src: null, alt: "", className: "img sp_i534r85sjIn sx_e94a2d" });
+    }
+    if (props.x === 91) {
+      return React.createElement("i", { src: null, alt: "", className: "img sp_i534r85sjIn sx_7ed7d4" });
+    }
+    if (props.x === 94) {
+      return React.createElement("i", { src: null, alt: "", className: "img sp_i534r85sjIn sx_930440" });
+    }
+    if (props.x === 98) {
+      return React.createElement("i", { src: null, alt: "", className: "img sp_i534r85sjIn sx_750c83" });
+    }
+    if (props.x === 108) {
+      return React.createElement("i", { src: null, alt: "", className: "img sp_i534r85sjIn sx_73c1bb" });
+    }
+    if (props.x === 111) {
+      return React.createElement("i", { src: null, alt: "", className: "img sp_i534r85sjIn sx_29f28d" });
+    }
+    if (props.x === 126) {
+      return React.createElement("i", { src: null, alt: "", className: "_3-8_ img sp_i534r85sjIn sx_91c59e" });
+    }
+    if (props.x === 127) {
+      return React.createElement("i", { alt: "", className: "_3-99 img sp_i534r85sjIn sx_538591", src: null });
+    }
+    if (props.x === 134) {
+      return React.createElement("i", { src: null, alt: "", className: "_3-8_ img sp_i534r85sjIn sx_c8eb75" });
+    }
+    if (props.x === 135) {
+      return React.createElement("i", { alt: "", className: "_3-99 img sp_i534r85sjIn sx_538591", src: null });
+    }
+    if (props.x === 148) {
+      return React.createElement("i", { className: "_3yz6 _5whs img sp_i534r85sjIn sx_896996", src: null, alt: "" });
+    }
+    if (props.x === 152) {
+      return React.createElement("i", { className: "_5b5p _4gem img sp_i534r85sjIn sx_896996", src: null, alt: "" });
+    }
+    if (props.x === 153) {
+      return React.createElement("i", { className: "_541d img sp_i534r85sjIn sx_2f396a", src: null, alt: "" });
+    }
+    if (props.x === 160) {
+      return React.createElement("i", { src: null, alt: "", className: "img sp_i534r85sjIn sx_31d9b0" });
+    }
+    if (props.x === 177) {
+      return React.createElement("i", { alt: "", className: "_3-99 img sp_i534r85sjIn sx_2c18b7", src: null });
+    }
+    if (props.x === 186) {
+      return React.createElement("i", { src: null, alt: "", className: "img sp_i534r85sjIn sx_0a681f" });
+    }
+    if (props.x === 195) {
+      return React.createElement("i", { className: "_1-lx img sp_OkER5ktbEyg sx_b369b4", src: null, alt: "" });
+    }
+    if (props.x === 198) {
+      return React.createElement("i", { className: "_1-lx img sp_i534r85sjIn sx_96948e", src: null, alt: "" });
+    }
+    if (props.x === 237) {
+      return React.createElement("i", { className: "_541d img sp_i534r85sjIn sx_2f396a", src: null, alt: "" });
+    }
+    if (props.x === 266) {
+      return React.createElement("i", { alt: "", className: "_3-99 img sp_i534r85sjIn sx_538591", src: null });
+    }
+    if (props.x === 314) {
+      return React.createElement("i", { className: "_1cie _1cif img sp_i534r85sjIn sx_6e6820", src: null, alt: "" });
+    }
+    if (props.x === 345) {
+      return React.createElement("i", { className: "_1cie img sp_i534r85sjIn sx_e896cf", src: null, alt: "" });
+    }
+    if (props.x === 351) {
+      return React.createElement("i", { className: "_1cie img sp_i534r85sjIn sx_38fed8", src: null, alt: "" });
+    }
+  };
+
+  var AbstractLink1 = function (props) {
+    if (props.x === 1) {
+      return React.createElement(
+        "a",
+        { className: "_387r _55pi _2agf _4jy0 _4jy4 _517h _51sy _42ft", style: { "width": 250, "maxWidth": "250px" }, disabled: null, label: null, href: "#", rel: undefined, onClick: function () {} },
+        null,
+        React.createElement(
+          "span",
+          { className: "_55pe", style: { "maxWidth": "236px" } },
+          null,
+          React.createElement(
+            "span",
+            null,
+            React.createElement(
+              "span",
+              { className: "_48u-" },
+              "Account:"
+            ),
+            " ",
+            "Dick Madanson (10149999073643408)"
+          )
+        ),
+        React.createElement(ReactImage0, { x: 0 })
+      );
+    }
+    if (props.x === 43) {
+      return React.createElement(
+        "a",
+        { className: "_585q _50zy _50-0 _50z- _5upp _42ft", size: "medium", shade: "dark", type: null, title: "Remove", "data-hover": undefined, "data-tooltip-alignh": undefined, "data-tooltip-content": undefined, disabled: null, label: null, href: "#", rel: undefined, onClick: function () {} },
+        undefined,
+        "Remove",
+        undefined
+      );
+    }
+    if (props.x === 49) {
+      return React.createElement(
+        "a",
+        { target: "_blank", href: "/ads/manage/billing.php?act=10149999073643408", rel: undefined, onClick: function () {} },
+        React.createElement(XUIText29, { x: 48 })
+      );
+    }
+    if (props.x === 128) {
+      return React.createElement(
+        "a",
+        { className: " _5bbf _55pi _2agf _4jy0 _4jy4 _517h _51sy _42ft", style: { "maxWidth": "200px" }, disabled: null, label: null, href: "#", rel: undefined, onClick: function () {} },
+        null,
+        React.createElement(
+          "span",
+          { className: "_55pe", style: { "maxWidth": "186px" } },
+          React.createElement(ReactImage0, { x: 126 }),
+          "Search"
+        ),
+        React.createElement(ReactImage0, { x: 127 })
+      );
+    }
+    if (props.x === 136) {
+      return React.createElement(
+        "a",
+        { className: " _5bbf _55pi _2agf _4jy0 _4jy4 _517h _51sy _42ft", style: { "maxWidth": "200px" }, disabled: null, label: null, href: "#", rel: undefined, onClick: function () {} },
+        null,
+        React.createElement(
+          "span",
+          { className: "_55pe", style: { "maxWidth": "186px" } },
+          React.createElement(ReactImage0, { x: 134 }),
+          "Filters"
+        ),
+        React.createElement(ReactImage0, { x: 135 })
+      );
+    }
+    if (props.x === 178) {
+      return React.createElement(
+        "a",
+        { className: "_1_-t _1_-v _42ft", disabled: null, height: "medium", role: "button", label: null, href: "#", rel: undefined, onClick: function () {} },
+        undefined,
+        "Lifetime",
+        React.createElement(ReactImage0, { x: 177 })
+      );
+    }
+    if (props.x === 207) {
+      return React.createElement(
+        "a",
+        { href: "#", rel: undefined, onClick: function () {} },
+        "Create Ad Set"
+      );
+    }
+    if (props.x === 209) {
+      return React.createElement(
+        "a",
+        { href: "#", rel: undefined, onClick: function () {} },
+        "View Ad Set"
+      );
+    }
+    if (props.x === 241) {
+      return React.createElement(
+        "a",
+        { href: "#", rel: undefined, onClick: function () {} },
+        "Set a Limit"
+      );
+    }
+    if (props.x === 267) {
+      return React.createElement(
+        "a",
+        { className: "_p _55pi _2agf _4jy0 _4jy3 _517h _51sy _42ft", style: { "maxWidth": "200px" }, disabled: null, label: null, href: "#", rel: undefined, onClick: function () {} },
+        null,
+        React.createElement(
+          "span",
+          { className: "_55pe", style: { "maxWidth": "186px" } },
+          null,
+          "Links"
+        ),
+        React.createElement(ReactImage0, { x: 266 })
+      );
+    }
+  };
+
+  var Link2 = function (props) {
+    if (props.x === 2) {
+      return React.createElement(AbstractLink1, { x: 1 });
+    }
+    if (props.x === 44) {
+      return React.createElement(AbstractLink1, { x: 43 });
+    }
+    if (props.x === 50) {
+      return React.createElement(AbstractLink1, { x: 49 });
+    }
+    if (props.x === 129) {
+      return React.createElement(AbstractLink1, { x: 128 });
+    }
+    if (props.x === 137) {
+      return React.createElement(AbstractLink1, { x: 136 });
+    }
+    if (props.x === 179) {
+      return React.createElement(AbstractLink1, { x: 178 });
+    }
+    if (props.x === 208) {
+      return React.createElement(AbstractLink1, { x: 207 });
+    }
+    if (props.x === 210) {
+      return React.createElement(AbstractLink1, { x: 209 });
+    }
+    if (props.x === 242) {
+      return React.createElement(AbstractLink1, { x: 241 });
+    }
+    if (props.x === 268) {
+      return React.createElement(AbstractLink1, { x: 267 });
+    }
+  };
+
+  var AbstractButton3 = function (props) {
+    if (props.x === 3) {
+      return React.createElement(Link2, { x: 2 });
+    }
+    if (props.x === 20) {
+      return React.createElement(
+        "button",
+        { className: "_5n7z _4jy0 _4jy4 _517h _51sy _42ft", onClick: function () {}, label: null, type: "submit", value: "1" },
+        undefined,
+        "Discard Changes",
+        undefined
+      );
+    }
+    if (props.x === 23) {
+      return React.createElement(
+        "button",
+        { className: "_5n7z _2yak _4lj- _4jy0 _4jy4 _517h _51sy _42ft _42fr", disabled: true, onClick: function () {}, "data-tooltip-content": "You have no changes to publish", "data-hover": "tooltip", label: null, type: "submit", value: "1" },
+        React.createElement(ReactImage0, { x: 22 }),
+        "Review Changes",
+        undefined
+      );
+    }
+    if (props.x === 45) {
+      return React.createElement(Link2, { x: 44 });
+    }
+    if (props.x === 68) {
+      return React.createElement(
+        "button",
+        { className: "_u_k _4jy0 _4jy4 _517h _51sy _42ft", onClick: function () {}, label: null, type: "submit", value: "1" },
+        React.createElement(ReactImage0, { x: 67 }),
+        "Create Campaign",
+        undefined
+      );
+    }
+    if (props.x === 71) {
+      return React.createElement(
+        "button",
+        { className: "_u_k _3qx6 _p _4jy0 _4jy4 _517h _51sy _42ft", label: null, type: "submit", value: "1" },
+        React.createElement(ReactImage0, { x: 70 }),
+        undefined,
+        undefined
+      );
+    }
+    if (props.x === 77) {
+      return React.createElement(
+        "button",
+        { "aria-label": "Edit", "data-tooltip-content": "Edit Campaigns (Ctrl+U)", "data-hover": "tooltip", className: "_d2_ _u_k noMargin _4jy0 _4jy4 _517h _51sy _42ft", disabled: false, onClick: function () {}, label: null, type: "submit", value: "1" },
+        React.createElement(ReactImage0, { x: 76 }),
+        "Edit",
+        undefined
+      );
+    }
+    if (props.x === 80) {
+      return React.createElement(
+        "button",
+        { className: "_u_k _3qx6 _p _4jy0 _4jy4 _517h _51sy _42ft", disabled: false, label: null, type: "submit", value: "1" },
+        React.createElement(ReactImage0, { x: 79 }),
+        undefined,
+        undefined
+      );
+    }
+    if (props.x === 89) {
+      return React.createElement(
+        "button",
+        { "aria-label": "Revert", className: "_u_k _4jy0 _4jy4 _517h _51sy _42ft _42fr", "data-hover": "tooltip", "data-tooltip-content": "Revert", disabled: true, onClick: function () {}, label: null, type: "submit", value: "1" },
+        React.createElement(ReactImage0, { x: 88 }),
+        undefined,
+        undefined
+      );
+    }
+    if (props.x === 92) {
+      return React.createElement(
+        "button",
+        { "aria-label": "Delete", className: "_u_k _4jy0 _4jy4 _517h _51sy _42ft", "data-hover": "tooltip", "data-tooltip-content": "Delete", disabled: false, onClick: function () {}, label: null, type: "submit", value: "1" },
+        React.createElement(ReactImage0, { x: 91 }),
+        undefined,
+        undefined
+      );
+    }
+    if (props.x === 95) {
+      return React.createElement(
+        "button",
+        { "aria-label": "Duplicate", className: "_u_k _4jy0 _4jy4 _517h _51sy _42ft", "data-hover": "tooltip", "data-tooltip-content": "Duplicate", disabled: false, onClick: function () {}, label: null, type: "submit", value: "1" },
+        React.createElement(ReactImage0, { x: 94 }),
+        undefined,
+        undefined
+      );
+    }
+    if (props.x === 99) {
+      return React.createElement(
+        "button",
+        { "aria-label": "Export & Import", className: "_u_k noMargin _p _4jy0 _4jy4 _517h _51sy _42ft", "data-hover": "tooltip", "data-tooltip-content": "Export & Import", onClick: function () {}, label: null, type: "submit", value: "1" },
+        React.createElement(ReactImage0, { x: 98 }),
+        undefined,
+        undefined
+      );
+    }
+    if (props.x === 109) {
+      return React.createElement(
+        "button",
+        { "aria-label": "Create Report", className: "_u_k _5n7z _4jy0 _4jy4 _517h _51sy _42ft", "data-hover": "tooltip", "data-tooltip-content": "Create Report", disabled: false, style: { "boxSizing": "border-box", "height": "28px", "width": "48px" }, onClick: function () {}, label: null, type: "submit", value: "1" },
+        React.createElement(ReactImage0, { x: 108 }),
+        undefined,
+        undefined
+      );
+    }
+    if (props.x === 112) {
+      return React.createElement(
+        "button",
+        { "aria-label": "Campaign Tags", className: " _5uy7 _4jy0 _4jy4 _517h _51sy _42ft", "data-hover": "tooltip", "data-tooltip-content": "Campaign Tags", disabled: false, haschevron: false, onClick: function () {}, label: null, type: "submit", value: "1" },
+        React.createElement(ReactImage0, { x: 111 }),
+        undefined,
+        undefined
+      );
+    }
+    if (props.x === 130) {
+      return React.createElement(Link2, { x: 129 });
+    }
+    if (props.x === 138) {
+      return React.createElement(Link2, { x: 137 });
+    }
+    if (props.x === 149) {
+      return React.createElement(
+        "button",
+        { className: "_3yz9 _1t-2 _50z- _50zy _50zz _50z- _5upp _42ft", size: "small", onClick: function () {}, shade: "dark", type: "button", title: "Remove", "data-hover": undefined, "data-tooltip-alignh": undefined, "data-tooltip-content": undefined, label: null },
+        undefined,
+        "Remove",
+        undefined
+      );
+    }
+    if (props.x === 156) {
+      return React.createElement(
+        "button",
+        { className: "_5b5u _5b5v _4jy0 _4jy3 _517h _51sy _42ft", onClick: function () {}, label: null, type: "submit", value: "1" },
+        undefined,
+        "Apply",
+        undefined
+      );
+    }
+    if (props.x === 161) {
+      return React.createElement(
+        "button",
+        { className: "_1wdf _4jy0 _517i _517h _51sy _42ft", onClick: function () {}, label: null, type: "submit", value: "1" },
+        React.createElement(ReactImage0, { x: 160 }),
+        undefined,
+        undefined
+      );
+    }
+    if (props.x === 180) {
+      return React.createElement(Link2, { x: 179 });
+    }
+    if (props.x === 187) {
+      return React.createElement(
+        "button",
+        { "aria-label": "List Settings", className: "_u_k _3c5o _1-r0 _4jy0 _4jy4 _517h _51sy _42ft", "data-hover": "tooltip", "data-tooltip-content": "List Settings", onClick: function () {}, label: null, type: "submit", value: "1" },
+        React.createElement(ReactImage0, { x: 186 }),
+        undefined,
+        undefined
+      );
+    }
+    if (props.x === 269) {
+      return React.createElement(Link2, { x: 268 });
+    }
+    if (props.x === 303) {
+      return React.createElement(
+        "button",
+        { className: "_tm3 _tm6 _tm7 _4jy0 _4jy6 _517h _51sy _42ft", "data-tooltip-position": "right", "data-tooltip-content": "Campaigns", "data-hover": "tooltip", onClick: function () {}, label: null, type: "submit", value: "1" },
+        undefined,
+        React.createElement(
+          "div",
+          null,
+          React.createElement("div", { className: "_tma" }),
+          React.createElement("div", { className: "_tm8" }),
+          React.createElement(
+            "div",
+            { className: "_tm9" },
+            1
+          )
+        ),
+        undefined
+      );
+    }
+    if (props.x === 305) {
+      return React.createElement(
+        "button",
+        { className: "_tm4 _tm6 _4jy0 _4jy6 _517h _51sy _42ft", "data-tooltip-position": "right", "data-tooltip-content": "Ad Sets", "data-hover": "tooltip", onClick: function () {}, label: null, type: "submit", value: "1" },
+        undefined,
+        React.createElement(
+          "div",
+          null,
+          React.createElement("div", { className: "_tma" }),
+          React.createElement("div", { className: "_tm8" }),
+          React.createElement(
+            "div",
+            { className: "_tm9" },
+            1
+          )
+        ),
+        undefined
+      );
+    }
+    if (props.x === 307) {
+      return React.createElement(
+        "button",
+        { className: "_tm5 _tm6 _4jy0 _4jy6 _517h _51sy _42ft", "data-tooltip-position": "right", "data-tooltip-content": "Ads", "data-hover": "tooltip", onClick: function () {}, label: null, type: "submit", value: "1" },
+        undefined,
+        React.createElement(
+          "div",
+          null,
+          React.createElement("div", { className: "_tma" }),
+          React.createElement("div", { className: "_tm8" }),
+          React.createElement(
+            "div",
+            { className: "_tm9" },
+            1
+          )
+        ),
+        undefined
+      );
+    }
+  };
+
+  var XUIButton4 = function (props) {
+    if (props.x === 4) {
+      return React.createElement(AbstractButton3, { x: 3 });
+    }
+    if (props.x === 21) {
+      return React.createElement(AbstractButton3, { x: 20 });
+    }
+    if (props.x === 24) {
+      return React.createElement(AbstractButton3, { x: 23 });
+    }
+    if (props.x === 69) {
+      return React.createElement(AbstractButton3, { x: 68 });
+    }
+    if (props.x === 72) {
+      return React.createElement(AbstractButton3, { x: 71 });
+    }
+    if (props.x === 78) {
+      return React.createElement(AbstractButton3, { x: 77 });
+    }
+    if (props.x === 81) {
+      return React.createElement(AbstractButton3, { x: 80 });
+    }
+    if (props.x === 90) {
+      return React.createElement(AbstractButton3, { x: 89 });
+    }
+    if (props.x === 93) {
+      return React.createElement(AbstractButton3, { x: 92 });
+    }
+    if (props.x === 96) {
+      return React.createElement(AbstractButton3, { x: 95 });
+    }
+    if (props.x === 100) {
+      return React.createElement(AbstractButton3, { x: 99 });
+    }
+    if (props.x === 110) {
+      return React.createElement(AbstractButton3, { x: 109 });
+    }
+    if (props.x === 113) {
+      return React.createElement(AbstractButton3, { x: 112 });
+    }
+    if (props.x === 131) {
+      return React.createElement(AbstractButton3, { x: 130 });
+    }
+    if (props.x === 139) {
+      return React.createElement(AbstractButton3, { x: 138 });
+    }
+    if (props.x === 157) {
+      return React.createElement(AbstractButton3, { x: 156 });
+    }
+    if (props.x === 162) {
+      return React.createElement(AbstractButton3, { x: 161 });
+    }
+    if (props.x === 188) {
+      return React.createElement(AbstractButton3, { x: 187 });
+    }
+    if (props.x === 270) {
+      return React.createElement(AbstractButton3, { x: 269 });
+    }
+    if (props.x === 304) {
+      return React.createElement(AbstractButton3, { x: 303 });
+    }
+    if (props.x === 306) {
+      return React.createElement(AbstractButton3, { x: 305 });
+    }
+    if (props.x === 308) {
+      return React.createElement(AbstractButton3, { x: 307 });
+    }
+  };
+
+  var AbstractPopoverButton5 = function (props) {
+    if (props.x === 5) {
+      return React.createElement(XUIButton4, { x: 4 });
+    }
+    if (props.x === 132) {
+      return React.createElement(XUIButton4, { x: 131 });
+    }
+    if (props.x === 140) {
+      return React.createElement(XUIButton4, { x: 139 });
+    }
+    if (props.x === 271) {
+      return React.createElement(XUIButton4, { x: 270 });
+    }
+  };
+
+  var ReactXUIPopoverButton6 = function (props) {
+    if (props.x === 6) {
+      return React.createElement(AbstractPopoverButton5, { x: 5 });
+    }
+    if (props.x === 133) {
+      return React.createElement(AbstractPopoverButton5, { x: 132 });
+    }
+    if (props.x === 141) {
+      return React.createElement(AbstractPopoverButton5, { x: 140 });
+    }
+    if (props.x === 272) {
+      return React.createElement(AbstractPopoverButton5, { x: 271 });
+    }
+  };
+
+  var BIGAdAccountSelector7 = function (props) {
+    if (props.x === 7) {
+      return React.createElement(
+        "div",
+        null,
+        React.createElement(ReactXUIPopoverButton6, { x: 6, ref: "openMenuButton" }),
+        null
+      );
+    }
+  };
+
+  var FluxContainer_AdsPEBIGAdAccountSelectorContainer_8 = function (props) {
+    if (props.x === 8) {
+      return React.createElement(BIGAdAccountSelector7, { x: 7 });
+    }
+  };
+
+  var ErrorBoundary9 = function (props) {
+    if (props.x === 9) {
+      return React.createElement(FluxContainer_AdsPEBIGAdAccountSelectorContainer_8, { x: 8 });
+    }
+    if (props.x === 13) {
+      return React.createElement(FluxContainer_AdsPENavigationBarContainer_12, { x: 12 });
+    }
+    if (props.x === 27) {
+      return React.createElement(FluxContainer_AdsPEPublishButtonContainer_18, { x: 26 });
+    }
+    if (props.x === 32) {
+      return React.createElement(ReactPopoverMenu20, { x: 31 });
+    }
+    if (props.x === 38) {
+      return React.createElement(AdsPEResetDialog24, { x: 37 });
+    }
+    if (props.x === 57) {
+      return React.createElement(FluxContainer_AdsPETopErrorContainer_35, { x: 56 });
+    }
+    if (props.x === 60) {
+      return React.createElement(FluxContainer_AdsGuidanceChannel_36, { x: 59 });
+    }
+    if (props.x === 64) {
+      return React.createElement(FluxContainer_AdsBulkEditDialogContainer_38, { x: 63 });
+    }
+    if (props.x === 124) {
+      return React.createElement(AdsPECampaignGroupToolbarContainer57, { x: 123 });
+    }
+    if (props.x === 170) {
+      return React.createElement(AdsPEFilterContainer72, { x: 169 });
+    }
+    if (props.x === 175) {
+      return React.createElement(AdsPETablePagerContainer75, { x: 174 });
+    }
+    if (props.x === 193) {
+      return React.createElement(AdsPEStatRangeContainer81, { x: 192 });
+    }
+    if (props.x === 301) {
+      return React.createElement(FluxContainer_AdsPEMultiTabDrawerContainer_137, { x: 300 });
+    }
+    if (props.x === 311) {
+      return React.createElement(AdsPEOrganizerContainer139, { x: 310 });
+    }
+    if (props.x === 471) {
+      return React.createElement(AdsPECampaignGroupTableContainer159, { x: 470 });
+    }
+    if (props.x === 475) {
+      return React.createElement(AdsPEContentContainer161, { x: 474 });
+    }
+  };
+
+  var AdsErrorBoundary10 = function (props) {
+    if (props.x === 10) {
+      return React.createElement(ErrorBoundary9, { x: 9 });
+    }
+    if (props.x === 14) {
+      return React.createElement(ErrorBoundary9, { x: 13 });
+    }
+    if (props.x === 28) {
+      return React.createElement(ErrorBoundary9, { x: 27 });
+    }
+    if (props.x === 33) {
+      return React.createElement(ErrorBoundary9, { x: 32 });
+    }
+    if (props.x === 39) {
+      return React.createElement(ErrorBoundary9, { x: 38 });
+    }
+    if (props.x === 58) {
+      return React.createElement(ErrorBoundary9, { x: 57 });
+    }
+    if (props.x === 61) {
+      return React.createElement(ErrorBoundary9, { x: 60 });
+    }
+    if (props.x === 65) {
+      return React.createElement(ErrorBoundary9, { x: 64 });
+    }
+    if (props.x === 125) {
+      return React.createElement(ErrorBoundary9, { x: 124 });
+    }
+    if (props.x === 171) {
+      return React.createElement(ErrorBoundary9, { x: 170 });
+    }
+    if (props.x === 176) {
+      return React.createElement(ErrorBoundary9, { x: 175 });
+    }
+    if (props.x === 194) {
+      return React.createElement(ErrorBoundary9, { x: 193 });
+    }
+    if (props.x === 302) {
+      return React.createElement(ErrorBoundary9, { x: 301 });
+    }
+    if (props.x === 312) {
+      return React.createElement(ErrorBoundary9, { x: 311 });
+    }
+    if (props.x === 472) {
+      return React.createElement(ErrorBoundary9, { x: 471 });
+    }
+    if (props.x === 476) {
+      return React.createElement(ErrorBoundary9, { x: 475 });
+    }
+  };
+
+  var AdsPENavigationBar11 = function (props) {
+    if (props.x === 11) {
+      return React.createElement("div", { className: "_4t_9" });
+    }
+  };
+
+  var FluxContainer_AdsPENavigationBarContainer_12 = function (props) {
+    if (props.x === 12) {
+      return React.createElement(AdsPENavigationBar11, { x: 11 });
+    }
+  };
+
+  var AdsPEDraftSyncStatus13 = function (props) {
+    if (props.x === 16) {
+      return React.createElement(
+        "div",
+        { className: "_3ut-", onClick: function () {} },
+        React.createElement(
+          "span",
+          { className: "_3uu0" },
+          React.createElement(ReactImage0, { x: 15 })
+        )
+      );
+    }
+  };
+
+  var FluxContainer_AdsPEDraftSyncStatusContainer_14 = function (props) {
+    if (props.x === 17) {
+      return React.createElement(AdsPEDraftSyncStatus13, { x: 16 });
+    }
+  };
+
+  var AdsPEDraftErrorsStatus15 = function (props) {
+    if (props.x === 18) {
+      return null;
+    }
+  };
+
+  var FluxContainer_viewFn_16 = function (props) {
+    if (props.x === 19) {
+      return React.createElement(AdsPEDraftErrorsStatus15, { x: 18 });
+    }
+  };
+
+  var AdsPEPublishButton17 = function (props) {
+    if (props.x === 25) {
+      return React.createElement(
+        "div",
+        { className: "_5533" },
+        React.createElement(FluxContainer_AdsPEDraftSyncStatusContainer_14, { x: 17 }),
+        React.createElement(FluxContainer_viewFn_16, { x: 19 }),
+        null,
+        React.createElement(XUIButton4, { x: 21, key: "discard" }),
+        React.createElement(XUIButton4, { x: 24, ref: "reviewChangesButton" })
+      );
+    }
+  };
+
+  var FluxContainer_AdsPEPublishButtonContainer_18 = function (props) {
+    if (props.x === 26) {
+      return React.createElement(AdsPEPublishButton17, { x: 25 });
+    }
+  };
+
+  var InlineBlock19 = function (props) {
+    if (props.x === 30) {
+      return React.createElement(
+        "div",
+        { className: "uiPopover _6a _6b", disabled: null },
+        React.createElement(ReactImage0, { x: 29, key: ".0" })
+      );
+    }
+    if (props.x === 73) {
+      return React.createElement(
+        "div",
+        { className: "uiPopover _6a _6b", disabled: null },
+        React.createElement(XUIButton4, { x: 72, key: ".0" })
+      );
+    }
+    if (props.x === 82) {
+      return React.createElement(
+        "div",
+        { className: "_1nwm uiPopover _6a _6b", disabled: null },
+        React.createElement(XUIButton4, { x: 81, key: ".0" })
+      );
+    }
+    if (props.x === 101) {
+      return React.createElement(
+        "div",
+        { size: "large", className: "uiPopover _6a _6b", disabled: null },
+        React.createElement(XUIButton4, { x: 100, key: ".0" })
+      );
+    }
+    if (props.x === 273) {
+      return React.createElement(
+        "div",
+        { className: "_3-90 uiPopover _6a _6b", style: { "marginTop": 2 }, disabled: null },
+        React.createElement(ReactXUIPopoverButton6, { x: 272, key: ".0" })
+      );
+    }
+  };
+
+  var ReactPopoverMenu20 = function (props) {
+    if (props.x === 31) {
+      return React.createElement(InlineBlock19, { x: 30, ref: "root" });
+    }
+    if (props.x === 74) {
+      return React.createElement(InlineBlock19, { x: 73, ref: "root" });
+    }
+    if (props.x === 83) {
+      return React.createElement(InlineBlock19, { x: 82, ref: "root" });
+    }
+    if (props.x === 102) {
+      return React.createElement(InlineBlock19, { x: 101, ref: "root" });
+    }
+    if (props.x === 274) {
+      return React.createElement(InlineBlock19, { x: 273, ref: "root" });
+    }
+  };
+
+  var LeftRight21 = function (props) {
+    if (props.x === 34) {
+      return React.createElement(
+        "div",
+        { className: "clearfix" },
+        React.createElement(
+          "div",
+          { key: "left", className: "_ohe lfloat" },
+          React.createElement(
+            "div",
+            { className: "_34_j" },
+            React.createElement(
+              "div",
+              { className: "_34_k" },
+              React.createElement(AdsErrorBoundary10, { x: 10 })
+            ),
+            React.createElement(
+              "div",
+              { className: "_2u-6" },
+              React.createElement(AdsErrorBoundary10, { x: 14 })
+            )
+          )
+        ),
+        React.createElement(
+          "div",
+          { key: "right", className: "_ohf rfloat" },
+          React.createElement(
+            "div",
+            { className: "_34_m" },
+            React.createElement(
+              "div",
+              { key: "0", className: "_5ju2" },
+              React.createElement(AdsErrorBoundary10, { x: 28 })
+            ),
+            React.createElement(
+              "div",
+              { key: "1", className: "_5ju2" },
+              React.createElement(AdsErrorBoundary10, { x: 33 })
+            )
+          )
+        )
+      );
+    }
+    if (props.x === 232) {
+      return React.createElement(
+        "div",
+        { flex: "right", direction: "left", className: "clearfix" },
+        React.createElement(
+          "div",
+          { key: "left", className: "_ohe lfloat" },
+          React.createElement(AdsLabeledField104, { x: 231 })
+        ),
+        React.createElement(
+          "div",
+          { key: "right", className: "" },
+          React.createElement(
+            "div",
+            { className: "_42ef" },
+            React.createElement(
+              "div",
+              { className: "_2oc7" },
+              "Clicks to Website"
+            )
+          )
+        )
+      );
+    }
+    if (props.x === 235) {
+      return React.createElement(
+        "div",
+        { className: "_3-8x clearfix", flex: "right", direction: "left" },
+        React.createElement(
+          "div",
+          { key: "left", className: "_ohe lfloat" },
+          React.createElement(AdsLabeledField104, { x: 234 })
+        ),
+        React.createElement(
+          "div",
+          { key: "right", className: "" },
+          React.createElement(
+            "div",
+            { className: "_42ef" },
+            React.createElement(
+              "div",
+              { className: "_2oc7" },
+              "Auction"
+            )
+          )
+        )
+      );
+    }
+    if (props.x === 245) {
+      return React.createElement(
+        "div",
+        { className: "_3-8y clearfix", flex: "right", direction: "left" },
+        React.createElement(
+          "div",
+          { key: "left", className: "_ohe lfloat" },
+          React.createElement(AdsLabeledField104, { x: 240 })
+        ),
+        React.createElement(
+          "div",
+          { key: "right", className: "" },
+          React.createElement(
+            "div",
+            { className: "_42ef" },
+            React.createElement(FluxContainer_AdsCampaignGroupSpendCapContainer_107, { x: 244 })
+          )
+        )
+      );
+    }
+    if (props.x === 277) {
+      return React.createElement(
+        "div",
+        { className: "_5dw9 _5dwa clearfix" },
+        React.createElement(
+          "div",
+          { key: "left", className: "_ohe lfloat" },
+          React.createElement(XUICardHeaderTitle100, { x: 265, key: ".0" })
+        ),
+        React.createElement(
+          "div",
+          { key: "right", className: "_ohf rfloat" },
+          React.createElement(FluxContainer_AdsPluginizedLinksMenuContainer_121, { x: 276, key: ".1" })
+        )
+      );
+    }
+  };
+
+  var AdsUnifiedNavigationLocalNav22 = function (props) {
+    if (props.x === 35) {
+      return React.createElement(
+        "div",
+        { className: "_34_i" },
+        React.createElement(LeftRight21, { x: 34 })
+      );
+    }
+  };
+
+  var XUIDialog23 = function (props) {
+    if (props.x === 36) {
+      return null;
+    }
+  };
+
+  var AdsPEResetDialog24 = function (props) {
+    if (props.x === 37) {
+      return React.createElement(
+        "span",
+        null,
+        React.createElement(XUIDialog23, { x: 36, key: "dialog/.0" })
+      );
+    }
+  };
+
+  var AdsPETopNav25 = function (props) {
+    if (props.x === 40) {
+      return React.createElement(
+        "div",
+        { style: { "width": 1306 } },
+        React.createElement(AdsUnifiedNavigationLocalNav22, { x: 35 }),
+        React.createElement(AdsErrorBoundary10, { x: 39 })
+      );
+    }
+  };
+
+  var FluxContainer_AdsPETopNavContainer_26 = function (props) {
+    if (props.x === 41) {
+      return React.createElement(AdsPETopNav25, { x: 40 });
+    }
+  };
+
+  var XUIAbstractGlyphButton27 = function (props) {
+    if (props.x === 46) {
+      return React.createElement(AbstractButton3, { x: 45 });
+    }
+    if (props.x === 150) {
+      return React.createElement(AbstractButton3, { x: 149 });
+    }
+  };
+
+  var XUICloseButton28 = function (props) {
+    if (props.x === 47) {
+      return React.createElement(XUIAbstractGlyphButton27, { x: 46 });
+    }
+    if (props.x === 151) {
+      return React.createElement(XUIAbstractGlyphButton27, { x: 150 });
+    }
+  };
+
+  var XUIText29 = function (props) {
+    if (props.x === 48) {
+      return React.createElement(
+        "span",
+        { display: "inline", className: " _50f7" },
+        "Ads Manager"
+      );
+    }
+    if (props.x === 205) {
+      return React.createElement(
+        "span",
+        { className: "_2x9f  _50f5 _50f7", display: "inline" },
+        "Editing Campaign"
+      );
+    }
+    if (props.x === 206) {
+      return React.createElement(
+        "span",
+        { display: "inline", className: " _50f5 _50f7" },
+        "Test Campaign"
+      );
+    }
+  };
+
+  var XUINotice30 = function (props) {
+    if (props.x === 51) {
+      return React.createElement(
+        "div",
+        { size: "medium", className: "_585n _585o _2wdd" },
+        React.createElement(ReactImage0, { x: 42 }),
+        React.createElement(XUICloseButton28, { x: 47 }),
+        React.createElement(
+          "div",
+          { className: "_585r _2i-a _50f4" },
+          "Please go to ",
+          React.createElement(Link2, { x: 50 }),
+          " to set up a payment method for this ad account."
+        )
+      );
+    }
+  };
+
+  var ReactCSSTransitionGroupChild31 = function (props) {
+    if (props.x === 52) {
+      return React.createElement(XUINotice30, { x: 51 });
+    }
+  };
+
+  var ReactTransitionGroup32 = function (props) {
+    if (props.x === 53) {
+      return React.createElement(
+        "span",
+        null,
+        React.createElement(ReactCSSTransitionGroupChild31, { x: 52, key: ".0", ref: ".0" })
+      );
+    }
+  };
+
+  var ReactCSSTransitionGroup33 = function (props) {
+    if (props.x === 54) {
+      return React.createElement(ReactTransitionGroup32, { x: 53 });
+    }
+  };
+
+  var AdsPETopError34 = function (props) {
+    if (props.x === 55) {
+      return React.createElement(
+        "div",
+        { className: "_2wdc" },
+        React.createElement(ReactCSSTransitionGroup33, { x: 54 })
+      );
+    }
+  };
+
+  var FluxContainer_AdsPETopErrorContainer_35 = function (props) {
+    if (props.x === 56) {
+      return React.createElement(AdsPETopError34, { x: 55 });
+    }
+  };
+
+  var FluxContainer_AdsGuidanceChannel_36 = function (props) {
+    if (props.x === 59) {
+      return null;
+    }
+  };
+
+  var ResponsiveBlock37 = function (props) {
+    if (props.x === 62) {
+      return React.createElement(
+        "div",
+        { onResize: function () {}, className: "_4u-c" },
+        [React.createElement(AdsErrorBoundary10, { x: 58 }), React.createElement(AdsErrorBoundary10, { x: 61 })],
+        React.createElement(
+          "div",
+          { key: "sensor", className: "_4u-f" },
+          React.createElement("iframe", { ref: "sensorNode", "aria-hidden": "true", className: "_1_xb", tabIndex: "-1" })
+        )
+      );
+    }
+    if (props.x === 469) {
+      return React.createElement(
+        "div",
+        { onResize: function () {}, className: "_4u-c" },
+        React.createElement(AdsPEDataTableContainer158, { x: 468 }),
+        React.createElement(
+          "div",
+          { key: "sensor", className: "_4u-f" },
+          React.createElement("iframe", { ref: "sensorNode", "aria-hidden": "true", className: "_1_xb", tabIndex: "-1" })
+        )
+      );
+    }
+  };
+
+  var FluxContainer_AdsBulkEditDialogContainer_38 = function (props) {
+    if (props.x === 63) {
+      return null;
+    }
+  };
+
+  var Column39 = function (props) {
+    if (props.x === 66) {
+      return React.createElement(
+        "div",
+        { className: "_4bl8 _4bl7" },
+        React.createElement(
+          "div",
+          { className: "_3c5f" },
+          null,
+          null,
+          React.createElement("div", { className: "_3c5i" }),
+          null
+        )
+      );
+    }
+  };
+
+  var XUIButtonGroup40 = function (props) {
+    if (props.x === 75) {
+      return React.createElement(
+        "div",
+        { className: "_5n7z _51xa" },
+        React.createElement(XUIButton4, { x: 69 }),
+        React.createElement(ReactPopoverMenu20, { x: 74 })
+      );
+    }
+    if (props.x === 84) {
+      return React.createElement(
+        "div",
+        { className: "_5n7z _51xa" },
+        React.createElement(XUIButton4, { x: 78, key: "edit" }),
+        React.createElement(ReactPopoverMenu20, { x: 83, key: "editMenu" })
+      );
+    }
+    if (props.x === 97) {
+      return React.createElement(
+        "div",
+        { className: "_5n7z _51xa" },
+        React.createElement(XUIButton4, { x: 90, key: "revert" }),
+        React.createElement(XUIButton4, { x: 93, key: "delete" }),
+        React.createElement(XUIButton4, { x: 96, key: "duplicate" })
+      );
+    }
+    if (props.x === 117) {
+      return React.createElement(
+        "div",
+        { className: "_5n7z _51xa" },
+        React.createElement(AdsPEExportImportMenuContainer48, { x: 107 }),
+        React.createElement(XUIButton4, { x: 110, key: "createReport", ref: "ads_create_report_button" }),
+        React.createElement(AdsPECampaignGroupTagContainer51, { x: 116, key: "tags" })
+      );
+    }
+  };
+
+  var AdsPEEditToolbarButton41 = function (props) {
+    if (props.x === 85) {
+      return React.createElement(XUIButtonGroup40, { x: 84 });
+    }
+  };
+
+  var FluxContainer_AdsPEEditCampaignGroupToolbarButtonContainer_42 = function (props) {
+    if (props.x === 86) {
+      return React.createElement(AdsPEEditToolbarButton41, { x: 85 });
+    }
+  };
+
+  var FluxContainer_AdsPEEditToolbarButtonContainer_43 = function (props) {
+    if (props.x === 87) {
+      return React.createElement(FluxContainer_AdsPEEditCampaignGroupToolbarButtonContainer_42, { x: 86 });
+    }
+  };
+
+  var AdsPEExportImportMenu44 = function (props) {
+    if (props.x === 103) {
+      return React.createElement(ReactPopoverMenu20, { x: 102, key: "export" });
+    }
+  };
+
+  var FluxContainer_AdsPECustomizeExportContainer_45 = function (props) {
+    if (props.x === 104) {
+      return null;
+    }
+  };
+
+  var AdsPEExportAsTextDialog46 = function (props) {
+    if (props.x === 105) {
+      return null;
+    }
+  };
+
+  var FluxContainer_AdsPEExportAsTextDialogContainer_47 = function (props) {
+    if (props.x === 106) {
+      return React.createElement(AdsPEExportAsTextDialog46, { x: 105 });
+    }
+  };
+
+  var AdsPEExportImportMenuContainer48 = function (props) {
+    if (props.x === 107) {
+      return React.createElement(
+        "span",
+        null,
+        React.createElement(AdsPEExportImportMenu44, { x: 103 }),
+        React.createElement(FluxContainer_AdsPECustomizeExportContainer_45, { x: 104 }),
+        React.createElement(FluxContainer_AdsPEExportAsTextDialogContainer_47, { x: 106 }),
+        null,
+        null
+      );
+    }
+  };
+
+  var Constructor49 = function (props) {
+    if (props.x === 114) {
+      return null;
+    }
+    if (props.x === 142) {
+      return null;
+    }
+    if (props.x === 143) {
+      return null;
+    }
+    if (props.x === 183) {
+      return null;
+    }
+  };
+
+  var TagSelectorPopover50 = function (props) {
+    if (props.x === 115) {
+      return React.createElement(
+        "span",
+        { className: " _3d6e" },
+        React.createElement(XUIButton4, { x: 113, ref: "button" }),
+        React.createElement(Constructor49, { x: 114, key: "layer", ref: "layer" })
+      );
+    }
+  };
+
+  var AdsPECampaignGroupTagContainer51 = function (props) {
+    if (props.x === 116) {
+      return React.createElement(TagSelectorPopover50, { x: 115, key: "98010048849317" });
+    }
+  };
+
+  var AdsRuleToolbarMenu52 = function (props) {
+    if (props.x === 118) {
+      return null;
+    }
+  };
+
+  var FluxContainer_AdsPERuleToolbarMenuContainer_53 = function (props) {
+    if (props.x === 119) {
+      return React.createElement(AdsRuleToolbarMenu52, { x: 118 });
+    }
+  };
+
+  var FillColumn54 = function (props) {
+    if (props.x === 120) {
+      return React.createElement(
+        "div",
+        { className: "_4bl9" },
+        React.createElement(
+          "span",
+          { className: "_3c5e" },
+          React.createElement(
+            "span",
+            null,
+            React.createElement(XUIButtonGroup40, { x: 75 }),
+            React.createElement(FluxContainer_AdsPEEditToolbarButtonContainer_43, { x: 87 }),
+            null,
+            React.createElement(XUIButtonGroup40, { x: 97 })
+          ),
+          React.createElement(XUIButtonGroup40, { x: 117 }),
+          React.createElement(FluxContainer_AdsPERuleToolbarMenuContainer_53, { x: 119 })
+        )
+      );
+    }
+  };
+
+  var Layout55 = function (props) {
+    if (props.x === 121) {
+      return React.createElement(
+        "div",
+        { className: "clearfix" },
+        React.createElement(Column39, { x: 66, key: "1" }),
+        React.createElement(FillColumn54, { x: 120, key: "0" })
+      );
+    }
+  };
+
+  var AdsPEMainPaneToolbar56 = function (props) {
+    if (props.x === 122) {
+      return React.createElement(
+        "div",
+        { className: "_3c5b clearfix" },
+        React.createElement(Layout55, { x: 121 })
+      );
+    }
+  };
+
+  var AdsPECampaignGroupToolbarContainer57 = function (props) {
+    if (props.x === 123) {
+      return React.createElement(AdsPEMainPaneToolbar56, { x: 122 });
+    }
+  };
+
+  var AdsPEFiltersPopover58 = function (props) {
+    if (props.x === 144) {
+      return React.createElement(
+        "span",
+        { className: "_5b-l  _5bbe" },
+        React.createElement(ReactXUIPopoverButton6, { x: 133, ref: "searchButton" }),
+        React.createElement(ReactXUIPopoverButton6, { x: 141, ref: "filterButton" }),
+        [React.createElement(Constructor49, { x: 142, key: "filterMenu/.0" }), React.createElement(Constructor49, { x: 143, key: "searchMenu/.0" })]
+      );
+    }
+  };
+
+  var AbstractCheckboxInput59 = function (props) {
+    if (props.x === 145) {
+      return React.createElement(
+        "label",
+        { className: "uiInputLabelInput _55sg _kv1" },
+        React.createElement("input", { checked: true, disabled: true, name: "filterUnpublished", value: "on", onClick: function () {}, className: null, id: "js_input_label_21", type: "checkbox" }),
+        React.createElement("span", { "data-hover": null, "data-tooltip-content": undefined })
+      );
+    }
+    if (props.x === 336) {
+      return React.createElement(
+        "label",
+        { className: "_4h2r _55sg _kv1" },
+        React.createElement("input", { checked: undefined, onChange: function () {}, className: null, type: "checkbox" }),
+        React.createElement("span", { "data-hover": null, "data-tooltip-content": undefined })
+      );
+    }
+  };
+
+  var XUICheckboxInput60 = function (props) {
+    if (props.x === 146) {
+      return React.createElement(AbstractCheckboxInput59, { x: 145 });
+    }
+    if (props.x === 337) {
+      return React.createElement(AbstractCheckboxInput59, { x: 336 });
+    }
+  };
+
+  var InputLabel61 = function (props) {
+    if (props.x === 147) {
+      return React.createElement(
+        "div",
+        { display: "block", className: "uiInputLabel clearfix" },
+        React.createElement(XUICheckboxInput60, { x: 146 }),
+        React.createElement(
+          "label",
+          { className: "uiInputLabelLabel", htmlFor: "js_input_label_21" },
+          "Always show new items"
+        )
+      );
+    }
+  };
+
+  var AdsPopoverLink62 = function (props) {
+    if (props.x === 154) {
+      return React.createElement(
+        "span",
+        null,
+        React.createElement(
+          "span",
+          { ref: "tipIcon", onMouseEnter: function () {}, onMouseLeave: function () {}, onMouseUp: undefined },
+          React.createElement("span", { className: "_3o_j" }),
+          React.createElement(ReactImage0, { x: 153 })
+        ),
+        null
+      );
+    }
+    if (props.x === 238) {
+      return React.createElement(
+        "span",
+        null,
+        React.createElement(
+          "span",
+          { ref: "tipIcon", onMouseEnter: function () {}, onMouseLeave: function () {}, onMouseUp: undefined },
+          React.createElement("span", { className: "_3o_j" }),
+          React.createElement(ReactImage0, { x: 237 })
+        ),
+        null
+      );
+    }
+  };
+
+  var AdsHelpLink63 = function (props) {
+    if (props.x === 155) {
+      return React.createElement(AdsPopoverLink62, { x: 154 });
+    }
+    if (props.x === 239) {
+      return React.createElement(AdsPopoverLink62, { x: 238 });
+    }
+  };
+
+  var BUIFilterTokenInput64 = function (props) {
+    if (props.x === 158) {
+      return React.createElement(
+        "div",
+        { className: "_5b5o _3yz3 _4cld" },
+        React.createElement(
+          "div",
+          { className: "_5b5t _2d2k" },
+          React.createElement(ReactImage0, { x: 152 }),
+          React.createElement(
+            "div",
+            { className: "_5b5r" },
+            "Campaigns: (1)",
+            React.createElement(AdsHelpLink63, { x: 155 })
+          )
+        ),
+        React.createElement(XUIButton4, { x: 157 })
+      );
+    }
+  };
+
+  var BUIFilterToken65 = function (props) {
+    if (props.x === 159) {
+      return React.createElement(
+        "div",
+        { className: "_3yz1 _3yz2 _3dad" },
+        React.createElement(
+          "div",
+          { ref: "filterToken", className: "_3yz4", "aria-hidden": false },
+          React.createElement(
+            "div",
+            { onClick: function () {}, className: "_3yz5" },
+            React.createElement(ReactImage0, { x: 148 }),
+            React.createElement(
+              "div",
+              { className: "_3yz7" },
+              "Campaigns:"
+            ),
+            React.createElement(
+              "div",
+              { className: "ellipsis _3yz8", "data-hover": "tooltip", "data-tooltip-display": "overflow" },
+              "(1)"
+            )
+          ),
+          null,
+          React.createElement(XUICloseButton28, { x: 151 })
+        ),
+        React.createElement(BUIFilterTokenInput64, { x: 158, ref: "filterTokenInput" })
+      );
+    }
+  };
+
+  var BUIFilterTokenCreateButton66 = function (props) {
+    if (props.x === 163) {
+      return React.createElement(
+        "div",
+        { className: "_1tc" },
+        React.createElement(XUIButton4, { x: 162 })
+      );
+    }
+  };
+
+  var BUIFilterTokenizer67 = function (props) {
+    if (props.x === 164) {
+      return React.createElement(
+        "div",
+        { className: "_5b-m  clearfix" },
+        undefined,
+        [],
+        React.createElement(BUIFilterToken65, { x: 159, key: "token0" }),
+        React.createElement(BUIFilterTokenCreateButton66, { x: 163 }),
+        null,
+        React.createElement("div", { className: "_49u3" })
+      );
+    }
+  };
+
+  var XUIAmbientNUX68 = function (props) {
+    if (props.x === 165) {
+      return null;
+    }
+    if (props.x === 189) {
+      return null;
+    }
+    if (props.x === 200) {
+      return null;
+    }
+  };
+
+  var XUIAmbientNUX69 = function (props) {
+    if (props.x === 166) {
+      return React.createElement(XUIAmbientNUX68, { x: 165 });
+    }
+    if (props.x === 190) {
+      return React.createElement(XUIAmbientNUX68, { x: 189 });
+    }
+    if (props.x === 201) {
+      return React.createElement(XUIAmbientNUX68, { x: 200 });
+    }
+  };
+
+  var AdsPEAmbientNUXMegaphone70 = function (props) {
+    if (props.x === 167) {
+      return React.createElement(
+        "span",
+        null,
+        React.createElement("span", { ref: "mainChild" }),
+        React.createElement(XUIAmbientNUX69, { x: 166, key: "nux" })
+      );
+    }
+  };
+
+  var AdsPEFilters71 = function (props) {
+    if (props.x === 168) {
+      return React.createElement(
+        "div",
+        { className: "_4rw_" },
+        React.createElement(AdsPEFiltersPopover58, { x: 144 }),
+        React.createElement(
+          "div",
+          { className: "_1eo" },
+          React.createElement(InputLabel61, { x: 147 })
+        ),
+        React.createElement(BUIFilterTokenizer67, { x: 164 }),
+        "",
+        React.createElement(AdsPEAmbientNUXMegaphone70, { x: 167 })
+      );
+    }
+  };
+
+  var AdsPEFilterContainer72 = function (props) {
+    if (props.x === 169) {
+      return React.createElement(AdsPEFilters71, { x: 168 });
+    }
+  };
+
+  var AdsPETablePager73 = function (props) {
+    if (props.x === 172) {
+      return null;
+    }
+  };
+
+  var AdsPECampaignGroupTablePagerContainer74 = function (props) {
+    if (props.x === 173) {
+      return React.createElement(AdsPETablePager73, { x: 172 });
+    }
+  };
+
+  var AdsPETablePagerContainer75 = function (props) {
+    if (props.x === 174) {
+      return React.createElement(AdsPECampaignGroupTablePagerContainer74, { x: 173 });
+    }
+  };
+
+  var ReactXUIError76 = function (props) {
+    if (props.x === 181) {
+      return React.createElement(AbstractButton3, { x: 180 });
+    }
+    if (props.x === 216) {
+      return React.createElement(
+        "div",
+        { className: "_40bf _2vl4 _1h18" },
+        null,
+        null,
+        React.createElement(
+          "div",
+          { className: "_2vl9 _1h1f", style: { "backgroundColor": "#fff" } },
+          React.createElement(
+            "div",
+            { className: "_2vla _1h1g" },
+            React.createElement(
+              "div",
+              null,
+              null,
+              React.createElement("textarea", { ref: "input", className: "_2vli _2vlj _1h26 _1h27", dir: "auto", disabled: undefined, id: undefined, maxLength: null, value: "Test Campaign", onBlur: function () {}, onChange: function () {}, onFocus: function () {}, onKeyDown: function () {} }),
+              null
+            ),
+            React.createElement("div", { ref: "shadowText", "aria-hidden": "true", className: "_2vlk" })
+          )
+        ),
+        null
+      );
+    }
+    if (props.x === 221) {
+      return React.createElement(XUICard94, { x: 220 });
+    }
+    if (props.x === 250) {
+      return React.createElement(XUICard94, { x: 249 });
+    }
+    if (props.x === 280) {
+      return React.createElement(XUICard94, { x: 279 });
+    }
+  };
+
+  var BUIPopoverButton77 = function (props) {
+    if (props.x === 182) {
+      return React.createElement(ReactXUIError76, { x: 181 });
+    }
+  };
+
+  var BUIDateRangePicker78 = function (props) {
+    if (props.x === 184) {
+      return React.createElement(
+        "span",
+        null,
+        React.createElement(BUIPopoverButton77, { x: 182, ref: function () {} }),
+        [React.createElement(Constructor49, { x: 183, key: "layer/.0" })]
+      );
+    }
+  };
+
+  var AdsPEStatsRangePicker79 = function (props) {
+    if (props.x === 185) {
+      return React.createElement(BUIDateRangePicker78, { x: 184 });
+    }
+  };
+
+  var AdsPEStatRange80 = function (props) {
+    if (props.x === 191) {
+      return React.createElement(
+        "div",
+        { className: "_3c5k" },
+        React.createElement(
+          "span",
+          { className: "_3c5j" },
+          "Stats:"
+        ),
+        React.createElement(
+          "span",
+          { className: "_3c5l" },
+          React.createElement(AdsPEStatsRangePicker79, { x: 185 }),
+          React.createElement(XUIButton4, { x: 188, key: "settings", ref: "PE_TABLE_LIST_SETTING" })
+        ),
+        [React.createElement(XUIAmbientNUX69, { x: 190, key: "roasNUX/.0" })]
+      );
+    }
+  };
+
+  var AdsPEStatRangeContainer81 = function (props) {
+    if (props.x === 192) {
+      return React.createElement(AdsPEStatRange80, { x: 191 });
+    }
+  };
+
+  var AdsPESideTrayTabButton82 = function (props) {
+    if (props.x === 196) {
+      return React.createElement(
+        "div",
+        { className: "_1-ly _59j9 _d9a", onClick: function () {} },
+        React.createElement(ReactImage0, { x: 195 }),
+        React.createElement("div", { className: "_vf7" }),
+        React.createElement("div", { className: "_vf8" })
+      );
+    }
+    if (props.x === 199) {
+      return React.createElement(
+        "div",
+        { className: " _1-lz _d9a", onClick: function () {} },
+        React.createElement(ReactImage0, { x: 198 }),
+        React.createElement("div", { className: "_vf7" }),
+        React.createElement("div", { className: "_vf8" })
+      );
+    }
+    if (props.x === 203) {
+      return null;
+    }
+  };
+
+  var AdsPEEditorTrayTabButton83 = function (props) {
+    if (props.x === 197) {
+      return React.createElement(AdsPESideTrayTabButton82, { x: 196 });
+    }
+  };
+
+  var AdsPEInsightsTrayTabButton84 = function (props) {
+    if (props.x === 202) {
+      return React.createElement(
+        "span",
+        null,
+        React.createElement(AdsPESideTrayTabButton82, { x: 199, ref: "PE_INSIGHTS_TAB_ICON" }),
+        React.createElement(XUIAmbientNUX69, { x: 201, key: "roasNUX" })
+      );
+    }
+  };
+
+  var AdsPENekoDebuggerTrayTabButton85 = function (props) {
+    if (props.x === 204) {
+      return React.createElement(AdsPESideTrayTabButton82, { x: 203 });
+    }
+  };
+
+  var AdsPEEditorChildLink86 = function (props) {
+    if (props.x === 211) {
+      return React.createElement(
+        "div",
+        { className: "_3ywr" },
+        React.createElement(Link2, { x: 208 }),
+        React.createElement(
+          "span",
+          { className: "_3ywq" },
+          "|"
+        ),
+        React.createElement(Link2, { x: 210 })
+      );
+    }
+  };
+
+  var AdsPEEditorChildLinkContainer87 = function (props) {
+    if (props.x === 212) {
+      return React.createElement(AdsPEEditorChildLink86, { x: 211 });
+    }
+  };
+
+  var AdsPEHeaderSection88 = function (props) {
+    if (props.x === 213) {
+      return React.createElement(
+        "div",
+        { className: "_yke" },
+        React.createElement("div", { className: "_2x9d _pr-" }),
+        React.createElement(XUIText29, { x: 205 }),
+        React.createElement(
+          "div",
+          { className: "_3a-a" },
+          React.createElement(
+            "div",
+            { className: "_3a-b" },
+            React.createElement(XUIText29, { x: 206 })
+          )
+        ),
+        React.createElement(AdsPEEditorChildLinkContainer87, { x: 212 })
+      );
+    }
+  };
+
+  var AdsPECampaignGroupHeaderSectionContainer89 = function (props) {
+    if (props.x === 214) {
+      return React.createElement(AdsPEHeaderSection88, { x: 213 });
+    }
+  };
+
+  var AdsEditorLoadingErrors90 = function (props) {
+    if (props.x === 215) {
+      return null;
+    }
+  };
+
+  var AdsTextInput91 = function (props) {
+    if (props.x === 217) {
+      return React.createElement(ReactXUIError76, { x: 216 });
+    }
+  };
+
+  var BUIFormElement92 = function (props) {
+    if (props.x === 218) {
+      return React.createElement(
+        "div",
+        { className: "_5521 clearfix" },
+        React.createElement(
+          "div",
+          { className: "_5522 _3w5q" },
+          React.createElement(
+            "label",
+            { onClick: undefined, htmlFor: "1467872040612:1961945894", className: "_5523 _3w5r" },
+            "Campaign Name",
+            null
+          )
+        ),
+        React.createElement(
+          "div",
+          { className: "_5527" },
+          React.createElement(
+            "div",
+            { className: "_5528" },
+            React.createElement(
+              "span",
+              { key: ".0", className: "_40bg", density: "snug", labelPosition: "left", id: "1467872040612:1961945894" },
+              React.createElement(AdsTextInput91, { x: 217, key: "nameEditor98010048849317", ref: "nameTextInput" }),
+              null
+            )
+          ),
+          null
+        )
+      );
+    }
+  };
+
+  var BUIForm93 = function (props) {
+    if (props.x === 219) {
+      return React.createElement(
+        "div",
+        { className: "_5ks1 _550r  _550t _550y _3w5n" },
+        React.createElement(BUIFormElement92, { x: 218, key: ".0" })
+      );
+    }
+  };
+
+  var XUICard94 = function (props) {
+    if (props.x === 220) {
+      return React.createElement(
+        "div",
+        { className: "_40bc _12k2 _4-u2  _4-u8", xuiErrorPosition: "above", background: "white" },
+        React.createElement(BUIForm93, { x: 219 })
+      );
+    }
+    if (props.x === 249) {
+      return React.createElement(
+        "div",
+        { xuiErrorPosition: "above", className: "_12k2 _4-u2  _4-u8", background: "white" },
+        React.createElement(AdsCardHeader103, { x: 230 }),
+        React.createElement(AdsCardSection108, { x: 248 })
+      );
+    }
+    if (props.x === 279) {
+      return React.createElement(
+        "div",
+        { xuiErrorPosition: "above", className: "_12k2 _4-u2  _4-u8", background: "white" },
+        React.createElement(AdsCardLeftRightHeader122, { x: 278 })
+      );
+    }
+  };
+
+  var AdsCard95 = function (props) {
+    if (props.x === 222) {
+      return React.createElement(ReactXUIError76, { x: 221 });
+    }
+    if (props.x === 251) {
+      return React.createElement(ReactXUIError76, { x: 250 });
+    }
+    if (props.x === 281) {
+      return React.createElement(ReactXUIError76, { x: 280 });
+    }
+  };
+
+  var AdsEditorNameSection96 = function (props) {
+    if (props.x === 223) {
+      return React.createElement(AdsCard95, { x: 222 });
+    }
+  };
+
+  var AdsCampaignGroupNameSectionContainer97 = function (props) {
+    if (props.x === 224) {
+      return React.createElement(AdsEditorNameSection96, { x: 223, key: "nameSection98010048849317" });
+    }
+  };
+
+  var _render98 = function (props) {
+    if (props.x === 225) {
+      return React.createElement(AdsCampaignGroupNameSectionContainer97, { x: 224 });
+    }
+  };
+
+  var AdsPluginWrapper99 = function (props) {
+    if (props.x === 226) {
+      return React.createElement(_render98, { x: 225 });
+    }
+    if (props.x === 255) {
+      return React.createElement(_render111, { x: 254 });
+    }
+    if (props.x === 258) {
+      return React.createElement(_render113, { x: 257 });
+    }
+    if (props.x === 287) {
+      return React.createElement(_render127, { x: 286 });
+    }
+    if (props.x === 291) {
+      return React.createElement(_render130, { x: 290 });
+    }
+  };
+
+  var XUICardHeaderTitle100 = function (props) {
+    if (props.x === 227) {
+      return React.createElement(
+        "span",
+        { itemComponent: "span", className: "_38my" },
+        "Campaign Details",
+        null,
+        React.createElement("span", { className: "_c1c" })
+      );
+    }
+    if (props.x === 265) {
+      return React.createElement(
+        "span",
+        { itemComponent: "span", className: "_38my" },
+        [React.createElement(
+          "span",
+          null,
+          "Campaign ID",
+          ": ",
+          "98010048849317"
+        ), React.createElement(
+          "div",
+          { className: "_5lh9" },
+          React.createElement(FluxContainer_AdsCampaignGroupStatusSwitchContainer_119, { x: 264 })
+        )],
+        null,
+        React.createElement("span", { className: "_c1c" })
+      );
+    }
+  };
+
+  var XUICardSection101 = function (props) {
+    if (props.x === 228) {
+      return React.createElement(
+        "div",
+        { className: "_5dw9 _5dwa _4-u3", background: "transparent" },
+        [React.createElement(XUICardHeaderTitle100, { x: 227, key: ".0" })],
+        undefined,
+        undefined,
+        React.createElement("div", { className: "_3s3-" })
+      );
+    }
+    if (props.x === 247) {
+      return React.createElement(
+        "div",
+        { className: "_12jy _4-u3", background: "transparent" },
+        React.createElement(
+          "div",
+          { className: "_3-8j" },
+          React.createElement(FlexibleBlock105, { x: 233 }),
+          React.createElement(FlexibleBlock105, { x: 236 }),
+          React.createElement(FlexibleBlock105, { x: 246 }),
+          null,
+          null
+        )
+      );
+    }
+  };
+
+  var XUICardHeader102 = function (props) {
+    if (props.x === 229) {
+      return React.createElement(XUICardSection101, { x: 228 });
+    }
+  };
+
+  var AdsCardHeader103 = function (props) {
+    if (props.x === 230) {
+      return React.createElement(XUICardHeader102, { x: 229 });
+    }
+  };
+
+  var AdsLabeledField104 = function (props) {
+    if (props.x === 231) {
+      return React.createElement(
+        "div",
+        { className: "_2oc6 _3bvz", label: "Objective", labelSize: "small", optionalText: "(optional)" },
+        React.createElement(
+          "label",
+          { className: "_4el4 _3qwj _3hy-", htmlFor: undefined },
+          "Objective "
+        ),
+        null,
+        React.createElement("div", { className: "_3bv-" })
+      );
+    }
+    if (props.x === 234) {
+      return React.createElement(
+        "div",
+        { className: "_2oc6 _3bvz", label: "Buying Type", labelSize: "small", optionalText: "(optional)" },
+        React.createElement(
+          "label",
+          { className: "_4el4 _3qwj _3hy-", htmlFor: undefined },
+          "Buying Type "
+        ),
+        null,
+        React.createElement("div", { className: "_3bv-" })
+      );
+    }
+    if (props.x === 240) {
+      return React.createElement(
+        "div",
+        { className: "_2oc6 _3bvz", helpText: "Set an overall spending limit for your ad campaign. This means your ad sets in the campaign will stop once you've reached your spending limit.", label: "Campaign Spending Limit", labelSize: "small", optionalText: "(optional)" },
+        React.createElement(
+          "label",
+          { className: "_4el4 _3qwj _3hy-", htmlFor: undefined },
+          "Campaign Spending Limit "
+        ),
+        React.createElement(AdsHelpLink63, { x: 239 }),
+        React.createElement("div", { className: "_3bv-" })
+      );
+    }
+  };
+
+  var FlexibleBlock105 = function (props) {
+    if (props.x === 233) {
+      return React.createElement(LeftRight21, { x: 232 });
+    }
+    if (props.x === 236) {
+      return React.createElement(LeftRight21, { x: 235 });
+    }
+    if (props.x === 246) {
+      return React.createElement(LeftRight21, { x: 245 });
+    }
+  };
+
+  var AdsBulkCampaignSpendCapField106 = function (props) {
+    if (props.x === 243) {
+      return React.createElement(
+        "div",
+        { className: "_33dv" },
+        "",
+        React.createElement(Link2, { x: 242 }),
+        " (optional)"
+      );
+    }
+  };
+
+  var FluxContainer_AdsCampaignGroupSpendCapContainer_107 = function (props) {
+    if (props.x === 244) {
+      return React.createElement(AdsBulkCampaignSpendCapField106, { x: 243 });
+    }
+  };
+
+  var AdsCardSection108 = function (props) {
+    if (props.x === 248) {
+      return React.createElement(XUICardSection101, { x: 247 });
+    }
+  };
+
+  var AdsEditorCampaignGroupDetailsSection109 = function (props) {
+    if (props.x === 252) {
+      return React.createElement(AdsCard95, { x: 251 });
+    }
+  };
+
+  var AdsEditorCampaignGroupDetailsSectionContainer110 = function (props) {
+    if (props.x === 253) {
+      return React.createElement(AdsEditorCampaignGroupDetailsSection109, { x: 252, key: "campaignGroupDetailsSection98010048849317" });
+    }
+  };
+
+  var _render111 = function (props) {
+    if (props.x === 254) {
+      return React.createElement(AdsEditorCampaignGroupDetailsSectionContainer110, { x: 253 });
+    }
+  };
+
+  var FluxContainer_AdsEditorToplineDetailsSectionContainer_112 = function (props) {
+    if (props.x === 256) {
+      return null;
+    }
+  };
+
+  var _render113 = function (props) {
+    if (props.x === 257) {
+      return React.createElement(FluxContainer_AdsEditorToplineDetailsSectionContainer_112, { x: 256 });
+    }
+  };
+
+  var AdsStickyArea114 = function (props) {
+    if (props.x === 259) {
+      return React.createElement(
+        "div",
+        { inContainingBlock: true },
+        React.createElement("div", { ref: "sticky", onWheel: function () {} })
+      );
+    }
+    if (props.x === 292) {
+      return React.createElement(
+        "div",
+        { inContainingBlock: true },
+        React.createElement(
+          "div",
+          { ref: "sticky", onWheel: function () {} },
+          [React.createElement(
+            "div",
+            { key: "campaign_group_errors_section98010048849317" },
+            React.createElement(AdsPluginWrapper99, { x: 291 })
+          )]
+        )
+      );
+    }
+  };
+
+  var FluxContainer_AdsEditorColumnContainer_115 = function (props) {
+    if (props.x === 260) {
+      return React.createElement(
+        "div",
+        null,
+        [React.createElement(
+          "div",
+          { key: "campaign_group_name_section98010048849317" },
+          React.createElement(AdsPluginWrapper99, { x: 226 })
+        ), React.createElement(
+          "div",
+          { key: "campaign_group_basic_section98010048849317" },
+          React.createElement(AdsPluginWrapper99, { x: 255 })
+        ), React.createElement(
+          "div",
+          { key: "campaign_group_topline_section98010048849317" },
+          React.createElement(AdsPluginWrapper99, { x: 258 })
+        )],
+        React.createElement(AdsStickyArea114, { x: 259 })
+      );
+    }
+    if (props.x === 293) {
+      return React.createElement(
+        "div",
+        null,
+        [React.createElement(
+          "div",
+          { key: "campaign_group_navigation_section98010048849317" },
+          React.createElement(AdsPluginWrapper99, { x: 287 })
+        )],
+        React.createElement(AdsStickyArea114, { x: 292 })
+      );
+    }
+  };
+
+  var BUISwitch116 = function (props) {
+    if (props.x === 261) {
+      return React.createElement(
+        "div",
+        { "data-hover": "tooltip", "data-tooltip-content": "Currently active. Click this switch to deactivate it.", "data-tooltip-position": "below", disabled: false, value: true, onToggle: function () {}, animate: true, className: "_128j _128k _128n", role: "checkbox", "aria-checked": "true" },
+        React.createElement(
+          "div",
+          { className: "_128o", onClick: function () {}, onKeyDown: function () {}, onMouseDown: function () {}, tabIndex: "0" },
+          React.createElement("div", { className: "_128p" })
+        ),
+        null
+      );
+    }
+  };
+
+  var AdsStatusSwitchInternal117 = function (props) {
+    if (props.x === 262) {
+      return React.createElement(BUISwitch116, { x: 261 });
+    }
+  };
+
+  var AdsStatusSwitch118 = function (props) {
+    if (props.x === 263) {
+      return React.createElement(AdsStatusSwitchInternal117, { x: 262 });
+    }
+  };
+
+  var FluxContainer_AdsCampaignGroupStatusSwitchContainer_119 = function (props) {
+    if (props.x === 264) {
+      return React.createElement(AdsStatusSwitch118, { x: 263, key: "status98010048849317" });
+    }
+  };
+
+  var AdsLinksMenu120 = function (props) {
+    if (props.x === 275) {
+      return React.createElement(ReactPopoverMenu20, { x: 274 });
+    }
+  };
+
+  var FluxContainer_AdsPluginizedLinksMenuContainer_121 = function (props) {
+    if (props.x === 276) {
+      return React.createElement(
+        "div",
+        null,
+        null,
+        React.createElement(AdsLinksMenu120, { x: 275 })
+      );
+    }
+  };
+
+  var AdsCardLeftRightHeader122 = function (props) {
+    if (props.x === 278) {
+      return React.createElement(LeftRight21, { x: 277 });
+    }
+  };
+
+  var AdsPEIDSection123 = function (props) {
+    if (props.x === 282) {
+      return React.createElement(AdsCard95, { x: 281 });
+    }
+  };
+
+  var FluxContainer_AdsPECampaignGroupIDSectionContainer_124 = function (props) {
+    if (props.x === 283) {
+      return React.createElement(AdsPEIDSection123, { x: 282 });
+    }
+  };
+
+  var DeferredComponent125 = function (props) {
+    if (props.x === 284) {
+      return React.createElement(FluxContainer_AdsPECampaignGroupIDSectionContainer_124, { x: 283 });
+    }
+  };
+
+  var BootloadedComponent126 = function (props) {
+    if (props.x === 285) {
+      return React.createElement(DeferredComponent125, { x: 284 });
+    }
+  };
+
+  var _render127 = function (props) {
+    if (props.x === 286) {
+      return React.createElement(BootloadedComponent126, { x: 285 });
+    }
+  };
+
+  var AdsEditorErrorsCard128 = function (props) {
+    if (props.x === 288) {
+      return null;
+    }
+  };
+
+  var FluxContainer_FunctionalContainer_129 = function (props) {
+    if (props.x === 289) {
+      return React.createElement(AdsEditorErrorsCard128, { x: 288 });
+    }
+  };
+
+  var _render130 = function (props) {
+    if (props.x === 290) {
+      return React.createElement(FluxContainer_FunctionalContainer_129, { x: 289 });
+    }
+  };
+
+  var AdsEditorMultiColumnLayout131 = function (props) {
+    if (props.x === 294) {
+      return React.createElement(
+        "div",
+        { className: "_psh" },
+        React.createElement(
+          "div",
+          { className: "_3cc0" },
+          React.createElement(
+            "div",
+            null,
+            React.createElement(AdsEditorLoadingErrors90, { x: 215, key: ".0" }),
+            React.createElement(
+              "div",
+              { className: "_3ms3" },
+              React.createElement(
+                "div",
+                { className: "_3ms4" },
+                React.createElement(FluxContainer_AdsEditorColumnContainer_115, { x: 260, key: ".1" })
+              ),
+              React.createElement(
+                "div",
+                { className: "_3pvg" },
+                React.createElement(FluxContainer_AdsEditorColumnContainer_115, { x: 293, key: ".2" })
+              )
+            )
+          )
+        )
+      );
+    }
+  };
+
+  var AdsPECampaignGroupEditor132 = function (props) {
+    if (props.x === 295) {
+      return React.createElement(
+        "div",
+        null,
+        React.createElement(AdsPECampaignGroupHeaderSectionContainer89, { x: 214 }),
+        React.createElement(AdsEditorMultiColumnLayout131, { x: 294 })
+      );
+    }
+  };
+
+  var AdsPECampaignGroupEditorContainer133 = function (props) {
+    if (props.x === 296) {
+      return React.createElement(AdsPECampaignGroupEditor132, { x: 295 });
+    }
+  };
+
+  var AdsPESideTrayTabContent134 = function (props) {
+    if (props.x === 297) {
+      return React.createElement(
+        "div",
+        { className: "_1o_8 _44ra _5cyn" },
+        React.createElement(AdsPECampaignGroupEditorContainer133, { x: 296 })
+      );
+    }
+  };
+
+  var AdsPEEditorTrayTabContentContainer135 = function (props) {
+    if (props.x === 298) {
+      return React.createElement(AdsPESideTrayTabContent134, { x: 297 });
+    }
+  };
+
+  var AdsPEMultiTabDrawer136 = function (props) {
+    if (props.x === 299) {
+      return React.createElement(
+        "div",
+        { className: "_2kev _2kex" },
+        React.createElement(
+          "div",
+          { className: "_5yno" },
+          React.createElement(AdsPEEditorTrayTabButton83, { x: 197, key: "editor_tray_button" }),
+          React.createElement(AdsPEInsightsTrayTabButton84, { x: 202, key: "insights_tray_button" }),
+          React.createElement(AdsPENekoDebuggerTrayTabButton85, { x: 204, key: "neko_debugger_tray_button" })
+        ),
+        React.createElement(
+          "div",
+          { className: "_5ynn" },
+          React.createElement(AdsPEEditorTrayTabContentContainer135, { x: 298, key: "EDITOR_DRAWER" }),
+          null
+        )
+      );
+    }
+  };
+
+  var FluxContainer_AdsPEMultiTabDrawerContainer_137 = function (props) {
+    if (props.x === 300) {
+      return React.createElement(AdsPEMultiTabDrawer136, { x: 299 });
+    }
+  };
+
+  var AdsPESimpleOrganizer138 = function (props) {
+    if (props.x === 309) {
+      return React.createElement(
+        "div",
+        { className: "_tm2" },
+        React.createElement(XUIButton4, { x: 304 }),
+        React.createElement(XUIButton4, { x: 306 }),
+        React.createElement(XUIButton4, { x: 308 })
+      );
+    }
+  };
+
+  var AdsPEOrganizerContainer139 = function (props) {
+    if (props.x === 310) {
+      return React.createElement(
+        "div",
+        null,
+        React.createElement(AdsPESimpleOrganizer138, { x: 309 })
+      );
+    }
+  };
+
+  var FixedDataTableColumnResizeHandle140 = function (props) {
+    if (props.x === 313) {
+      return React.createElement(
+        "div",
+        { className: "_3487 _3488 _3489", style: { "width": 0, "height": 25, "left": 0 } },
+        React.createElement("div", { className: "_348a", style: { "height": 25 } })
+      );
+    }
+  };
+
+  var AdsPETableHeader141 = function (props) {
+    if (props.x === 315) {
+      return React.createElement(
+        "div",
+        { className: "_1cig _1ksv _1vd7 _4h2r", id: undefined },
+        React.createElement(ReactImage0, { x: 314 }),
+        React.createElement(
+          "span",
+          { className: "_1cid" },
+          "Campaigns"
+        )
+      );
+    }
+    if (props.x === 320) {
+      return React.createElement(
+        "div",
+        { className: "_1cig _1vd7 _4h2r", id: undefined },
+        null,
+        React.createElement(
+          "span",
+          { className: "_1cid" },
+          "Performance"
+        )
+      );
+    }
+    if (props.x === 323) {
+      return React.createElement(
+        "div",
+        { className: "_1cig _1vd7 _4h2r", id: undefined },
+        null,
+        React.createElement(
+          "span",
+          { className: "_1cid" },
+          "Overview"
+        )
+      );
+    }
+    if (props.x === 326) {
+      return React.createElement(
+        "div",
+        { className: "_1cig _1vd7 _4h2r", id: undefined },
+        null,
+        React.createElement(
+          "span",
+          { className: "_1cid" },
+          "Toplines"
+        )
+      );
+    }
+    if (props.x === 329) {
+      return React.createElement("div", { className: "_1cig _1vd7 _4h2r", id: undefined });
+    }
+    if (props.x === 340) {
+      return React.createElement(
+        "div",
+        { className: "_1cig _25fg", id: undefined },
+        null,
+        React.createElement(
+          "span",
+          { className: "_1cid" },
+          "Campaign Name"
+        )
+      );
+    }
+    if (props.x === 346) {
+      return React.createElement(
+        "div",
+        { className: "_1cig _25fg", id: undefined, "data-tooltip-content": "Changed", "data-hover": "tooltip" },
+        React.createElement(ReactImage0, { x: 345 }),
+        null
+      );
+    }
+    if (props.x === 352) {
+      return React.createElement(
+        "div",
+        { className: "_1cig _25fg", id: "ads_pe_table_error_header", "data-tooltip-content": "Errors", "data-hover": "tooltip" },
+        React.createElement(ReactImage0, { x: 351 }),
+        null
+      );
+    }
+    if (props.x === 357) {
+      return React.createElement(
+        "div",
+        { className: "_1cig _25fg", id: undefined },
+        null,
+        React.createElement(
+          "span",
+          { className: "_1cid" },
+          "Status"
+        )
+      );
+    }
+    if (props.x === 362) {
+      return React.createElement(
+        "div",
+        { className: "_1cig _25fg", id: undefined },
+        null,
+        React.createElement(
+          "span",
+          { className: "_1cid" },
+          "Delivery"
+        )
+      );
+    }
+    if (props.x === 369) {
+      return React.createElement(
+        "div",
+        { className: "_1cig _25fg", id: undefined },
+        null,
+        React.createElement(
+          "span",
+          { className: "_1cid" },
+          "Results"
+        )
+      );
+    }
+    if (props.x === 374) {
+      return React.createElement(
+        "div",
+        { className: "_1cig _25fg", id: undefined },
+        null,
+        React.createElement(
+          "span",
+          { className: "_1cid" },
+          "Cost"
+        )
+      );
+    }
+    if (props.x === 379) {
+      return React.createElement(
+        "div",
+        { className: "_1cig _25fg", id: undefined },
+        null,
+        React.createElement(
+          "span",
+          { className: "_1cid" },
+          "Reach"
+        )
+      );
+    }
+    if (props.x === 384) {
+      return React.createElement(
+        "div",
+        { className: "_1cig _25fg", id: undefined },
+        null,
+        React.createElement(
+          "span",
+          { className: "_1cid" },
+          "Impressions"
+        )
+      );
+    }
+    if (props.x === 389) {
+      return React.createElement(
+        "div",
+        { className: "_1cig _25fg", id: undefined },
+        null,
+        React.createElement(
+          "span",
+          { className: "_1cid" },
+          "Clicks"
+        )
+      );
+    }
+    if (props.x === 394) {
+      return React.createElement(
+        "div",
+        { className: "_1cig _25fg", id: undefined },
+        null,
+        React.createElement(
+          "span",
+          { className: "_1cid" },
+          "Avg. CPM"
+        )
+      );
+    }
+    if (props.x === 399) {
+      return React.createElement(
+        "div",
+        { className: "_1cig _25fg", id: undefined },
+        null,
+        React.createElement(
+          "span",
+          { className: "_1cid" },
+          "Avg. CPC"
+        )
+      );
+    }
+    if (props.x === 404) {
+      return React.createElement(
+        "div",
+        { className: "_1cig _25fg", id: undefined },
+        null,
+        React.createElement(
+          "span",
+          { className: "_1cid" },
+          "CTR %"
+        )
+      );
+    }
+    if (props.x === 409) {
+      return React.createElement(
+        "div",
+        { className: "_1cig _25fg", id: undefined },
+        null,
+        React.createElement(
+          "span",
+          { className: "_1cid" },
+          "Spent"
+        )
+      );
+    }
+    if (props.x === 414) {
+      return React.createElement(
+        "div",
+        { className: "_1cig _25fg", id: undefined },
+        null,
+        React.createElement(
+          "span",
+          { className: "_1cid" },
+          "Objective"
+        )
+      );
+    }
+    if (props.x === 419) {
+      return React.createElement(
+        "div",
+        { className: "_1cig _25fg", id: undefined },
+        null,
+        React.createElement(
+          "span",
+          { className: "_1cid" },
+          "Buying Type"
+        )
+      );
+    }
+    if (props.x === 424) {
+      return React.createElement(
+        "div",
+        { className: "_1cig _25fg", id: undefined },
+        null,
+        React.createElement(
+          "span",
+          { className: "_1cid" },
+          "Campaign ID"
+        )
+      );
+    }
+    if (props.x === 429) {
+      return React.createElement(
+        "div",
+        { className: "_1cig _25fg", id: undefined },
+        null,
+        React.createElement(
+          "span",
+          { className: "_1cid" },
+          "Start"
+        )
+      );
+    }
+    if (props.x === 434) {
+      return React.createElement(
+        "div",
+        { className: "_1cig _25fg", id: undefined },
+        null,
+        React.createElement(
+          "span",
+          { className: "_1cid" },
+          "End"
+        )
+      );
+    }
+    if (props.x === 439) {
+      return React.createElement(
+        "div",
+        { className: "_1cig _25fg", id: undefined },
+        null,
+        React.createElement(
+          "span",
+          { className: "_1cid" },
+          "Date created"
+        )
+      );
+    }
+    if (props.x === 444) {
+      return React.createElement(
+        "div",
+        { className: "_1cig _25fg", id: undefined },
+        null,
+        React.createElement(
+          "span",
+          { className: "_1cid" },
+          "Date last edited"
+        )
+      );
+    }
+    if (props.x === 449) {
+      return React.createElement(
+        "div",
+        { className: "_1cig _25fg _4h2r", id: undefined },
+        null,
+        React.createElement(
+          "span",
+          { className: "_1cid" },
+          "Tags"
+        )
+      );
+    }
+    if (props.x === 452) {
+      return React.createElement("div", { className: "_1cig _25fg _4h2r", id: undefined });
+    }
+  };
+
+  var TransitionCell142 = function (props) {
+    if (props.x === 316) {
+      return React.createElement(
+        "div",
+        { isHeaderCell: true, label: "Campaigns", dataKey: 0, groupHeaderRenderer: function () {}, groupHeaderLabels: {}, groupHeaderData: {}, columnKey: undefined, height: 40, width: 721, rowIndex: 0, className: "_4lgc _4h2u", style: { "height": 40, "width": 721 } },
+        React.createElement(
+          "div",
+          { className: "_4lgd _4h2w" },
+          React.createElement(
+            "div",
+            { className: "_4lge _4h2x" },
+            React.createElement(AdsPETableHeader141, { x: 315 })
+          )
+        )
+      );
+    }
+    if (props.x === 321) {
+      return React.createElement(
+        "div",
+        { isHeaderCell: true, label: "Performance", dataKey: 1, groupHeaderRenderer: function () {}, groupHeaderLabels: {}, groupHeaderData: {}, columnKey: undefined, height: 40, width: 798, rowIndex: 0, className: "_4lgc _4h2u", style: { "height": 40, "width": 798 } },
+        React.createElement(
+          "div",
+          { className: "_4lgd _4h2w" },
+          React.createElement(
+            "div",
+            { className: "_4lge _4h2x" },
+            React.createElement(AdsPETableHeader141, { x: 320 })
+          )
+        )
+      );
+    }
+    if (props.x === 324) {
+      return React.createElement(
+        "div",
+        { isHeaderCell: true, label: "Overview", dataKey: 2, groupHeaderRenderer: function () {}, groupHeaderLabels: {}, groupHeaderData: {}, columnKey: undefined, height: 40, width: 1022, rowIndex: 0, className: "_4lgc _4h2u", style: { "height": 40, "width": 1022 } },
+        React.createElement(
+          "div",
+          { className: "_4lgd _4h2w" },
+          React.createElement(
+            "div",
+            { className: "_4lge _4h2x" },
+            React.createElement(AdsPETableHeader141, { x: 323 })
+          )
+        )
+      );
+    }
+    if (props.x === 327) {
+      return React.createElement(
+        "div",
+        { isHeaderCell: true, label: "Toplines", dataKey: 3, groupHeaderRenderer: function () {}, groupHeaderLabels: {}, groupHeaderData: {}, columnKey: undefined, height: 40, width: 0, rowIndex: 0, className: "_4lgc _4h2u", style: { "height": 40, "width": 0 } },
+        React.createElement(
+          "div",
+          { className: "_4lgd _4h2w" },
+          React.createElement(
+            "div",
+            { className: "_4lge _4h2x" },
+            React.createElement(AdsPETableHeader141, { x: 326 })
+          )
+        )
+      );
+    }
+    if (props.x === 330) {
+      return React.createElement(
+        "div",
+        { isHeaderCell: true, label: "", dataKey: 4, groupHeaderRenderer: function () {}, groupHeaderLabels: {}, groupHeaderData: {}, columnKey: undefined, height: 40, width: 25, rowIndex: 0, className: "_4lgc _4h2u", style: { "height": 40, "width": 25 } },
+        React.createElement(
+          "div",
+          { className: "_4lgd _4h2w" },
+          React.createElement(
+            "div",
+            { className: "_4lge _4h2x" },
+            React.createElement(AdsPETableHeader141, { x: 329 })
+          )
+        )
+      );
+    }
+    if (props.x === 338) {
+      return React.createElement(
+        "div",
+        { isHeaderCell: true, label: undefined, width: 42, dataKey: "common.id", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "common.id", height: 25, style: { "height": 25, "width": 42 } },
+        React.createElement(
+          "div",
+          { className: "_4lgd _4h2w" },
+          React.createElement(
+            "div",
+            { className: "_4lge _4h2x" },
+            React.createElement(XUICheckboxInput60, { x: 337 })
+          )
+        )
+      );
+    }
+    if (props.x === 343) {
+      return React.createElement(
+        "div",
+        { isHeaderCell: true, label: "Campaign Name", width: 400, dataKey: "campaignGroup.name", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "campaignGroup.name", height: 25, style: { "height": 25, "width": 400 } },
+        React.createElement(
+          "div",
+          { className: "_4lgd _4h2w" },
+          React.createElement(
+            "div",
+            { className: "_4lge _4h2x" },
+            React.createElement(FixedDataTableSortableHeader149, { x: 342 })
+          )
+        )
+      );
+    }
+    if (props.x === 349) {
+      return React.createElement(
+        "div",
+        { isHeaderCell: true, label: undefined, width: 33, dataKey: "edit_status", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "edit_status", height: 25, style: { "height": 25, "width": 33 } },
+        React.createElement(
+          "div",
+          { className: "_4lgd _4h2w" },
+          React.createElement(
+            "div",
+            { className: "_4lge _4h2x" },
+            React.createElement(FixedDataTableSortableHeader149, { x: 348 })
+          )
+        )
+      );
+    }
+    if (props.x === 355) {
+      return React.createElement(
+        "div",
+        { isHeaderCell: true, label: undefined, width: 36, dataKey: "errors", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "errors", height: 25, style: { "height": 25, "width": 36 } },
+        React.createElement(
+          "div",
+          { className: "_4lgd _4h2w" },
+          React.createElement(
+            "div",
+            { className: "_4lge _4h2x" },
+            React.createElement(FixedDataTableSortableHeader149, { x: 354 })
+          )
+        )
+      );
+    }
+    if (props.x === 360) {
+      return React.createElement(
+        "div",
+        { isHeaderCell: true, label: "Status", width: 60, dataKey: "campaignGroup.status", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "campaignGroup.status", height: 25, style: { "height": 25, "width": 60 } },
+        React.createElement(
+          "div",
+          { className: "_4lgd _4h2w" },
+          React.createElement(
+            "div",
+            { className: "_4lge _4h2x" },
+            React.createElement(FixedDataTableSortableHeader149, { x: 359 })
+          )
+        )
+      );
+    }
+    if (props.x === 365) {
+      return React.createElement(
+        "div",
+        { isHeaderCell: true, label: "Delivery", width: 150, dataKey: "derivedCampaignGroup.activity_status", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "derivedCampaignGroup.activity_status", height: 25, style: { "height": 25, "width": 150 } },
+        React.createElement(
+          "div",
+          { className: "_4lgd _4h2w" },
+          React.createElement(
+            "div",
+            { className: "_4lge _4h2x" },
+            React.createElement(FixedDataTableSortableHeader149, { x: 364 })
+          )
+        )
+      );
+    }
+    if (props.x === 372) {
+      return React.createElement(
+        "div",
+        { isHeaderCell: true, label: "Results", width: 140, dataKey: "stats.actions", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "stats.actions", height: 25, style: { "height": 25, "width": 140 } },
+        React.createElement(
+          "div",
+          { className: "_4lgd _4h2w" },
+          React.createElement(
+            "div",
+            { className: "_4lge _4h2x" },
+            React.createElement(FixedDataTableSortableHeader149, { x: 371 })
+          )
+        )
+      );
+    }
+    if (props.x === 377) {
+      return React.createElement(
+        "div",
+        { isHeaderCell: true, label: "Cost", width: 140, dataKey: "stats.cpa", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "stats.cpa", height: 25, style: { "height": 25, "width": 140 } },
+        React.createElement(
+          "div",
+          { className: "_4lgd _4h2w" },
+          React.createElement(
+            "div",
+            { className: "_4lge _4h2x" },
+            React.createElement(FixedDataTableSortableHeader149, { x: 376 })
+          )
+        )
+      );
+    }
+    if (props.x === 382) {
+      return React.createElement(
+        "div",
+        { isHeaderCell: true, label: "Reach", width: 80, dataKey: "stats.unique_impressions", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "stats.unique_impressions", height: 25, style: { "height": 25, "width": 80 } },
+        React.createElement(
+          "div",
+          { className: "_4lgd _4h2w" },
+          React.createElement(
+            "div",
+            { className: "_4lge _4h2x" },
+            React.createElement(FixedDataTableSortableHeader149, { x: 381 })
+          )
+        )
+      );
+    }
+    if (props.x === 387) {
+      return React.createElement(
+        "div",
+        { isHeaderCell: true, label: "Impressions", width: 80, dataKey: "stats.impressions", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "stats.impressions", height: 25, style: { "height": 25, "width": 80 } },
+        React.createElement(
+          "div",
+          { className: "_4lgd _4h2w" },
+          React.createElement(
+            "div",
+            { className: "_4lge _4h2x" },
+            React.createElement(FixedDataTableSortableHeader149, { x: 386 })
+          )
+        )
+      );
+    }
+    if (props.x === 392) {
+      return React.createElement(
+        "div",
+        { isHeaderCell: true, label: "Clicks", width: 60, dataKey: "stats.clicks", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "stats.clicks", height: 25, style: { "height": 25, "width": 60 } },
+        React.createElement(
+          "div",
+          { className: "_4lgd _4h2w" },
+          React.createElement(
+            "div",
+            { className: "_4lge _4h2x" },
+            React.createElement(FixedDataTableSortableHeader149, { x: 391 })
+          )
+        )
+      );
+    }
+    if (props.x === 397) {
+      return React.createElement(
+        "div",
+        { isHeaderCell: true, label: "Avg. CPM", width: 80, dataKey: "stats.avg_cpm", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "stats.avg_cpm", height: 25, style: { "height": 25, "width": 80 } },
+        React.createElement(
+          "div",
+          { className: "_4lgd _4h2w" },
+          React.createElement(
+            "div",
+            { className: "_4lge _4h2x" },
+            React.createElement(FixedDataTableSortableHeader149, { x: 396 })
+          )
+        )
+      );
+    }
+    if (props.x === 402) {
+      return React.createElement(
+        "div",
+        { isHeaderCell: true, label: "Avg. CPC", width: 78, dataKey: "stats.avg_cpc", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "stats.avg_cpc", height: 25, style: { "height": 25, "width": 78 } },
+        React.createElement(
+          "div",
+          { className: "_4lgd _4h2w" },
+          React.createElement(
+            "div",
+            { className: "_4lge _4h2x" },
+            React.createElement(FixedDataTableSortableHeader149, { x: 401 })
+          )
+        )
+      );
+    }
+    if (props.x === 407) {
+      return React.createElement(
+        "div",
+        { isHeaderCell: true, label: "CTR %", width: 70, dataKey: "stats.ctr", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "stats.ctr", height: 25, style: { "height": 25, "width": 70 } },
+        React.createElement(
+          "div",
+          { className: "_4lgd _4h2w" },
+          React.createElement(
+            "div",
+            { className: "_4lge _4h2x" },
+            React.createElement(FixedDataTableSortableHeader149, { x: 406 })
+          )
+        )
+      );
+    }
+    if (props.x === 412) {
+      return React.createElement(
+        "div",
+        { isHeaderCell: true, label: "Spent", width: 70, dataKey: "stats.spent_100", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "stats.spent_100", height: 25, style: { "height": 25, "width": 70 } },
+        React.createElement(
+          "div",
+          { className: "_4lgd _4h2w" },
+          React.createElement(
+            "div",
+            { className: "_4lge _4h2x" },
+            React.createElement(FixedDataTableSortableHeader149, { x: 411 })
+          )
+        )
+      );
+    }
+    if (props.x === 417) {
+      return React.createElement(
+        "div",
+        { isHeaderCell: true, label: "Objective", width: 200, dataKey: "campaignGroup.objective", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "campaignGroup.objective", height: 25, style: { "height": 25, "width": 200 } },
+        React.createElement(
+          "div",
+          { className: "_4lgd _4h2w" },
+          React.createElement(
+            "div",
+            { className: "_4lge _4h2x" },
+            React.createElement(FixedDataTableSortableHeader149, { x: 416 })
+          )
+        )
+      );
+    }
+    if (props.x === 422) {
+      return React.createElement(
+        "div",
+        { isHeaderCell: true, label: "Buying Type", width: 100, dataKey: "campaignGroup.buying_type", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "campaignGroup.buying_type", height: 25, style: { "height": 25, "width": 100 } },
+        React.createElement(
+          "div",
+          { className: "_4lgd _4h2w" },
+          React.createElement(
+            "div",
+            { className: "_4lge _4h2x" },
+            React.createElement(FixedDataTableSortableHeader149, { x: 421 })
+          )
+        )
+      );
+    }
+    if (props.x === 427) {
+      return React.createElement(
+        "div",
+        { isHeaderCell: true, label: "Campaign ID", width: 120, dataKey: "campaignGroup.id", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "campaignGroup.id", height: 25, style: { "height": 25, "width": 120 } },
+        React.createElement(
+          "div",
+          { className: "_4lgd _4h2w" },
+          React.createElement(
+            "div",
+            { className: "_4lge _4h2x" },
+            React.createElement(FixedDataTableSortableHeader149, { x: 426 })
+          )
+        )
+      );
+    }
+    if (props.x === 432) {
+      return React.createElement(
+        "div",
+        { isHeaderCell: true, label: "Start", width: 113, dataKey: "derivedCampaignGroup.startDate", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "derivedCampaignGroup.startDate", height: 25, style: { "height": 25, "width": 113 } },
+        React.createElement(
+          "div",
+          { className: "_4lgd _4h2w" },
+          React.createElement(
+            "div",
+            { className: "_4lge _4h2x" },
+            React.createElement(FixedDataTableSortableHeader149, { x: 431 })
+          )
+        )
+      );
+    }
+    if (props.x === 437) {
+      return React.createElement(
+        "div",
+        { isHeaderCell: true, label: "End", width: 113, dataKey: "derivedCampaignGroup.stopDate", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "derivedCampaignGroup.stopDate", height: 25, style: { "height": 25, "width": 113 } },
+        React.createElement(
+          "div",
+          { className: "_4lgd _4h2w" },
+          React.createElement(
+            "div",
+            { className: "_4lge _4h2x" },
+            React.createElement(FixedDataTableSortableHeader149, { x: 436 })
+          )
+        )
+      );
+    }
+    if (props.x === 442) {
+      return React.createElement(
+        "div",
+        { isHeaderCell: true, label: "Date created", width: 113, dataKey: "derivedCampaignGroup.createdDate", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "derivedCampaignGroup.createdDate", height: 25, style: { "height": 25, "width": 113 } },
+        React.createElement(
+          "div",
+          { className: "_4lgd _4h2w" },
+          React.createElement(
+            "div",
+            { className: "_4lge _4h2x" },
+            React.createElement(FixedDataTableSortableHeader149, { x: 441 })
+          )
+        )
+      );
+    }
+    if (props.x === 447) {
+      return React.createElement(
+        "div",
+        { isHeaderCell: true, label: "Date last edited", width: 113, dataKey: "derivedCampaignGroup.updatedDate", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "derivedCampaignGroup.updatedDate", height: 25, style: { "height": 25, "width": 113 } },
+        React.createElement(
+          "div",
+          { className: "_4lgd _4h2w" },
+          React.createElement(
+            "div",
+            { className: "_4lge _4h2x" },
+            React.createElement(FixedDataTableSortableHeader149, { x: 446 })
+          )
+        )
+      );
+    }
+    if (props.x === 450) {
+      return React.createElement(
+        "div",
+        { isHeaderCell: true, label: "Tags", width: 150, dataKey: "labels", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "labels", height: 25, style: { "height": 25, "width": 150 } },
+        React.createElement(
+          "div",
+          { className: "_4lgd _4h2w" },
+          React.createElement(
+            "div",
+            { className: "_4lge _4h2x" },
+            React.createElement(AdsPETableHeader141, { x: 449 })
+          )
+        )
+      );
+    }
+    if (props.x === 453) {
+      return React.createElement(
+        "div",
+        { isHeaderCell: true, label: "", width: 25, dataKey: "scrollbar_spacer", className: "_4lgc _4h2u", columnData: {}, cellRenderer: function () {}, headerDataGetter: function () {}, columnKey: "scrollbar_spacer", height: 25, style: { "height": 25, "width": 25 } },
+        React.createElement(
+          "div",
+          { className: "_4lgd _4h2w" },
+          React.createElement(
+            "div",
+            { className: "_4lge _4h2x" },
+            React.createElement(AdsPETableHeader141, { x: 452 })
+          )
+        )
+      );
+    }
+  };
+
+  var FixedDataTableCell143 = function (props) {
+    if (props.x === 317) {
+      return React.createElement(
+        "div",
+        { className: "_4lg0 _4h2m", style: { "height": 40, "width": 721, "left": 0 } },
+        undefined,
+        React.createElement(TransitionCell142, { x: 316 })
+      );
+    }
+    if (props.x === 322) {
+      return React.createElement(
+        "div",
+        { className: "_4lg0 _4h2m", style: { "height": 40, "width": 798, "left": 0 } },
+        undefined,
+        React.createElement(TransitionCell142, { x: 321 })
+      );
+    }
+    if (props.x === 325) {
+      return React.createElement(
+        "div",
+        { className: "_4lg0 _4h2m", style: { "height": 40, "width": 1022, "left": 798 } },
+        undefined,
+        React.createElement(TransitionCell142, { x: 324 })
+      );
+    }
+    if (props.x === 328) {
+      return React.createElement(
+        "div",
+        { className: "_4lg0 _4h2m", style: { "height": 40, "width": 0, "left": 1820 } },
+        undefined,
+        React.createElement(TransitionCell142, { x: 327 })
+      );
+    }
+    if (props.x === 331) {
+      return React.createElement(
+        "div",
+        { className: "_4lg0 _4h2m", style: { "height": 40, "width": 25, "left": 1820 } },
+        undefined,
+        React.createElement(TransitionCell142, { x: 330 })
+      );
+    }
+    if (props.x === 339) {
+      return React.createElement(
+        "div",
+        { className: "_4lg0 _4lg6 _4h2m", style: { "height": 25, "width": 42, "left": 0 } },
+        undefined,
+        React.createElement(TransitionCell142, { x: 338 })
+      );
+    }
+    if (props.x === 344) {
+      return React.createElement(
+        "div",
+        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 400, "left": 42 } },
+        React.createElement(
+          "div",
+          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+        ),
+        React.createElement(TransitionCell142, { x: 343 })
+      );
+    }
+    if (props.x === 350) {
+      return React.createElement(
+        "div",
+        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 33, "left": 442 } },
+        undefined,
+        React.createElement(TransitionCell142, { x: 349 })
+      );
+    }
+    if (props.x === 356) {
+      return React.createElement(
+        "div",
+        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 36, "left": 475 } },
+        undefined,
+        React.createElement(TransitionCell142, { x: 355 })
+      );
+    }
+    if (props.x === 361) {
+      return React.createElement(
+        "div",
+        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 60, "left": 511 } },
+        undefined,
+        React.createElement(TransitionCell142, { x: 360 })
+      );
+    }
+    if (props.x === 366) {
+      return React.createElement(
+        "div",
+        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 150, "left": 571 } },
+        React.createElement(
+          "div",
+          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+        ),
+        React.createElement(TransitionCell142, { x: 365 })
+      );
+    }
+    if (props.x === 373) {
+      return React.createElement(
+        "div",
+        { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 25, "width": 140, "left": 0 } },
+        React.createElement(
+          "div",
+          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+        ),
+        React.createElement(TransitionCell142, { x: 372 })
+      );
+    }
+    if (props.x === 378) {
+      return React.createElement(
+        "div",
+        { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 25, "width": 140, "left": 140 } },
+        React.createElement(
+          "div",
+          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+        ),
+        React.createElement(TransitionCell142, { x: 377 })
+      );
+    }
+    if (props.x === 383) {
+      return React.createElement(
+        "div",
+        { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 25, "width": 80, "left": 280 } },
+        React.createElement(
+          "div",
+          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+        ),
+        React.createElement(TransitionCell142, { x: 382 })
+      );
+    }
+    if (props.x === 388) {
+      return React.createElement(
+        "div",
+        { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 25, "width": 80, "left": 360 } },
+        React.createElement(
+          "div",
+          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+        ),
+        React.createElement(TransitionCell142, { x: 387 })
+      );
+    }
+    if (props.x === 393) {
+      return React.createElement(
+        "div",
+        { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 25, "width": 60, "left": 440 } },
+        React.createElement(
+          "div",
+          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+        ),
+        React.createElement(TransitionCell142, { x: 392 })
+      );
+    }
+    if (props.x === 398) {
+      return React.createElement(
+        "div",
+        { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 25, "width": 80, "left": 500 } },
+        React.createElement(
+          "div",
+          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+        ),
+        React.createElement(TransitionCell142, { x: 397 })
+      );
+    }
+    if (props.x === 403) {
+      return React.createElement(
+        "div",
+        { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 25, "width": 78, "left": 580 } },
+        React.createElement(
+          "div",
+          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+        ),
+        React.createElement(TransitionCell142, { x: 402 })
+      );
+    }
+    if (props.x === 408) {
+      return React.createElement(
+        "div",
+        { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 25, "width": 70, "left": 658 } },
+        React.createElement(
+          "div",
+          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+        ),
+        React.createElement(TransitionCell142, { x: 407 })
+      );
+    }
+    if (props.x === 413) {
+      return React.createElement(
+        "div",
+        { className: "_4lg0 _4lg5 _4h2p _4h2m", style: { "height": 25, "width": 70, "left": 728 } },
+        React.createElement(
+          "div",
+          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+        ),
+        React.createElement(TransitionCell142, { x: 412 })
+      );
+    }
+    if (props.x === 418) {
+      return React.createElement(
+        "div",
+        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 200, "left": 798 } },
+        React.createElement(
+          "div",
+          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+        ),
+        React.createElement(TransitionCell142, { x: 417 })
+      );
+    }
+    if (props.x === 423) {
+      return React.createElement(
+        "div",
+        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 100, "left": 998 } },
+        React.createElement(
+          "div",
+          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+        ),
+        React.createElement(TransitionCell142, { x: 422 })
+      );
+    }
+    if (props.x === 428) {
+      return React.createElement(
+        "div",
+        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 120, "left": 1098 } },
+        React.createElement(
+          "div",
+          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+        ),
+        React.createElement(TransitionCell142, { x: 427 })
+      );
+    }
+    if (props.x === 433) {
+      return React.createElement(
+        "div",
+        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 113, "left": 1218 } },
+        React.createElement(
+          "div",
+          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+        ),
+        React.createElement(TransitionCell142, { x: 432 })
+      );
+    }
+    if (props.x === 438) {
+      return React.createElement(
+        "div",
+        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 113, "left": 1331 } },
+        React.createElement(
+          "div",
+          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+        ),
+        React.createElement(TransitionCell142, { x: 437 })
+      );
+    }
+    if (props.x === 443) {
+      return React.createElement(
+        "div",
+        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 113, "left": 1444 } },
+        React.createElement(
+          "div",
+          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+        ),
+        React.createElement(TransitionCell142, { x: 442 })
+      );
+    }
+    if (props.x === 448) {
+      return React.createElement(
+        "div",
+        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 113, "left": 1557 } },
+        React.createElement(
+          "div",
+          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+        ),
+        React.createElement(TransitionCell142, { x: 447 })
+      );
+    }
+    if (props.x === 451) {
+      return React.createElement(
+        "div",
+        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 150, "left": 1670 } },
+        React.createElement(
+          "div",
+          { className: "_4lg9", style: { "height": 25 }, onMouseDown: function () {} },
+          React.createElement("div", { className: "_4lga _4lgb", style: { "height": 25 } })
+        ),
+        React.createElement(TransitionCell142, { x: 450 })
+      );
+    }
+    if (props.x === 454) {
+      return React.createElement(
+        "div",
+        { className: "_4lg0 _4h2m", style: { "height": 25, "width": 25, "left": 1820 } },
+        undefined,
+        React.createElement(TransitionCell142, { x: 453 })
+      );
+    }
+  };
+
+  var FixedDataTableCellGroupImpl144 = function (props) {
+    if (props.x === 318) {
+      return React.createElement(
+        "div",
+        { className: "_3pzj", style: { "height": 40, "position": "absolute", "width": 721, "zIndex": 2, "transform": "translate3d(0px,0px,0)", "backfaceVisibility": "hidden" } },
+        React.createElement(FixedDataTableCell143, { x: 317, key: "cell_0" })
+      );
+    }
+    if (props.x === 332) {
+      return React.createElement(
+        "div",
+        { className: "_3pzj", style: { "height": 40, "position": "absolute", "width": 1845, "zIndex": 0, "transform": "translate3d(0px,0px,0)", "backfaceVisibility": "hidden" } },
+        React.createElement(FixedDataTableCell143, { x: 322, key: "cell_0" }),
+        React.createElement(FixedDataTableCell143, { x: 325, key: "cell_1" }),
+        React.createElement(FixedDataTableCell143, { x: 328, key: "cell_2" }),
+        React.createElement(FixedDataTableCell143, { x: 331, key: "cell_3" })
+      );
+    }
+    if (props.x === 367) {
+      return React.createElement(
+        "div",
+        { className: "_3pzj", style: { "height": 25, "position": "absolute", "width": 721, "zIndex": 2, "transform": "translate3d(0px,0px,0)", "backfaceVisibility": "hidden" } },
+        React.createElement(FixedDataTableCell143, { x: 339, key: "cell_0" }),
+        React.createElement(FixedDataTableCell143, { x: 344, key: "cell_1" }),
+        React.createElement(FixedDataTableCell143, { x: 350, key: "cell_2" }),
+        React.createElement(FixedDataTableCell143, { x: 356, key: "cell_3" }),
+        React.createElement(FixedDataTableCell143, { x: 361, key: "cell_4" }),
+        React.createElement(FixedDataTableCell143, { x: 366, key: "cell_5" })
+      );
+    }
+    if (props.x === 455) {
+      return React.createElement(
+        "div",
+        { className: "_3pzj", style: { "height": 25, "position": "absolute", "width": 1845, "zIndex": 0, "transform": "translate3d(0px,0px,0)", "backfaceVisibility": "hidden" } },
+        React.createElement(FixedDataTableCell143, { x: 373, key: "cell_0" }),
+        React.createElement(FixedDataTableCell143, { x: 378, key: "cell_1" }),
+        React.createElement(FixedDataTableCell143, { x: 383, key: "cell_2" }),
+        React.createElement(FixedDataTableCell143, { x: 388, key: "cell_3" }),
+        React.createElement(FixedDataTableCell143, { x: 393, key: "cell_4" }),
+        React.createElement(FixedDataTableCell143, { x: 398, key: "cell_5" }),
+        React.createElement(FixedDataTableCell143, { x: 403, key: "cell_6" }),
+        React.createElement(FixedDataTableCell143, { x: 408, key: "cell_7" }),
+        React.createElement(FixedDataTableCell143, { x: 413, key: "cell_8" }),
+        React.createElement(FixedDataTableCell143, { x: 418, key: "cell_9" }),
+        React.createElement(FixedDataTableCell143, { x: 423, key: "cell_10" }),
+        React.createElement(FixedDataTableCell143, { x: 428, key: "cell_11" }),
+        React.createElement(FixedDataTableCell143, { x: 433, key: "cell_12" }),
+        React.createElement(FixedDataTableCell143, { x: 438, key: "cell_13" }),
+        React.createElement(FixedDataTableCell143, { x: 443, key: "cell_14" }),
+        React.createElement(FixedDataTableCell143, { x: 448, key: "cell_15" }),
+        React.createElement(FixedDataTableCell143, { x: 451, key: "cell_16" }),
+        React.createElement(FixedDataTableCell143, { x: 454, key: "cell_17" })
+      );
+    }
+  };
+
+  var FixedDataTableCellGroup145 = function (props) {
+    if (props.x === 319) {
+      return React.createElement(
+        "div",
+        { style: { "height": 40, "left": 0 }, className: "_3pzk" },
+        React.createElement(FixedDataTableCellGroupImpl144, { x: 318 })
+      );
+    }
+    if (props.x === 333) {
+      return React.createElement(
+        "div",
+        { style: { "height": 40, "left": 721 }, className: "_3pzk" },
+        React.createElement(FixedDataTableCellGroupImpl144, { x: 332 })
+      );
+    }
+    if (props.x === 368) {
+      return React.createElement(
+        "div",
+        { style: { "height": 25, "left": 0 }, className: "_3pzk" },
+        React.createElement(FixedDataTableCellGroupImpl144, { x: 367 })
+      );
+    }
+    if (props.x === 456) {
+      return React.createElement(
+        "div",
+        { style: { "height": 25, "left": 721 }, className: "_3pzk" },
+        React.createElement(FixedDataTableCellGroupImpl144, { x: 455 })
+      );
+    }
+  };
+
+  var FixedDataTableRowImpl146 = function (props) {
+    if (props.x === 334) {
+      return React.createElement(
+        "div",
+        { className: "_1gd4 _4li _52no _3h1a _1mib", onClick: null, onDoubleClick: null, onMouseDown: null, onMouseEnter: null, onMouseLeave: null, style: { "width": 1209, "height": 40 } },
+        React.createElement(
+          "div",
+          { className: "_1gd5" },
+          React.createElement(FixedDataTableCellGroup145, { x: 319, key: "fixed_cells" }),
+          React.createElement(FixedDataTableCellGroup145, { x: 333, key: "scrollable_cells" }),
+          React.createElement("div", { className: "_1gd6 _1gd8", style: { "left": 721, "height": 40 } })
+        )
+      );
+    }
+    if (props.x === 457) {
+      return React.createElement(
+        "div",
+        { className: "_1gd4 _4li _3h1a _1mib", onClick: null, onDoubleClick: null, onMouseDown: null, onMouseEnter: null, onMouseLeave: null, style: { "width": 1209, "height": 25 } },
+        React.createElement(
+          "div",
+          { className: "_1gd5" },
+          React.createElement(FixedDataTableCellGroup145, { x: 368, key: "fixed_cells" }),
+          React.createElement(FixedDataTableCellGroup145, { x: 456, key: "scrollable_cells" }),
+          React.createElement("div", { className: "_1gd6 _1gd8", style: { "left": 721, "height": 25 } })
+        )
+      );
+    }
+  };
+
+  var FixedDataTableRow147 = function (props) {
+    if (props.x === 335) {
+      return React.createElement(
+        "div",
+        { style: { "width": 1209, "height": 40, "zIndex": 1, "transform": "translate3d(0px,0px,0)", "backfaceVisibility": "hidden" }, className: "_1gda" },
+        React.createElement(FixedDataTableRowImpl146, { x: 334 })
+      );
+    }
+    if (props.x === 458) {
+      return React.createElement(
+        "div",
+        { style: { "width": 1209, "height": 25, "zIndex": 1, "transform": "translate3d(0px,40px,0)", "backfaceVisibility": "hidden" }, className: "_1gda" },
+        React.createElement(FixedDataTableRowImpl146, { x: 457 })
+      );
+    }
+  };
+
+  var FixedDataTableAbstractSortableHeader148 = function (props) {
+    if (props.x === 341) {
+      return React.createElement(
+        "div",
+        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+        React.createElement(
+          "div",
+          { className: "_2eq6" },
+          null,
+          React.createElement(AdsPETableHeader141, { x: 340 })
+        )
+      );
+    }
+    if (props.x === 347) {
+      return React.createElement(
+        "div",
+        { onClick: function () {}, className: "_54_8 _1kst _4h2r _2wzx" },
+        React.createElement(
+          "div",
+          { className: "_2eq6" },
+          null,
+          React.createElement(AdsPETableHeader141, { x: 346 })
+        )
+      );
+    }
+    if (props.x === 353) {
+      return React.createElement(
+        "div",
+        { onClick: function () {}, className: "_54_8 _1kst _4h2r _2wzx" },
+        React.createElement(
+          "div",
+          { className: "_2eq6" },
+          null,
+          React.createElement(AdsPETableHeader141, { x: 352 })
+        )
+      );
+    }
+    if (props.x === 358) {
+      return React.createElement(
+        "div",
+        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+        React.createElement(
+          "div",
+          { className: "_2eq6" },
+          null,
+          React.createElement(AdsPETableHeader141, { x: 357 })
+        )
+      );
+    }
+    if (props.x === 363) {
+      return React.createElement(
+        "div",
+        { onClick: function () {}, className: "_54_8 _54_9 _4h2r _2wzx" },
+        React.createElement(
+          "div",
+          { className: "_2eq6" },
+          null,
+          React.createElement(AdsPETableHeader141, { x: 362 })
+        )
+      );
+    }
+    if (props.x === 370) {
+      return React.createElement(
+        "div",
+        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+        React.createElement(
+          "div",
+          { className: "_2eq6" },
+          null,
+          React.createElement(AdsPETableHeader141, { x: 369 })
+        )
+      );
+    }
+    if (props.x === 375) {
+      return React.createElement(
+        "div",
+        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+        React.createElement(
+          "div",
+          { className: "_2eq6" },
+          null,
+          React.createElement(AdsPETableHeader141, { x: 374 })
+        )
+      );
+    }
+    if (props.x === 380) {
+      return React.createElement(
+        "div",
+        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+        React.createElement(
+          "div",
+          { className: "_2eq6" },
+          null,
+          React.createElement(AdsPETableHeader141, { x: 379 })
+        )
+      );
+    }
+    if (props.x === 385) {
+      return React.createElement(
+        "div",
+        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+        React.createElement(
+          "div",
+          { className: "_2eq6" },
+          null,
+          React.createElement(AdsPETableHeader141, { x: 384 })
+        )
+      );
+    }
+    if (props.x === 390) {
+      return React.createElement(
+        "div",
+        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+        React.createElement(
+          "div",
+          { className: "_2eq6" },
+          null,
+          React.createElement(AdsPETableHeader141, { x: 389 })
+        )
+      );
+    }
+    if (props.x === 395) {
+      return React.createElement(
+        "div",
+        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+        React.createElement(
+          "div",
+          { className: "_2eq6" },
+          null,
+          React.createElement(AdsPETableHeader141, { x: 394 })
+        )
+      );
+    }
+    if (props.x === 400) {
+      return React.createElement(
+        "div",
+        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+        React.createElement(
+          "div",
+          { className: "_2eq6" },
+          null,
+          React.createElement(AdsPETableHeader141, { x: 399 })
+        )
+      );
+    }
+    if (props.x === 405) {
+      return React.createElement(
+        "div",
+        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+        React.createElement(
+          "div",
+          { className: "_2eq6" },
+          null,
+          React.createElement(AdsPETableHeader141, { x: 404 })
+        )
+      );
+    }
+    if (props.x === 410) {
+      return React.createElement(
+        "div",
+        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+        React.createElement(
+          "div",
+          { className: "_2eq6" },
+          null,
+          React.createElement(AdsPETableHeader141, { x: 409 })
+        )
+      );
+    }
+    if (props.x === 415) {
+      return React.createElement(
+        "div",
+        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+        React.createElement(
+          "div",
+          { className: "_2eq6" },
+          null,
+          React.createElement(AdsPETableHeader141, { x: 414 })
+        )
+      );
+    }
+    if (props.x === 420) {
+      return React.createElement(
+        "div",
+        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+        React.createElement(
+          "div",
+          { className: "_2eq6" },
+          null,
+          React.createElement(AdsPETableHeader141, { x: 419 })
+        )
+      );
+    }
+    if (props.x === 425) {
+      return React.createElement(
+        "div",
+        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+        React.createElement(
+          "div",
+          { className: "_2eq6" },
+          null,
+          React.createElement(AdsPETableHeader141, { x: 424 })
+        )
+      );
+    }
+    if (props.x === 430) {
+      return React.createElement(
+        "div",
+        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+        React.createElement(
+          "div",
+          { className: "_2eq6" },
+          null,
+          React.createElement(AdsPETableHeader141, { x: 429 })
+        )
+      );
+    }
+    if (props.x === 435) {
+      return React.createElement(
+        "div",
+        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+        React.createElement(
+          "div",
+          { className: "_2eq6" },
+          null,
+          React.createElement(AdsPETableHeader141, { x: 434 })
+        )
+      );
+    }
+    if (props.x === 440) {
+      return React.createElement(
+        "div",
+        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+        React.createElement(
+          "div",
+          { className: "_2eq6" },
+          null,
+          React.createElement(AdsPETableHeader141, { x: 439 })
+        )
+      );
+    }
+    if (props.x === 445) {
+      return React.createElement(
+        "div",
+        { onClick: function () {}, className: "_54_8 _4h2r _2wzx" },
+        React.createElement(
+          "div",
+          { className: "_2eq6" },
+          null,
+          React.createElement(AdsPETableHeader141, { x: 444 })
+        )
+      );
+    }
+  };
+
+  var FixedDataTableSortableHeader149 = function (props) {
+    if (props.x === 342) {
+      return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 341 });
+    }
+    if (props.x === 348) {
+      return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 347 });
+    }
+    if (props.x === 354) {
+      return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 353 });
+    }
+    if (props.x === 359) {
+      return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 358 });
+    }
+    if (props.x === 364) {
+      return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 363 });
+    }
+    if (props.x === 371) {
+      return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 370 });
+    }
+    if (props.x === 376) {
+      return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 375 });
+    }
+    if (props.x === 381) {
+      return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 380 });
+    }
+    if (props.x === 386) {
+      return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 385 });
+    }
+    if (props.x === 391) {
+      return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 390 });
+    }
+    if (props.x === 396) {
+      return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 395 });
+    }
+    if (props.x === 401) {
+      return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 400 });
+    }
+    if (props.x === 406) {
+      return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 405 });
+    }
+    if (props.x === 411) {
+      return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 410 });
+    }
+    if (props.x === 416) {
+      return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 415 });
+    }
+    if (props.x === 421) {
+      return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 420 });
+    }
+    if (props.x === 426) {
+      return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 425 });
+    }
+    if (props.x === 431) {
+      return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 430 });
+    }
+    if (props.x === 436) {
+      return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 435 });
+    }
+    if (props.x === 441) {
+      return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 440 });
+    }
+    if (props.x === 446) {
+      return React.createElement(FixedDataTableAbstractSortableHeader148, { x: 445 });
+    }
+  };
+
+  var FixedDataTableBufferedRows150 = function (props) {
+    if (props.x === 459) {
+      return React.createElement("div", { style: { "position": "absolute", "pointerEvents": "auto", "transform": "translate3d(0px,65px,0)", "backfaceVisibility": "hidden" } });
+    }
+  };
+
+  var Scrollbar151 = function (props) {
+    if (props.x === 460) {
+      return null;
+    }
+    if (props.x === 461) {
+      return React.createElement(
+        "div",
+        { onFocus: function () {}, onBlur: function () {}, onKeyDown: function () {}, onMouseDown: function () {}, onWheel: function () {}, className: "_1t0r _1t0t _4jdr _1t0u", style: { "width": 1209, "zIndex": 99 }, tabIndex: 0 },
+        React.createElement("div", { ref: "face", className: "_1t0w _1t0y _1t0_", style: { "width": 561.6340607950117, "transform": "translate3d(4px,0px,0)", "backfaceVisibility": "hidden" } })
+      );
+    }
+  };
+
+  var HorizontalScrollbar152 = function (props) {
+    if (props.x === 462) {
+      return React.createElement(
+        "div",
+        { className: "_3h1k _3h1m", style: { "height": 15, "width": 1209 } },
+        React.createElement(
+          "div",
+          { style: { "height": 15, "position": "absolute", "overflow": "hidden", "width": 1209, "transform": "translate3d(0px,0px,0)", "backfaceVisibility": "hidden" } },
+          React.createElement(Scrollbar151, { x: 461 })
+        )
+      );
+    }
+  };
+
+  var FixedDataTable153 = function (props) {
+    if (props.x === 463) {
+      return React.createElement(
+        "div",
+        { className: "_3h1i _1mie", onWheel: function () {}, style: { "height": 25, "width": 1209 } },
+        React.createElement(
+          "div",
+          { className: "_3h1j", style: { "height": 8, "width": 1209 } },
+          React.createElement(FixedDataTableColumnResizeHandle140, { x: 313 }),
+          React.createElement(FixedDataTableRow147, { x: 335, key: "group_header" }),
+          React.createElement(FixedDataTableRow147, { x: 458, key: "header" }),
+          React.createElement(FixedDataTableBufferedRows150, { x: 459 }),
+          null,
+          undefined,
+          React.createElement("div", { className: "_3h1e _3h1h", style: { "top": 8 } })
+        ),
+        React.createElement(Scrollbar151, { x: 460 }),
+        React.createElement(HorizontalScrollbar152, { x: 462 })
+      );
+    }
+  };
+
+  var TransitionTable154 = function (props) {
+    if (props.x === 464) {
+      return React.createElement(FixedDataTable153, { x: 463, ref: "fixedDataTable" });
+    }
+  };
+
+  var AdsSelectableFixedDataTable155 = function (props) {
+    if (props.x === 465) {
+      return React.createElement(
+        "div",
+        { className: "_5hht" },
+        React.createElement(TransitionTable154, { x: 464 })
+      );
+    }
+  };
+
+  var AdsDataTableKeyboardSupportDecorator156 = function (props) {
+    if (props.x === 466) {
+      return React.createElement(
+        "div",
+        { ref: "tableContainer", className: "_5d6f", tabIndex: "0", onKeyDown: function () {} },
+        React.createElement(AdsSelectableFixedDataTable155, { x: 465 })
+      );
+    }
+  };
+
+  var AdsEditableDataTableDecorator157 = function (props) {
+    if (props.x === 467) {
+      return React.createElement(
+        "div",
+        { onCopy: function () {} },
+        React.createElement(AdsDataTableKeyboardSupportDecorator156, { x: 466, ref: "decoratedTable" })
+      );
+    }
+  };
+
+  var AdsPEDataTableContainer158 = function (props) {
+    if (props.x === 468) {
+      return React.createElement(
+        "div",
+        { className: "_35l_ _1hr clearfix" },
+        null,
+        null,
+        null,
+        React.createElement(AdsEditableDataTableDecorator157, { x: 467 })
+      );
+    }
+  };
+
+  var AdsPECampaignGroupTableContainer159 = function (props) {
+    if (props.x === 470) {
+      return React.createElement(ResponsiveBlock37, { x: 469 });
+    }
+  };
+
+  var AdsPEManageAdsPaneContainer160 = function (props) {
+    if (props.x === 473) {
+      return React.createElement(
+        "div",
+        null,
+        React.createElement(AdsErrorBoundary10, { x: 65 }),
+        React.createElement(
+          "div",
+          { className: "_2uty" },
+          React.createElement(AdsErrorBoundary10, { x: 125 })
+        ),
+        React.createElement(
+          "div",
+          { className: "_2utx _21oc" },
+          React.createElement(AdsErrorBoundary10, { x: 171 }),
+          React.createElement(
+            "div",
+            { className: "_41tu" },
+            React.createElement(AdsErrorBoundary10, { x: 176 }),
+            React.createElement(AdsErrorBoundary10, { x: 194 })
+          )
+        ),
+        React.createElement(
+          "div",
+          { className: "_2utz", style: { "height": 25 } },
+          React.createElement(AdsErrorBoundary10, { x: 302 }),
+          React.createElement(
+            "div",
+            { className: "_2ut-" },
+            React.createElement(AdsErrorBoundary10, { x: 312 })
+          ),
+          React.createElement(
+            "div",
+            { className: "_2ut_" },
+            React.createElement(AdsErrorBoundary10, { x: 472 })
+          )
+        )
+      );
+    }
+  };
+
+  var AdsPEContentContainer161 = function (props) {
+    if (props.x === 474) {
+      return React.createElement(AdsPEManageAdsPaneContainer160, { x: 473 });
+    }
+  };
+
+  var FluxContainer_AdsPEWorkspaceContainer_162 = function (props) {
+    if (props.x === 477) {
+      return React.createElement(
+        "div",
+        { className: "_49wu", style: { "height": 177, "top": 43, "width": 1306 } },
+        React.createElement(ResponsiveBlock37, { x: 62 }),
+        React.createElement(AdsErrorBoundary10, { x: 476 }),
+        null
+      );
+    }
+  };
+
+  var FluxContainer_AdsSessionExpiredDialogContainer_163 = function (props) {
+    if (props.x === 478) {
+      return null;
+    }
+  };
+
+  var FluxContainer_AdsPEUploadDialogLazyContainer_164 = function (props) {
+    if (props.x === 479) {
+      return null;
+    }
+  };
+
+  var FluxContainer_DialogContainer_165 = function (props) {
+    if (props.x === 480) {
+      return null;
+    }
+  };
+
+  var AdsBugReportContainer166 = function (props) {
+    if (props.x === 481) {
+      return React.createElement("span", null);
+    }
+  };
+
+  var AdsPEAudienceSplittingDialog167 = function (props) {
+    if (props.x === 482) {
+      return null;
+    }
+  };
+
+  var AdsPEAudienceSplittingDialogContainer168 = function (props) {
+    if (props.x === 483) {
+      return React.createElement(
+        "div",
+        null,
+        React.createElement(AdsPEAudienceSplittingDialog167, { x: 482 })
+      );
+    }
+  };
+
+  var FluxContainer_AdsRuleDialogBootloadContainer_169 = function (props) {
+    if (props.x === 484) {
+      return null;
+    }
+  };
+
+  var FluxContainer_AdsPECFTrayContainer_170 = function (props) {
+    if (props.x === 485) {
+      return null;
+    }
+  };
+
+  var FluxContainer_AdsPEDeleteDraftContainer_171 = function (props) {
+    if (props.x === 486) {
+      return null;
+    }
+  };
+
+  var FluxContainer_AdsPEInitialDraftPublishDialogContainer_172 = function (props) {
+    if (props.x === 487) {
+      return null;
+    }
+  };
+
+  var FluxContainer_AdsPEReachFrequencyStatusTransitionDialogBootloadContainer_173 = function (props) {
+    if (props.x === 488) {
+      return null;
+    }
+  };
+
+  var FluxContainer_AdsPEPurgeArchiveDialogContainer_174 = function (props) {
+    if (props.x === 489) {
+      return null;
+    }
+  };
+
+  var AdsPECreateDialogContainer175 = function (props) {
+    if (props.x === 490) {
+      return React.createElement("span", null);
+    }
+  };
+
+  var FluxContainer_AdsPEModalStatusContainer_176 = function (props) {
+    if (props.x === 491) {
+      return null;
+    }
+  };
+
+  var FluxContainer_AdsBrowserExtensionErrorDialogContainer_177 = function (props) {
+    if (props.x === 492) {
+      return null;
+    }
+  };
+
+  var FluxContainer_AdsPESortByErrorTipContainer_178 = function (props) {
+    if (props.x === 493) {
+      return null;
+    }
+  };
+
+  var LeadDownloadDialogSelector179 = function (props) {
+    if (props.x === 494) {
+      return null;
+    }
+  };
+
+  var FluxContainer_AdsPELeadDownloadDialogContainerClass_180 = function (props) {
+    if (props.x === 495) {
+      return React.createElement(LeadDownloadDialogSelector179, { x: 494 });
+    }
+  };
+
+  var AdsPEContainer181 = function (props) {
+    if (props.x === 496) {
+      return React.createElement(
+        "div",
+        { id: "ads_pe_container" },
+        React.createElement(FluxContainer_AdsPETopNavContainer_26, { x: 41 }),
+        null,
+        React.createElement(FluxContainer_AdsPEWorkspaceContainer_162, { x: 477 }),
+        React.createElement(FluxContainer_AdsSessionExpiredDialogContainer_163, { x: 478 }),
+        React.createElement(FluxContainer_AdsPEUploadDialogLazyContainer_164, { x: 479 }),
+        React.createElement(FluxContainer_DialogContainer_165, { x: 480 }),
+        React.createElement(AdsBugReportContainer166, { x: 481 }),
+        React.createElement(AdsPEAudienceSplittingDialogContainer168, { x: 483 }),
+        React.createElement(FluxContainer_AdsRuleDialogBootloadContainer_169, { x: 484 }),
+        React.createElement(FluxContainer_AdsPECFTrayContainer_170, { x: 485 }),
+        React.createElement(
+          "span",
+          null,
+          React.createElement(FluxContainer_AdsPEDeleteDraftContainer_171, { x: 486 }),
+          React.createElement(FluxContainer_AdsPEInitialDraftPublishDialogContainer_172, { x: 487 }),
+          React.createElement(FluxContainer_AdsPEReachFrequencyStatusTransitionDialogBootloadContainer_173, { x: 488 })
+        ),
+        React.createElement(FluxContainer_AdsPEPurgeArchiveDialogContainer_174, { x: 489 }),
+        React.createElement(AdsPECreateDialogContainer175, { x: 490 }),
+        React.createElement(FluxContainer_AdsPEModalStatusContainer_176, { x: 491 }),
+        React.createElement(FluxContainer_AdsBrowserExtensionErrorDialogContainer_177, { x: 492 }),
+        React.createElement(FluxContainer_AdsPESortByErrorTipContainer_178, { x: 493 }),
+        React.createElement(FluxContainer_AdsPELeadDownloadDialogContainerClass_180, { x: 495 }),
+        React.createElement("div", { id: "web_ads_guidance_tips" })
+      );
+    }
+  };
+
+  var Benchmark = function (props) {
+    if (props.x === undefined) {
+      return React.createElement(AdsPEContainer181, { x: 496 });
+    }
+  };
+
+  this.Benchmark = Benchmark;
+})(this);
diff --git a/scripts/bench/bench-pe-sfc.js b/scripts/bench/bench-pe-sfc.js
new file mode 100644
index 000000000000..583d524455c9
--- /dev/null
+++ b/scripts/bench/bench-pe-sfc.js
@@ -0,0 +1,3687 @@
+(function() {
+
+var ReactImage0 = function(props) {
+    if (props.x === 0) {
+      return <i alt={""} className={"_3-99 img sp_i534r85sjIn sx_538591"} src={null}></i>;
+    }
+    if (props.x === 15) {
+      return <i className={"_3ut_ img sp_i534r85sjIn sx_e8ac93"} src={null} alt={""}></i>;
+    }
+    if (props.x === 22) {
+      return <i alt={""} className={"_3-8_ img sp_i534r85sjIn sx_7b15bc"} src={null}></i>;
+    }
+    if (props.x === 29) {
+      return <i className={"_1m1s _4540 _p img sp_i534r85sjIn sx_f40b1c"} src={null} alt={""}></i>;
+    }
+    if (props.x === 42) {
+      return (
+        <i alt={"Warning"} className={"_585p img sp_i534r85sjIn sx_20273d"} src={null}>
+          <u>{"Warning"}</u>
+        </i>
+      );
+    }
+    if (props.x === 67) {
+      return <i alt={""} className={"_3-8_ img sp_i534r85sjIn sx_b5d079"} src={null}></i>;
+    }
+    if (props.x === 70) {
+      return <i src={null} alt={""} className={"img sp_i534r85sjIn sx_29f8c9"}></i>;
+    }
+    if (props.x === 76) {
+      return <i alt={""} className={"_3-8_ img sp_i534r85sjIn sx_ef6a9c"} src={null}></i>;
+    }
+    if (props.x === 79) {
+      return <i src={null} alt={""} className={"img sp_i534r85sjIn sx_6f8c43"}></i>;
+    }
+    if (props.x === 88) {
+      return <i src={null} alt={""} className={"img sp_i534r85sjIn sx_e94a2d"}></i>;
+    }
+    if (props.x === 91) {
+      return <i src={null} alt={""} className={"img sp_i534r85sjIn sx_7ed7d4"}></i>;
+    }
+    if (props.x === 94) {
+      return <i src={null} alt={""} className={"img sp_i534r85sjIn sx_930440"}></i>;
+    }
+    if (props.x === 98) {
+      return <i src={null} alt={""} className={"img sp_i534r85sjIn sx_750c83"}></i>;
+    }
+    if (props.x === 108) {
+      return <i src={null} alt={""} className={"img sp_i534r85sjIn sx_73c1bb"}></i>;
+    }
+    if (props.x === 111) {
+      return <i src={null} alt={""} className={"img sp_i534r85sjIn sx_29f28d"}></i>;
+    }
+    if (props.x === 126) {
+      return <i src={null} alt={""} className={"_3-8_ img sp_i534r85sjIn sx_91c59e"}></i>;
+    }
+    if (props.x === 127) {
+      return <i alt={""} className={"_3-99 img sp_i534r85sjIn sx_538591"} src={null}></i>;
+    }
+    if (props.x === 134) {
+      return <i src={null} alt={""} className={"_3-8_ img sp_i534r85sjIn sx_c8eb75"}></i>;
+    }
+    if (props.x === 135) {
+      return <i alt={""} className={"_3-99 img sp_i534r85sjIn sx_538591"} src={null}></i>;
+    }
+    if (props.x === 148) {
+      return <i className={"_3yz6 _5whs img sp_i534r85sjIn sx_896996"} src={null} alt={""}></i>;
+    }
+    if (props.x === 152) {
+      return <i className={"_5b5p _4gem img sp_i534r85sjIn sx_896996"} src={null} alt={""}></i>;
+    }
+    if (props.x === 153) {
+      return <i className={"_541d img sp_i534r85sjIn sx_2f396a"} src={null} alt={""}></i>;
+    }
+    if (props.x === 160) {
+      return <i src={null} alt={""} className={"img sp_i534r85sjIn sx_31d9b0"}></i>;
+    }
+    if (props.x === 177) {
+      return <i alt={""} className={"_3-99 img sp_i534r85sjIn sx_2c18b7"} src={null}></i>;
+    }
+    if (props.x === 186) {
+      return <i src={null} alt={""} className={"img sp_i534r85sjIn sx_0a681f"}></i>;
+    }
+    if (props.x === 195) {
+      return <i className={"_1-lx img sp_OkER5ktbEyg sx_b369b4"} src={null} alt={""}></i>;
+    }
+    if (props.x === 198) {
+      return <i className={"_1-lx img sp_i534r85sjIn sx_96948e"} src={null} alt={""}></i>;
+    }
+    if (props.x === 237) {
+      return <i className={"_541d img sp_i534r85sjIn sx_2f396a"} src={null} alt={""}></i>;
+    }
+    if (props.x === 266) {
+      return <i alt={""} className={"_3-99 img sp_i534r85sjIn sx_538591"} src={null}></i>;
+    }
+    if (props.x === 314) {
+      return <i className={"_1cie _1cif img sp_i534r85sjIn sx_6e6820"} src={null} alt={""}></i>;
+    }
+    if (props.x === 345) {
+      return <i className={"_1cie img sp_i534r85sjIn sx_e896cf"} src={null} alt={""}></i>;
+    }
+    if (props.x === 351) {
+      return <i className={"_1cie img sp_i534r85sjIn sx_38fed8"} src={null} alt={""}></i>;
+    }
+};
+
+var AbstractLink1 = function(props) {
+    if (props.x === 1) {
+      return (
+        <a className={"_387r _55pi _2agf _4jy0 _4jy4 _517h _51sy _42ft"} style={{"width":250,"maxWidth":"250px"}} disabled={null} label={null} href={"#"} rel={undefined} onClick={function() {}}>
+          {null}
+          <span className={"_55pe"} style={{"maxWidth":"236px"}}>
+            {null}
+            <span>
+              <span className={"_48u-"}>{"Account:"}</span>
+              {" "}
+              {"Dick Madanson (10149999073643408)"}
+            </span>
+          </span>
+          <ReactImage0 x={0} />
+        </a>
+      );
+    }
+    if (props.x === 43) {
+      return (
+        <a className={"_585q _50zy _50-0 _50z- _5upp _42ft"} size={"medium"} shade={"dark"} type={null} title={"Remove"} data-hover={undefined} data-tooltip-alignh={undefined} data-tooltip-content={undefined} disabled={null} label={null} href={"#"} rel={undefined} onClick={function() {}}>
+          {undefined}
+          {"Remove"}
+          {undefined}
+        </a>
+      );
+    }
+    if (props.x === 49) {
+      return (
+        <a target={"_blank"} href={"/ads/manage/billing.php?act=10149999073643408"} rel={undefined} onClick={function() {}}>
+          <XUIText29 x={48} />
+        </a>
+      );
+    }
+    if (props.x === 128) {
+      return (
+        <a className={" _5bbf _55pi _2agf _4jy0 _4jy4 _517h _51sy _42ft"} style={{"maxWidth":"200px"}} disabled={null} label={null} href={"#"} rel={undefined} onClick={function() {}}>
+          {null}
+          <span className={"_55pe"} style={{"maxWidth":"186px"}}>
+            <ReactImage0 x={126} />
+            {"Search"}
+          </span>
+          <ReactImage0 x={127} />
+        </a>
+      );
+    }
+    if (props.x === 136) {
+      return (
+        <a className={" _5bbf _55pi _2agf _4jy0 _4jy4 _517h _51sy _42ft"} style={{"maxWidth":"200px"}} disabled={null} label={null} href={"#"} rel={undefined} onClick={function() {}}>
+          {null}
+          <span className={"_55pe"} style={{"maxWidth":"186px"}}>
+            <ReactImage0 x={134} />
+            {"Filters"}
+          </span>
+          <ReactImage0 x={135} />
+        </a>
+      );
+    }
+    if (props.x === 178) {
+      return (
+        <a className={"_1_-t _1_-v _42ft"} disabled={null} height={"medium"} role={"button"} label={null} href={"#"} rel={undefined} onClick={function() {}}>
+          {undefined}
+          {"Lifetime"}
+          <ReactImage0 x={177} />
+        </a>
+      );
+    }
+    if (props.x === 207) {
+      return <a href={"#"} rel={undefined} onClick={function() {}}>{"Create Ad Set"}</a>;
+    }
+    if (props.x === 209) {
+      return <a href={"#"} rel={undefined} onClick={function() {}}>{"View Ad Set"}</a>;
+    }
+    if (props.x === 241) {
+      return <a href={"#"} rel={undefined} onClick={function() {}}>{"Set a Limit"}</a>;
+    }
+    if (props.x === 267) {
+      return (
+        <a className={"_p _55pi _2agf _4jy0 _4jy3 _517h _51sy _42ft"} style={{"maxWidth":"200px"}} disabled={null} label={null} href={"#"} rel={undefined} onClick={function() {}}>
+          {null}
+          <span className={"_55pe"} style={{"maxWidth":"186px"}}>
+            {null}
+            {"Links"}
+          </span>
+          <ReactImage0 x={266} />
+        </a>
+      );
+    }
+};
+
+var Link2 = function(props) {
+    if (props.x === 2) {
+      return <AbstractLink1 x={1} />;
+    }
+    if (props.x === 44) {
+      return <AbstractLink1 x={43} />;
+    }
+    if (props.x === 50) {
+      return <AbstractLink1 x={49} />;
+    }
+    if (props.x === 129) {
+      return <AbstractLink1 x={128} />;
+    }
+    if (props.x === 137) {
+      return <AbstractLink1 x={136} />;
+    }
+    if (props.x === 179) {
+      return <AbstractLink1 x={178} />;
+    }
+    if (props.x === 208) {
+      return <AbstractLink1 x={207} />;
+    }
+    if (props.x === 210) {
+      return <AbstractLink1 x={209} />;
+    }
+    if (props.x === 242) {
+      return <AbstractLink1 x={241} />;
+    }
+    if (props.x === 268) {
+      return <AbstractLink1 x={267} />;
+    }
+};
+
+var AbstractButton3 = function(props) {
+    if (props.x === 3) {
+      return <Link2 x={2} />;
+    }
+    if (props.x === 20) {
+      return (
+        <button className={"_5n7z _4jy0 _4jy4 _517h _51sy _42ft"} onClick={function() {}} label={null} type={"submit"} value={"1"}>
+          {undefined}
+          {"Discard Changes"}
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 23) {
+      return (
+        <button className={"_5n7z _2yak _4lj- _4jy0 _4jy4 _517h _51sy _42ft _42fr"} disabled={true} onClick={function() {}} data-tooltip-content={"You have no changes to publish"} data-hover={"tooltip"} label={null} type={"submit"} value={"1"}>
+          <ReactImage0 x={22} />
+          {"Review Changes"}
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 45) {
+      return <Link2 x={44} />;
+    }
+    if (props.x === 68) {
+      return (
+        <button className={"_u_k _4jy0 _4jy4 _517h _51sy _42ft"} onClick={function() {}} label={null} type={"submit"} value={"1"}>
+          <ReactImage0 x={67} />
+          {"Create Campaign"}
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 71) {
+      return (
+        <button className={"_u_k _3qx6 _p _4jy0 _4jy4 _517h _51sy _42ft"} label={null} type={"submit"} value={"1"}>
+          <ReactImage0 x={70} />
+          {undefined}
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 77) {
+      return (
+        <button aria-label={"Edit"} data-tooltip-content={"Edit Campaigns (Ctrl+U)"} data-hover={"tooltip"} className={"_d2_ _u_k noMargin _4jy0 _4jy4 _517h _51sy _42ft"} disabled={false} onClick={function() {}} label={null} type={"submit"} value={"1"}>
+          <ReactImage0 x={76} />
+          {"Edit"}
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 80) {
+      return (
+        <button className={"_u_k _3qx6 _p _4jy0 _4jy4 _517h _51sy _42ft"} disabled={false} label={null} type={"submit"} value={"1"}>
+          <ReactImage0 x={79} />
+          {undefined}
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 89) {
+      return (
+        <button aria-label={"Revert"} className={"_u_k _4jy0 _4jy4 _517h _51sy _42ft _42fr"} data-hover={"tooltip"} data-tooltip-content={"Revert"} disabled={true} onClick={function() {}} label={null} type={"submit"} value={"1"}>
+          <ReactImage0 x={88} />
+          {undefined}
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 92) {
+      return (
+        <button aria-label={"Delete"} className={"_u_k _4jy0 _4jy4 _517h _51sy _42ft"} data-hover={"tooltip"} data-tooltip-content={"Delete"} disabled={false} onClick={function() {}} label={null} type={"submit"} value={"1"}>
+          <ReactImage0 x={91} />
+          {undefined}
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 95) {
+      return (
+        <button aria-label={"Duplicate"} className={"_u_k _4jy0 _4jy4 _517h _51sy _42ft"} data-hover={"tooltip"} data-tooltip-content={"Duplicate"} disabled={false} onClick={function() {}} label={null} type={"submit"} value={"1"}>
+          <ReactImage0 x={94} />
+          {undefined}
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 99) {
+      return (
+        <button aria-label={"Export & Import"} className={"_u_k noMargin _p _4jy0 _4jy4 _517h _51sy _42ft"} data-hover={"tooltip"} data-tooltip-content={"Export & Import"} onClick={function() {}} label={null} type={"submit"} value={"1"}>
+          <ReactImage0 x={98} />
+          {undefined}
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 109) {
+      return (
+        <button aria-label={"Create Report"} className={"_u_k _5n7z _4jy0 _4jy4 _517h _51sy _42ft"} data-hover={"tooltip"} data-tooltip-content={"Create Report"} disabled={false} style={{"boxSizing":"border-box","height":"28px","width":"48px"}} onClick={function() {}} label={null} type={"submit"} value={"1"}>
+          <ReactImage0 x={108} />
+          {undefined}
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 112) {
+      return (
+        <button aria-label={"Campaign Tags"} className={" _5uy7 _4jy0 _4jy4 _517h _51sy _42ft"} data-hover={"tooltip"} data-tooltip-content={"Campaign Tags"} disabled={false} haschevron={false} onClick={function() {}} label={null} type={"submit"} value={"1"}>
+          <ReactImage0 x={111} />
+          {undefined}
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 130) {
+      return <Link2 x={129} />;
+    }
+    if (props.x === 138) {
+      return <Link2 x={137} />;
+    }
+    if (props.x === 149) {
+      return (
+        <button className={"_3yz9 _1t-2 _50z- _50zy _50zz _50z- _5upp _42ft"} size={"small"} onClick={function() {}} shade={"dark"} type={"button"} title={"Remove"} data-hover={undefined} data-tooltip-alignh={undefined} data-tooltip-content={undefined} label={null}>
+          {undefined}
+          {"Remove"}
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 156) {
+      return (
+        <button className={"_5b5u _5b5v _4jy0 _4jy3 _517h _51sy _42ft"} onClick={function() {}} label={null} type={"submit"} value={"1"}>
+          {undefined}
+          {"Apply"}
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 161) {
+      return (
+        <button className={"_1wdf _4jy0 _517i _517h _51sy _42ft"} onClick={function() {}} label={null} type={"submit"} value={"1"}>
+          <ReactImage0 x={160} />
+          {undefined}
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 180) {
+      return <Link2 x={179} />;
+    }
+    if (props.x === 187) {
+      return (
+        <button aria-label={"List Settings"} className={"_u_k _3c5o _1-r0 _4jy0 _4jy4 _517h _51sy _42ft"} data-hover={"tooltip"} data-tooltip-content={"List Settings"} onClick={function() {}} label={null} type={"submit"} value={"1"}>
+          <ReactImage0 x={186} />
+          {undefined}
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 269) {
+      return <Link2 x={268} />;
+    }
+    if (props.x === 303) {
+      return (
+        <button className={"_tm3 _tm6 _tm7 _4jy0 _4jy6 _517h _51sy _42ft"} data-tooltip-position={"right"} data-tooltip-content={"Campaigns"} data-hover={"tooltip"} onClick={function() {}} label={null} type={"submit"} value={"1"}>
+          {undefined}
+          <div>
+            <div className={"_tma"}></div>
+            <div className={"_tm8"}></div>
+            <div className={"_tm9"}>{1}</div>
+          </div>
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 305) {
+      return (
+        <button className={"_tm4 _tm6 _4jy0 _4jy6 _517h _51sy _42ft"} data-tooltip-position={"right"} data-tooltip-content={"Ad Sets"} data-hover={"tooltip"} onClick={function() {}} label={null} type={"submit"} value={"1"}>
+          {undefined}
+          <div>
+            <div className={"_tma"}></div>
+            <div className={"_tm8"}></div>
+            <div className={"_tm9"}>{1}</div>
+          </div>
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 307) {
+      return (
+        <button className={"_tm5 _tm6 _4jy0 _4jy6 _517h _51sy _42ft"} data-tooltip-position={"right"} data-tooltip-content={"Ads"} data-hover={"tooltip"} onClick={function() {}} label={null} type={"submit"} value={"1"}>
+          {undefined}
+          <div>
+            <div className={"_tma"}></div>
+            <div className={"_tm8"}></div>
+            <div className={"_tm9"}>{1}</div>
+          </div>
+          {undefined}
+        </button>
+      );
+    }
+};
+
+var XUIButton4 = function(props) {
+    if (props.x === 4) {
+      return <AbstractButton3 x={3} />;
+    }
+    if (props.x === 21) {
+      return <AbstractButton3 x={20} />;
+    }
+    if (props.x === 24) {
+      return <AbstractButton3 x={23} />;
+    }
+    if (props.x === 69) {
+      return <AbstractButton3 x={68} />;
+    }
+    if (props.x === 72) {
+      return <AbstractButton3 x={71} />;
+    }
+    if (props.x === 78) {
+      return <AbstractButton3 x={77} />;
+    }
+    if (props.x === 81) {
+      return <AbstractButton3 x={80} />;
+    }
+    if (props.x === 90) {
+      return <AbstractButton3 x={89} />;
+    }
+    if (props.x === 93) {
+      return <AbstractButton3 x={92} />;
+    }
+    if (props.x === 96) {
+      return <AbstractButton3 x={95} />;
+    }
+    if (props.x === 100) {
+      return <AbstractButton3 x={99} />;
+    }
+    if (props.x === 110) {
+      return <AbstractButton3 x={109} />;
+    }
+    if (props.x === 113) {
+      return <AbstractButton3 x={112} />;
+    }
+    if (props.x === 131) {
+      return <AbstractButton3 x={130} />;
+    }
+    if (props.x === 139) {
+      return <AbstractButton3 x={138} />;
+    }
+    if (props.x === 157) {
+      return <AbstractButton3 x={156} />;
+    }
+    if (props.x === 162) {
+      return <AbstractButton3 x={161} />;
+    }
+    if (props.x === 188) {
+      return <AbstractButton3 x={187} />;
+    }
+    if (props.x === 270) {
+      return <AbstractButton3 x={269} />;
+    }
+    if (props.x === 304) {
+      return <AbstractButton3 x={303} />;
+    }
+    if (props.x === 306) {
+      return <AbstractButton3 x={305} />;
+    }
+    if (props.x === 308) {
+      return <AbstractButton3 x={307} />;
+    }
+};
+
+var AbstractPopoverButton5 = function(props) {
+    if (props.x === 5) {
+      return <XUIButton4 x={4} />;
+    }
+    if (props.x === 132) {
+      return <XUIButton4 x={131} />;
+    }
+    if (props.x === 140) {
+      return <XUIButton4 x={139} />;
+    }
+    if (props.x === 271) {
+      return <XUIButton4 x={270} />;
+    }
+};
+
+var ReactXUIPopoverButton6 = function(props) {
+    if (props.x === 6) {
+      return <AbstractPopoverButton5 x={5} />;
+    }
+    if (props.x === 133) {
+      return <AbstractPopoverButton5 x={132} />;
+    }
+    if (props.x === 141) {
+      return <AbstractPopoverButton5 x={140} />;
+    }
+    if (props.x === 272) {
+      return <AbstractPopoverButton5 x={271} />;
+    }
+};
+
+var BIGAdAccountSelector7 = function(props) {
+    if (props.x === 7) {
+      return (
+        <div>
+          <ReactXUIPopoverButton6 x={6} ref={"openMenuButton"} />
+          {null}
+        </div>
+      );
+    }
+};
+
+var FluxContainer_AdsPEBIGAdAccountSelectorContainer_8 = function(props) {
+    if (props.x === 8) {
+      return <BIGAdAccountSelector7 x={7} />;
+    }
+};
+
+var ErrorBoundary9 = function(props) {
+    if (props.x === 9) {
+      return <FluxContainer_AdsPEBIGAdAccountSelectorContainer_8 x={8} />;
+    }
+    if (props.x === 13) {
+      return <FluxContainer_AdsPENavigationBarContainer_12 x={12} />;
+    }
+    if (props.x === 27) {
+      return <FluxContainer_AdsPEPublishButtonContainer_18 x={26} />;
+    }
+    if (props.x === 32) {
+      return <ReactPopoverMenu20 x={31} />;
+    }
+    if (props.x === 38) {
+      return <AdsPEResetDialog24 x={37} />;
+    }
+    if (props.x === 57) {
+      return <FluxContainer_AdsPETopErrorContainer_35 x={56} />;
+    }
+    if (props.x === 60) {
+      return <FluxContainer_AdsGuidanceChannel_36 x={59} />;
+    }
+    if (props.x === 64) {
+      return <FluxContainer_AdsBulkEditDialogContainer_38 x={63} />;
+    }
+    if (props.x === 124) {
+      return <AdsPECampaignGroupToolbarContainer57 x={123} />;
+    }
+    if (props.x === 170) {
+      return <AdsPEFilterContainer72 x={169} />;
+    }
+    if (props.x === 175) {
+      return <AdsPETablePagerContainer75 x={174} />;
+    }
+    if (props.x === 193) {
+      return <AdsPEStatRangeContainer81 x={192} />;
+    }
+    if (props.x === 301) {
+      return <FluxContainer_AdsPEMultiTabDrawerContainer_137 x={300} />;
+    }
+    if (props.x === 311) {
+      return <AdsPEOrganizerContainer139 x={310} />;
+    }
+    if (props.x === 471) {
+      return <AdsPECampaignGroupTableContainer159 x={470} />;
+    }
+    if (props.x === 475) {
+      return <AdsPEContentContainer161 x={474} />;
+    }
+};
+
+var AdsErrorBoundary10 = function(props) {
+    if (props.x === 10) {
+      return <ErrorBoundary9 x={9} />;
+    }
+    if (props.x === 14) {
+      return <ErrorBoundary9 x={13} />;
+    }
+    if (props.x === 28) {
+      return <ErrorBoundary9 x={27} />;
+    }
+    if (props.x === 33) {
+      return <ErrorBoundary9 x={32} />;
+    }
+    if (props.x === 39) {
+      return <ErrorBoundary9 x={38} />;
+    }
+    if (props.x === 58) {
+      return <ErrorBoundary9 x={57} />;
+    }
+    if (props.x === 61) {
+      return <ErrorBoundary9 x={60} />;
+    }
+    if (props.x === 65) {
+      return <ErrorBoundary9 x={64} />;
+    }
+    if (props.x === 125) {
+      return <ErrorBoundary9 x={124} />;
+    }
+    if (props.x === 171) {
+      return <ErrorBoundary9 x={170} />;
+    }
+    if (props.x === 176) {
+      return <ErrorBoundary9 x={175} />;
+    }
+    if (props.x === 194) {
+      return <ErrorBoundary9 x={193} />;
+    }
+    if (props.x === 302) {
+      return <ErrorBoundary9 x={301} />;
+    }
+    if (props.x === 312) {
+      return <ErrorBoundary9 x={311} />;
+    }
+    if (props.x === 472) {
+      return <ErrorBoundary9 x={471} />;
+    }
+    if (props.x === 476) {
+      return <ErrorBoundary9 x={475} />;
+    }
+};
+
+var AdsPENavigationBar11 = function(props) {
+    if (props.x === 11) {
+      return <div className={"_4t_9"}></div>;
+    }
+};
+
+var FluxContainer_AdsPENavigationBarContainer_12 = function(props) {
+    if (props.x === 12) {
+      return <AdsPENavigationBar11 x={11} />;
+    }
+};
+
+var AdsPEDraftSyncStatus13 = function(props) {
+    if (props.x === 16) {
+      return (
+        <div className={"_3ut-"} onClick={function() {}}>
+          <span className={"_3uu0"}>
+            <ReactImage0 x={15} />
+          </span>
+        </div>
+      );
+    }
+};
+
+var FluxContainer_AdsPEDraftSyncStatusContainer_14 = function(props) {
+    if (props.x === 17) {
+      return <AdsPEDraftSyncStatus13 x={16} />;
+    }
+};
+
+var AdsPEDraftErrorsStatus15 = function(props) {
+    if (props.x === 18) {
+      return null;
+    }
+};
+
+var FluxContainer_viewFn_16 = function(props) {
+    if (props.x === 19) {
+      return <AdsPEDraftErrorsStatus15 x={18} />;
+    }
+};
+
+var AdsPEPublishButton17 = function(props) {
+    if (props.x === 25) {
+      return (
+        <div className={"_5533"}>
+          <FluxContainer_AdsPEDraftSyncStatusContainer_14 x={17} />
+          <FluxContainer_viewFn_16 x={19} />
+          {null}
+          <XUIButton4 x={21} key={"discard"} />
+          <XUIButton4 x={24} ref={"reviewChangesButton"} />
+        </div>
+      );
+    }
+};
+
+var FluxContainer_AdsPEPublishButtonContainer_18 = function(props) {
+    if (props.x === 26) {
+      return <AdsPEPublishButton17 x={25} />;
+    }
+};
+
+var InlineBlock19 = function(props) {
+    if (props.x === 30) {
+      return (
+        <div className={"uiPopover _6a _6b"} disabled={null}>
+          <ReactImage0 x={29} key={".0"} />
+        </div>
+      );
+    }
+    if (props.x === 73) {
+      return (
+        <div className={"uiPopover _6a _6b"} disabled={null}>
+          <XUIButton4 x={72} key={".0"} />
+        </div>
+      );
+    }
+    if (props.x === 82) {
+      return (
+        <div className={"_1nwm uiPopover _6a _6b"} disabled={null}>
+          <XUIButton4 x={81} key={".0"} />
+        </div>
+      );
+    }
+    if (props.x === 101) {
+      return (
+        <div size={"large"} className={"uiPopover _6a _6b"} disabled={null}>
+          <XUIButton4 x={100} key={".0"} />
+        </div>
+      );
+    }
+    if (props.x === 273) {
+      return (
+        <div className={"_3-90 uiPopover _6a _6b"} style={{"marginTop":2}} disabled={null}>
+          <ReactXUIPopoverButton6 x={272} key={".0"} />
+        </div>
+      );
+    }
+};
+
+var ReactPopoverMenu20 = function(props) {
+    if (props.x === 31) {
+      return <InlineBlock19 x={30} ref={"root"} />;
+    }
+    if (props.x === 74) {
+      return <InlineBlock19 x={73} ref={"root"} />;
+    }
+    if (props.x === 83) {
+      return <InlineBlock19 x={82} ref={"root"} />;
+    }
+    if (props.x === 102) {
+      return <InlineBlock19 x={101} ref={"root"} />;
+    }
+    if (props.x === 274) {
+      return <InlineBlock19 x={273} ref={"root"} />;
+    }
+};
+
+var LeftRight21 = function(props) {
+    if (props.x === 34) {
+      return (
+        <div className={"clearfix"}>
+          <div key={"left"} className={"_ohe lfloat"}>
+            <div className={"_34_j"}>
+              <div className={"_34_k"}>
+                <AdsErrorBoundary10 x={10} />
+              </div>
+              <div className={"_2u-6"}>
+                <AdsErrorBoundary10 x={14} />
+              </div>
+            </div>
+          </div>
+          <div key={"right"} className={"_ohf rfloat"}>
+            <div className={"_34_m"}>
+              <div key={"0"} className={"_5ju2"}>
+                <AdsErrorBoundary10 x={28} />
+              </div>
+              <div key={"1"} className={"_5ju2"}>
+                <AdsErrorBoundary10 x={33} />
+              </div>
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 232) {
+      return (
+        <div flex={"right"} direction={"left"} className={"clearfix"}>
+          <div key={"left"} className={"_ohe lfloat"}>
+            <AdsLabeledField104 x={231} />
+          </div>
+          <div key={"right"} className={""}>
+            <div className={"_42ef"}>
+              <div className={"_2oc7"}>{"Clicks to Website"}</div>
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 235) {
+      return (
+        <div className={"_3-8x clearfix"} flex={"right"} direction={"left"}>
+          <div key={"left"} className={"_ohe lfloat"}>
+            <AdsLabeledField104 x={234} />
+          </div>
+          <div key={"right"} className={""}>
+            <div className={"_42ef"}>
+              <div className={"_2oc7"}>{"Auction"}</div>
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 245) {
+      return (
+        <div className={"_3-8y clearfix"} flex={"right"} direction={"left"}>
+          <div key={"left"} className={"_ohe lfloat"}>
+            <AdsLabeledField104 x={240} />
+          </div>
+          <div key={"right"} className={""}>
+            <div className={"_42ef"}>
+              <FluxContainer_AdsCampaignGroupSpendCapContainer_107 x={244} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 277) {
+      return (
+        <div className={"_5dw9 _5dwa clearfix"}>
+          <div key={"left"} className={"_ohe lfloat"}>
+            <XUICardHeaderTitle100 x={265} key={".0"} />
+          </div>
+          <div key={"right"} className={"_ohf rfloat"}>
+            <FluxContainer_AdsPluginizedLinksMenuContainer_121 x={276} key={".1"} />
+          </div>
+        </div>
+      );
+    }
+};
+
+var AdsUnifiedNavigationLocalNav22 = function(props) {
+    if (props.x === 35) {
+      return (
+        <div className={"_34_i"}>
+          <LeftRight21 x={34} />
+        </div>
+      );
+    }
+};
+
+var XUIDialog23 = function(props) {
+    if (props.x === 36) {
+      return null;
+    }
+};
+
+var AdsPEResetDialog24 = function(props) {
+    if (props.x === 37) {
+      return (
+        <span>
+          <XUIDialog23 x={36} key={"dialog/.0"} />
+        </span>
+      );
+    }
+};
+
+var AdsPETopNav25 = function(props) {
+    if (props.x === 40) {
+      return (
+        <div style={{"width":1306}}>
+          <AdsUnifiedNavigationLocalNav22 x={35} />
+          <AdsErrorBoundary10 x={39} />
+        </div>
+      );
+    }
+};
+
+var FluxContainer_AdsPETopNavContainer_26 = function(props) {
+    if (props.x === 41) {
+      return <AdsPETopNav25 x={40} />;
+    }
+};
+
+var XUIAbstractGlyphButton27 = function(props) {
+    if (props.x === 46) {
+      return <AbstractButton3 x={45} />;
+    }
+    if (props.x === 150) {
+      return <AbstractButton3 x={149} />;
+    }
+};
+
+var XUICloseButton28 = function(props) {
+    if (props.x === 47) {
+      return <XUIAbstractGlyphButton27 x={46} />;
+    }
+    if (props.x === 151) {
+      return <XUIAbstractGlyphButton27 x={150} />;
+    }
+};
+
+var XUIText29 = function(props) {
+    if (props.x === 48) {
+      return <span display={"inline"} className={" _50f7"}>{"Ads Manager"}</span>;
+    }
+    if (props.x === 205) {
+      return <span className={"_2x9f  _50f5 _50f7"} display={"inline"}>{"Editing Campaign"}</span>;
+    }
+    if (props.x === 206) {
+      return <span display={"inline"} className={" _50f5 _50f7"}>{"Test Campaign"}</span>;
+    }
+};
+
+var XUINotice30 = function(props) {
+    if (props.x === 51) {
+      return (
+        <div size={"medium"} className={"_585n _585o _2wdd"}>
+          <ReactImage0 x={42} />
+          <XUICloseButton28 x={47} />
+          <div className={"_585r _2i-a _50f4"}>
+            {"Please go to "}
+            <Link2 x={50} />
+            {" to set up a payment method for this ad account."}
+          </div>
+        </div>
+      );
+    }
+};
+
+var ReactCSSTransitionGroupChild31 = function(props) {
+    if (props.x === 52) {
+      return <XUINotice30 x={51} />;
+    }
+};
+
+var ReactTransitionGroup32 = function(props) {
+    if (props.x === 53) {
+      return (
+        <span>
+          <ReactCSSTransitionGroupChild31 x={52} key={".0"} ref={".0"} />
+        </span>
+      );
+    }
+};
+
+var ReactCSSTransitionGroup33 = function(props) {
+    if (props.x === 54) {
+      return <ReactTransitionGroup32 x={53} />;
+    }
+};
+
+var AdsPETopError34 = function(props) {
+    if (props.x === 55) {
+      return (
+        <div className={"_2wdc"}>
+          <ReactCSSTransitionGroup33 x={54} />
+        </div>
+      );
+    }
+};
+
+var FluxContainer_AdsPETopErrorContainer_35 = function(props) {
+    if (props.x === 56) {
+      return <AdsPETopError34 x={55} />;
+    }
+};
+
+var FluxContainer_AdsGuidanceChannel_36 = function(props) {
+    if (props.x === 59) {
+      return null;
+    }
+};
+
+var ResponsiveBlock37 = function(props) {
+    if (props.x === 62) {
+      return (
+        <div onResize={function() {}} className={"_4u-c"}>
+          {[
+            <AdsErrorBoundary10 x={58} />,
+            <AdsErrorBoundary10 x={61} />,
+          ]}
+          <div key={"sensor"} className={"_4u-f"}>
+            <iframe ref={"sensorNode"} aria-hidden={"true"} className={"_1_xb"} tabIndex={"-1"}></iframe>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 469) {
+      return (
+        <div onResize={function() {}} className={"_4u-c"}>
+          <AdsPEDataTableContainer158 x={468} />
+          <div key={"sensor"} className={"_4u-f"}>
+            <iframe ref={"sensorNode"} aria-hidden={"true"} className={"_1_xb"} tabIndex={"-1"}></iframe>
+          </div>
+        </div>
+      );
+    }
+};
+
+var FluxContainer_AdsBulkEditDialogContainer_38 = function(props) {
+    if (props.x === 63) {
+      return null;
+    }
+};
+
+var Column39 = function(props) {
+    if (props.x === 66) {
+      return (
+        <div className={"_4bl8 _4bl7"}>
+          <div className={"_3c5f"}>
+            {null}
+            {null}
+            <div className={"_3c5i"}></div>
+            {null}
+          </div>
+        </div>
+      );
+    }
+};
+
+var XUIButtonGroup40 = function(props) {
+    if (props.x === 75) {
+      return (
+        <div className={"_5n7z _51xa"}>
+          <XUIButton4 x={69} />
+          <ReactPopoverMenu20 x={74} />
+        </div>
+      );
+    }
+    if (props.x === 84) {
+      return (
+        <div className={"_5n7z _51xa"}>
+          <XUIButton4 x={78} key={"edit"} />
+          <ReactPopoverMenu20 x={83} key={"editMenu"} />
+        </div>
+      );
+    }
+    if (props.x === 97) {
+      return (
+        <div className={"_5n7z _51xa"}>
+          <XUIButton4 x={90} key={"revert"} />
+          <XUIButton4 x={93} key={"delete"} />
+          <XUIButton4 x={96} key={"duplicate"} />
+        </div>
+      );
+    }
+    if (props.x === 117) {
+      return (
+        <div className={"_5n7z _51xa"}>
+          <AdsPEExportImportMenuContainer48 x={107} />
+          <XUIButton4 x={110} key={"createReport"} ref={"ads_create_report_button"} />
+          <AdsPECampaignGroupTagContainer51 x={116} key={"tags"} />
+        </div>
+      );
+    }
+};
+
+var AdsPEEditToolbarButton41 = function(props) {
+    if (props.x === 85) {
+      return <XUIButtonGroup40 x={84} />;
+    }
+};
+
+var FluxContainer_AdsPEEditCampaignGroupToolbarButtonContainer_42 = function(props) {
+    if (props.x === 86) {
+      return <AdsPEEditToolbarButton41 x={85} />;
+    }
+};
+
+var FluxContainer_AdsPEEditToolbarButtonContainer_43 = function(props) {
+    if (props.x === 87) {
+      return <FluxContainer_AdsPEEditCampaignGroupToolbarButtonContainer_42 x={86} />;
+    }
+};
+
+var AdsPEExportImportMenu44 = function(props) {
+    if (props.x === 103) {
+      return <ReactPopoverMenu20 x={102} key={"export"} />;
+    }
+};
+
+var FluxContainer_AdsPECustomizeExportContainer_45 = function(props) {
+    if (props.x === 104) {
+      return null;
+    }
+};
+
+var AdsPEExportAsTextDialog46 = function(props) {
+    if (props.x === 105) {
+      return null;
+    }
+};
+
+var FluxContainer_AdsPEExportAsTextDialogContainer_47 = function(props) {
+    if (props.x === 106) {
+      return <AdsPEExportAsTextDialog46 x={105} />;
+    }
+};
+
+var AdsPEExportImportMenuContainer48 = function(props) {
+    if (props.x === 107) {
+      return (
+        <span>
+          <AdsPEExportImportMenu44 x={103} />
+          <FluxContainer_AdsPECustomizeExportContainer_45 x={104} />
+          <FluxContainer_AdsPEExportAsTextDialogContainer_47 x={106} />
+          {null}
+          {null}
+        </span>
+      );
+    }
+};
+
+var Constructor49 = function(props) {
+    if (props.x === 114) {
+      return null;
+    }
+    if (props.x === 142) {
+      return null;
+    }
+    if (props.x === 143) {
+      return null;
+    }
+    if (props.x === 183) {
+      return null;
+    }
+};
+
+var TagSelectorPopover50 = function(props) {
+    if (props.x === 115) {
+      return (
+        <span className={" _3d6e"}>
+          <XUIButton4 x={113} ref={"button"} />
+          <Constructor49 x={114} key={"layer"} ref={"layer"} />
+        </span>
+      );
+    }
+};
+
+var AdsPECampaignGroupTagContainer51 = function(props) {
+    if (props.x === 116) {
+      return <TagSelectorPopover50 x={115} key={"98010048849317"} />;
+    }
+};
+
+var AdsRuleToolbarMenu52 = function(props) {
+    if (props.x === 118) {
+      return null;
+    }
+};
+
+var FluxContainer_AdsPERuleToolbarMenuContainer_53 = function(props) {
+    if (props.x === 119) {
+      return <AdsRuleToolbarMenu52 x={118} />;
+    }
+};
+
+var FillColumn54 = function(props) {
+    if (props.x === 120) {
+      return (
+        <div className={"_4bl9"}>
+          <span className={"_3c5e"}>
+            <span>
+              <XUIButtonGroup40 x={75} />
+              <FluxContainer_AdsPEEditToolbarButtonContainer_43 x={87} />
+              {null}
+              <XUIButtonGroup40 x={97} />
+            </span>
+            <XUIButtonGroup40 x={117} />
+            <FluxContainer_AdsPERuleToolbarMenuContainer_53 x={119} />
+          </span>
+        </div>
+      );
+    }
+};
+
+var Layout55 = function(props) {
+    if (props.x === 121) {
+      return (
+        <div className={"clearfix"}>
+          <Column39 x={66} key={"1"} />
+          <FillColumn54 x={120} key={"0"} />
+        </div>
+      );
+    }
+};
+
+var AdsPEMainPaneToolbar56 = function(props) {
+    if (props.x === 122) {
+      return (
+        <div className={"_3c5b clearfix"}>
+          <Layout55 x={121} />
+        </div>
+      );
+    }
+};
+
+var AdsPECampaignGroupToolbarContainer57 = function(props) {
+    if (props.x === 123) {
+      return <AdsPEMainPaneToolbar56 x={122} />;
+    }
+};
+
+var AdsPEFiltersPopover58 = function(props) {
+    if (props.x === 144) {
+      return (
+        <span className={"_5b-l  _5bbe"}>
+          <ReactXUIPopoverButton6 x={133} ref={"searchButton"} />
+          <ReactXUIPopoverButton6 x={141} ref={"filterButton"} />
+          {[
+            <Constructor49 x={142} key={"filterMenu/.0"} />,
+            <Constructor49 x={143} key={"searchMenu/.0"} />,
+          ]}
+        </span>
+      );
+    }
+};
+
+var AbstractCheckboxInput59 = function(props) {
+    if (props.x === 145) {
+      return (
+        <label className={"uiInputLabelInput _55sg _kv1"}>
+          <input checked={true} disabled={true} name={"filterUnpublished"} value={"on"} onClick={function() {}} className={null} id={"js_input_label_21"} type={"checkbox"}></input>
+          <span data-hover={null} data-tooltip-content={undefined}></span>
+        </label>
+      );
+    }
+    if (props.x === 336) {
+      return (
+        <label className={"_4h2r _55sg _kv1"}>
+          <input checked={undefined} onChange={function() {}} className={null} type={"checkbox"}></input>
+          <span data-hover={null} data-tooltip-content={undefined}></span>
+        </label>
+      );
+    }
+};
+
+var XUICheckboxInput60 = function(props) {
+    if (props.x === 146) {
+      return <AbstractCheckboxInput59 x={145} />;
+    }
+    if (props.x === 337) {
+      return <AbstractCheckboxInput59 x={336} />;
+    }
+};
+
+var InputLabel61 = function(props) {
+    if (props.x === 147) {
+      return (
+        <div display={"block"} className={"uiInputLabel clearfix"}>
+          <XUICheckboxInput60 x={146} />
+          <label className={"uiInputLabelLabel"} htmlFor={"js_input_label_21"}>{"Always show new items"}</label>
+        </div>
+      );
+    }
+};
+
+var AdsPopoverLink62 = function(props) {
+    if (props.x === 154) {
+      return (
+        <span>
+          <span ref={"tipIcon"} onMouseEnter={function() {}} onMouseLeave={function() {}} onMouseUp={undefined}>
+            <span className={"_3o_j"}></span>
+            <ReactImage0 x={153} />
+          </span>
+          {null}
+        </span>
+      );
+    }
+    if (props.x === 238) {
+      return (
+        <span>
+          <span ref={"tipIcon"} onMouseEnter={function() {}} onMouseLeave={function() {}} onMouseUp={undefined}>
+            <span className={"_3o_j"}></span>
+            <ReactImage0 x={237} />
+          </span>
+          {null}
+        </span>
+      );
+    }
+};
+
+var AdsHelpLink63 = function(props) {
+    if (props.x === 155) {
+      return <AdsPopoverLink62 x={154} />;
+    }
+    if (props.x === 239) {
+      return <AdsPopoverLink62 x={238} />;
+    }
+};
+
+var BUIFilterTokenInput64 = function(props) {
+    if (props.x === 158) {
+      return (
+        <div className={"_5b5o _3yz3 _4cld"}>
+          <div className={"_5b5t _2d2k"}>
+            <ReactImage0 x={152} />
+            <div className={"_5b5r"}>
+              {"Campaigns: (1)"}
+              <AdsHelpLink63 x={155} />
+            </div>
+          </div>
+          <XUIButton4 x={157} />
+        </div>
+      );
+    }
+};
+
+var BUIFilterToken65 = function(props) {
+    if (props.x === 159) {
+      return (
+        <div className={"_3yz1 _3yz2 _3dad"}>
+          <div ref={"filterToken"} className={"_3yz4"} aria-hidden={false}>
+            <div onClick={function() {}} className={"_3yz5"}>
+              <ReactImage0 x={148} />
+              <div className={"_3yz7"}>{"Campaigns:"}</div>
+              <div className={"ellipsis _3yz8"} data-hover={"tooltip"} data-tooltip-display={"overflow"}>{"(1)"}</div>
+            </div>
+            {null}
+            <XUICloseButton28 x={151} />
+          </div>
+          <BUIFilterTokenInput64 x={158} ref={"filterTokenInput"} />
+        </div>
+      );
+    }
+};
+
+var BUIFilterTokenCreateButton66 = function(props) {
+    if (props.x === 163) {
+      return (
+        <div className={"_1tc"}>
+          <XUIButton4 x={162} />
+        </div>
+      );
+    }
+};
+
+var BUIFilterTokenizer67 = function(props) {
+    if (props.x === 164) {
+      return (
+        <div className={"_5b-m  clearfix"}>
+          {undefined}
+          {[]}
+          <BUIFilterToken65 x={159} key={"token0"} />
+          <BUIFilterTokenCreateButton66 x={163} />
+          {null}
+          <div className={"_49u3"}></div>
+        </div>
+      );
+    }
+};
+
+var XUIAmbientNUX68 = function(props) {
+    if (props.x === 165) {
+      return null;
+    }
+    if (props.x === 189) {
+      return null;
+    }
+    if (props.x === 200) {
+      return null;
+    }
+};
+
+var XUIAmbientNUX69 = function(props) {
+    if (props.x === 166) {
+      return <XUIAmbientNUX68 x={165} />;
+    }
+    if (props.x === 190) {
+      return <XUIAmbientNUX68 x={189} />;
+    }
+    if (props.x === 201) {
+      return <XUIAmbientNUX68 x={200} />;
+    }
+};
+
+var AdsPEAmbientNUXMegaphone70 = function(props) {
+    if (props.x === 167) {
+      return (
+        <span>
+          <span ref={"mainChild"}></span>
+          <XUIAmbientNUX69 x={166} key={"nux"} />
+        </span>
+      );
+    }
+};
+
+var AdsPEFilters71 = function(props) {
+    if (props.x === 168) {
+      return (
+        <div className={"_4rw_"}>
+          <AdsPEFiltersPopover58 x={144} />
+          <div className={"_1eo"}>
+            <InputLabel61 x={147} />
+          </div>
+          <BUIFilterTokenizer67 x={164} />
+          {""}
+          <AdsPEAmbientNUXMegaphone70 x={167} />
+        </div>
+      );
+    }
+};
+
+var AdsPEFilterContainer72 = function(props) {
+    if (props.x === 169) {
+      return <AdsPEFilters71 x={168} />;
+    }
+};
+
+var AdsPETablePager73 = function(props) {
+    if (props.x === 172) {
+      return null;
+    }
+};
+
+var AdsPECampaignGroupTablePagerContainer74 = function(props) {
+    if (props.x === 173) {
+      return <AdsPETablePager73 x={172} />;
+    }
+};
+
+var AdsPETablePagerContainer75 = function(props) {
+    if (props.x === 174) {
+      return <AdsPECampaignGroupTablePagerContainer74 x={173} />;
+    }
+};
+
+var ReactXUIError76 = function(props) {
+    if (props.x === 181) {
+      return <AbstractButton3 x={180} />;
+    }
+    if (props.x === 216) {
+      return (
+        <div className={"_40bf _2vl4 _1h18"}>
+          {null}
+          {null}
+          <div className={"_2vl9 _1h1f"} style={{"backgroundColor":"#fff"}}>
+            <div className={"_2vla _1h1g"}>
+              <div>
+                {null}
+                <textarea ref={"input"} className={"_2vli _2vlj _1h26 _1h27"} dir={"auto"} disabled={undefined} id={undefined} maxLength={null} value={"Test Campaign"} onBlur={function() {}} onChange={function() {}} onFocus={function() {}} onKeyDown={function() {}}></textarea>
+                {null}
+              </div>
+              <div ref={"shadowText"} aria-hidden={"true"} className={"_2vlk"}></div>
+            </div>
+          </div>
+          {null}
+        </div>
+      );
+    }
+    if (props.x === 221) {
+      return <XUICard94 x={220} />;
+    }
+    if (props.x === 250) {
+      return <XUICard94 x={249} />;
+    }
+    if (props.x === 280) {
+      return <XUICard94 x={279} />;
+    }
+};
+
+var BUIPopoverButton77 = function(props) {
+    if (props.x === 182) {
+      return <ReactXUIError76 x={181} />;
+    }
+};
+
+var BUIDateRangePicker78 = function(props) {
+    if (props.x === 184) {
+      return (
+        <span>
+          <BUIPopoverButton77 x={182} ref={function() {}} />
+          {[
+            <Constructor49 x={183} key={"layer/.0"} />,
+          ]}
+        </span>
+      );
+    }
+};
+
+var AdsPEStatsRangePicker79 = function(props) {
+    if (props.x === 185) {
+      return <BUIDateRangePicker78 x={184} />;
+    }
+};
+
+var AdsPEStatRange80 = function(props) {
+    if (props.x === 191) {
+      return (
+        <div className={"_3c5k"}>
+          <span className={"_3c5j"}>{"Stats:"}</span>
+          <span className={"_3c5l"}>
+            <AdsPEStatsRangePicker79 x={185} />
+            <XUIButton4 x={188} key={"settings"} ref={"PE_TABLE_LIST_SETTING"} />
+          </span>
+          {[
+            <XUIAmbientNUX69 x={190} key={"roasNUX/.0"} />,
+          ]}
+        </div>
+      );
+    }
+};
+
+var AdsPEStatRangeContainer81 = function(props) {
+    if (props.x === 192) {
+      return <AdsPEStatRange80 x={191} />;
+    }
+};
+
+var AdsPESideTrayTabButton82 = function(props) {
+    if (props.x === 196) {
+      return (
+        <div className={"_1-ly _59j9 _d9a"} onClick={function() {}}>
+          <ReactImage0 x={195} />
+          <div className={"_vf7"}></div>
+          <div className={"_vf8"}></div>
+        </div>
+      );
+    }
+    if (props.x === 199) {
+      return (
+        <div className={" _1-lz _d9a"} onClick={function() {}}>
+          <ReactImage0 x={198} />
+          <div className={"_vf7"}></div>
+          <div className={"_vf8"}></div>
+        </div>
+      );
+    }
+    if (props.x === 203) {
+      return null;
+    }
+};
+
+var AdsPEEditorTrayTabButton83 = function(props) {
+    if (props.x === 197) {
+      return <AdsPESideTrayTabButton82 x={196} />;
+    }
+};
+
+var AdsPEInsightsTrayTabButton84 = function(props) {
+    if (props.x === 202) {
+      return (
+        <span>
+          <AdsPESideTrayTabButton82 x={199} ref={"PE_INSIGHTS_TAB_ICON"} />
+          <XUIAmbientNUX69 x={201} key={"roasNUX"} />
+        </span>
+      );
+    }
+};
+
+var AdsPENekoDebuggerTrayTabButton85 = function(props) {
+    if (props.x === 204) {
+      return <AdsPESideTrayTabButton82 x={203} />;
+    }
+};
+
+var AdsPEEditorChildLink86 = function(props) {
+    if (props.x === 211) {
+      return (
+        <div className={"_3ywr"}>
+          <Link2 x={208} />
+          <span className={"_3ywq"}>{"|"}</span>
+          <Link2 x={210} />
+        </div>
+      );
+    }
+};
+
+var AdsPEEditorChildLinkContainer87 = function(props) {
+    if (props.x === 212) {
+      return <AdsPEEditorChildLink86 x={211} />;
+    }
+};
+
+var AdsPEHeaderSection88 = function(props) {
+    if (props.x === 213) {
+      return (
+        <div className={"_yke"}>
+          <div className={"_2x9d _pr-"}></div>
+          <XUIText29 x={205} />
+          <div className={"_3a-a"}>
+            <div className={"_3a-b"}>
+              <XUIText29 x={206} />
+            </div>
+          </div>
+          <AdsPEEditorChildLinkContainer87 x={212} />
+        </div>
+      );
+    }
+};
+
+var AdsPECampaignGroupHeaderSectionContainer89 = function(props) {
+    if (props.x === 214) {
+      return <AdsPEHeaderSection88 x={213} />;
+    }
+};
+
+var AdsEditorLoadingErrors90 = function(props) {
+    if (props.x === 215) {
+      return null;
+    }
+};
+
+var AdsTextInput91 = function(props) {
+    if (props.x === 217) {
+      return <ReactXUIError76 x={216} />;
+    }
+};
+
+var BUIFormElement92 = function(props) {
+    if (props.x === 218) {
+      return (
+        <div className={"_5521 clearfix"}>
+          <div className={"_5522 _3w5q"}>
+            <label onClick={undefined} htmlFor={"1467872040612:1961945894"} className={"_5523 _3w5r"}>
+              {"Campaign Name"}
+              {null}
+            </label>
+          </div>
+          <div className={"_5527"}>
+            <div className={"_5528"}>
+              <span key={".0"} className={"_40bg"} density={"snug"} labelPosition={"left"} id={"1467872040612:1961945894"}>
+                <AdsTextInput91 x={217} key={"nameEditor98010048849317"} ref={"nameTextInput"} />
+                {null}
+              </span>
+            </div>
+            {null}
+          </div>
+        </div>
+      );
+    }
+};
+
+var BUIForm93 = function(props) {
+    if (props.x === 219) {
+      return (
+        <div className={"_5ks1 _550r  _550t _550y _3w5n"}>
+          <BUIFormElement92 x={218} key={".0"} />
+        </div>
+      );
+    }
+};
+
+var XUICard94 = function(props) {
+    if (props.x === 220) {
+      return (
+        <div className={"_40bc _12k2 _4-u2  _4-u8"} xuiErrorPosition={"above"} background={"white"}>
+          <BUIForm93 x={219} />
+        </div>
+      );
+    }
+    if (props.x === 249) {
+      return (
+        <div xuiErrorPosition={"above"} className={"_12k2 _4-u2  _4-u8"} background={"white"}>
+          <AdsCardHeader103 x={230} />
+          <AdsCardSection108 x={248} />
+        </div>
+      );
+    }
+    if (props.x === 279) {
+      return (
+        <div xuiErrorPosition={"above"} className={"_12k2 _4-u2  _4-u8"} background={"white"}>
+          <AdsCardLeftRightHeader122 x={278} />
+        </div>
+      );
+    }
+};
+
+var AdsCard95 = function(props) {
+    if (props.x === 222) {
+      return <ReactXUIError76 x={221} />;
+    }
+    if (props.x === 251) {
+      return <ReactXUIError76 x={250} />;
+    }
+    if (props.x === 281) {
+      return <ReactXUIError76 x={280} />;
+    }
+};
+
+var AdsEditorNameSection96 = function(props) {
+    if (props.x === 223) {
+      return <AdsCard95 x={222} />;
+    }
+};
+
+var AdsCampaignGroupNameSectionContainer97 = function(props) {
+    if (props.x === 224) {
+      return <AdsEditorNameSection96 x={223} key={"nameSection98010048849317"} />;
+    }
+};
+
+var _render98 = function(props) {
+    if (props.x === 225) {
+      return <AdsCampaignGroupNameSectionContainer97 x={224} />;
+    }
+};
+
+var AdsPluginWrapper99 = function(props) {
+    if (props.x === 226) {
+      return <_render98 x={225} />;
+    }
+    if (props.x === 255) {
+      return <_render111 x={254} />;
+    }
+    if (props.x === 258) {
+      return <_render113 x={257} />;
+    }
+    if (props.x === 287) {
+      return <_render127 x={286} />;
+    }
+    if (props.x === 291) {
+      return <_render130 x={290} />;
+    }
+};
+
+var XUICardHeaderTitle100 = function(props) {
+    if (props.x === 227) {
+      return (
+        <span itemComponent={"span"} className={"_38my"}>
+          {"Campaign Details"}
+          {null}
+          <span className={"_c1c"}></span>
+        </span>
+      );
+    }
+    if (props.x === 265) {
+      return (
+        <span itemComponent={"span"} className={"_38my"}>
+          {[
+            <span>
+              {"Campaign ID"}
+              {": "}
+              {"98010048849317"}
+            </span>,
+            <div className={"_5lh9"}>
+              <FluxContainer_AdsCampaignGroupStatusSwitchContainer_119 x={264} />
+            </div>,
+          ]}
+          {null}
+          <span className={"_c1c"}></span>
+        </span>
+      );
+    }
+};
+
+var XUICardSection101 = function(props) {
+    if (props.x === 228) {
+      return (
+        <div className={"_5dw9 _5dwa _4-u3"} background={"transparent"}>
+          {[
+            <XUICardHeaderTitle100 x={227} key={".0"} />,
+          ]}
+          {undefined}
+          {undefined}
+          <div className={"_3s3-"}></div>
+        </div>
+      );
+    }
+    if (props.x === 247) {
+      return (
+        <div className={"_12jy _4-u3"} background={"transparent"}>
+          <div className={"_3-8j"}>
+            <FlexibleBlock105 x={233} />
+            <FlexibleBlock105 x={236} />
+            <FlexibleBlock105 x={246} />
+            {null}
+            {null}
+          </div>
+        </div>
+      );
+    }
+};
+
+var XUICardHeader102 = function(props) {
+    if (props.x === 229) {
+      return <XUICardSection101 x={228} />;
+    }
+};
+
+var AdsCardHeader103 = function(props) {
+    if (props.x === 230) {
+      return <XUICardHeader102 x={229} />;
+    }
+};
+
+var AdsLabeledField104 = function(props) {
+    if (props.x === 231) {
+      return (
+        <div className={"_2oc6 _3bvz"} label={"Objective"} labelSize={"small"} optionalText={"(optional)"}>
+          <label className={"_4el4 _3qwj _3hy-"} htmlFor={undefined}>{"Objective "}</label>
+          {null}
+          <div className={"_3bv-"}></div>
+        </div>
+      );
+    }
+    if (props.x === 234) {
+      return (
+        <div className={"_2oc6 _3bvz"} label={"Buying Type"} labelSize={"small"} optionalText={"(optional)"}>
+          <label className={"_4el4 _3qwj _3hy-"} htmlFor={undefined}>{"Buying Type "}</label>
+          {null}
+          <div className={"_3bv-"}></div>
+        </div>
+      );
+    }
+    if (props.x === 240) {
+      return (
+        <div className={"_2oc6 _3bvz"} helpText={"Set an overall spending limit for your ad campaign. This means your ad sets in the campaign will stop once you've reached your spending limit."} label={"Campaign Spending Limit"} labelSize={"small"} optionalText={"(optional)"}>
+          <label className={"_4el4 _3qwj _3hy-"} htmlFor={undefined}>{"Campaign Spending Limit "}</label>
+          <AdsHelpLink63 x={239} />
+          <div className={"_3bv-"}></div>
+        </div>
+      );
+    }
+};
+
+var FlexibleBlock105 = function(props) {
+    if (props.x === 233) {
+      return <LeftRight21 x={232} />;
+    }
+    if (props.x === 236) {
+      return <LeftRight21 x={235} />;
+    }
+    if (props.x === 246) {
+      return <LeftRight21 x={245} />;
+    }
+};
+
+var AdsBulkCampaignSpendCapField106 = function(props) {
+    if (props.x === 243) {
+      return (
+        <div className={"_33dv"}>
+          {""}
+          <Link2 x={242} />
+          {" (optional)"}
+        </div>
+      );
+    }
+};
+
+var FluxContainer_AdsCampaignGroupSpendCapContainer_107 = function(props) {
+    if (props.x === 244) {
+      return <AdsBulkCampaignSpendCapField106 x={243} />;
+    }
+};
+
+var AdsCardSection108 = function(props) {
+    if (props.x === 248) {
+      return <XUICardSection101 x={247} />;
+    }
+};
+
+var AdsEditorCampaignGroupDetailsSection109 = function(props) {
+    if (props.x === 252) {
+      return <AdsCard95 x={251} />;
+    }
+};
+
+var AdsEditorCampaignGroupDetailsSectionContainer110 = function(props) {
+    if (props.x === 253) {
+      return <AdsEditorCampaignGroupDetailsSection109 x={252} key={"campaignGroupDetailsSection98010048849317"} />;
+    }
+};
+
+var _render111 = function(props) {
+    if (props.x === 254) {
+      return <AdsEditorCampaignGroupDetailsSectionContainer110 x={253} />;
+    }
+};
+
+var FluxContainer_AdsEditorToplineDetailsSectionContainer_112 = function(props) {
+    if (props.x === 256) {
+      return null;
+    }
+};
+
+var _render113 = function(props) {
+    if (props.x === 257) {
+      return <FluxContainer_AdsEditorToplineDetailsSectionContainer_112 x={256} />;
+    }
+};
+
+var AdsStickyArea114 = function(props) {
+    if (props.x === 259) {
+      return (
+        <div inContainingBlock={true}>
+          <div ref={"sticky"} onWheel={function() {}}></div>
+        </div>
+      );
+    }
+    if (props.x === 292) {
+      return (
+        <div inContainingBlock={true}>
+          <div ref={"sticky"} onWheel={function() {}}>
+            {[
+              <div key={"campaign_group_errors_section98010048849317"}>
+                <AdsPluginWrapper99 x={291} />
+              </div>,
+            ]}
+          </div>
+        </div>
+      );
+    }
+};
+
+var FluxContainer_AdsEditorColumnContainer_115 = function(props) {
+    if (props.x === 260) {
+      return (
+        <div>
+          {[
+            <div key={"campaign_group_name_section98010048849317"}>
+              <AdsPluginWrapper99 x={226} />
+            </div>,
+            <div key={"campaign_group_basic_section98010048849317"}>
+              <AdsPluginWrapper99 x={255} />
+            </div>,
+            <div key={"campaign_group_topline_section98010048849317"}>
+              <AdsPluginWrapper99 x={258} />
+            </div>,
+          ]}
+          <AdsStickyArea114 x={259} />
+        </div>
+      );
+    }
+    if (props.x === 293) {
+      return (
+        <div>
+          {[
+            <div key={"campaign_group_navigation_section98010048849317"}>
+              <AdsPluginWrapper99 x={287} />
+            </div>,
+          ]}
+          <AdsStickyArea114 x={292} />
+        </div>
+      );
+    }
+};
+
+var BUISwitch116 = function(props) {
+    if (props.x === 261) {
+      return (
+        <div data-hover={"tooltip"} data-tooltip-content={"Currently active. Click this switch to deactivate it."} data-tooltip-position={"below"} disabled={false} value={true} onToggle={function() {}} animate={true} className={"_128j _128k _128n"} role={"checkbox"} aria-checked={"true"}>
+          <div className={"_128o"} onClick={function() {}} onKeyDown={function() {}} onMouseDown={function() {}} tabIndex={"0"}>
+            <div className={"_128p"}></div>
+          </div>
+          {null}
+        </div>
+      );
+    }
+};
+
+var AdsStatusSwitchInternal117 = function(props) {
+    if (props.x === 262) {
+      return <BUISwitch116 x={261} />;
+    }
+};
+
+var AdsStatusSwitch118 = function(props) {
+    if (props.x === 263) {
+      return <AdsStatusSwitchInternal117 x={262} />;
+    }
+};
+
+var FluxContainer_AdsCampaignGroupStatusSwitchContainer_119 = function(props) {
+    if (props.x === 264) {
+      return <AdsStatusSwitch118 x={263} key={"status98010048849317"} />;
+    }
+};
+
+var AdsLinksMenu120 = function(props) {
+    if (props.x === 275) {
+      return <ReactPopoverMenu20 x={274} />;
+    }
+};
+
+var FluxContainer_AdsPluginizedLinksMenuContainer_121 = function(props) {
+    if (props.x === 276) {
+      return (
+        <div>
+          {null}
+          <AdsLinksMenu120 x={275} />
+        </div>
+      );
+    }
+};
+
+var AdsCardLeftRightHeader122 = function(props) {
+    if (props.x === 278) {
+      return <LeftRight21 x={277} />;
+    }
+};
+
+var AdsPEIDSection123 = function(props) {
+    if (props.x === 282) {
+      return <AdsCard95 x={281} />;
+    }
+};
+
+var FluxContainer_AdsPECampaignGroupIDSectionContainer_124 = function(props) {
+    if (props.x === 283) {
+      return <AdsPEIDSection123 x={282} />;
+    }
+};
+
+var DeferredComponent125 = function(props) {
+    if (props.x === 284) {
+      return <FluxContainer_AdsPECampaignGroupIDSectionContainer_124 x={283} />;
+    }
+};
+
+var BootloadedComponent126 = function(props) {
+    if (props.x === 285) {
+      return <DeferredComponent125 x={284} />;
+    }
+};
+
+var _render127 = function(props) {
+    if (props.x === 286) {
+      return <BootloadedComponent126 x={285} />;
+    }
+};
+
+var AdsEditorErrorsCard128 = function(props) {
+    if (props.x === 288) {
+      return null;
+    }
+};
+
+var FluxContainer_FunctionalContainer_129 = function(props) {
+    if (props.x === 289) {
+      return <AdsEditorErrorsCard128 x={288} />;
+    }
+};
+
+var _render130 = function(props) {
+    if (props.x === 290) {
+      return <FluxContainer_FunctionalContainer_129 x={289} />;
+    }
+};
+
+var AdsEditorMultiColumnLayout131 = function(props) {
+    if (props.x === 294) {
+      return (
+        <div className={"_psh"}>
+          <div className={"_3cc0"}>
+            <div>
+              <AdsEditorLoadingErrors90 x={215} key={".0"} />
+              <div className={"_3ms3"}>
+                <div className={"_3ms4"}>
+                  <FluxContainer_AdsEditorColumnContainer_115 x={260} key={".1"} />
+                </div>
+                <div className={"_3pvg"}>
+                  <FluxContainer_AdsEditorColumnContainer_115 x={293} key={".2"} />
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      );
+    }
+};
+
+var AdsPECampaignGroupEditor132 = function(props) {
+    if (props.x === 295) {
+      return (
+        <div>
+          <AdsPECampaignGroupHeaderSectionContainer89 x={214} />
+          <AdsEditorMultiColumnLayout131 x={294} />
+        </div>
+      );
+    }
+};
+
+var AdsPECampaignGroupEditorContainer133 = function(props) {
+    if (props.x === 296) {
+      return <AdsPECampaignGroupEditor132 x={295} />;
+    }
+};
+
+var AdsPESideTrayTabContent134 = function(props) {
+    if (props.x === 297) {
+      return (
+        <div className={"_1o_8 _44ra _5cyn"}>
+          <AdsPECampaignGroupEditorContainer133 x={296} />
+        </div>
+      );
+    }
+};
+
+var AdsPEEditorTrayTabContentContainer135 = function(props) {
+    if (props.x === 298) {
+      return <AdsPESideTrayTabContent134 x={297} />;
+    }
+};
+
+var AdsPEMultiTabDrawer136 = function(props) {
+    if (props.x === 299) {
+      return (
+        <div className={"_2kev _2kex"}>
+          <div className={"_5yno"}>
+            <AdsPEEditorTrayTabButton83 x={197} key={"editor_tray_button"} />
+            <AdsPEInsightsTrayTabButton84 x={202} key={"insights_tray_button"} />
+            <AdsPENekoDebuggerTrayTabButton85 x={204} key={"neko_debugger_tray_button"} />
+          </div>
+          <div className={"_5ynn"}>
+            <AdsPEEditorTrayTabContentContainer135 x={298} key={"EDITOR_DRAWER"} />
+            {null}
+          </div>
+        </div>
+      );
+    }
+};
+
+var FluxContainer_AdsPEMultiTabDrawerContainer_137 = function(props) {
+    if (props.x === 300) {
+      return <AdsPEMultiTabDrawer136 x={299} />;
+    }
+};
+
+var AdsPESimpleOrganizer138 = function(props) {
+    if (props.x === 309) {
+      return (
+        <div className={"_tm2"}>
+          <XUIButton4 x={304} />
+          <XUIButton4 x={306} />
+          <XUIButton4 x={308} />
+        </div>
+      );
+    }
+};
+
+var AdsPEOrganizerContainer139 = function(props) {
+    if (props.x === 310) {
+      return (
+        <div>
+          <AdsPESimpleOrganizer138 x={309} />
+        </div>
+      );
+    }
+};
+
+var FixedDataTableColumnResizeHandle140 = function(props) {
+    if (props.x === 313) {
+      return (
+        <div className={"_3487 _3488 _3489"} style={{"width":0,"height":25,"left":0}}>
+          <div className={"_348a"} style={{"height":25}}></div>
+        </div>
+      );
+    }
+};
+
+var AdsPETableHeader141 = function(props) {
+    if (props.x === 315) {
+      return (
+        <div className={"_1cig _1ksv _1vd7 _4h2r"} id={undefined}>
+          <ReactImage0 x={314} />
+          <span className={"_1cid"}>{"Campaigns"}</span>
+        </div>
+      );
+    }
+    if (props.x === 320) {
+      return (
+        <div className={"_1cig _1vd7 _4h2r"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Performance"}</span>
+        </div>
+      );
+    }
+    if (props.x === 323) {
+      return (
+        <div className={"_1cig _1vd7 _4h2r"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Overview"}</span>
+        </div>
+      );
+    }
+    if (props.x === 326) {
+      return (
+        <div className={"_1cig _1vd7 _4h2r"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Toplines"}</span>
+        </div>
+      );
+    }
+    if (props.x === 329) {
+      return <div className={"_1cig _1vd7 _4h2r"} id={undefined}></div>;
+    }
+    if (props.x === 340) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Campaign Name"}</span>
+        </div>
+      );
+    }
+    if (props.x === 346) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined} data-tooltip-content={"Changed"} data-hover={"tooltip"}>
+          <ReactImage0 x={345} />
+          {null}
+        </div>
+      );
+    }
+    if (props.x === 352) {
+      return (
+        <div className={"_1cig _25fg"} id={"ads_pe_table_error_header"} data-tooltip-content={"Errors"} data-hover={"tooltip"}>
+          <ReactImage0 x={351} />
+          {null}
+        </div>
+      );
+    }
+    if (props.x === 357) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Status"}</span>
+        </div>
+      );
+    }
+    if (props.x === 362) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Delivery"}</span>
+        </div>
+      );
+    }
+    if (props.x === 369) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Results"}</span>
+        </div>
+      );
+    }
+    if (props.x === 374) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Cost"}</span>
+        </div>
+      );
+    }
+    if (props.x === 379) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Reach"}</span>
+        </div>
+      );
+    }
+    if (props.x === 384) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Impressions"}</span>
+        </div>
+      );
+    }
+    if (props.x === 389) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Clicks"}</span>
+        </div>
+      );
+    }
+    if (props.x === 394) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Avg. CPM"}</span>
+        </div>
+      );
+    }
+    if (props.x === 399) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Avg. CPC"}</span>
+        </div>
+      );
+    }
+    if (props.x === 404) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"CTR %"}</span>
+        </div>
+      );
+    }
+    if (props.x === 409) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Spent"}</span>
+        </div>
+      );
+    }
+    if (props.x === 414) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Objective"}</span>
+        </div>
+      );
+    }
+    if (props.x === 419) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Buying Type"}</span>
+        </div>
+      );
+    }
+    if (props.x === 424) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Campaign ID"}</span>
+        </div>
+      );
+    }
+    if (props.x === 429) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Start"}</span>
+        </div>
+      );
+    }
+    if (props.x === 434) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"End"}</span>
+        </div>
+      );
+    }
+    if (props.x === 439) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Date created"}</span>
+        </div>
+      );
+    }
+    if (props.x === 444) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Date last edited"}</span>
+        </div>
+      );
+    }
+    if (props.x === 449) {
+      return (
+        <div className={"_1cig _25fg _4h2r"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Tags"}</span>
+        </div>
+      );
+    }
+    if (props.x === 452) {
+      return <div className={"_1cig _25fg _4h2r"} id={undefined}></div>;
+    }
+};
+
+var TransitionCell142 = function(props) {
+    if (props.x === 316) {
+      return (
+        <div isHeaderCell={true} label={"Campaigns"} dataKey={0} groupHeaderRenderer={function() {}} groupHeaderLabels={{}} groupHeaderData={{}} columnKey={undefined} height={40} width={721} rowIndex={0} className={"_4lgc _4h2u"} style={{"height":40,"width":721}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <AdsPETableHeader141 x={315} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 321) {
+      return (
+        <div isHeaderCell={true} label={"Performance"} dataKey={1} groupHeaderRenderer={function() {}} groupHeaderLabels={{}} groupHeaderData={{}} columnKey={undefined} height={40} width={798} rowIndex={0} className={"_4lgc _4h2u"} style={{"height":40,"width":798}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <AdsPETableHeader141 x={320} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 324) {
+      return (
+        <div isHeaderCell={true} label={"Overview"} dataKey={2} groupHeaderRenderer={function() {}} groupHeaderLabels={{}} groupHeaderData={{}} columnKey={undefined} height={40} width={1022} rowIndex={0} className={"_4lgc _4h2u"} style={{"height":40,"width":1022}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <AdsPETableHeader141 x={323} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 327) {
+      return (
+        <div isHeaderCell={true} label={"Toplines"} dataKey={3} groupHeaderRenderer={function() {}} groupHeaderLabels={{}} groupHeaderData={{}} columnKey={undefined} height={40} width={0} rowIndex={0} className={"_4lgc _4h2u"} style={{"height":40,"width":0}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <AdsPETableHeader141 x={326} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 330) {
+      return (
+        <div isHeaderCell={true} label={""} dataKey={4} groupHeaderRenderer={function() {}} groupHeaderLabels={{}} groupHeaderData={{}} columnKey={undefined} height={40} width={25} rowIndex={0} className={"_4lgc _4h2u"} style={{"height":40,"width":25}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <AdsPETableHeader141 x={329} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 338) {
+      return (
+        <div isHeaderCell={true} label={undefined} width={42} dataKey={"common.id"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"common.id"} height={25} style={{"height":25,"width":42}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <XUICheckboxInput60 x={337} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 343) {
+      return (
+        <div isHeaderCell={true} label={"Campaign Name"} width={400} dataKey={"campaignGroup.name"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"campaignGroup.name"} height={25} style={{"height":25,"width":400}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={342} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 349) {
+      return (
+        <div isHeaderCell={true} label={undefined} width={33} dataKey={"edit_status"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"edit_status"} height={25} style={{"height":25,"width":33}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={348} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 355) {
+      return (
+        <div isHeaderCell={true} label={undefined} width={36} dataKey={"errors"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"errors"} height={25} style={{"height":25,"width":36}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={354} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 360) {
+      return (
+        <div isHeaderCell={true} label={"Status"} width={60} dataKey={"campaignGroup.status"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"campaignGroup.status"} height={25} style={{"height":25,"width":60}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={359} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 365) {
+      return (
+        <div isHeaderCell={true} label={"Delivery"} width={150} dataKey={"derivedCampaignGroup.activity_status"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"derivedCampaignGroup.activity_status"} height={25} style={{"height":25,"width":150}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={364} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 372) {
+      return (
+        <div isHeaderCell={true} label={"Results"} width={140} dataKey={"stats.actions"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"stats.actions"} height={25} style={{"height":25,"width":140}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={371} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 377) {
+      return (
+        <div isHeaderCell={true} label={"Cost"} width={140} dataKey={"stats.cpa"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"stats.cpa"} height={25} style={{"height":25,"width":140}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={376} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 382) {
+      return (
+        <div isHeaderCell={true} label={"Reach"} width={80} dataKey={"stats.unique_impressions"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"stats.unique_impressions"} height={25} style={{"height":25,"width":80}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={381} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 387) {
+      return (
+        <div isHeaderCell={true} label={"Impressions"} width={80} dataKey={"stats.impressions"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"stats.impressions"} height={25} style={{"height":25,"width":80}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={386} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 392) {
+      return (
+        <div isHeaderCell={true} label={"Clicks"} width={60} dataKey={"stats.clicks"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"stats.clicks"} height={25} style={{"height":25,"width":60}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={391} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 397) {
+      return (
+        <div isHeaderCell={true} label={"Avg. CPM"} width={80} dataKey={"stats.avg_cpm"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"stats.avg_cpm"} height={25} style={{"height":25,"width":80}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={396} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 402) {
+      return (
+        <div isHeaderCell={true} label={"Avg. CPC"} width={78} dataKey={"stats.avg_cpc"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"stats.avg_cpc"} height={25} style={{"height":25,"width":78}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={401} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 407) {
+      return (
+        <div isHeaderCell={true} label={"CTR %"} width={70} dataKey={"stats.ctr"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"stats.ctr"} height={25} style={{"height":25,"width":70}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={406} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 412) {
+      return (
+        <div isHeaderCell={true} label={"Spent"} width={70} dataKey={"stats.spent_100"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"stats.spent_100"} height={25} style={{"height":25,"width":70}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={411} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 417) {
+      return (
+        <div isHeaderCell={true} label={"Objective"} width={200} dataKey={"campaignGroup.objective"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"campaignGroup.objective"} height={25} style={{"height":25,"width":200}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={416} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 422) {
+      return (
+        <div isHeaderCell={true} label={"Buying Type"} width={100} dataKey={"campaignGroup.buying_type"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"campaignGroup.buying_type"} height={25} style={{"height":25,"width":100}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={421} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 427) {
+      return (
+        <div isHeaderCell={true} label={"Campaign ID"} width={120} dataKey={"campaignGroup.id"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"campaignGroup.id"} height={25} style={{"height":25,"width":120}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={426} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 432) {
+      return (
+        <div isHeaderCell={true} label={"Start"} width={113} dataKey={"derivedCampaignGroup.startDate"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"derivedCampaignGroup.startDate"} height={25} style={{"height":25,"width":113}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={431} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 437) {
+      return (
+        <div isHeaderCell={true} label={"End"} width={113} dataKey={"derivedCampaignGroup.stopDate"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"derivedCampaignGroup.stopDate"} height={25} style={{"height":25,"width":113}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={436} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 442) {
+      return (
+        <div isHeaderCell={true} label={"Date created"} width={113} dataKey={"derivedCampaignGroup.createdDate"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"derivedCampaignGroup.createdDate"} height={25} style={{"height":25,"width":113}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={441} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 447) {
+      return (
+        <div isHeaderCell={true} label={"Date last edited"} width={113} dataKey={"derivedCampaignGroup.updatedDate"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"derivedCampaignGroup.updatedDate"} height={25} style={{"height":25,"width":113}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={446} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 450) {
+      return (
+        <div isHeaderCell={true} label={"Tags"} width={150} dataKey={"labels"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"labels"} height={25} style={{"height":25,"width":150}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <AdsPETableHeader141 x={449} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 453) {
+      return (
+        <div isHeaderCell={true} label={""} width={25} dataKey={"scrollbar_spacer"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"scrollbar_spacer"} height={25} style={{"height":25,"width":25}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <AdsPETableHeader141 x={452} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+};
+
+var FixedDataTableCell143 = function(props) {
+    if (props.x === 317) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":40,"width":721,"left":0}}>
+          {undefined}
+          <TransitionCell142 x={316} />
+        </div>
+      );
+    }
+    if (props.x === 322) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":40,"width":798,"left":0}}>
+          {undefined}
+          <TransitionCell142 x={321} />
+        </div>
+      );
+    }
+    if (props.x === 325) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":40,"width":1022,"left":798}}>
+          {undefined}
+          <TransitionCell142 x={324} />
+        </div>
+      );
+    }
+    if (props.x === 328) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":40,"width":0,"left":1820}}>
+          {undefined}
+          <TransitionCell142 x={327} />
+        </div>
+      );
+    }
+    if (props.x === 331) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":40,"width":25,"left":1820}}>
+          {undefined}
+          <TransitionCell142 x={330} />
+        </div>
+      );
+    }
+    if (props.x === 339) {
+      return (
+        <div className={"_4lg0 _4lg6 _4h2m"} style={{"height":25,"width":42,"left":0}}>
+          {undefined}
+          <TransitionCell142 x={338} />
+        </div>
+      );
+    }
+    if (props.x === 344) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":25,"width":400,"left":42}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={343} />
+        </div>
+      );
+    }
+    if (props.x === 350) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":25,"width":33,"left":442}}>
+          {undefined}
+          <TransitionCell142 x={349} />
+        </div>
+      );
+    }
+    if (props.x === 356) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":25,"width":36,"left":475}}>
+          {undefined}
+          <TransitionCell142 x={355} />
+        </div>
+      );
+    }
+    if (props.x === 361) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":25,"width":60,"left":511}}>
+          {undefined}
+          <TransitionCell142 x={360} />
+        </div>
+      );
+    }
+    if (props.x === 366) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":25,"width":150,"left":571}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={365} />
+        </div>
+      );
+    }
+    if (props.x === 373) {
+      return (
+        <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":25,"width":140,"left":0}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={372} />
+        </div>
+      );
+    }
+    if (props.x === 378) {
+      return (
+        <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":25,"width":140,"left":140}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={377} />
+        </div>
+      );
+    }
+    if (props.x === 383) {
+      return (
+        <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":25,"width":80,"left":280}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={382} />
+        </div>
+      );
+    }
+    if (props.x === 388) {
+      return (
+        <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":25,"width":80,"left":360}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={387} />
+        </div>
+      );
+    }
+    if (props.x === 393) {
+      return (
+        <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":25,"width":60,"left":440}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={392} />
+        </div>
+      );
+    }
+    if (props.x === 398) {
+      return (
+        <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":25,"width":80,"left":500}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={397} />
+        </div>
+      );
+    }
+    if (props.x === 403) {
+      return (
+        <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":25,"width":78,"left":580}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={402} />
+        </div>
+      );
+    }
+    if (props.x === 408) {
+      return (
+        <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":25,"width":70,"left":658}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={407} />
+        </div>
+      );
+    }
+    if (props.x === 413) {
+      return (
+        <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":25,"width":70,"left":728}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={412} />
+        </div>
+      );
+    }
+    if (props.x === 418) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":25,"width":200,"left":798}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={417} />
+        </div>
+      );
+    }
+    if (props.x === 423) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":25,"width":100,"left":998}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={422} />
+        </div>
+      );
+    }
+    if (props.x === 428) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":25,"width":120,"left":1098}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={427} />
+        </div>
+      );
+    }
+    if (props.x === 433) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":25,"width":113,"left":1218}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={432} />
+        </div>
+      );
+    }
+    if (props.x === 438) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":25,"width":113,"left":1331}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={437} />
+        </div>
+      );
+    }
+    if (props.x === 443) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":25,"width":113,"left":1444}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={442} />
+        </div>
+      );
+    }
+    if (props.x === 448) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":25,"width":113,"left":1557}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={447} />
+        </div>
+      );
+    }
+    if (props.x === 451) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":25,"width":150,"left":1670}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={450} />
+        </div>
+      );
+    }
+    if (props.x === 454) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":25,"width":25,"left":1820}}>
+          {undefined}
+          <TransitionCell142 x={453} />
+        </div>
+      );
+    }
+};
+
+var FixedDataTableCellGroupImpl144 = function(props) {
+    if (props.x === 318) {
+      return (
+        <div className={"_3pzj"} style={{"height":40,"position":"absolute","width":721,"zIndex":2,"transform":"translate3d(0px,0px,0)","backfaceVisibility":"hidden"}}>
+          <FixedDataTableCell143 x={317} key={"cell_0"} />
+        </div>
+      );
+    }
+    if (props.x === 332) {
+      return (
+        <div className={"_3pzj"} style={{"height":40,"position":"absolute","width":1845,"zIndex":0,"transform":"translate3d(0px,0px,0)","backfaceVisibility":"hidden"}}>
+          <FixedDataTableCell143 x={322} key={"cell_0"} />
+          <FixedDataTableCell143 x={325} key={"cell_1"} />
+          <FixedDataTableCell143 x={328} key={"cell_2"} />
+          <FixedDataTableCell143 x={331} key={"cell_3"} />
+        </div>
+      );
+    }
+    if (props.x === 367) {
+      return (
+        <div className={"_3pzj"} style={{"height":25,"position":"absolute","width":721,"zIndex":2,"transform":"translate3d(0px,0px,0)","backfaceVisibility":"hidden"}}>
+          <FixedDataTableCell143 x={339} key={"cell_0"} />
+          <FixedDataTableCell143 x={344} key={"cell_1"} />
+          <FixedDataTableCell143 x={350} key={"cell_2"} />
+          <FixedDataTableCell143 x={356} key={"cell_3"} />
+          <FixedDataTableCell143 x={361} key={"cell_4"} />
+          <FixedDataTableCell143 x={366} key={"cell_5"} />
+        </div>
+      );
+    }
+    if (props.x === 455) {
+      return (
+        <div className={"_3pzj"} style={{"height":25,"position":"absolute","width":1845,"zIndex":0,"transform":"translate3d(0px,0px,0)","backfaceVisibility":"hidden"}}>
+          <FixedDataTableCell143 x={373} key={"cell_0"} />
+          <FixedDataTableCell143 x={378} key={"cell_1"} />
+          <FixedDataTableCell143 x={383} key={"cell_2"} />
+          <FixedDataTableCell143 x={388} key={"cell_3"} />
+          <FixedDataTableCell143 x={393} key={"cell_4"} />
+          <FixedDataTableCell143 x={398} key={"cell_5"} />
+          <FixedDataTableCell143 x={403} key={"cell_6"} />
+          <FixedDataTableCell143 x={408} key={"cell_7"} />
+          <FixedDataTableCell143 x={413} key={"cell_8"} />
+          <FixedDataTableCell143 x={418} key={"cell_9"} />
+          <FixedDataTableCell143 x={423} key={"cell_10"} />
+          <FixedDataTableCell143 x={428} key={"cell_11"} />
+          <FixedDataTableCell143 x={433} key={"cell_12"} />
+          <FixedDataTableCell143 x={438} key={"cell_13"} />
+          <FixedDataTableCell143 x={443} key={"cell_14"} />
+          <FixedDataTableCell143 x={448} key={"cell_15"} />
+          <FixedDataTableCell143 x={451} key={"cell_16"} />
+          <FixedDataTableCell143 x={454} key={"cell_17"} />
+        </div>
+      );
+    }
+};
+
+var FixedDataTableCellGroup145 = function(props) {
+    if (props.x === 319) {
+      return (
+        <div style={{"height":40,"left":0}} className={"_3pzk"}>
+          <FixedDataTableCellGroupImpl144 x={318} />
+        </div>
+      );
+    }
+    if (props.x === 333) {
+      return (
+        <div style={{"height":40,"left":721}} className={"_3pzk"}>
+          <FixedDataTableCellGroupImpl144 x={332} />
+        </div>
+      );
+    }
+    if (props.x === 368) {
+      return (
+        <div style={{"height":25,"left":0}} className={"_3pzk"}>
+          <FixedDataTableCellGroupImpl144 x={367} />
+        </div>
+      );
+    }
+    if (props.x === 456) {
+      return (
+        <div style={{"height":25,"left":721}} className={"_3pzk"}>
+          <FixedDataTableCellGroupImpl144 x={455} />
+        </div>
+      );
+    }
+};
+
+var FixedDataTableRowImpl146 = function(props) {
+    if (props.x === 334) {
+      return (
+        <div className={"_1gd4 _4li _52no _3h1a _1mib"} onClick={null} onDoubleClick={null} onMouseDown={null} onMouseEnter={null} onMouseLeave={null} style={{"width":1209,"height":40}}>
+          <div className={"_1gd5"}>
+            <FixedDataTableCellGroup145 x={319} key={"fixed_cells"} />
+            <FixedDataTableCellGroup145 x={333} key={"scrollable_cells"} />
+            <div className={"_1gd6 _1gd8"} style={{"left":721,"height":40}}></div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 457) {
+      return (
+        <div className={"_1gd4 _4li _3h1a _1mib"} onClick={null} onDoubleClick={null} onMouseDown={null} onMouseEnter={null} onMouseLeave={null} style={{"width":1209,"height":25}}>
+          <div className={"_1gd5"}>
+            <FixedDataTableCellGroup145 x={368} key={"fixed_cells"} />
+            <FixedDataTableCellGroup145 x={456} key={"scrollable_cells"} />
+            <div className={"_1gd6 _1gd8"} style={{"left":721,"height":25}}></div>
+          </div>
+        </div>
+      );
+    }
+};
+
+var FixedDataTableRow147 = function(props) {
+    if (props.x === 335) {
+      return (
+        <div style={{"width":1209,"height":40,"zIndex":1,"transform":"translate3d(0px,0px,0)","backfaceVisibility":"hidden"}} className={"_1gda"}>
+          <FixedDataTableRowImpl146 x={334} />
+        </div>
+      );
+    }
+    if (props.x === 458) {
+      return (
+        <div style={{"width":1209,"height":25,"zIndex":1,"transform":"translate3d(0px,40px,0)","backfaceVisibility":"hidden"}} className={"_1gda"}>
+          <FixedDataTableRowImpl146 x={457} />
+        </div>
+      );
+    }
+};
+
+var FixedDataTableAbstractSortableHeader148 = function(props) {
+    if (props.x === 341) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={340} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 347) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _1kst _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={346} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 353) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _1kst _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={352} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 358) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={357} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 363) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _54_9 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={362} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 370) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={369} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 375) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={374} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 380) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={379} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 385) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={384} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 390) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={389} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 395) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={394} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 400) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={399} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 405) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={404} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 410) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={409} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 415) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={414} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 420) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={419} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 425) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={424} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 430) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={429} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 435) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={434} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 440) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={439} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 445) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={444} />
+          </div>
+        </div>
+      );
+    }
+};
+
+var FixedDataTableSortableHeader149 = function(props) {
+    if (props.x === 342) {
+      return <FixedDataTableAbstractSortableHeader148 x={341} />;
+    }
+    if (props.x === 348) {
+      return <FixedDataTableAbstractSortableHeader148 x={347} />;
+    }
+    if (props.x === 354) {
+      return <FixedDataTableAbstractSortableHeader148 x={353} />;
+    }
+    if (props.x === 359) {
+      return <FixedDataTableAbstractSortableHeader148 x={358} />;
+    }
+    if (props.x === 364) {
+      return <FixedDataTableAbstractSortableHeader148 x={363} />;
+    }
+    if (props.x === 371) {
+      return <FixedDataTableAbstractSortableHeader148 x={370} />;
+    }
+    if (props.x === 376) {
+      return <FixedDataTableAbstractSortableHeader148 x={375} />;
+    }
+    if (props.x === 381) {
+      return <FixedDataTableAbstractSortableHeader148 x={380} />;
+    }
+    if (props.x === 386) {
+      return <FixedDataTableAbstractSortableHeader148 x={385} />;
+    }
+    if (props.x === 391) {
+      return <FixedDataTableAbstractSortableHeader148 x={390} />;
+    }
+    if (props.x === 396) {
+      return <FixedDataTableAbstractSortableHeader148 x={395} />;
+    }
+    if (props.x === 401) {
+      return <FixedDataTableAbstractSortableHeader148 x={400} />;
+    }
+    if (props.x === 406) {
+      return <FixedDataTableAbstractSortableHeader148 x={405} />;
+    }
+    if (props.x === 411) {
+      return <FixedDataTableAbstractSortableHeader148 x={410} />;
+    }
+    if (props.x === 416) {
+      return <FixedDataTableAbstractSortableHeader148 x={415} />;
+    }
+    if (props.x === 421) {
+      return <FixedDataTableAbstractSortableHeader148 x={420} />;
+    }
+    if (props.x === 426) {
+      return <FixedDataTableAbstractSortableHeader148 x={425} />;
+    }
+    if (props.x === 431) {
+      return <FixedDataTableAbstractSortableHeader148 x={430} />;
+    }
+    if (props.x === 436) {
+      return <FixedDataTableAbstractSortableHeader148 x={435} />;
+    }
+    if (props.x === 441) {
+      return <FixedDataTableAbstractSortableHeader148 x={440} />;
+    }
+    if (props.x === 446) {
+      return <FixedDataTableAbstractSortableHeader148 x={445} />;
+    }
+};
+
+var FixedDataTableBufferedRows150 = function(props) {
+    if (props.x === 459) {
+      return <div style={{"position":"absolute","pointerEvents":"auto","transform":"translate3d(0px,65px,0)","backfaceVisibility":"hidden"}}></div>;
+    }
+};
+
+var Scrollbar151 = function(props) {
+    if (props.x === 460) {
+      return null;
+    }
+    if (props.x === 461) {
+      return (
+        <div onFocus={function() {}} onBlur={function() {}} onKeyDown={function() {}} onMouseDown={function() {}} onWheel={function() {}} className={"_1t0r _1t0t _4jdr _1t0u"} style={{"width":1209,"zIndex":99}} tabIndex={0}>
+          <div ref={"face"} className={"_1t0w _1t0y _1t0_"} style={{"width":561.6340607950117,"transform":"translate3d(4px,0px,0)","backfaceVisibility":"hidden"}}></div>
+        </div>
+      );
+    }
+};
+
+var HorizontalScrollbar152 = function(props) {
+    if (props.x === 462) {
+      return (
+        <div className={"_3h1k _3h1m"} style={{"height":15,"width":1209}}>
+          <div style={{"height":15,"position":"absolute","overflow":"hidden","width":1209,"transform":"translate3d(0px,0px,0)","backfaceVisibility":"hidden"}}>
+            <Scrollbar151 x={461} />
+          </div>
+        </div>
+      );
+    }
+};
+
+var FixedDataTable153 = function(props) {
+    if (props.x === 463) {
+      return (
+        <div className={"_3h1i _1mie"} onWheel={function() {}} style={{"height":25,"width":1209}}>
+          <div className={"_3h1j"} style={{"height":8,"width":1209}}>
+            <FixedDataTableColumnResizeHandle140 x={313} />
+            <FixedDataTableRow147 x={335} key={"group_header"} />
+            <FixedDataTableRow147 x={458} key={"header"} />
+            <FixedDataTableBufferedRows150 x={459} />
+            {null}
+            {undefined}
+            <div className={"_3h1e _3h1h"} style={{"top":8}}></div>
+          </div>
+          <Scrollbar151 x={460} />
+          <HorizontalScrollbar152 x={462} />
+        </div>
+      );
+    }
+};
+
+var TransitionTable154 = function(props) {
+    if (props.x === 464) {
+      return <FixedDataTable153 x={463} ref={"fixedDataTable"} />;
+    }
+};
+
+var AdsSelectableFixedDataTable155 = function(props) {
+    if (props.x === 465) {
+      return (
+        <div className={"_5hht"}>
+          <TransitionTable154 x={464} />
+        </div>
+      );
+    }
+};
+
+var AdsDataTableKeyboardSupportDecorator156 = function(props) {
+    if (props.x === 466) {
+      return (
+        <div ref={"tableContainer"} className={"_5d6f"} tabIndex={"0"} onKeyDown={function() {}}>
+          <AdsSelectableFixedDataTable155 x={465} />
+        </div>
+      );
+    }
+};
+
+var AdsEditableDataTableDecorator157 = function(props) {
+    if (props.x === 467) {
+      return (
+        <div onCopy={function() {}}>
+          <AdsDataTableKeyboardSupportDecorator156 x={466} ref={"decoratedTable"} />
+        </div>
+      );
+    }
+};
+
+var AdsPEDataTableContainer158 = function(props) {
+    if (props.x === 468) {
+      return (
+        <div className={"_35l_ _1hr clearfix"}>
+          {null}
+          {null}
+          {null}
+          <AdsEditableDataTableDecorator157 x={467} />
+        </div>
+      );
+    }
+};
+
+var AdsPECampaignGroupTableContainer159 = function(props) {
+    if (props.x === 470) {
+      return <ResponsiveBlock37 x={469} />;
+    }
+};
+
+var AdsPEManageAdsPaneContainer160 = function(props) {
+    if (props.x === 473) {
+      return (
+        <div>
+          <AdsErrorBoundary10 x={65} />
+          <div className={"_2uty"}>
+            <AdsErrorBoundary10 x={125} />
+          </div>
+          <div className={"_2utx _21oc"}>
+            <AdsErrorBoundary10 x={171} />
+            <div className={"_41tu"}>
+              <AdsErrorBoundary10 x={176} />
+              <AdsErrorBoundary10 x={194} />
+            </div>
+          </div>
+          <div className={"_2utz"} style={{"height":25}}>
+            <AdsErrorBoundary10 x={302} />
+            <div className={"_2ut-"}>
+              <AdsErrorBoundary10 x={312} />
+            </div>
+            <div className={"_2ut_"}>
+              <AdsErrorBoundary10 x={472} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+};
+
+var AdsPEContentContainer161 = function(props) {
+    if (props.x === 474) {
+      return <AdsPEManageAdsPaneContainer160 x={473} />;
+    }
+};
+
+var FluxContainer_AdsPEWorkspaceContainer_162 = function(props) {
+    if (props.x === 477) {
+      return (
+        <div className={"_49wu"} style={{"height":177,"top":43,"width":1306}}>
+          <ResponsiveBlock37 x={62} />
+          <AdsErrorBoundary10 x={476} />
+          {null}
+        </div>
+      );
+    }
+};
+
+var FluxContainer_AdsSessionExpiredDialogContainer_163 = function(props) {
+    if (props.x === 478) {
+      return null;
+    }
+};
+
+var FluxContainer_AdsPEUploadDialogLazyContainer_164 = function(props) {
+    if (props.x === 479) {
+      return null;
+    }
+};
+
+var FluxContainer_DialogContainer_165 = function(props) {
+    if (props.x === 480) {
+      return null;
+    }
+};
+
+var AdsBugReportContainer166 = function(props) {
+    if (props.x === 481) {
+      return <span></span>;
+    }
+};
+
+var AdsPEAudienceSplittingDialog167 = function(props) {
+    if (props.x === 482) {
+      return null;
+    }
+};
+
+var AdsPEAudienceSplittingDialogContainer168 = function(props) {
+    if (props.x === 483) {
+      return (
+        <div>
+          <AdsPEAudienceSplittingDialog167 x={482} />
+        </div>
+      );
+    }
+};
+
+var FluxContainer_AdsRuleDialogBootloadContainer_169 = function(props) {
+    if (props.x === 484) {
+      return null;
+    }
+};
+
+var FluxContainer_AdsPECFTrayContainer_170 = function(props) {
+    if (props.x === 485) {
+      return null;
+    }
+};
+
+var FluxContainer_AdsPEDeleteDraftContainer_171 = function(props) {
+    if (props.x === 486) {
+      return null;
+    }
+};
+
+var FluxContainer_AdsPEInitialDraftPublishDialogContainer_172 = function(props) {
+    if (props.x === 487) {
+      return null;
+    }
+};
+
+var FluxContainer_AdsPEReachFrequencyStatusTransitionDialogBootloadContainer_173 = function(props) {
+    if (props.x === 488) {
+      return null;
+    }
+};
+
+var FluxContainer_AdsPEPurgeArchiveDialogContainer_174 = function(props) {
+    if (props.x === 489) {
+      return null;
+    }
+};
+
+var AdsPECreateDialogContainer175 = function(props) {
+    if (props.x === 490) {
+      return <span></span>;
+    }
+};
+
+var FluxContainer_AdsPEModalStatusContainer_176 = function(props) {
+    if (props.x === 491) {
+      return null;
+    }
+};
+
+var FluxContainer_AdsBrowserExtensionErrorDialogContainer_177 = function(props) {
+    if (props.x === 492) {
+      return null;
+    }
+};
+
+var FluxContainer_AdsPESortByErrorTipContainer_178 = function(props) {
+    if (props.x === 493) {
+      return null;
+    }
+};
+
+var LeadDownloadDialogSelector179 = function(props) {
+    if (props.x === 494) {
+      return null;
+    }
+};
+
+var FluxContainer_AdsPELeadDownloadDialogContainerClass_180 = function(props) {
+    if (props.x === 495) {
+      return <LeadDownloadDialogSelector179 x={494} />;
+    }
+};
+
+var AdsPEContainer181 = function(props) {
+    if (props.x === 496) {
+      return (
+        <div id={"ads_pe_container"}>
+          <FluxContainer_AdsPETopNavContainer_26 x={41} />
+          {null}
+          <FluxContainer_AdsPEWorkspaceContainer_162 x={477} />
+          <FluxContainer_AdsSessionExpiredDialogContainer_163 x={478} />
+          <FluxContainer_AdsPEUploadDialogLazyContainer_164 x={479} />
+          <FluxContainer_DialogContainer_165 x={480} />
+          <AdsBugReportContainer166 x={481} />
+          <AdsPEAudienceSplittingDialogContainer168 x={483} />
+          <FluxContainer_AdsRuleDialogBootloadContainer_169 x={484} />
+          <FluxContainer_AdsPECFTrayContainer_170 x={485} />
+          <span>
+            <FluxContainer_AdsPEDeleteDraftContainer_171 x={486} />
+            <FluxContainer_AdsPEInitialDraftPublishDialogContainer_172 x={487} />
+            <FluxContainer_AdsPEReachFrequencyStatusTransitionDialogBootloadContainer_173 x={488} />
+          </span>
+          <FluxContainer_AdsPEPurgeArchiveDialogContainer_174 x={489} />
+          <AdsPECreateDialogContainer175 x={490} />
+          <FluxContainer_AdsPEModalStatusContainer_176 x={491} />
+          <FluxContainer_AdsBrowserExtensionErrorDialogContainer_177 x={492} />
+          <FluxContainer_AdsPESortByErrorTipContainer_178 x={493} />
+          <FluxContainer_AdsPELeadDownloadDialogContainerClass_180 x={495} />
+          <div id={"web_ads_guidance_tips"}></div>
+        </div>
+      );
+    }
+};
+
+var Benchmark = function(props) {
+    if (props.x === undefined) {
+      return <AdsPEContainer181 x={496} />;
+    }
+};
+
+this.Benchmark = Benchmark;
+
+})(this);
+
diff --git a/scripts/bench/bench-pe.js b/scripts/bench/bench-pe.js
index 924dedee6802..5518abefa5ac 100644
--- a/scripts/bench/bench-pe.js
+++ b/scripts/bench/bench-pe.js
@@ -1,6678 +1,4232 @@
 (function() {
 
-var Link0 = React.createClass({
-  render: function() {
-    return <a href={"/"} className={"_5ljn"} rel={undefined} onClick={function() {}}></a>;
-  },
-});
-
-var ReactImage1 = React.createClass({
-  render: function() {
-    return <i alt={""} className={"_3-99 img sp_UuU9HmrQ397 sx_7e56e9"} src={null}></i>;
+var ReactImage0 = React.createClass({
+  render: function() {
+    var props = this.props;
+    if (props.x === 0) {
+      return <i alt={""} className={"_3-99 img sp_i534r85sjIn sx_538591"} src={null}></i>;
+    }
+    if (props.x === 15) {
+      return <i className={"_3ut_ img sp_i534r85sjIn sx_e8ac93"} src={null} alt={""}></i>;
+    }
+    if (props.x === 22) {
+      return <i alt={""} className={"_3-8_ img sp_i534r85sjIn sx_7b15bc"} src={null}></i>;
+    }
+    if (props.x === 29) {
+      return <i className={"_1m1s _4540 _p img sp_i534r85sjIn sx_f40b1c"} src={null} alt={""}></i>;
+    }
+    if (props.x === 42) {
+      return (
+        <i alt={"Warning"} className={"_585p img sp_i534r85sjIn sx_20273d"} src={null}>
+          <u>{"Warning"}</u>
+        </i>
+      );
+    }
+    if (props.x === 67) {
+      return <i alt={""} className={"_3-8_ img sp_i534r85sjIn sx_b5d079"} src={null}></i>;
+    }
+    if (props.x === 70) {
+      return <i src={null} alt={""} className={"img sp_i534r85sjIn sx_29f8c9"}></i>;
+    }
+    if (props.x === 76) {
+      return <i alt={""} className={"_3-8_ img sp_i534r85sjIn sx_ef6a9c"} src={null}></i>;
+    }
+    if (props.x === 79) {
+      return <i src={null} alt={""} className={"img sp_i534r85sjIn sx_6f8c43"}></i>;
+    }
+    if (props.x === 88) {
+      return <i src={null} alt={""} className={"img sp_i534r85sjIn sx_e94a2d"}></i>;
+    }
+    if (props.x === 91) {
+      return <i src={null} alt={""} className={"img sp_i534r85sjIn sx_7ed7d4"}></i>;
+    }
+    if (props.x === 94) {
+      return <i src={null} alt={""} className={"img sp_i534r85sjIn sx_930440"}></i>;
+    }
+    if (props.x === 98) {
+      return <i src={null} alt={""} className={"img sp_i534r85sjIn sx_750c83"}></i>;
+    }
+    if (props.x === 108) {
+      return <i src={null} alt={""} className={"img sp_i534r85sjIn sx_73c1bb"}></i>;
+    }
+    if (props.x === 111) {
+      return <i src={null} alt={""} className={"img sp_i534r85sjIn sx_29f28d"}></i>;
+    }
+    if (props.x === 126) {
+      return <i src={null} alt={""} className={"_3-8_ img sp_i534r85sjIn sx_91c59e"}></i>;
+    }
+    if (props.x === 127) {
+      return <i alt={""} className={"_3-99 img sp_i534r85sjIn sx_538591"} src={null}></i>;
+    }
+    if (props.x === 134) {
+      return <i src={null} alt={""} className={"_3-8_ img sp_i534r85sjIn sx_c8eb75"}></i>;
+    }
+    if (props.x === 135) {
+      return <i alt={""} className={"_3-99 img sp_i534r85sjIn sx_538591"} src={null}></i>;
+    }
+    if (props.x === 148) {
+      return <i className={"_3yz6 _5whs img sp_i534r85sjIn sx_896996"} src={null} alt={""}></i>;
+    }
+    if (props.x === 152) {
+      return <i className={"_5b5p _4gem img sp_i534r85sjIn sx_896996"} src={null} alt={""}></i>;
+    }
+    if (props.x === 153) {
+      return <i className={"_541d img sp_i534r85sjIn sx_2f396a"} src={null} alt={""}></i>;
+    }
+    if (props.x === 160) {
+      return <i src={null} alt={""} className={"img sp_i534r85sjIn sx_31d9b0"}></i>;
+    }
+    if (props.x === 177) {
+      return <i alt={""} className={"_3-99 img sp_i534r85sjIn sx_2c18b7"} src={null}></i>;
+    }
+    if (props.x === 186) {
+      return <i src={null} alt={""} className={"img sp_i534r85sjIn sx_0a681f"}></i>;
+    }
+    if (props.x === 195) {
+      return <i className={"_1-lx img sp_OkER5ktbEyg sx_b369b4"} src={null} alt={""}></i>;
+    }
+    if (props.x === 198) {
+      return <i className={"_1-lx img sp_i534r85sjIn sx_96948e"} src={null} alt={""}></i>;
+    }
+    if (props.x === 237) {
+      return <i className={"_541d img sp_i534r85sjIn sx_2f396a"} src={null} alt={""}></i>;
+    }
+    if (props.x === 266) {
+      return <i alt={""} className={"_3-99 img sp_i534r85sjIn sx_538591"} src={null}></i>;
+    }
+    if (props.x === 314) {
+      return <i className={"_1cie _1cif img sp_i534r85sjIn sx_6e6820"} src={null} alt={""}></i>;
+    }
+    if (props.x === 345) {
+      return <i className={"_1cie img sp_i534r85sjIn sx_e896cf"} src={null} alt={""}></i>;
+    }
+    if (props.x === 351) {
+      return <i className={"_1cie img sp_i534r85sjIn sx_38fed8"} src={null} alt={""}></i>;
+    }
+  },
+});
+
+var AbstractLink1 = React.createClass({
+  render: function() {
+    var props = this.props;
+    if (props.x === 1) {
+      return (
+        <a className={"_387r _55pi _2agf _4jy0 _4jy4 _517h _51sy _42ft"} style={{"width":250,"maxWidth":"250px"}} disabled={null} label={null} href={"#"} rel={undefined} onClick={function() {}}>
+          {null}
+          <span className={"_55pe"} style={{"maxWidth":"236px"}}>
+            {null}
+            <span>
+              <span className={"_48u-"}>{"Account:"}</span>
+              {" "}
+              {"Dick Madanson (10149999073643408)"}
+            </span>
+          </span>
+          <ReactImage0 x={0} />
+        </a>
+      );
+    }
+    if (props.x === 43) {
+      return (
+        <a className={"_585q _50zy _50-0 _50z- _5upp _42ft"} size={"medium"} shade={"dark"} type={null} title={"Remove"} data-hover={undefined} data-tooltip-alignh={undefined} data-tooltip-content={undefined} disabled={null} label={null} href={"#"} rel={undefined} onClick={function() {}}>
+          {undefined}
+          {"Remove"}
+          {undefined}
+        </a>
+      );
+    }
+    if (props.x === 49) {
+      return (
+        <a target={"_blank"} href={"/ads/manage/billing.php?act=10149999073643408"} rel={undefined} onClick={function() {}}>
+          <XUIText29 x={48} />
+        </a>
+      );
+    }
+    if (props.x === 128) {
+      return (
+        <a className={" _5bbf _55pi _2agf _4jy0 _4jy4 _517h _51sy _42ft"} style={{"maxWidth":"200px"}} disabled={null} label={null} href={"#"} rel={undefined} onClick={function() {}}>
+          {null}
+          <span className={"_55pe"} style={{"maxWidth":"186px"}}>
+            <ReactImage0 x={126} />
+            {"Search"}
+          </span>
+          <ReactImage0 x={127} />
+        </a>
+      );
+    }
+    if (props.x === 136) {
+      return (
+        <a className={" _5bbf _55pi _2agf _4jy0 _4jy4 _517h _51sy _42ft"} style={{"maxWidth":"200px"}} disabled={null} label={null} href={"#"} rel={undefined} onClick={function() {}}>
+          {null}
+          <span className={"_55pe"} style={{"maxWidth":"186px"}}>
+            <ReactImage0 x={134} />
+            {"Filters"}
+          </span>
+          <ReactImage0 x={135} />
+        </a>
+      );
+    }
+    if (props.x === 178) {
+      return (
+        <a className={"_1_-t _1_-v _42ft"} disabled={null} height={"medium"} role={"button"} label={null} href={"#"} rel={undefined} onClick={function() {}}>
+          {undefined}
+          {"Lifetime"}
+          <ReactImage0 x={177} />
+        </a>
+      );
+    }
+    if (props.x === 207) {
+      return <a href={"#"} rel={undefined} onClick={function() {}}>{"Create Ad Set"}</a>;
+    }
+    if (props.x === 209) {
+      return <a href={"#"} rel={undefined} onClick={function() {}}>{"View Ad Set"}</a>;
+    }
+    if (props.x === 241) {
+      return <a href={"#"} rel={undefined} onClick={function() {}}>{"Set a Limit"}</a>;
+    }
+    if (props.x === 267) {
+      return (
+        <a className={"_p _55pi _2agf _4jy0 _4jy3 _517h _51sy _42ft"} style={{"maxWidth":"200px"}} disabled={null} label={null} href={"#"} rel={undefined} onClick={function() {}}>
+          {null}
+          <span className={"_55pe"} style={{"maxWidth":"186px"}}>
+            {null}
+            {"Links"}
+          </span>
+          <ReactImage0 x={266} />
+        </a>
+      );
+    }
   },
 });
 
 var Link2 = React.createClass({
   render: function() {
-    return (
-      <a style={{"maxWidth":"200px"}} image={null} label={null} imageRight={{}} className={"_387r _55pi _2agf _387r _55pi _4jy0 _4jy3 _517h _51sy _42ft"} href={"#"} haschevron={true} onClick={function() {}} onToggle={function() {}} size={"medium"} use={"default"} borderShade={"light"} suppressed={false} disabled={null} rel={undefined}>
-        {null}
-        <span className={"_55pe"} style={{"maxWidth":"186px"}}>
-          {null}
-          {"Dick Madanson (10149999073643408)"}
-        </span>
-        <ReactImage1 />
-      </a>
-    );
+    var props = this.props;
+    if (props.x === 2) {
+      return <AbstractLink1 x={1} />;
+    }
+    if (props.x === 44) {
+      return <AbstractLink1 x={43} />;
+    }
+    if (props.x === 50) {
+      return <AbstractLink1 x={49} />;
+    }
+    if (props.x === 129) {
+      return <AbstractLink1 x={128} />;
+    }
+    if (props.x === 137) {
+      return <AbstractLink1 x={136} />;
+    }
+    if (props.x === 179) {
+      return <AbstractLink1 x={178} />;
+    }
+    if (props.x === 208) {
+      return <AbstractLink1 x={207} />;
+    }
+    if (props.x === 210) {
+      return <AbstractLink1 x={209} />;
+    }
+    if (props.x === 242) {
+      return <AbstractLink1 x={241} />;
+    }
+    if (props.x === 268) {
+      return <AbstractLink1 x={267} />;
+    }
   },
 });
 
 var AbstractButton3 = React.createClass({
   render: function() {
-    return <Link2 />;
+    var props = this.props;
+    if (props.x === 3) {
+      return <Link2 x={2} />;
+    }
+    if (props.x === 20) {
+      return (
+        <button className={"_5n7z _4jy0 _4jy4 _517h _51sy _42ft"} onClick={function() {}} label={null} type={"submit"} value={"1"}>
+          {undefined}
+          {"Discard Changes"}
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 23) {
+      return (
+        <button className={"_5n7z _2yak _4lj- _4jy0 _4jy4 _517h _51sy _42ft _42fr"} disabled={true} onClick={function() {}} data-tooltip-content={"You have no changes to publish"} data-hover={"tooltip"} label={null} type={"submit"} value={"1"}>
+          <ReactImage0 x={22} />
+          {"Review Changes"}
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 45) {
+      return <Link2 x={44} />;
+    }
+    if (props.x === 68) {
+      return (
+        <button className={"_u_k _4jy0 _4jy4 _517h _51sy _42ft"} onClick={function() {}} label={null} type={"submit"} value={"1"}>
+          <ReactImage0 x={67} />
+          {"Create Campaign"}
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 71) {
+      return (
+        <button className={"_u_k _3qx6 _p _4jy0 _4jy4 _517h _51sy _42ft"} label={null} type={"submit"} value={"1"}>
+          <ReactImage0 x={70} />
+          {undefined}
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 77) {
+      return (
+        <button aria-label={"Edit"} data-tooltip-content={"Edit Campaigns (Ctrl+U)"} data-hover={"tooltip"} className={"_d2_ _u_k noMargin _4jy0 _4jy4 _517h _51sy _42ft"} disabled={false} onClick={function() {}} label={null} type={"submit"} value={"1"}>
+          <ReactImage0 x={76} />
+          {"Edit"}
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 80) {
+      return (
+        <button className={"_u_k _3qx6 _p _4jy0 _4jy4 _517h _51sy _42ft"} disabled={false} label={null} type={"submit"} value={"1"}>
+          <ReactImage0 x={79} />
+          {undefined}
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 89) {
+      return (
+        <button aria-label={"Revert"} className={"_u_k _4jy0 _4jy4 _517h _51sy _42ft _42fr"} data-hover={"tooltip"} data-tooltip-content={"Revert"} disabled={true} onClick={function() {}} label={null} type={"submit"} value={"1"}>
+          <ReactImage0 x={88} />
+          {undefined}
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 92) {
+      return (
+        <button aria-label={"Delete"} className={"_u_k _4jy0 _4jy4 _517h _51sy _42ft"} data-hover={"tooltip"} data-tooltip-content={"Delete"} disabled={false} onClick={function() {}} label={null} type={"submit"} value={"1"}>
+          <ReactImage0 x={91} />
+          {undefined}
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 95) {
+      return (
+        <button aria-label={"Duplicate"} className={"_u_k _4jy0 _4jy4 _517h _51sy _42ft"} data-hover={"tooltip"} data-tooltip-content={"Duplicate"} disabled={false} onClick={function() {}} label={null} type={"submit"} value={"1"}>
+          <ReactImage0 x={94} />
+          {undefined}
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 99) {
+      return (
+        <button aria-label={"Export & Import"} className={"_u_k noMargin _p _4jy0 _4jy4 _517h _51sy _42ft"} data-hover={"tooltip"} data-tooltip-content={"Export & Import"} onClick={function() {}} label={null} type={"submit"} value={"1"}>
+          <ReactImage0 x={98} />
+          {undefined}
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 109) {
+      return (
+        <button aria-label={"Create Report"} className={"_u_k _5n7z _4jy0 _4jy4 _517h _51sy _42ft"} data-hover={"tooltip"} data-tooltip-content={"Create Report"} disabled={false} style={{"boxSizing":"border-box","height":"28px","width":"48px"}} onClick={function() {}} label={null} type={"submit"} value={"1"}>
+          <ReactImage0 x={108} />
+          {undefined}
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 112) {
+      return (
+        <button aria-label={"Campaign Tags"} className={" _5uy7 _4jy0 _4jy4 _517h _51sy _42ft"} data-hover={"tooltip"} data-tooltip-content={"Campaign Tags"} disabled={false} haschevron={false} onClick={function() {}} label={null} type={"submit"} value={"1"}>
+          <ReactImage0 x={111} />
+          {undefined}
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 130) {
+      return <Link2 x={129} />;
+    }
+    if (props.x === 138) {
+      return <Link2 x={137} />;
+    }
+    if (props.x === 149) {
+      return (
+        <button className={"_3yz9 _1t-2 _50z- _50zy _50zz _50z- _5upp _42ft"} size={"small"} onClick={function() {}} shade={"dark"} type={"button"} title={"Remove"} data-hover={undefined} data-tooltip-alignh={undefined} data-tooltip-content={undefined} label={null}>
+          {undefined}
+          {"Remove"}
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 156) {
+      return (
+        <button className={"_5b5u _5b5v _4jy0 _4jy3 _517h _51sy _42ft"} onClick={function() {}} label={null} type={"submit"} value={"1"}>
+          {undefined}
+          {"Apply"}
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 161) {
+      return (
+        <button className={"_1wdf _4jy0 _517i _517h _51sy _42ft"} onClick={function() {}} label={null} type={"submit"} value={"1"}>
+          <ReactImage0 x={160} />
+          {undefined}
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 180) {
+      return <Link2 x={179} />;
+    }
+    if (props.x === 187) {
+      return (
+        <button aria-label={"List Settings"} className={"_u_k _3c5o _1-r0 _4jy0 _4jy4 _517h _51sy _42ft"} data-hover={"tooltip"} data-tooltip-content={"List Settings"} onClick={function() {}} label={null} type={"submit"} value={"1"}>
+          <ReactImage0 x={186} />
+          {undefined}
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 269) {
+      return <Link2 x={268} />;
+    }
+    if (props.x === 303) {
+      return (
+        <button className={"_tm3 _tm6 _tm7 _4jy0 _4jy6 _517h _51sy _42ft"} data-tooltip-position={"right"} data-tooltip-content={"Campaigns"} data-hover={"tooltip"} onClick={function() {}} label={null} type={"submit"} value={"1"}>
+          {undefined}
+          <div>
+            <div className={"_tma"}></div>
+            <div className={"_tm8"}></div>
+            <div className={"_tm9"}>{1}</div>
+          </div>
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 305) {
+      return (
+        <button className={"_tm4 _tm6 _4jy0 _4jy6 _517h _51sy _42ft"} data-tooltip-position={"right"} data-tooltip-content={"Ad Sets"} data-hover={"tooltip"} onClick={function() {}} label={null} type={"submit"} value={"1"}>
+          {undefined}
+          <div>
+            <div className={"_tma"}></div>
+            <div className={"_tm8"}></div>
+            <div className={"_tm9"}>{1}</div>
+          </div>
+          {undefined}
+        </button>
+      );
+    }
+    if (props.x === 307) {
+      return (
+        <button className={"_tm5 _tm6 _4jy0 _4jy6 _517h _51sy _42ft"} data-tooltip-position={"right"} data-tooltip-content={"Ads"} data-hover={"tooltip"} onClick={function() {}} label={null} type={"submit"} value={"1"}>
+          {undefined}
+          <div>
+            <div className={"_tma"}></div>
+            <div className={"_tm8"}></div>
+            <div className={"_tm9"}>{1}</div>
+          </div>
+          {undefined}
+        </button>
+      );
+    }
   },
 });
 
 var XUIButton4 = React.createClass({
   render: function() {
-    return <AbstractButton3 />;
+    var props = this.props;
+    if (props.x === 4) {
+      return <AbstractButton3 x={3} />;
+    }
+    if (props.x === 21) {
+      return <AbstractButton3 x={20} />;
+    }
+    if (props.x === 24) {
+      return <AbstractButton3 x={23} />;
+    }
+    if (props.x === 69) {
+      return <AbstractButton3 x={68} />;
+    }
+    if (props.x === 72) {
+      return <AbstractButton3 x={71} />;
+    }
+    if (props.x === 78) {
+      return <AbstractButton3 x={77} />;
+    }
+    if (props.x === 81) {
+      return <AbstractButton3 x={80} />;
+    }
+    if (props.x === 90) {
+      return <AbstractButton3 x={89} />;
+    }
+    if (props.x === 93) {
+      return <AbstractButton3 x={92} />;
+    }
+    if (props.x === 96) {
+      return <AbstractButton3 x={95} />;
+    }
+    if (props.x === 100) {
+      return <AbstractButton3 x={99} />;
+    }
+    if (props.x === 110) {
+      return <AbstractButton3 x={109} />;
+    }
+    if (props.x === 113) {
+      return <AbstractButton3 x={112} />;
+    }
+    if (props.x === 131) {
+      return <AbstractButton3 x={130} />;
+    }
+    if (props.x === 139) {
+      return <AbstractButton3 x={138} />;
+    }
+    if (props.x === 157) {
+      return <AbstractButton3 x={156} />;
+    }
+    if (props.x === 162) {
+      return <AbstractButton3 x={161} />;
+    }
+    if (props.x === 188) {
+      return <AbstractButton3 x={187} />;
+    }
+    if (props.x === 270) {
+      return <AbstractButton3 x={269} />;
+    }
+    if (props.x === 304) {
+      return <AbstractButton3 x={303} />;
+    }
+    if (props.x === 306) {
+      return <AbstractButton3 x={305} />;
+    }
+    if (props.x === 308) {
+      return <AbstractButton3 x={307} />;
+    }
   },
 });
 
 var AbstractPopoverButton5 = React.createClass({
   render: function() {
-    return <XUIButton4 />;
+    var props = this.props;
+    if (props.x === 5) {
+      return <XUIButton4 x={4} />;
+    }
+    if (props.x === 132) {
+      return <XUIButton4 x={131} />;
+    }
+    if (props.x === 140) {
+      return <XUIButton4 x={139} />;
+    }
+    if (props.x === 271) {
+      return <XUIButton4 x={270} />;
+    }
   },
 });
 
 var ReactXUIPopoverButton6 = React.createClass({
   render: function() {
-    return <AbstractPopoverButton5 />;
-  },
-});
-
-var AdsPEAccountSelector7 = React.createClass({
-  render: function() {
-    return <ReactXUIPopoverButton6 ref={"button"} />;
+    var props = this.props;
+    if (props.x === 6) {
+      return <AbstractPopoverButton5 x={5} />;
+    }
+    if (props.x === 133) {
+      return <AbstractPopoverButton5 x={132} />;
+    }
+    if (props.x === 141) {
+      return <AbstractPopoverButton5 x={140} />;
+    }
+    if (props.x === 272) {
+      return <AbstractPopoverButton5 x={271} />;
+    }
   },
 });
 
-var AdsPEAccountSelectorContainer8 = React.createClass({
+var BIGAdAccountSelector7 = React.createClass({
   render: function() {
-    return <AdsPEAccountSelector7 />;
+    var props = this.props;
+    if (props.x === 7) {
+      return (
+        <div>
+          <ReactXUIPopoverButton6 x={6} ref={"openMenuButton"} />
+          {null}
+        </div>
+      );
+    }
+  },
+});
+
+var FluxContainer_AdsPEBIGAdAccountSelectorContainer_8 = React.createClass({
+  render: function() {
+    var props = this.props;
+    if (props.x === 8) {
+      return <BIGAdAccountSelector7 x={7} />;
+    }
+  },
+});
+
+var ErrorBoundary9 = React.createClass({
+  render: function() {
+    var props = this.props;
+    if (props.x === 9) {
+      return <FluxContainer_AdsPEBIGAdAccountSelectorContainer_8 x={8} />;
+    }
+    if (props.x === 13) {
+      return <FluxContainer_AdsPENavigationBarContainer_12 x={12} />;
+    }
+    if (props.x === 27) {
+      return <FluxContainer_AdsPEPublishButtonContainer_18 x={26} />;
+    }
+    if (props.x === 32) {
+      return <ReactPopoverMenu20 x={31} />;
+    }
+    if (props.x === 38) {
+      return <AdsPEResetDialog24 x={37} />;
+    }
+    if (props.x === 57) {
+      return <FluxContainer_AdsPETopErrorContainer_35 x={56} />;
+    }
+    if (props.x === 60) {
+      return <FluxContainer_AdsGuidanceChannel_36 x={59} />;
+    }
+    if (props.x === 64) {
+      return <FluxContainer_AdsBulkEditDialogContainer_38 x={63} />;
+    }
+    if (props.x === 124) {
+      return <AdsPECampaignGroupToolbarContainer57 x={123} />;
+    }
+    if (props.x === 170) {
+      return <AdsPEFilterContainer72 x={169} />;
+    }
+    if (props.x === 175) {
+      return <AdsPETablePagerContainer75 x={174} />;
+    }
+    if (props.x === 193) {
+      return <AdsPEStatRangeContainer81 x={192} />;
+    }
+    if (props.x === 301) {
+      return <FluxContainer_AdsPEMultiTabDrawerContainer_137 x={300} />;
+    }
+    if (props.x === 311) {
+      return <AdsPEOrganizerContainer139 x={310} />;
+    }
+    if (props.x === 471) {
+      return <AdsPECampaignGroupTableContainer159 x={470} />;
+    }
+    if (props.x === 475) {
+      return <AdsPEContentContainer161 x={474} />;
+    }
+  },
+});
+
+var AdsErrorBoundary10 = React.createClass({
+  render: function() {
+    var props = this.props;
+    if (props.x === 10) {
+      return <ErrorBoundary9 x={9} />;
+    }
+    if (props.x === 14) {
+      return <ErrorBoundary9 x={13} />;
+    }
+    if (props.x === 28) {
+      return <ErrorBoundary9 x={27} />;
+    }
+    if (props.x === 33) {
+      return <ErrorBoundary9 x={32} />;
+    }
+    if (props.x === 39) {
+      return <ErrorBoundary9 x={38} />;
+    }
+    if (props.x === 58) {
+      return <ErrorBoundary9 x={57} />;
+    }
+    if (props.x === 61) {
+      return <ErrorBoundary9 x={60} />;
+    }
+    if (props.x === 65) {
+      return <ErrorBoundary9 x={64} />;
+    }
+    if (props.x === 125) {
+      return <ErrorBoundary9 x={124} />;
+    }
+    if (props.x === 171) {
+      return <ErrorBoundary9 x={170} />;
+    }
+    if (props.x === 176) {
+      return <ErrorBoundary9 x={175} />;
+    }
+    if (props.x === 194) {
+      return <ErrorBoundary9 x={193} />;
+    }
+    if (props.x === 302) {
+      return <ErrorBoundary9 x={301} />;
+    }
+    if (props.x === 312) {
+      return <ErrorBoundary9 x={311} />;
+    }
+    if (props.x === 472) {
+      return <ErrorBoundary9 x={471} />;
+    }
+    if (props.x === 476) {
+      return <ErrorBoundary9 x={475} />;
+    }
+  },
+});
+
+var AdsPENavigationBar11 = React.createClass({
+  render: function() {
+    var props = this.props;
+    if (props.x === 11) {
+      return <div className={"_4t_9"}></div>;
+    }
+  },
+});
+
+var FluxContainer_AdsPENavigationBarContainer_12 = React.createClass({
+  render: function() {
+    var props = this.props;
+    if (props.x === 12) {
+      return <AdsPENavigationBar11 x={11} />;
+    }
+  },
+});
+
+var AdsPEDraftSyncStatus13 = React.createClass({
+  render: function() {
+    var props = this.props;
+    if (props.x === 16) {
+      return (
+        <div className={"_3ut-"} onClick={function() {}}>
+          <span className={"_3uu0"}>
+            <ReactImage0 x={15} />
+          </span>
+        </div>
+      );
+    }
   },
 });
 
-var AbstractButton9 = React.createClass({
+var FluxContainer_AdsPEDraftSyncStatusContainer_14 = React.createClass({
   render: function() {
-    return (
-      <button id={"downloadButton"} className={"_5lk0 _4jy0 _4jy3 _517h _51sy _42ft"} label={null} onClick={function() {}} use={"default"} size={"medium"} borderShade={"light"} suppressed={false} type={"submit"} value={"1"}>
-        {undefined}
-        {"Download to Power Editor"}
-        {undefined}
-      </button>
-    );
+    var props = this.props;
+    if (props.x === 17) {
+      return <AdsPEDraftSyncStatus13 x={16} />;
+    }
   },
 });
 
-var XUIButton10 = React.createClass({
+var AdsPEDraftErrorsStatus15 = React.createClass({
   render: function() {
-    return <AbstractButton9 />;
+    var props = this.props;
+    if (props.x === 18) {
+      return null;
+    }
   },
 });
 
-var DownloadUploadTimestamp11 = React.createClass({
+var FluxContainer_viewFn_16 = React.createClass({
   render: function() {
-    return (
-      <div>
-        {"Last downloaded"}
-        {" "}
-        <abbr className={"livetimestamp"} data-utime={1446062352} data-shorten={false}>{"a few seconds ago"}</abbr>
-      </div>
-    );
+    var props = this.props;
+    if (props.x === 19) {
+      return <AdsPEDraftErrorsStatus15 x={18} />;
+    }
   },
 });
 
-var ReactImage12 = React.createClass({
+var AdsPEPublishButton17 = React.createClass({
   render: function() {
-    return <i alt={""} className={"_3-8_ img sp_UuU9HmrQ397 sx_dbc06a"} src={null}></i>;
+    var props = this.props;
+    if (props.x === 25) {
+      return (
+        <div className={"_5533"}>
+          <FluxContainer_AdsPEDraftSyncStatusContainer_14 x={17} />
+          <FluxContainer_viewFn_16 x={19} />
+          {null}
+          <XUIButton4 x={21} key={"discard"} />
+          <XUIButton4 x={24} ref={"reviewChangesButton"} />
+        </div>
+      );
+    }
   },
 });
 
-var AbstractButton13 = React.createClass({
+var FluxContainer_AdsPEPublishButtonContainer_18 = React.createClass({
   render: function() {
-    return (
-      <button id={"uploadButton"} className={"_5lk0 _4jy0 _4jy3 _517h _51sy _42ft"} image={{}} use={"default"} label={null} onClick={function() {}} size={"medium"} borderShade={"light"} suppressed={false} type={"submit"} value={"1"}>
-        <ReactImage12 />
-        {"Upload Changes"}
-        {undefined}
-      </button>
-    );
+    var props = this.props;
+    if (props.x === 26) {
+      return <AdsPEPublishButton17 x={25} />;
+    }
   },
 });
 
-var XUIButton14 = React.createClass({
+var InlineBlock19 = React.createClass({
   render: function() {
-    return <AbstractButton13 />;
+    var props = this.props;
+    if (props.x === 30) {
+      return (
+        <div className={"uiPopover _6a _6b"} disabled={null}>
+          <ReactImage0 x={29} key={".0"} />
+        </div>
+      );
+    }
+    if (props.x === 73) {
+      return (
+        <div className={"uiPopover _6a _6b"} disabled={null}>
+          <XUIButton4 x={72} key={".0"} />
+        </div>
+      );
+    }
+    if (props.x === 82) {
+      return (
+        <div className={"_1nwm uiPopover _6a _6b"} disabled={null}>
+          <XUIButton4 x={81} key={".0"} />
+        </div>
+      );
+    }
+    if (props.x === 101) {
+      return (
+        <div size={"large"} className={"uiPopover _6a _6b"} disabled={null}>
+          <XUIButton4 x={100} key={".0"} />
+        </div>
+      );
+    }
+    if (props.x === 273) {
+      return (
+        <div className={"_3-90 uiPopover _6a _6b"} style={{"marginTop":2}} disabled={null}>
+          <ReactXUIPopoverButton6 x={272} key={".0"} />
+        </div>
+      );
+    }
   },
 });
 
-var DownloadUploadTimestamp15 = React.createClass({
+var ReactPopoverMenu20 = React.createClass({
   render: function() {
-    return <div></div>;
+    var props = this.props;
+    if (props.x === 31) {
+      return <InlineBlock19 x={30} ref={"root"} />;
+    }
+    if (props.x === 74) {
+      return <InlineBlock19 x={73} ref={"root"} />;
+    }
+    if (props.x === 83) {
+      return <InlineBlock19 x={82} ref={"root"} />;
+    }
+    if (props.x === 102) {
+      return <InlineBlock19 x={101} ref={"root"} />;
+    }
+    if (props.x === 274) {
+      return <InlineBlock19 x={273} ref={"root"} />;
+    }
   },
 });
 
-var AbstractButton16 = React.createClass({
+var LeftRight21 = React.createClass({
   render: function() {
-    return (
-      <button className={"_5ljz _4jy0 _4jy3 _517h _51sy _42ft"} label={null} onClick={function() {}} use={"default"} size={"medium"} borderShade={"light"} suppressed={false} type={"submit"} value={"1"}>
-        {undefined}
-        {"Help"}
-        {undefined}
-      </button>
-    );
+    var props = this.props;
+    if (props.x === 34) {
+      return (
+        <div className={"clearfix"}>
+          <div key={"left"} className={"_ohe lfloat"}>
+            <div className={"_34_j"}>
+              <div className={"_34_k"}>
+                <AdsErrorBoundary10 x={10} />
+              </div>
+              <div className={"_2u-6"}>
+                <AdsErrorBoundary10 x={14} />
+              </div>
+            </div>
+          </div>
+          <div key={"right"} className={"_ohf rfloat"}>
+            <div className={"_34_m"}>
+              <div key={"0"} className={"_5ju2"}>
+                <AdsErrorBoundary10 x={28} />
+              </div>
+              <div key={"1"} className={"_5ju2"}>
+                <AdsErrorBoundary10 x={33} />
+              </div>
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 232) {
+      return (
+        <div flex={"right"} direction={"left"} className={"clearfix"}>
+          <div key={"left"} className={"_ohe lfloat"}>
+            <AdsLabeledField104 x={231} />
+          </div>
+          <div key={"right"} className={""}>
+            <div className={"_42ef"}>
+              <div className={"_2oc7"}>{"Clicks to Website"}</div>
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 235) {
+      return (
+        <div className={"_3-8x clearfix"} flex={"right"} direction={"left"}>
+          <div key={"left"} className={"_ohe lfloat"}>
+            <AdsLabeledField104 x={234} />
+          </div>
+          <div key={"right"} className={""}>
+            <div className={"_42ef"}>
+              <div className={"_2oc7"}>{"Auction"}</div>
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 245) {
+      return (
+        <div className={"_3-8y clearfix"} flex={"right"} direction={"left"}>
+          <div key={"left"} className={"_ohe lfloat"}>
+            <AdsLabeledField104 x={240} />
+          </div>
+          <div key={"right"} className={""}>
+            <div className={"_42ef"}>
+              <FluxContainer_AdsCampaignGroupSpendCapContainer_107 x={244} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 277) {
+      return (
+        <div className={"_5dw9 _5dwa clearfix"}>
+          <div key={"left"} className={"_ohe lfloat"}>
+            <XUICardHeaderTitle100 x={265} key={".0"} />
+          </div>
+          <div key={"right"} className={"_ohf rfloat"}>
+            <FluxContainer_AdsPluginizedLinksMenuContainer_121 x={276} key={".1"} />
+          </div>
+        </div>
+      );
+    }
   },
 });
 
-var XUIButton17 = React.createClass({
+var AdsUnifiedNavigationLocalNav22 = React.createClass({
   render: function() {
-    return <AbstractButton16 />;
+    var props = this.props;
+    if (props.x === 35) {
+      return (
+        <div className={"_34_i"}>
+          <LeftRight21 x={34} />
+        </div>
+      );
+    }
   },
 });
 
-var ReactImage18 = React.createClass({
+var XUIDialog23 = React.createClass({
   render: function() {
-    return <i src={null} className={"img sp_UuU9HmrQ397 sx_d5a685"}></i>;
+    var props = this.props;
+    if (props.x === 36) {
+      return null;
+    }
   },
 });
 
-var AbstractButton19 = React.createClass({
+var AdsPEResetDialog24 = React.createClass({
   render: function() {
-    return (
-      <button className={"_5ljw _p _4jy0 _4jy3 _517h _51sy _42ft"} image={{}} use={"default"} size={"medium"} borderShade={"light"} suppressed={false} label={null} type={"submit"} value={"1"}>
-        <ReactImage18 />
-        {undefined}
-        {undefined}
-      </button>
-    );
+    var props = this.props;
+    if (props.x === 37) {
+      return (
+        <span>
+          <XUIDialog23 x={36} key={"dialog/.0"} />
+        </span>
+      );
+    }
   },
 });
 
-var XUIButton20 = React.createClass({
+var AdsPETopNav25 = React.createClass({
   render: function() {
-    return <AbstractButton19 />;
+    var props = this.props;
+    if (props.x === 40) {
+      return (
+        <div style={{"width":1306}}>
+          <AdsUnifiedNavigationLocalNav22 x={35} />
+          <AdsErrorBoundary10 x={39} />
+        </div>
+      );
+    }
   },
 });
 
-var InlineBlock21 = React.createClass({
+var FluxContainer_AdsPETopNavContainer_26 = React.createClass({
   render: function() {
-    return (
-      <div className={"_5ljz uiPopover _6a _6b"} alignh={"right"} menu={{}} alignv={"middle"} disabled={null} fullWidth={false}>
-        <XUIButton20 key={"/.0"} />
-      </div>
-    );
+    var props = this.props;
+    if (props.x === 41) {
+      return <AdsPETopNav25 x={40} />;
+    }
   },
 });
 
-var ReactPopoverMenu22 = React.createClass({
+var XUIAbstractGlyphButton27 = React.createClass({
   render: function() {
-    return <InlineBlock21 ref={"root"} />;
+    var props = this.props;
+    if (props.x === 46) {
+      return <AbstractButton3 x={45} />;
+    }
+    if (props.x === 150) {
+      return <AbstractButton3 x={149} />;
+    }
   },
 });
 
-var XUIButtonGroup23 = React.createClass({
+var XUICloseButton28 = React.createClass({
   render: function() {
-    return (
-      <div className={"_13xj _51xa"} id={"helpButton"}>
-        <XUIButton17 />
-        <ReactPopoverMenu22 />
-      </div>
-    );
+    var props = this.props;
+    if (props.x === 47) {
+      return <XUIAbstractGlyphButton27 x={46} />;
+    }
+    if (props.x === 151) {
+      return <XUIAbstractGlyphButton27 x={150} />;
+    }
   },
 });
 
-var AdsPEResetDialog24 = React.createClass({
+var XUIText29 = React.createClass({
   render: function() {
-    return <span></span>;
+    var props = this.props;
+    if (props.x === 48) {
+      return <span display={"inline"} className={" _50f7"}>{"Ads Manager"}</span>;
+    }
+    if (props.x === 205) {
+      return <span className={"_2x9f  _50f5 _50f7"} display={"inline"}>{"Editing Campaign"}</span>;
+    }
+    if (props.x === 206) {
+      return <span display={"inline"} className={" _50f5 _50f7"}>{"Test Campaign"}</span>;
+    }
   },
 });
 
-var AdsPETopNav25 = React.createClass({
+var XUINotice30 = React.createClass({
   render: function() {
-    return (
-      <div className={"_5ljl"} id={"ads_pe_top_nav"}>
-        <div ref={"logo"} className={"_5ljm"}>
-          <Link0 />
-          <div className={"_5rne"}>
-            <span className={"_5ljs"} data-testid={"PETopNavLogoText"}>{"Power Editor"}</span>
-          </div>
-          <span className={"_5ljt _5lju"}>{"Dick Madanson"}</span>
-        </div>
-        <div ref={"leftButtonGroup"} className={"_5ljy"}>
-          <div ref={"accountDropdown"} className={"_5ljz _5mun"}>
-            <AdsPEAccountSelectorContainer8 />
-            <div className={"_5lj- _5lju"}>{"Account 10149999073643408"}</div>
-          </div>
-          <div className={"_5ljz"}>
-            <div className={"_5lj_"}>
-              <XUIButton10 />
-            </div>
-            <div className={"_5lj- _5lju"}>
-              <DownloadUploadTimestamp11 />
-            </div>
-          </div>
-          <div className={"_5ljz"}>
-            <div className={"_5lj_"}>
-              <XUIButton14 />
-            </div>
-            <div className={"_5lj- _5lju"}>
-              <DownloadUploadTimestamp15 />
-            </div>
+    var props = this.props;
+    if (props.x === 51) {
+      return (
+        <div size={"medium"} className={"_585n _585o _2wdd"}>
+          <ReactImage0 x={42} />
+          <XUICloseButton28 x={47} />
+          <div className={"_585r _2i-a _50f4"}>
+            {"Please go to "}
+            <Link2 x={50} />
+            {" to set up a payment method for this ad account."}
           </div>
         </div>
-        <div ref={"rightButtonGroup"} className={"_5lk3"}>
-          <XUIButtonGroup23 />
-        </div>
-        <AdsPEResetDialog24 />
-      </div>
-    );
+      );
+    }
   },
 });
 
-var FluxContainer_ja_26 = React.createClass({
+var ReactCSSTransitionGroupChild31 = React.createClass({
   render: function() {
-    return <AdsPETopNav25 />;
+    var props = this.props;
+    if (props.x === 52) {
+      return <XUINotice30 x={51} />;
+    }
   },
 });
 
-var _wrapper27 = React.createClass({
+var ReactTransitionGroup32 = React.createClass({
   render: function() {
-    return (
-      <li selected={true} focused={false} tabIndex={null} hideFocusRing={true} onClick={function() {}} onMouseDown={function() {}} onFocus={function() {}} onBlur={function() {}} className={"_5vwz _5vwy _45hc _1hqh"} wrapper={function() {}} shouldWrapTab={true} mockSpacebarClick={true} role={"presentation"}>
-        <a ref={"tab"} ajaxify={undefined} href={"#"} role={"tab"} rel={undefined} target={undefined} tabIndex={0} className={""} aria-selected={true} onKeyDown={function() {}}>
-          <div className={"_4jq5"}>{"Manage Ads"}</div>
-          <span className={"_13xf"}></span>
-        </a>
-      </li>
-    );
+    var props = this.props;
+    if (props.x === 53) {
+      return (
+        <span>
+          <ReactCSSTransitionGroupChild31 x={52} key={".0"} ref={".0"} />
+        </span>
+      );
+    }
   },
 });
 
-var TabBarItem28 = React.createClass({
+var ReactCSSTransitionGroup33 = React.createClass({
   render: function() {
-    return <_wrapper27 />;
+    var props = this.props;
+    if (props.x === 54) {
+      return <ReactTransitionGroup32 x={53} />;
+    }
   },
 });
 
-var XUIPageNavigationItem29 = React.createClass({
+var AdsPETopError34 = React.createClass({
   render: function() {
-    return <TabBarItem28 />;
+    var props = this.props;
+    if (props.x === 55) {
+      return (
+        <div className={"_2wdc"}>
+          <ReactCSSTransitionGroup33 x={54} />
+        </div>
+      );
+    }
   },
 });
 
-var TabBarItemWrapper30 = React.createClass({
+var FluxContainer_AdsPETopErrorContainer_35 = React.createClass({
   render: function() {
-    return <XUIPageNavigationItem29 key={"MANAGE_ADS"} />;
+    var props = this.props;
+    if (props.x === 56) {
+      return <AdsPETopError34 x={55} />;
+    }
   },
 });
 
-var _wrapper31 = React.createClass({
+var FluxContainer_AdsGuidanceChannel_36 = React.createClass({
   render: function() {
-    return (
-      <li selected={false} focused={false} tabIndex={null} hideFocusRing={true} onClick={function() {}} onMouseDown={function() {}} onFocus={function() {}} onBlur={function() {}} className={"_5vwz _45hc"} wrapper={function() {}} shouldWrapTab={true} mockSpacebarClick={true} role={"presentation"}>
-        <a ref={"tab"} ajaxify={undefined} href={"#"} role={"tab"} rel={undefined} target={undefined} tabIndex={-1} className={""} aria-selected={false} onKeyDown={function() {}}>
-          <div className={"_4jq5"}>{"Audiences"}</div>
-          <span className={"_13xf"}></span>
-        </a>
-      </li>
-    );
+    var props = this.props;
+    if (props.x === 59) {
+      return null;
+    }
   },
 });
 
-var TabBarItem32 = React.createClass({
+var ResponsiveBlock37 = React.createClass({
   render: function() {
-    return <_wrapper31 />;
+    var props = this.props;
+    if (props.x === 62) {
+      return (
+        <div onResize={function() {}} className={"_4u-c"}>
+          {[
+            <AdsErrorBoundary10 x={58} />,
+            <AdsErrorBoundary10 x={61} />,
+          ]}
+          <div key={"sensor"} className={"_4u-f"}>
+            <iframe ref={"sensorNode"} aria-hidden={"true"} className={"_1_xb"} tabIndex={"-1"}></iframe>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 469) {
+      return (
+        <div onResize={function() {}} className={"_4u-c"}>
+          <AdsPEDataTableContainer158 x={468} />
+          <div key={"sensor"} className={"_4u-f"}>
+            <iframe ref={"sensorNode"} aria-hidden={"true"} className={"_1_xb"} tabIndex={"-1"}></iframe>
+          </div>
+        </div>
+      );
+    }
   },
 });
 
-var XUIPageNavigationItem33 = React.createClass({
+var FluxContainer_AdsBulkEditDialogContainer_38 = React.createClass({
   render: function() {
-    return <TabBarItem32 />;
+    var props = this.props;
+    if (props.x === 63) {
+      return null;
+    }
   },
 });
 
-var TabBarItemWrapper34 = React.createClass({
+var Column39 = React.createClass({
   render: function() {
-    return <XUIPageNavigationItem33 key={"AUDIENCES"} />;
+    var props = this.props;
+    if (props.x === 66) {
+      return (
+        <div className={"_4bl8 _4bl7"}>
+          <div className={"_3c5f"}>
+            {null}
+            {null}
+            <div className={"_3c5i"}></div>
+            {null}
+          </div>
+        </div>
+      );
+    }
   },
 });
 
-var _wrapper35 = React.createClass({
+var XUIButtonGroup40 = React.createClass({
   render: function() {
-    return (
-      <li selected={false} focused={false} tabIndex={null} hideFocusRing={true} onClick={function() {}} onMouseDown={function() {}} onFocus={function() {}} onBlur={function() {}} className={"_5vwz _45hc"} wrapper={function() {}} shouldWrapTab={true} mockSpacebarClick={true} role={"presentation"}>
-        <a ref={"tab"} ajaxify={undefined} href={"#"} role={"tab"} rel={undefined} target={undefined} tabIndex={-1} className={""} aria-selected={false} onKeyDown={function() {}}>
-          <div className={"_4jq5"}>{"Image Library"}</div>
-          <span className={"_13xf"}></span>
-        </a>
-      </li>
-    );
+    var props = this.props;
+    if (props.x === 75) {
+      return (
+        <div className={"_5n7z _51xa"}>
+          <XUIButton4 x={69} />
+          <ReactPopoverMenu20 x={74} />
+        </div>
+      );
+    }
+    if (props.x === 84) {
+      return (
+        <div className={"_5n7z _51xa"}>
+          <XUIButton4 x={78} key={"edit"} />
+          <ReactPopoverMenu20 x={83} key={"editMenu"} />
+        </div>
+      );
+    }
+    if (props.x === 97) {
+      return (
+        <div className={"_5n7z _51xa"}>
+          <XUIButton4 x={90} key={"revert"} />
+          <XUIButton4 x={93} key={"delete"} />
+          <XUIButton4 x={96} key={"duplicate"} />
+        </div>
+      );
+    }
+    if (props.x === 117) {
+      return (
+        <div className={"_5n7z _51xa"}>
+          <AdsPEExportImportMenuContainer48 x={107} />
+          <XUIButton4 x={110} key={"createReport"} ref={"ads_create_report_button"} />
+          <AdsPECampaignGroupTagContainer51 x={116} key={"tags"} />
+        </div>
+      );
+    }
   },
 });
 
-var TabBarItem36 = React.createClass({
+var AdsPEEditToolbarButton41 = React.createClass({
   render: function() {
-    return <_wrapper35 />;
+    var props = this.props;
+    if (props.x === 85) {
+      return <XUIButtonGroup40 x={84} />;
+    }
   },
 });
 
-var XUIPageNavigationItem37 = React.createClass({
+var FluxContainer_AdsPEEditCampaignGroupToolbarButtonContainer_42 = React.createClass({
   render: function() {
-    return <TabBarItem36 />;
+    var props = this.props;
+    if (props.x === 86) {
+      return <AdsPEEditToolbarButton41 x={85} />;
+    }
   },
 });
 
-var TabBarItemWrapper38 = React.createClass({
+var FluxContainer_AdsPEEditToolbarButtonContainer_43 = React.createClass({
   render: function() {
-    return <XUIPageNavigationItem37 key={"IMAGES"} />;
+    var props = this.props;
+    if (props.x === 87) {
+      return <FluxContainer_AdsPEEditCampaignGroupToolbarButtonContainer_42 x={86} />;
+    }
   },
 });
 
-var _wrapper39 = React.createClass({
+var AdsPEExportImportMenu44 = React.createClass({
   render: function() {
-    return (
-      <li selected={false} focused={false} tabIndex={null} hideFocusRing={true} onClick={function() {}} onMouseDown={function() {}} onFocus={function() {}} onBlur={function() {}} className={"_5vwz _45hc"} wrapper={function() {}} shouldWrapTab={true} mockSpacebarClick={true} role={"presentation"}>
-        <a ref={"tab"} ajaxify={undefined} href={"#"} role={"tab"} rel={undefined} target={undefined} tabIndex={-1} className={""} aria-selected={false} onKeyDown={function() {}}>
-          <div className={"_4jq5"}>
-            {"Reporting"}
-            {null}
-          </div>
-          <span className={"_13xf"}></span>
-        </a>
-      </li>
-    );
+    var props = this.props;
+    if (props.x === 103) {
+      return <ReactPopoverMenu20 x={102} key={"export"} />;
+    }
   },
 });
 
-var TabBarItem40 = React.createClass({
+var FluxContainer_AdsPECustomizeExportContainer_45 = React.createClass({
   render: function() {
-    return <_wrapper39 />;
+    var props = this.props;
+    if (props.x === 104) {
+      return null;
+    }
   },
 });
 
-var XUIPageNavigationItem41 = React.createClass({
+var AdsPEExportAsTextDialog46 = React.createClass({
   render: function() {
-    return <TabBarItem40 />;
+    var props = this.props;
+    if (props.x === 105) {
+      return null;
+    }
   },
 });
 
-var TabBarItemWrapper42 = React.createClass({
+var FluxContainer_AdsPEExportAsTextDialogContainer_47 = React.createClass({
   render: function() {
-    return <XUIPageNavigationItem41 key={"REPORTING"} />;
+    var props = this.props;
+    if (props.x === 106) {
+      return <AdsPEExportAsTextDialog46 x={105} />;
+    }
   },
 });
 
-var _wrapper43 = React.createClass({
+var AdsPEExportImportMenuContainer48 = React.createClass({
   render: function() {
-    return (
-      <li selected={false} focused={false} tabIndex={null} hideFocusRing={true} onClick={function() {}} onMouseDown={function() {}} onFocus={function() {}} onBlur={function() {}} className={"_5vwz _45hc"} wrapper={function() {}} shouldWrapTab={true} mockSpacebarClick={true} role={"presentation"}>
-        <a ref={"tab"} ajaxify={undefined} href={"#"} role={"tab"} rel={undefined} target={undefined} tabIndex={-1} className={""} aria-selected={false} onKeyDown={function() {}}>
-          <div className={"_4jq5"}>{"Page Posts"}</div>
-          <span className={"_13xf"}></span>
-        </a>
-      </li>
-    );
+    var props = this.props;
+    if (props.x === 107) {
+      return (
+        <span>
+          <AdsPEExportImportMenu44 x={103} />
+          <FluxContainer_AdsPECustomizeExportContainer_45 x={104} />
+          <FluxContainer_AdsPEExportAsTextDialogContainer_47 x={106} />
+          {null}
+          {null}
+        </span>
+      );
+    }
   },
 });
 
-var TabBarItem44 = React.createClass({
+var Constructor49 = React.createClass({
   render: function() {
-    return <_wrapper43 />;
+    var props = this.props;
+    if (props.x === 114) {
+      return null;
+    }
+    if (props.x === 142) {
+      return null;
+    }
+    if (props.x === 143) {
+      return null;
+    }
+    if (props.x === 183) {
+      return null;
+    }
   },
 });
 
-var XUIPageNavigationItem45 = React.createClass({
+var TagSelectorPopover50 = React.createClass({
   render: function() {
-    return <TabBarItem44 />;
+    var props = this.props;
+    if (props.x === 115) {
+      return (
+        <span className={" _3d6e"}>
+          <XUIButton4 x={113} ref={"button"} />
+          <Constructor49 x={114} key={"layer"} ref={"layer"} />
+        </span>
+      );
+    }
   },
 });
 
-var TabBarItemWrapper46 = React.createClass({
+var AdsPECampaignGroupTagContainer51 = React.createClass({
   render: function() {
-    return <XUIPageNavigationItem45 key={"PAGES"} />;
+    var props = this.props;
+    if (props.x === 116) {
+      return <TagSelectorPopover50 x={115} key={"98010048849317"} />;
+    }
   },
 });
 
-var TabBarItem47 = React.createClass({
+var AdsRuleToolbarMenu52 = React.createClass({
   render: function() {
-    return (
-      <a ref={"tab"} menuClassName={undefined} selected={false} focused={false} hideFocusRing={true} onMouseDown={function() {}} onFocus={function() {}} onBlur={function() {}} label={"Tools"} tabComponent={function() {}} shouldWrapTab={false} className={"_45hd _45hc _p _45hc"} tabIndex={-1} mockSpacebarClick={false} wrapper={function() {}} href={"#"} role={"tab"} aria-selected={false}>
-        <span className={"_1b0"}>
-          {"Tools"}
-          <span className={"accessible_elem"}>{"additional tabs menu"}</span>
-        </span>
-      </a>
-    );
+    var props = this.props;
+    if (props.x === 118) {
+      return null;
+    }
   },
 });
 
-var InlineBlock48 = React.createClass({
+var FluxContainer_AdsPERuleToolbarMenuContainer_53 = React.createClass({
   render: function() {
-    return (
-      <div menu={{}} layerBehaviors={{}} alignv={"middle"} className={"uiPopover _6a _6b"} disabled={null} fullWidth={false}>
-        <TabBarItem47 key={"/.0"} />
-      </div>
-    );
+    var props = this.props;
+    if (props.x === 119) {
+      return <AdsRuleToolbarMenu52 x={118} />;
+    }
   },
 });
 
-var ReactPopoverMenu49 = React.createClass({
+var FillColumn54 = React.createClass({
   render: function() {
-    return <InlineBlock48 ref={"root"} />;
+    var props = this.props;
+    if (props.x === 120) {
+      return (
+        <div className={"_4bl9"}>
+          <span className={"_3c5e"}>
+            <span>
+              <XUIButtonGroup40 x={75} />
+              <FluxContainer_AdsPEEditToolbarButtonContainer_43 x={87} />
+              {null}
+              <XUIButtonGroup40 x={97} />
+            </span>
+            <XUIButtonGroup40 x={117} />
+            <FluxContainer_AdsPERuleToolbarMenuContainer_53 x={119} />
+          </span>
+        </div>
+      );
+    }
   },
 });
 
-var TabBarDropdownItem50 = React.createClass({
+var Layout55 = React.createClass({
   render: function() {
-    return (
-      <li className={" _45hd"} role={"tab"}>
-        <ReactPopoverMenu49 />
-      </li>
-    );
+    var props = this.props;
+    if (props.x === 121) {
+      return (
+        <div className={"clearfix"}>
+          <Column39 x={66} key={"1"} />
+          <FillColumn54 x={120} key={"0"} />
+        </div>
+      );
+    }
   },
 });
 
-var TabBar51 = React.createClass({
+var AdsPEMainPaneToolbar56 = React.createClass({
   render: function() {
-    return (
-      <ul onTabClick={function() {}} activeTabKey={"MANAGE_ADS"} onWidthCalculated={function() {}} width={null} maxTabsVisible={5} moreLabel={"Tools"} alwaysShowActive={true} dropdownTabComponent={function() {}} shouldCalculateVisibleTabs={true} className={"_43o4"} role={"tablist"} onKeyDown={function() {}} onKeyUp={function() {}}>
-        <TabBarItemWrapper30 key={"MANAGE_ADS"} />
-        <TabBarItemWrapper34 key={"AUDIENCES"} />
-        <TabBarItemWrapper38 key={"IMAGES"} />
-        <TabBarItemWrapper42 key={"REPORTING"} />
-        <TabBarItemWrapper46 key={"PAGES"} />
-        <TabBarDropdownItem50 key={"_dropdown"} ref={"more"} />
-      </ul>
-    );
+    var props = this.props;
+    if (props.x === 122) {
+      return (
+        <div className={"_3c5b clearfix"}>
+          <Layout55 x={121} />
+        </div>
+      );
+    }
   },
 });
 
-var XUIPageNavigationGroup52 = React.createClass({
+var AdsPECampaignGroupToolbarContainer57 = React.createClass({
   render: function() {
-    return <TabBar51 ref={"bar"} />;
+    var props = this.props;
+    if (props.x === 123) {
+      return <AdsPEMainPaneToolbar56 x={122} />;
+    }
   },
 });
 
-var LeftRight53 = React.createClass({
+var AdsPEFiltersPopover58 = React.createClass({
   render: function() {
-    return (
-      <div className={"_5vx7 clearfix"}>
-        <div key={"left"} className={"_ohe lfloat"}>
-          <XUIPageNavigationGroup52 key={"0"} ref={"left"} />
-        </div>
-        {null}
-      </div>
-    );
+    var props = this.props;
+    if (props.x === 144) {
+      return (
+        <span className={"_5b-l  _5bbe"}>
+          <ReactXUIPopoverButton6 x={133} ref={"searchButton"} />
+          <ReactXUIPopoverButton6 x={141} ref={"filterButton"} />
+          {[
+            <Constructor49 x={142} key={"filterMenu/.0"} />,
+            <Constructor49 x={143} key={"searchMenu/.0"} />,
+          ]}
+        </span>
+      );
+    }
   },
 });
 
-var XUIPageNavigation54 = React.createClass({
+var AbstractCheckboxInput59 = React.createClass({
   render: function() {
-    return (
-      <div className={"_5vx2 _5vx4 _5vx6 _5kkt"}>
-        <LeftRight53 />
-      </div>
-    );
+    var props = this.props;
+    if (props.x === 145) {
+      return (
+        <label className={"uiInputLabelInput _55sg _kv1"}>
+          <input checked={true} disabled={true} name={"filterUnpublished"} value={"on"} onClick={function() {}} className={null} id={"js_input_label_21"} type={"checkbox"}></input>
+          <span data-hover={null} data-tooltip-content={undefined}></span>
+        </label>
+      );
+    }
+    if (props.x === 336) {
+      return (
+        <label className={"_4h2r _55sg _kv1"}>
+          <input checked={undefined} onChange={function() {}} className={null} type={"checkbox"}></input>
+          <span data-hover={null} data-tooltip-content={undefined}></span>
+        </label>
+      );
+    }
   },
 });
 
-var AdsPENavigationBar55 = React.createClass({
+var XUICheckboxInput60 = React.createClass({
   render: function() {
-    return (
-      <div className={"_5_a"} id={"ads_pe_navigation_bar"}>
-        <XUIPageNavigation54 />
-      </div>
-    );
+    var props = this.props;
+    if (props.x === 146) {
+      return <AbstractCheckboxInput59 x={145} />;
+    }
+    if (props.x === 337) {
+      return <AbstractCheckboxInput59 x={336} />;
+    }
   },
 });
 
-var FluxContainer_w_56 = React.createClass({
+var InputLabel61 = React.createClass({
   render: function() {
-    return <AdsPENavigationBar55 />;
+    var props = this.props;
+    if (props.x === 147) {
+      return (
+        <div display={"block"} className={"uiInputLabel clearfix"}>
+          <XUICheckboxInput60 x={146} />
+          <label className={"uiInputLabelLabel"} htmlFor={"js_input_label_21"}>{"Always show new items"}</label>
+        </div>
+      );
+    }
   },
 });
 
-var ReactImage57 = React.createClass({
+var AdsPopoverLink62 = React.createClass({
   render: function() {
-    return (
-      <i alt={"Warning"} className={"_585p img sp_R48dKBxiJkP sx_aed870"} src={null}>
-        <u>{"Warning"}</u>
-      </i>
-    );
+    var props = this.props;
+    if (props.x === 154) {
+      return (
+        <span>
+          <span ref={"tipIcon"} onMouseEnter={function() {}} onMouseLeave={function() {}} onMouseUp={undefined}>
+            <span className={"_3o_j"}></span>
+            <ReactImage0 x={153} />
+          </span>
+          {null}
+        </span>
+      );
+    }
+    if (props.x === 238) {
+      return (
+        <span>
+          <span ref={"tipIcon"} onMouseEnter={function() {}} onMouseLeave={function() {}} onMouseUp={undefined}>
+            <span className={"_3o_j"}></span>
+            <ReactImage0 x={237} />
+          </span>
+          {null}
+        </span>
+      );
+    }
   },
 });
 
-var Link58 = React.createClass({
+var AdsHelpLink63 = React.createClass({
   render: function() {
-    return (
-      <a className={"_585q _50zy _50-0 _50z- _5upp _42ft"} href={"#"} onClick={function() {}} size={"medium"} shade={"dark"} type={null} label={null} title={"Remove"} aria-label={undefined} data-hover={undefined} data-tooltip-alignh={undefined} disabled={null} rel={undefined}>
-        {undefined}
-        {"Remove"}
-        {undefined}
-      </a>
-    );
+    var props = this.props;
+    if (props.x === 155) {
+      return <AdsPopoverLink62 x={154} />;
+    }
+    if (props.x === 239) {
+      return <AdsPopoverLink62 x={238} />;
+    }
   },
 });
 
-var AbstractButton59 = React.createClass({
+var BUIFilterTokenInput64 = React.createClass({
   render: function() {
-    return <Link58 />;
+    var props = this.props;
+    if (props.x === 158) {
+      return (
+        <div className={"_5b5o _3yz3 _4cld"}>
+          <div className={"_5b5t _2d2k"}>
+            <ReactImage0 x={152} />
+            <div className={"_5b5r"}>
+              {"Campaigns: (1)"}
+              <AdsHelpLink63 x={155} />
+            </div>
+          </div>
+          <XUIButton4 x={157} />
+        </div>
+      );
+    }
   },
 });
 
-var XUIAbstractGlyphButton60 = React.createClass({
+var BUIFilterToken65 = React.createClass({
   render: function() {
-    return <AbstractButton59 />;
+    var props = this.props;
+    if (props.x === 159) {
+      return (
+        <div className={"_3yz1 _3yz2 _3dad"}>
+          <div ref={"filterToken"} className={"_3yz4"} aria-hidden={false}>
+            <div onClick={function() {}} className={"_3yz5"}>
+              <ReactImage0 x={148} />
+              <div className={"_3yz7"}>{"Campaigns:"}</div>
+              <div className={"ellipsis _3yz8"} data-hover={"tooltip"} data-tooltip-display={"overflow"}>{"(1)"}</div>
+            </div>
+            {null}
+            <XUICloseButton28 x={151} />
+          </div>
+          <BUIFilterTokenInput64 x={158} ref={"filterTokenInput"} />
+        </div>
+      );
+    }
   },
 });
 
-var XUICloseButton61 = React.createClass({
+var BUIFilterTokenCreateButton66 = React.createClass({
   render: function() {
-    return <XUIAbstractGlyphButton60 />;
+    var props = this.props;
+    if (props.x === 163) {
+      return (
+        <div className={"_1tc"}>
+          <XUIButton4 x={162} />
+        </div>
+      );
+    }
   },
 });
 
-var XUIText62 = React.createClass({
+var BUIFilterTokenizer67 = React.createClass({
   render: function() {
-    return <span weight={"bold"} size={"inherit"} display={"inline"} className={" _50f7"}>{"Ads Manager"}</span>;
+    var props = this.props;
+    if (props.x === 164) {
+      return (
+        <div className={"_5b-m  clearfix"}>
+          {undefined}
+          {[]}
+          <BUIFilterToken65 x={159} key={"token0"} />
+          <BUIFilterTokenCreateButton66 x={163} />
+          {null}
+          <div className={"_49u3"}></div>
+        </div>
+      );
+    }
   },
 });
 
-var Link63 = React.createClass({
+var XUIAmbientNUX68 = React.createClass({
   render: function() {
-    return (
-      <a href={"/ads/manage/billing.php?act=10149999073643408"} target={"_blank"} rel={undefined} onClick={function() {}}>
-        <XUIText62 />
-      </a>
-    );
+    var props = this.props;
+    if (props.x === 165) {
+      return null;
+    }
+    if (props.x === 189) {
+      return null;
+    }
+    if (props.x === 200) {
+      return null;
+    }
   },
 });
 
-var XUINotice64 = React.createClass({
+var XUIAmbientNUX69 = React.createClass({
   render: function() {
-    return (
-      <div size={"medium"} className={"_585n _585o _2wdd"}>
-        <ReactImage57 />
-        <XUICloseButton61 />
-        <div className={"_585r _2i-a _50f4"}>
-          {"Please go to "}
-          <Link63 />
-          {" to set up a payment method for this ad account."}
-        </div>
-      </div>
-    );
+    var props = this.props;
+    if (props.x === 166) {
+      return <XUIAmbientNUX68 x={165} />;
+    }
+    if (props.x === 190) {
+      return <XUIAmbientNUX68 x={189} />;
+    }
+    if (props.x === 201) {
+      return <XUIAmbientNUX68 x={200} />;
+    }
   },
 });
 
-var ReactCSSTransitionGroupChild65 = React.createClass({
+var AdsPEAmbientNUXMegaphone70 = React.createClass({
   render: function() {
-    return <XUINotice64 />;
+    var props = this.props;
+    if (props.x === 167) {
+      return (
+        <span>
+          <span ref={"mainChild"}></span>
+          <XUIAmbientNUX69 x={166} key={"nux"} />
+        </span>
+      );
+    }
   },
 });
 
-var ReactTransitionGroup66 = React.createClass({
+var AdsPEFilters71 = React.createClass({
   render: function() {
-    return (
-      <span transitionEnterTimeout={500} transitionLeaveTimeout={500} transitionName={{}} transitionAppear={false} transitionEnter={true} transitionLeave={true} childFactory={function() {}} component={"span"}>
-        <ReactCSSTransitionGroupChild65 key={".0"} ref={".0"} />
-      </span>
-    );
+    var props = this.props;
+    if (props.x === 168) {
+      return (
+        <div className={"_4rw_"}>
+          <AdsPEFiltersPopover58 x={144} />
+          <div className={"_1eo"}>
+            <InputLabel61 x={147} />
+          </div>
+          <BUIFilterTokenizer67 x={164} />
+          {""}
+          <AdsPEAmbientNUXMegaphone70 x={167} />
+        </div>
+      );
+    }
   },
 });
 
-var ReactCSSTransitionGroup67 = React.createClass({
+var AdsPEFilterContainer72 = React.createClass({
   render: function() {
-    return <ReactTransitionGroup66 />;
+    var props = this.props;
+    if (props.x === 169) {
+      return <AdsPEFilters71 x={168} />;
+    }
   },
 });
 
-var AdsPETopError68 = React.createClass({
+var AdsPETablePager73 = React.createClass({
   render: function() {
-    return (
-      <div className={"_2wdc"}>
-        <ReactCSSTransitionGroup67 />
-      </div>
-    );
+    var props = this.props;
+    if (props.x === 172) {
+      return null;
+    }
   },
 });
 
-var FluxContainer_r_69 = React.createClass({
+var AdsPECampaignGroupTablePagerContainer74 = React.createClass({
   render: function() {
-    return <AdsPETopError68 />;
+    var props = this.props;
+    if (props.x === 173) {
+      return <AdsPETablePager73 x={172} />;
+    }
   },
 });
 
-var ReactImage70 = React.createClass({
+var AdsPETablePagerContainer75 = React.createClass({
   render: function() {
-    return <i className={"_3-8_ img sp_UuU9HmrQ397 sx_bae57d"} src={null}></i>;
+    var props = this.props;
+    if (props.x === 174) {
+      return <AdsPECampaignGroupTablePagerContainer74 x={173} />;
+    }
   },
 });
 
-var ReactImage71 = React.createClass({
+var ReactXUIError76 = React.createClass({
   render: function() {
-    return <i alt={""} className={"_3-99 img sp_UuU9HmrQ397 sx_7e56e9"} src={null}></i>;
+    var props = this.props;
+    if (props.x === 181) {
+      return <AbstractButton3 x={180} />;
+    }
+    if (props.x === 216) {
+      return (
+        <div className={"_40bf _2vl4 _1h18"}>
+          {null}
+          {null}
+          <div className={"_2vl9 _1h1f"} style={{"backgroundColor":"#fff"}}>
+            <div className={"_2vla _1h1g"}>
+              <div>
+                {null}
+                <textarea ref={"input"} className={"_2vli _2vlj _1h26 _1h27"} dir={"auto"} disabled={undefined} id={undefined} maxLength={null} value={"Test Campaign"} onBlur={function() {}} onChange={function() {}} onFocus={function() {}} onKeyDown={function() {}}></textarea>
+                {null}
+              </div>
+              <div ref={"shadowText"} aria-hidden={"true"} className={"_2vlk"}></div>
+            </div>
+          </div>
+          {null}
+        </div>
+      );
+    }
+    if (props.x === 221) {
+      return <XUICard94 x={220} />;
+    }
+    if (props.x === 250) {
+      return <XUICard94 x={249} />;
+    }
+    if (props.x === 280) {
+      return <XUICard94 x={279} />;
+    }
   },
 });
 
-var Link72 = React.createClass({
+var BUIPopoverButton77 = React.createClass({
   render: function() {
-    return (
-      <a style={{"maxWidth":"200px"}} image={null} label={null} imageRight={{}} className={" _5bbf _55pi _2agf  _5bbf _55pi _4jy0 _4jy4 _517h _51sy _42ft"} href={"#"} haschevron={true} onClick={function() {}} size={"large"} use={"default"} borderShade={"light"} suppressed={false} disabled={null} rel={undefined}>
-        {null}
-        <span className={"_55pe"} style={{"maxWidth":"186px"}}>
-          <ReactImage70 />
-          {"Search"}
-        </span>
-        <ReactImage71 />
-      </a>
-    );
+    var props = this.props;
+    if (props.x === 182) {
+      return <ReactXUIError76 x={181} />;
+    }
   },
 });
 
-var AbstractButton73 = React.createClass({
+var BUIDateRangePicker78 = React.createClass({
   render: function() {
-    return <Link72 />;
+    var props = this.props;
+    if (props.x === 184) {
+      return (
+        <span>
+          <BUIPopoverButton77 x={182} ref={function() {}} />
+          {[
+            <Constructor49 x={183} key={"layer/.0"} />,
+          ]}
+        </span>
+      );
+    }
   },
 });
 
-var XUIButton74 = React.createClass({
+var AdsPEStatsRangePicker79 = React.createClass({
   render: function() {
-    return <AbstractButton73 />;
+    var props = this.props;
+    if (props.x === 185) {
+      return <BUIDateRangePicker78 x={184} />;
+    }
   },
 });
 
-var AbstractPopoverButton75 = React.createClass({
+var AdsPEStatRange80 = React.createClass({
   render: function() {
-    return <XUIButton74 />;
+    var props = this.props;
+    if (props.x === 191) {
+      return (
+        <div className={"_3c5k"}>
+          <span className={"_3c5j"}>{"Stats:"}</span>
+          <span className={"_3c5l"}>
+            <AdsPEStatsRangePicker79 x={185} />
+            <XUIButton4 x={188} key={"settings"} ref={"PE_TABLE_LIST_SETTING"} />
+          </span>
+          {[
+            <XUIAmbientNUX69 x={190} key={"roasNUX/.0"} />,
+          ]}
+        </div>
+      );
+    }
   },
 });
 
-var ReactXUIPopoverButton76 = React.createClass({
+var AdsPEStatRangeContainer81 = React.createClass({
   render: function() {
-    return <AbstractPopoverButton75 />;
+    var props = this.props;
+    if (props.x === 192) {
+      return <AdsPEStatRange80 x={191} />;
+    }
   },
 });
 
-var ReactImage77 = React.createClass({
+var AdsPESideTrayTabButton82 = React.createClass({
   render: function() {
-    return <i className={"_3-8_ img sp_UuU9HmrQ397 sx_81d5f0"} src={null}></i>;
+    var props = this.props;
+    if (props.x === 196) {
+      return (
+        <div className={"_1-ly _59j9 _d9a"} onClick={function() {}}>
+          <ReactImage0 x={195} />
+          <div className={"_vf7"}></div>
+          <div className={"_vf8"}></div>
+        </div>
+      );
+    }
+    if (props.x === 199) {
+      return (
+        <div className={" _1-lz _d9a"} onClick={function() {}}>
+          <ReactImage0 x={198} />
+          <div className={"_vf7"}></div>
+          <div className={"_vf8"}></div>
+        </div>
+      );
+    }
+    if (props.x === 203) {
+      return null;
+    }
   },
 });
 
-var ReactImage78 = React.createClass({
+var AdsPEEditorTrayTabButton83 = React.createClass({
   render: function() {
-    return <i alt={""} className={"_3-99 img sp_UuU9HmrQ397 sx_7e56e9"} src={null}></i>;
+    var props = this.props;
+    if (props.x === 197) {
+      return <AdsPESideTrayTabButton82 x={196} />;
+    }
   },
 });
 
-var Link79 = React.createClass({
+var AdsPEInsightsTrayTabButton84 = React.createClass({
   render: function() {
-    return (
-      <a style={{"maxWidth":"200px"}} image={null} label={null} imageRight={{}} className={" _5bbf _55pi _2agf  _5bbf _55pi _4jy0 _4jy4 _517h _51sy _42ft"} href={"#"} haschevron={true} onClick={function() {}} size={"large"} use={"default"} borderShade={"light"} suppressed={false} disabled={null} rel={undefined}>
-        {null}
-        <span className={"_55pe"} style={{"maxWidth":"186px"}}>
-          <ReactImage77 />
-          {"Filters"}
+    var props = this.props;
+    if (props.x === 202) {
+      return (
+        <span>
+          <AdsPESideTrayTabButton82 x={199} ref={"PE_INSIGHTS_TAB_ICON"} />
+          <XUIAmbientNUX69 x={201} key={"roasNUX"} />
         </span>
-        <ReactImage78 />
-      </a>
-    );
+      );
+    }
   },
 });
 
-var AbstractButton80 = React.createClass({
+var AdsPENekoDebuggerTrayTabButton85 = React.createClass({
   render: function() {
-    return <Link79 />;
+    var props = this.props;
+    if (props.x === 204) {
+      return <AdsPESideTrayTabButton82 x={203} />;
+    }
   },
 });
 
-var XUIButton81 = React.createClass({
+var AdsPEEditorChildLink86 = React.createClass({
   render: function() {
-    return <AbstractButton80 />;
+    var props = this.props;
+    if (props.x === 211) {
+      return (
+        <div className={"_3ywr"}>
+          <Link2 x={208} />
+          <span className={"_3ywq"}>{"|"}</span>
+          <Link2 x={210} />
+        </div>
+      );
+    }
   },
 });
 
-var AbstractPopoverButton82 = React.createClass({
+var AdsPEEditorChildLinkContainer87 = React.createClass({
   render: function() {
-    return <XUIButton81 />;
+    var props = this.props;
+    if (props.x === 212) {
+      return <AdsPEEditorChildLink86 x={211} />;
+    }
   },
 });
 
-var ReactXUIPopoverButton83 = React.createClass({
+var AdsPEHeaderSection88 = React.createClass({
   render: function() {
-    return <AbstractPopoverButton82 />;
+    var props = this.props;
+    if (props.x === 213) {
+      return (
+        <div className={"_yke"}>
+          <div className={"_2x9d _pr-"}></div>
+          <XUIText29 x={205} />
+          <div className={"_3a-a"}>
+            <div className={"_3a-b"}>
+              <XUIText29 x={206} />
+            </div>
+          </div>
+          <AdsPEEditorChildLinkContainer87 x={212} />
+        </div>
+      );
+    }
   },
 });
 
-var AdsPEFiltersPopover84 = React.createClass({
+var AdsPECampaignGroupHeaderSectionContainer89 = React.createClass({
   render: function() {
-    return (
-      <span className={"_5b-l  _5bbe"}>
-        <ReactXUIPopoverButton76 ref={"searchButton"} />
-        <ReactXUIPopoverButton83 ref={"filterButton"} />
-      </span>
-    );
+    var props = this.props;
+    if (props.x === 214) {
+      return <AdsPEHeaderSection88 x={213} />;
+    }
   },
 });
 
-var ReactImage85 = React.createClass({
+var AdsEditorLoadingErrors90 = React.createClass({
   render: function() {
-    return <i className={"_3yz6 _5whs img sp_UuU9HmrQ397 sx_5fe5c2"} src={null}></i>;
+    var props = this.props;
+    if (props.x === 215) {
+      return null;
+    }
   },
 });
 
-var AbstractButton86 = React.createClass({
+var AdsTextInput91 = React.createClass({
   render: function() {
-    return (
-      <button className={"_3yz9 _1t-2 _50z_ _50zy _50zz _50z- _5upp _42ft"} size={"small"} onClick={function() {}} shade={"dark"} type={"button"} label={null} title={"Remove"} aria-label={undefined} data-hover={undefined} data-tooltip-alignh={undefined}>
-        {undefined}
-        {"Remove"}
-        {undefined}
-      </button>
-    );
+    var props = this.props;
+    if (props.x === 217) {
+      return <ReactXUIError76 x={216} />;
+    }
   },
 });
 
-var XUIAbstractGlyphButton87 = React.createClass({
+var BUIFormElement92 = React.createClass({
   render: function() {
-    return <AbstractButton86 />;
+    var props = this.props;
+    if (props.x === 218) {
+      return (
+        <div className={"_5521 clearfix"}>
+          <div className={"_5522 _3w5q"}>
+            <label onClick={undefined} htmlFor={"1467872040612:1961945894"} className={"_5523 _3w5r"}>
+              {"Campaign Name"}
+              {null}
+            </label>
+          </div>
+          <div className={"_5527"}>
+            <div className={"_5528"}>
+              <span key={".0"} className={"_40bg"} density={"snug"} labelPosition={"left"} id={"1467872040612:1961945894"}>
+                <AdsTextInput91 x={217} key={"nameEditor98010048849317"} ref={"nameTextInput"} />
+                {null}
+              </span>
+            </div>
+            {null}
+          </div>
+        </div>
+      );
+    }
   },
 });
 
-var XUICloseButton88 = React.createClass({
+var BUIForm93 = React.createClass({
   render: function() {
-    return <XUIAbstractGlyphButton87 />;
+    var props = this.props;
+    if (props.x === 219) {
+      return (
+        <div className={"_5ks1 _550r  _550t _550y _3w5n"}>
+          <BUIFormElement92 x={218} key={".0"} />
+        </div>
+      );
+    }
   },
 });
 
-var ReactImage89 = React.createClass({
+var XUICard94 = React.createClass({
   render: function() {
-    return <i className={"_5b5p _4gem img sp_UuU9HmrQ397 sx_5fe5c2"} src={null}></i>;
+    var props = this.props;
+    if (props.x === 220) {
+      return (
+        <div className={"_40bc _12k2 _4-u2  _4-u8"} xuiErrorPosition={"above"} background={"white"}>
+          <BUIForm93 x={219} />
+        </div>
+      );
+    }
+    if (props.x === 249) {
+      return (
+        <div xuiErrorPosition={"above"} className={"_12k2 _4-u2  _4-u8"} background={"white"}>
+          <AdsCardHeader103 x={230} />
+          <AdsCardSection108 x={248} />
+        </div>
+      );
+    }
+    if (props.x === 279) {
+      return (
+        <div xuiErrorPosition={"above"} className={"_12k2 _4-u2  _4-u8"} background={"white"}>
+          <AdsCardLeftRightHeader122 x={278} />
+        </div>
+      );
+    }
   },
 });
 
-var ReactImage90 = React.createClass({
+var AdsCard95 = React.createClass({
   render: function() {
-    return <i src={null} className={"_541d img sp_R48dKBxiJkP sx_dc2cdb"}></i>;
+    var props = this.props;
+    if (props.x === 222) {
+      return <ReactXUIError76 x={221} />;
+    }
+    if (props.x === 251) {
+      return <ReactXUIError76 x={250} />;
+    }
+    if (props.x === 281) {
+      return <ReactXUIError76 x={280} />;
+    }
   },
 });
 
-var AdsPopoverLink91 = React.createClass({
+var AdsEditorNameSection96 = React.createClass({
   render: function() {
-    return (
-      <span ref={"tipIcon"} onMouseEnter={function() {}} onMouseLeave={function() {}}>
-        <span className={"_3o_j"}></span>
-        <ReactImage90 />
-      </span>
-    );
+    var props = this.props;
+    if (props.x === 223) {
+      return <AdsCard95 x={222} />;
+    }
   },
 });
 
-var AdsHelpLink92 = React.createClass({
+var AdsCampaignGroupNameSectionContainer97 = React.createClass({
   render: function() {
-    return <AdsPopoverLink91 />;
+    var props = this.props;
+    if (props.x === 224) {
+      return <AdsEditorNameSection96 x={223} key={"nameSection98010048849317"} />;
+    }
   },
 });
 
-var AbstractButton93 = React.createClass({
+var _render98 = React.createClass({
   render: function() {
-    return (
-      <button className={"_5b5u _5b5v _4jy0 _4jy3 _517h _51sy _42ft"} label={null} use={"default"} onClick={function() {}} size={"medium"} borderShade={"light"} suppressed={false} type={"submit"} value={"1"}>
-        {undefined}
-        {"Apply"}
-        {undefined}
-      </button>
-    );
+    var props = this.props;
+    if (props.x === 225) {
+      return <AdsCampaignGroupNameSectionContainer97 x={224} />;
+    }
   },
 });
 
-var XUIButton94 = React.createClass({
+var AdsPluginWrapper99 = React.createClass({
   render: function() {
-    return <AbstractButton93 />;
+    var props = this.props;
+    if (props.x === 226) {
+      return <_render98 x={225} />;
+    }
+    if (props.x === 255) {
+      return <_render111 x={254} />;
+    }
+    if (props.x === 258) {
+      return <_render113 x={257} />;
+    }
+    if (props.x === 287) {
+      return <_render127 x={286} />;
+    }
+    if (props.x === 291) {
+      return <_render130 x={290} />;
+    }
   },
 });
 
-var BUIFilterTokenInput95 = React.createClass({
+var XUICardHeaderTitle100 = React.createClass({
   render: function() {
-    return (
-      <div className={"_5b5o _3yz3 _4cld"}>
-        <div className={"_5b5t _2d2k"}>
-          <ReactImage89 />
-          <div className={"_5b5r"}>
-            {"Ads: (1)"}
-            <AdsHelpLink92 />
-          </div>
-        </div>
-        <XUIButton94 />
-      </div>
-    );
+    var props = this.props;
+    if (props.x === 227) {
+      return (
+        <span itemComponent={"span"} className={"_38my"}>
+          {"Campaign Details"}
+          {null}
+          <span className={"_c1c"}></span>
+        </span>
+      );
+    }
+    if (props.x === 265) {
+      return (
+        <span itemComponent={"span"} className={"_38my"}>
+          {[
+            <span>
+              {"Campaign ID"}
+              {": "}
+              {"98010048849317"}
+            </span>,
+            <div className={"_5lh9"}>
+              <FluxContainer_AdsCampaignGroupStatusSwitchContainer_119 x={264} />
+            </div>,
+          ]}
+          {null}
+          <span className={"_c1c"}></span>
+        </span>
+      );
+    }
   },
 });
 
-var BUIFilterToken96 = React.createClass({
+var XUICardSection101 = React.createClass({
   render: function() {
-    return (
-      <div className={"_3yz1 _3yz2 _3dad"}>
-        <div ref={"filterToken"} className={"_3yz4"} aria-hidden={false}>
-          <div onClick={function() {}} className={"_3yz5"}>
-            <ReactImage85 />
-            <div className={"_3yz7"}>{"Ads:"}</div>
-            <div className={"ellipsis _3yz8"} data-hover={"tooltip"} data-tooltip-display={"overflow"}>{"(1)"}</div>
+    var props = this.props;
+    if (props.x === 228) {
+      return (
+        <div className={"_5dw9 _5dwa _4-u3"} background={"transparent"}>
+          {[
+            <XUICardHeaderTitle100 x={227} key={".0"} />,
+          ]}
+          {undefined}
+          {undefined}
+          <div className={"_3s3-"}></div>
+        </div>
+      );
+    }
+    if (props.x === 247) {
+      return (
+        <div className={"_12jy _4-u3"} background={"transparent"}>
+          <div className={"_3-8j"}>
+            <FlexibleBlock105 x={233} />
+            <FlexibleBlock105 x={236} />
+            <FlexibleBlock105 x={246} />
+            {null}
+            {null}
           </div>
-          <XUICloseButton88 />
         </div>
-        <BUIFilterTokenInput95 ref={"filterTokenInput"} />
-      </div>
-    );
+      );
+    }
   },
 });
 
-var ReactImage97 = React.createClass({
+var XUICardHeader102 = React.createClass({
   render: function() {
-    return <i src={null} className={"img sp_UuU9HmrQ397 sx_158e8d"}></i>;
+    var props = this.props;
+    if (props.x === 229) {
+      return <XUICardSection101 x={228} />;
+    }
   },
 });
 
-var AbstractButton98 = React.createClass({
+var AdsCardHeader103 = React.createClass({
   render: function() {
-    return (
-      <button className={"_1wdf _4jy0 _517i _517h _51sy _42ft"} size={"small"} onClick={function() {}} image={{}} use={"default"} borderShade={"light"} suppressed={false} label={null} type={"submit"} value={"1"}>
-        <ReactImage97 />
-        {undefined}
-        {undefined}
-      </button>
-    );
+    var props = this.props;
+    if (props.x === 230) {
+      return <XUICardHeader102 x={229} />;
+    }
   },
 });
 
-var XUIButton99 = React.createClass({
+var AdsLabeledField104 = React.createClass({
   render: function() {
-    return <AbstractButton98 />;
+    var props = this.props;
+    if (props.x === 231) {
+      return (
+        <div className={"_2oc6 _3bvz"} label={"Objective"} labelSize={"small"} optionalText={"(optional)"}>
+          <label className={"_4el4 _3qwj _3hy-"} htmlFor={undefined}>{"Objective "}</label>
+          {null}
+          <div className={"_3bv-"}></div>
+        </div>
+      );
+    }
+    if (props.x === 234) {
+      return (
+        <div className={"_2oc6 _3bvz"} label={"Buying Type"} labelSize={"small"} optionalText={"(optional)"}>
+          <label className={"_4el4 _3qwj _3hy-"} htmlFor={undefined}>{"Buying Type "}</label>
+          {null}
+          <div className={"_3bv-"}></div>
+        </div>
+      );
+    }
+    if (props.x === 240) {
+      return (
+        <div className={"_2oc6 _3bvz"} helpText={"Set an overall spending limit for your ad campaign. This means your ad sets in the campaign will stop once you've reached your spending limit."} label={"Campaign Spending Limit"} labelSize={"small"} optionalText={"(optional)"}>
+          <label className={"_4el4 _3qwj _3hy-"} htmlFor={undefined}>{"Campaign Spending Limit "}</label>
+          <AdsHelpLink63 x={239} />
+          <div className={"_3bv-"}></div>
+        </div>
+      );
+    }
   },
 });
 
-var BUIFilterTokenCreateButton100 = React.createClass({
+var FlexibleBlock105 = React.createClass({
   render: function() {
-    return (
-      <div className={"_1tc"}>
-        <XUIButton99 />
-      </div>
-    );
+    var props = this.props;
+    if (props.x === 233) {
+      return <LeftRight21 x={232} />;
+    }
+    if (props.x === 236) {
+      return <LeftRight21 x={235} />;
+    }
+    if (props.x === 246) {
+      return <LeftRight21 x={245} />;
+    }
   },
 });
 
-var BUIFilterTokenizer101 = React.createClass({
+var AdsBulkCampaignSpendCapField106 = React.createClass({
   render: function() {
-    return (
-      <div className={"_5b-m _3o1v clearfix"}>
-        {undefined}
-        {[]}
-        <BUIFilterToken96 key={"token0"} />
-        <BUIFilterTokenCreateButton100 />
-        {null}
-        <div className={"_49u3"}></div>
-      </div>
-    );
+    var props = this.props;
+    if (props.x === 243) {
+      return (
+        <div className={"_33dv"}>
+          {""}
+          <Link2 x={242} />
+          {" (optional)"}
+        </div>
+      );
+    }
   },
 });
 
-var AdsPEAmbientNUXMegaphone102 = React.createClass({
+var FluxContainer_AdsCampaignGroupSpendCapContainer_107 = React.createClass({
   render: function() {
-    return <span ref={"mainChild"}></span>;
+    var props = this.props;
+    if (props.x === 244) {
+      return <AdsBulkCampaignSpendCapField106 x={243} />;
+    }
   },
 });
 
-var AdsPEFilters103 = React.createClass({
+var AdsCardSection108 = React.createClass({
   render: function() {
-    return (
-      <div className={"_4rw_"}>
-        <AdsPEFiltersPopover84 />
-        {null}
-        <BUIFilterTokenizer101 />
-        {""}
-        <AdsPEAmbientNUXMegaphone102 />
-      </div>
-    );
+    var props = this.props;
+    if (props.x === 248) {
+      return <XUICardSection101 x={247} />;
+    }
   },
 });
 
-var AdsPEFilterContainer104 = React.createClass({
+var AdsEditorCampaignGroupDetailsSection109 = React.createClass({
   render: function() {
-    return <AdsPEFilters103 />;
+    var props = this.props;
+    if (props.x === 252) {
+      return <AdsCard95 x={251} />;
+    }
   },
 });
 
-var AdsPECampaignTimeLimitNotice105 = React.createClass({
+var AdsEditorCampaignGroupDetailsSectionContainer110 = React.createClass({
   render: function() {
-    return <div></div>;
+    var props = this.props;
+    if (props.x === 253) {
+      return <AdsEditorCampaignGroupDetailsSection109 x={252} key={"campaignGroupDetailsSection98010048849317"} />;
+    }
   },
 });
 
-var AdsPECampaignTimeLimitNoticeContainer106 = React.createClass({
+var _render111 = React.createClass({
   render: function() {
-    return <AdsPECampaignTimeLimitNotice105 />;
+    var props = this.props;
+    if (props.x === 254) {
+      return <AdsEditorCampaignGroupDetailsSectionContainer110 x={253} />;
+    }
   },
 });
 
-var AdsPETablePager107 = React.createClass({
+var FluxContainer_AdsEditorToplineDetailsSectionContainer_112 = React.createClass({
   render: function() {
-    return null;
+    var props = this.props;
+    if (props.x === 256) {
+      return null;
+    }
   },
 });
 
-var AdsPEAdgroupTablePagerContainer108 = React.createClass({
+var _render113 = React.createClass({
   render: function() {
-    return <AdsPETablePager107 />;
+    var props = this.props;
+    if (props.x === 257) {
+      return <FluxContainer_AdsEditorToplineDetailsSectionContainer_112 x={256} />;
+    }
   },
 });
 
-var AdsPETablePagerContainer109 = React.createClass({
+var AdsStickyArea114 = React.createClass({
   render: function() {
-    return <AdsPEAdgroupTablePagerContainer108 />;
+    var props = this.props;
+    if (props.x === 259) {
+      return (
+        <div inContainingBlock={true}>
+          <div ref={"sticky"} onWheel={function() {}}></div>
+        </div>
+      );
+    }
+    if (props.x === 292) {
+      return (
+        <div inContainingBlock={true}>
+          <div ref={"sticky"} onWheel={function() {}}>
+            {[
+              <div key={"campaign_group_errors_section98010048849317"}>
+                <AdsPluginWrapper99 x={291} />
+              </div>,
+            ]}
+          </div>
+        </div>
+      );
+    }
   },
 });
 
-var ReactImage110 = React.createClass({
+var FluxContainer_AdsEditorColumnContainer_115 = React.createClass({
   render: function() {
-    return <i alt={""} className={"_3-99 img sp_UuU9HmrQ397 sx_132804"} src={null}></i>;
+    var props = this.props;
+    if (props.x === 260) {
+      return (
+        <div>
+          {[
+            <div key={"campaign_group_name_section98010048849317"}>
+              <AdsPluginWrapper99 x={226} />
+            </div>,
+            <div key={"campaign_group_basic_section98010048849317"}>
+              <AdsPluginWrapper99 x={255} />
+            </div>,
+            <div key={"campaign_group_topline_section98010048849317"}>
+              <AdsPluginWrapper99 x={258} />
+            </div>,
+          ]}
+          <AdsStickyArea114 x={259} />
+        </div>
+      );
+    }
+    if (props.x === 293) {
+      return (
+        <div>
+          {[
+            <div key={"campaign_group_navigation_section98010048849317"}>
+              <AdsPluginWrapper99 x={287} />
+            </div>,
+          ]}
+          <AdsStickyArea114 x={292} />
+        </div>
+      );
+    }
   },
 });
 
-var Link111 = React.createClass({
+var BUISwitch116 = React.createClass({
   render: function() {
-    return (
-      <a style={{"maxWidth":"200px"}} image={null} label={null} imageRight={{}} className={"_55pi _2agf _55pi _4jy0 _4jy4 _517h _51sy _42ft"} href={"#"} disabled={null} maxwidth={undefined} size={"large"} suppressed={false} chevron={{}} use={"default"} borderShade={"light"} onClick={function() {}} rel={undefined}>
-        {null}
-        <span className={"_55pe"} style={{"maxWidth":"186px"}}>
+    var props = this.props;
+    if (props.x === 261) {
+      return (
+        <div data-hover={"tooltip"} data-tooltip-content={"Currently active. Click this switch to deactivate it."} data-tooltip-position={"below"} disabled={false} value={true} onToggle={function() {}} animate={true} className={"_128j _128k _128n"} role={"checkbox"} aria-checked={"true"}>
+          <div className={"_128o"} onClick={function() {}} onKeyDown={function() {}} onMouseDown={function() {}} tabIndex={"0"}>
+            <div className={"_128p"}></div>
+          </div>
           {null}
-          {"Lifetime"}
-        </span>
-        <ReactImage110 />
-      </a>
-    );
+        </div>
+      );
+    }
   },
 });
 
-var AbstractButton112 = React.createClass({
+var AdsStatusSwitchInternal117 = React.createClass({
   render: function() {
-    return <Link111 />;
+    var props = this.props;
+    if (props.x === 262) {
+      return <BUISwitch116 x={261} />;
+    }
   },
 });
 
-var XUIButton113 = React.createClass({
+var AdsStatusSwitch118 = React.createClass({
   render: function() {
-    return <AbstractButton112 />;
+    var props = this.props;
+    if (props.x === 263) {
+      return <AdsStatusSwitchInternal117 x={262} />;
+    }
   },
 });
 
-var AbstractPopoverButton114 = React.createClass({
+var FluxContainer_AdsCampaignGroupStatusSwitchContainer_119 = React.createClass({
   render: function() {
-    return <XUIButton113 />;
+    var props = this.props;
+    if (props.x === 264) {
+      return <AdsStatusSwitch118 x={263} key={"status98010048849317"} />;
+    }
   },
 });
 
-var ReactXUIPopoverButton115 = React.createClass({
+var AdsLinksMenu120 = React.createClass({
   render: function() {
-    return <AbstractPopoverButton114 />;
+    var props = this.props;
+    if (props.x === 275) {
+      return <ReactPopoverMenu20 x={274} />;
+    }
   },
 });
 
-var XUISingleSelectorButton116 = React.createClass({
+var FluxContainer_AdsPluginizedLinksMenuContainer_121 = React.createClass({
   render: function() {
-    return <ReactXUIPopoverButton115 />;
+    var props = this.props;
+    if (props.x === 276) {
+      return (
+        <div>
+          {null}
+          <AdsLinksMenu120 x={275} />
+        </div>
+      );
+    }
   },
 });
 
-var InlineBlock117 = React.createClass({
+var AdsCardLeftRightHeader122 = React.createClass({
   render: function() {
-    return (
-      <div className={"_3c5o _3c5p _6a _6b"} defaultValue={"LIFETIME"} size={"large"} onChange={function() {}} disabled={false} alignv={"middle"} fullWidth={false}>
-        <input type={"hidden"} autoComplete={"off"} name={undefined} value={"LIFETIME"}></input>
-        <XUISingleSelectorButton116 ref={"button"} />
-      </div>
-    );
+    var props = this.props;
+    if (props.x === 278) {
+      return <LeftRight21 x={277} />;
+    }
   },
 });
 
-var XUISingleSelector118 = React.createClass({
+var AdsPEIDSection123 = React.createClass({
   render: function() {
-    return <InlineBlock117 />;
+    var props = this.props;
+    if (props.x === 282) {
+      return <AdsCard95 x={281} />;
+    }
   },
 });
 
-var ReactImage119 = React.createClass({
+var FluxContainer_AdsPECampaignGroupIDSectionContainer_124 = React.createClass({
   render: function() {
-    return <i src={null} className={"img sp_UuU9HmrQ397 sx_6c732d"}></i>;
+    var props = this.props;
+    if (props.x === 283) {
+      return <AdsPEIDSection123 x={282} />;
+    }
   },
 });
 
-var AbstractButton120 = React.createClass({
+var DeferredComponent125 = React.createClass({
   render: function() {
-    return (
-      <button aria-label={"List Settings"} className={"_u_k _3c5o _1-r0 _4jy0 _4jy4 _517h _51sy _42ft"} data-hover={"tooltip"} image={{}} size={"large"} onClick={function() {}} use={"default"} borderShade={"light"} suppressed={false} label={null} type={"submit"} value={"1"}>
-        <ReactImage119 />
-        {undefined}
-        {undefined}
-      </button>
-    );
+    var props = this.props;
+    if (props.x === 284) {
+      return <FluxContainer_AdsPECampaignGroupIDSectionContainer_124 x={283} />;
+    }
   },
 });
 
-var XUIButton121 = React.createClass({
+var BootloadedComponent126 = React.createClass({
   render: function() {
-    return <AbstractButton120 />;
+    var props = this.props;
+    if (props.x === 285) {
+      return <DeferredComponent125 x={284} />;
+    }
   },
 });
 
-var AdsPEStatRange122 = React.createClass({
+var _render127 = React.createClass({
   render: function() {
-    return (
-      <div className={"_3c5k"}>
-        <span className={"_3c5j"}>{"Stats:"}</span>
-        <span className={"_3c5l"}>
-          <XUISingleSelector118 key={"range"} />
-          {null}
-          <XUIButton121 key={"settings"} />
-        </span>
-      </div>
-    );
+    var props = this.props;
+    if (props.x === 286) {
+      return <BootloadedComponent126 x={285} />;
+    }
   },
 });
 
-var AdsPEStatRangeContainer123 = React.createClass({
+var AdsEditorErrorsCard128 = React.createClass({
   render: function() {
-    return <AdsPEStatRange122 />;
+    var props = this.props;
+    if (props.x === 288) {
+      return null;
+    }
   },
 });
 
-var Column124 = React.createClass({
+var FluxContainer_FunctionalContainer_129 = React.createClass({
   render: function() {
-    return (
-      <div className={"_4bl8 _4bl7"}>
-        <div className={"_3c5f"}>
-          {null}
-          <AdsPETablePagerContainer109 />
-          <div className={"_3c5i"}></div>
-          <AdsPEStatRangeContainer123 />
-        </div>
-      </div>
-    );
+    var props = this.props;
+    if (props.x === 289) {
+      return <AdsEditorErrorsCard128 x={288} />;
+    }
   },
 });
 
-var ReactImage125 = React.createClass({
+var _render130 = React.createClass({
   render: function() {
-    return <i alt={""} className={"_3-8_ img sp_UuU9HmrQ397 sx_158e8d"} src={null}></i>;
+    var props = this.props;
+    if (props.x === 290) {
+      return <FluxContainer_FunctionalContainer_129 x={289} />;
+    }
   },
 });
 
-var AbstractButton126 = React.createClass({
+var AdsEditorMultiColumnLayout131 = React.createClass({
   render: function() {
-    return (
-      <button className={"_u_k _4jy0 _4jy4 _517h _51sy _42ft"} label={null} size={"large"} onClick={function() {}} image={{}} use={"default"} borderShade={"light"} suppressed={false} type={"submit"} value={"1"}>
-        <ReactImage125 />
-        {"Create Ad"}
-        {undefined}
-      </button>
-    );
+    var props = this.props;
+    if (props.x === 294) {
+      return (
+        <div className={"_psh"}>
+          <div className={"_3cc0"}>
+            <div>
+              <AdsEditorLoadingErrors90 x={215} key={".0"} />
+              <div className={"_3ms3"}>
+                <div className={"_3ms4"}>
+                  <FluxContainer_AdsEditorColumnContainer_115 x={260} key={".1"} />
+                </div>
+                <div className={"_3pvg"}>
+                  <FluxContainer_AdsEditorColumnContainer_115 x={293} key={".2"} />
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      );
+    }
   },
 });
 
-var XUIButton127 = React.createClass({
+var AdsPECampaignGroupEditor132 = React.createClass({
   render: function() {
-    return <AbstractButton126 />;
+    var props = this.props;
+    if (props.x === 295) {
+      return (
+        <div>
+          <AdsPECampaignGroupHeaderSectionContainer89 x={214} />
+          <AdsEditorMultiColumnLayout131 x={294} />
+        </div>
+      );
+    }
   },
 });
 
-var ReactImage128 = React.createClass({
+var AdsPECampaignGroupEditorContainer133 = React.createClass({
   render: function() {
-    return <i src={null} className={"img sp_UuU9HmrQ397 sx_d5a685"}></i>;
+    var props = this.props;
+    if (props.x === 296) {
+      return <AdsPECampaignGroupEditor132 x={295} />;
+    }
   },
 });
 
-var AbstractButton129 = React.createClass({
+var AdsPESideTrayTabContent134 = React.createClass({
   render: function() {
-    return (
-      <button className={"_u_k _p _4jy0 _4jy4 _517h _51sy _42ft"} image={{}} size={"large"} use={"default"} borderShade={"light"} suppressed={false} label={null} type={"submit"} value={"1"}>
-        <ReactImage128 />
-        {undefined}
-        {undefined}
-      </button>
-    );
+    var props = this.props;
+    if (props.x === 297) {
+      return (
+        <div className={"_1o_8 _44ra _5cyn"}>
+          <AdsPECampaignGroupEditorContainer133 x={296} />
+        </div>
+      );
+    }
   },
 });
 
-var XUIButton130 = React.createClass({
+var AdsPEEditorTrayTabContentContainer135 = React.createClass({
   render: function() {
-    return <AbstractButton129 />;
+    var props = this.props;
+    if (props.x === 298) {
+      return <AdsPESideTrayTabContent134 x={297} />;
+    }
   },
 });
 
-var InlineBlock131 = React.createClass({
+var AdsPEMultiTabDrawer136 = React.createClass({
   render: function() {
-    return (
-      <div menu={{}} alignh={"right"} layerBehaviors={{}} alignv={"middle"} className={"uiPopover _6a _6b"} disabled={null} fullWidth={false}>
-        <XUIButton130 key={"/.0"} />
-      </div>
-    );
+    var props = this.props;
+    if (props.x === 299) {
+      return (
+        <div className={"_2kev _2kex"}>
+          <div className={"_5yno"}>
+            <AdsPEEditorTrayTabButton83 x={197} key={"editor_tray_button"} />
+            <AdsPEInsightsTrayTabButton84 x={202} key={"insights_tray_button"} />
+            <AdsPENekoDebuggerTrayTabButton85 x={204} key={"neko_debugger_tray_button"} />
+          </div>
+          <div className={"_5ynn"}>
+            <AdsPEEditorTrayTabContentContainer135 x={298} key={"EDITOR_DRAWER"} />
+            {null}
+          </div>
+        </div>
+      );
+    }
   },
 });
 
-var ReactPopoverMenu132 = React.createClass({
+var FluxContainer_AdsPEMultiTabDrawerContainer_137 = React.createClass({
   render: function() {
-    return <InlineBlock131 ref={"root"} />;
+    var props = this.props;
+    if (props.x === 300) {
+      return <AdsPEMultiTabDrawer136 x={299} />;
+    }
   },
 });
 
-var XUIButtonGroup133 = React.createClass({
+var AdsPESimpleOrganizer138 = React.createClass({
   render: function() {
-    return (
-      <div className={"_5n7z _51xa"}>
-        <XUIButton127 />
-        <ReactPopoverMenu132 />
-      </div>
-    );
-  },
-});
-
-var ReactImage134 = React.createClass({
-  render: function() {
-    return <i alt={""} className={"_3-8_ img sp_UuU9HmrQ397 sx_990b54"} src={null}></i>;
-  },
-});
-
-var AbstractButton135 = React.createClass({
-  render: function() {
-    return (
-      <button size={"large"} disabled={false} className={"_d2_ _u_k _5n7z _4jy0 _4jy4 _517h _51sy _42ft"} image={{}} data-hover={"tooltip"} aria-label={"Edit Ads (Ctrl+U)"} onClick={function() {}} use={"default"} label={null} borderShade={"light"} suppressed={false} type={"submit"} value={"1"}>
-        <ReactImage134 />
-        {"Edit"}
-        {undefined}
-      </button>
-    );
-  },
-});
-
-var XUIButton136 = React.createClass({
-  render: function() {
-    return <AbstractButton135 />;
-  },
-});
-
-var ReactImage137 = React.createClass({
-  render: function() {
-    return <i src={null} className={"img sp_UuU9HmrQ397 sx_203adb"}></i>;
-  },
-});
-
-var AbstractButton138 = React.createClass({
-  render: function() {
-    return (
-      <button aria-label={"Duplicate"} className={"_u_k _4jy0 _4jy4 _517h _51sy _42ft"} data-hover={"tooltip"} disabled={false} image={{}} size={"large"} onClick={function() {}} use={"default"} borderShade={"light"} suppressed={false} label={null} type={"submit"} value={"1"}>
-        <ReactImage137 />
-        {undefined}
-        {undefined}
-      </button>
-    );
-  },
-});
-
-var XUIButton139 = React.createClass({
-  render: function() {
-    return <AbstractButton138 />;
-  },
-});
-
-var ReactImage140 = React.createClass({
-  render: function() {
-    return <i src={null} className={"img sp_UuU9HmrQ397 sx_0c342e"}></i>;
-  },
-});
-
-var AbstractButton141 = React.createClass({
-  render: function() {
-    return (
-      <button aria-label={"Revert"} className={"_u_k _4jy0 _4jy4 _517h _51sy _42ft _42fr"} data-hover={"tooltip"} disabled={true} image={{}} size={"large"} onClick={function() {}} use={"default"} borderShade={"light"} suppressed={false} label={null} type={"submit"} value={"1"}>
-        <ReactImage140 />
-        {undefined}
-        {undefined}
-      </button>
-    );
-  },
-});
-
-var XUIButton142 = React.createClass({
-  render: function() {
-    return <AbstractButton141 />;
-  },
-});
-
-var ReactImage143 = React.createClass({
-  render: function() {
-    return <i src={null} className={"img sp_UuU9HmrQ397 sx_0e75f5"}></i>;
-  },
-});
-
-var AbstractButton144 = React.createClass({
-  render: function() {
-    return (
-      <button aria-label={"Delete"} className={"_u_k _4jy0 _4jy4 _517h _51sy _42ft"} image={{}} data-hover={"tooltip"} disabled={false} size={"large"} onClick={function() {}} use={"default"} borderShade={"light"} suppressed={false} label={null} type={"submit"} value={"1"}>
-        <ReactImage143 />
-        {undefined}
-        {undefined}
-      </button>
-    );
-  },
-});
-
-var XUIButton145 = React.createClass({
-  render: function() {
-    return <AbstractButton144 />;
-  },
-});
-
-var XUIButtonGroup146 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_5n7z _51xa"}>
-        <XUIButton139 key={"duplicate"} />
-        <XUIButton142 key={"revert"} />
-        <XUIButton145 key={"delete"} />
-      </div>
-    );
-  },
-});
-
-var ReactImage147 = React.createClass({
-  render: function() {
-    return <i src={null} className={"img sp_UuU9HmrQ397 sx_8c19ae"}></i>;
-  },
-});
-
-var AbstractButton148 = React.createClass({
-  render: function() {
-    return (
-      <button size={"large"} disabled={false} className={"_u_k _4jy0 _4jy4 _517h _51sy _42ft"} image={{}} data-hover={"tooltip"} aria-label={"Save Audience"} onClick={function() {}} use={"default"} borderShade={"light"} suppressed={false} label={null} type={"submit"} value={"1"}>
-        <ReactImage147 />
-        {undefined}
-        {undefined}
-      </button>
-    );
-  },
-});
-
-var XUIButton149 = React.createClass({
-  render: function() {
-    return <AbstractButton148 />;
-  },
-});
-
-var ReactImage150 = React.createClass({
-  render: function() {
-    return <i src={null} className={"img sp_UuU9HmrQ397 sx_d2b33c"}></i>;
-  },
-});
-
-var AbstractButton151 = React.createClass({
-  render: function() {
-    return (
-      <button size={"large"} className={"_u_k noMargin _p _4jy0 _4jy4 _517h _51sy _42ft"} onClick={function() {}} image={{}} data-hover={"tooltip"} aria-label={"Export & Import"} use={"default"} borderShade={"light"} suppressed={false} label={null} type={"submit"} value={"1"}>
-        <ReactImage150 />
-        {undefined}
-        {undefined}
-      </button>
-    );
-  },
-});
-
-var XUIButton152 = React.createClass({
-  render: function() {
-    return <AbstractButton151 />;
-  },
-});
-
-var InlineBlock153 = React.createClass({
-  render: function() {
-    return (
-      <div menu={{}} size={"large"} alignv={"middle"} className={"uiPopover _6a _6b"} disabled={null} fullWidth={false}>
-        <XUIButton152 key={"/.0"} />
-      </div>
-    );
-  },
-});
-
-var ReactPopoverMenu154 = React.createClass({
-  render: function() {
-    return <InlineBlock153 ref={"root"} />;
-  },
-});
-
-var AdsPEExportImportMenu155 = React.createClass({
-  render: function() {
-    return <ReactPopoverMenu154 key={"export"} />;
-  },
-});
-
-var FluxContainer_x_156 = React.createClass({
-  render: function() {
-    return null;
-  },
-});
-
-var AdsPEExportAsTextDialog157 = React.createClass({
-  render: function() {
-    return null;
-  },
-});
-
-var FluxContainer_q_158 = React.createClass({
-  render: function() {
-    return <AdsPEExportAsTextDialog157 />;
-  },
-});
-
-var AdsPEExportImportMenuContainer159 = React.createClass({
-  render: function() {
-    return (
-      <span>
-        <AdsPEExportImportMenu155 />
-        <FluxContainer_x_156 />
-        <FluxContainer_q_158 />
-        {null}
-      </span>
-    );
-  },
-});
-
-var ReactImage160 = React.createClass({
-  render: function() {
-    return <i src={null} className={"img sp_UuU9HmrQ397 sx_872db1"}></i>;
-  },
-});
-
-var AbstractButton161 = React.createClass({
-  render: function() {
-    return (
-      <button size={"large"} disabled={false} onClick={function() {}} className={"_u_k _5n7z _4jy0 _4jy4 _517h _51sy _42ft"} image={{}} style={{"boxSizing":"border-box","height":"28px","width":"48px"}} data-hover={"tooltip"} aria-label={"Create Report"} use={"default"} borderShade={"light"} suppressed={false} label={null} type={"submit"} value={"1"}>
-        <ReactImage160 />
-        {undefined}
-        {undefined}
-      </button>
-    );
-  },
-});
-
-var XUIButton162 = React.createClass({
-  render: function() {
-    return <AbstractButton161 />;
-  },
-});
-
-var AbstractButton163 = React.createClass({
-  render: function() {
-    return (
-      <button size={"large"} disabled={true} className={"hidden_elem _5n7z _4jy0 _4jy4 _517h _51sy _42ft _42fr"} label={null} onClick={function() {}} use={"default"} borderShade={"light"} suppressed={false} type={"submit"} value={"1"}>
-        {undefined}
-        {"Generate Variations"}
-        {undefined}
-      </button>
-    );
-  },
-});
-
-var XUIButton164 = React.createClass({
-  render: function() {
-    return <AbstractButton163 />;
-  },
-});
-
-var XUIButtonGroup165 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_5n7z _51xa"}>
-        <XUIButton149 key={"saveAudience"} />
-        <AdsPEExportImportMenuContainer159 />
-        <XUIButton162 key={"createReport"} ref={"ads_create_report_button"} />
-        <XUIButton164 key={"variations"} />
-      </div>
-    );
-  },
-});
-
-var FillColumn166 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4bl9"}>
-        <span className={"_3c5e"}>
-          <span>
-            <XUIButtonGroup133 />
-            <XUIButton136 key={"edit"} />
-            <XUIButtonGroup146 />
-          </span>
-          <XUIButtonGroup165 />
-        </span>
-      </div>
-    );
-  },
-});
-
-var Layout167 = React.createClass({
-  render: function() {
-    return (
-      <div className={"clearfix"}>
-        <Column124 key={"1"} />
-        <FillColumn166 key={"0"} />
-      </div>
-    );
-  },
-});
-
-var AdsPEMainPaneToolbar168 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_3c5b clearfix"}>
-        <Layout167 />
-      </div>
-    );
-  },
-});
-
-var AdsPEAdgroupToolbarContainer169 = React.createClass({
-  render: function() {
-    return (
-      <div>
-        <AdsPEMainPaneToolbar168 />
-        {null}
-      </div>
-    );
-  },
-});
-
-var AbstractButton170 = React.createClass({
-  render: function() {
-    return (
-      <button className={"_tm3 _tm6 _4jy0 _4jy6 _517h _51sy _42ft"} label={null} data-tooltip-position={"right"} aria-label={"Campaigns"} data-hover={"tooltip"} onClick={function() {}} size={"xxlarge"} use={"default"} borderShade={"light"} suppressed={false} type={"submit"} value={"1"}>
-        {undefined}
-        <div>
-          <div className={"_tma"}></div>
-          <div className={"_tm8"}></div>
-          <div className={"_tm9"}>{1}</div>
+    var props = this.props;
+    if (props.x === 309) {
+      return (
+        <div className={"_tm2"}>
+          <XUIButton4 x={304} />
+          <XUIButton4 x={306} />
+          <XUIButton4 x={308} />
         </div>
-        {undefined}
-      </button>
-    );
+      );
+    }
   },
 });
 
-var XUIButton171 = React.createClass({
+var AdsPEOrganizerContainer139 = React.createClass({
   render: function() {
-    return <AbstractButton170 />;
-  },
-});
-
-var AbstractButton172 = React.createClass({
-  render: function() {
-    return (
-      <button className={"_tm4 _tm6 _4jy0 _4jy6 _517h _51sy _42ft"} label={null} data-tooltip-position={"right"} aria-label={"Ad Sets"} data-hover={"tooltip"} onClick={function() {}} size={"xxlarge"} use={"default"} borderShade={"light"} suppressed={false} type={"submit"} value={"1"}>
-        {undefined}
+    var props = this.props;
+    if (props.x === 310) {
+      return (
         <div>
-          <div className={"_tma"}></div>
-          <div className={"_tm8"}></div>
-          <div className={"_tm9"}>{1}</div>
+          <AdsPESimpleOrganizer138 x={309} />
         </div>
-        {undefined}
-      </button>
-    );
-  },
-});
-
-var XUIButton173 = React.createClass({
-  render: function() {
-    return <AbstractButton172 />;
+      );
+    }
   },
 });
 
-var AbstractButton174 = React.createClass({
+var FixedDataTableColumnResizeHandle140 = React.createClass({
   render: function() {
-    return (
-      <button className={"_tm5 _tm6 _tm7 _4jy0 _4jy6 _517h _51sy _42ft"} label={null} data-tooltip-position={"right"} aria-label={"Ads"} data-hover={"tooltip"} onClick={function() {}} size={"xxlarge"} use={"default"} borderShade={"light"} suppressed={false} type={"submit"} value={"1"}>
-        {undefined}
-        <div>
-          <div className={"_tma"}></div>
-          <div className={"_tm8"}></div>
-          <div className={"_tm9"}>{1}</div>
+    var props = this.props;
+    if (props.x === 313) {
+      return (
+        <div className={"_3487 _3488 _3489"} style={{"width":0,"height":25,"left":0}}>
+          <div className={"_348a"} style={{"height":25}}></div>
         </div>
-        {undefined}
-      </button>
-    );
-  },
-});
-
-var XUIButton175 = React.createClass({
-  render: function() {
-    return <AbstractButton174 />;
-  },
-});
-
-var AdsPESimpleOrganizer176 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_tm2"}>
-        <XUIButton171 />
-        <XUIButton173 />
-        <XUIButton175 />
-      </div>
-    );
-  },
-});
-
-var AdsPEOrganizerContainer177 = React.createClass({
-  render: function() {
-    return (
-      <div>
-        <AdsPESimpleOrganizer176 />
-      </div>
-    );
-  },
-});
-
-var FixedDataTableColumnResizeHandle178 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_3487 _3488 _3489"} style={{"width":0,"height":532,"left":0}}>
-        <div className={"_348a"} style={{"height":532}}></div>
-      </div>
-    );
-  },
-});
-
-var ReactImage179 = React.createClass({
-  render: function() {
-    return <i className={"_1cie _1cif img sp_R48dKBxiJkP sx_dc0ad2"} src={null}></i>;
-  },
-});
-
-var AdsPETableHeader180 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _1ksv _1vd7 _4h2r"}>
-        <ReactImage179 />
-        <span className={"_1cid"}>{"Ads"}</span>
-      </div>
-    );
+      );
+    }
   },
 });
 
-var TransitionCell181 = React.createClass({
+var AdsPETableHeader141 = React.createClass({
   render: function() {
-    return (
-      <div isHeaderCell={true} label={"Ads"} dataKey={0} groupHeaderRenderer={function() {}} groupHeaderLabels={{}} groupHeaderData={{}} columnKey={undefined} height={40} width={521} rowIndex={0} className={"_4lgc _4h2u"} style={{"height":40,"width":521}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <AdsPETableHeader180 />
-          </div>
+    var props = this.props;
+    if (props.x === 315) {
+      return (
+        <div className={"_1cig _1ksv _1vd7 _4h2r"} id={undefined}>
+          <ReactImage0 x={314} />
+          <span className={"_1cid"}>{"Campaigns"}</span>
         </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell182 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":40,"width":521,"left":0}}>
-        {undefined}
-        <TransitionCell181 />
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCellGroupImpl183 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_3pzj"} style={{"height":40,"position":"absolute","width":521,"zIndex":2,"transform":"translate3d(0px,0px,0)","backfaceVisibility":"hidden"}}>
-        <FixedDataTableCell182 key={"cell_0"} />
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCellGroup184 = React.createClass({
-  render: function() {
-    return (
-      <div style={{"height":40,"left":0}} className={"_3pzk"}>
-        <FixedDataTableCellGroupImpl183 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader185 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _1vd7 _4h2r"}>
-        {null}
-        <span className={"_1cid"}>{"Delivery"}</span>
-      </div>
-    );
-  },
-});
-
-var TransitionCell186 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={"Delivery"} dataKey={1} groupHeaderRenderer={function() {}} groupHeaderLabels={{}} groupHeaderData={{}} columnKey={undefined} height={40} width={298} rowIndex={0} className={"_4lgc _4h2u"} style={{"height":40,"width":298}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <AdsPETableHeader185 />
-          </div>
+      );
+    }
+    if (props.x === 320) {
+      return (
+        <div className={"_1cig _1vd7 _4h2r"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Performance"}</span>
         </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell187 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":40,"width":298,"left":0}}>
-        {undefined}
-        <TransitionCell186 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader188 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _1vd7 _4h2r"}>
-        {null}
-        <span className={"_1cid"}>{"Performance"}</span>
-      </div>
-    );
-  },
-});
-
-var TransitionCell189 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={"Performance"} dataKey={2} groupHeaderRenderer={function() {}} groupHeaderLabels={{}} groupHeaderData={{}} columnKey={undefined} height={40} width={490} rowIndex={0} className={"_4lgc _4h2u"} style={{"height":40,"width":490}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <AdsPETableHeader188 />
-          </div>
+      );
+    }
+    if (props.x === 323) {
+      return (
+        <div className={"_1cig _1vd7 _4h2r"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Overview"}</span>
         </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell190 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":40,"width":490,"left":298}}>
-        {undefined}
-        <TransitionCell189 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader191 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _1vd7 _4h2r"}>
-        {null}
-        <span className={"_1cid"}>{"Overview"}</span>
-      </div>
-    );
-  },
-});
-
-var TransitionCell192 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={"Overview"} dataKey={3} groupHeaderRenderer={function() {}} groupHeaderLabels={{}} groupHeaderData={{}} columnKey={undefined} height={40} width={972} rowIndex={0} className={"_4lgc _4h2u"} style={{"height":40,"width":972}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <AdsPETableHeader191 />
-          </div>
+      );
+    }
+    if (props.x === 326) {
+      return (
+        <div className={"_1cig _1vd7 _4h2r"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Toplines"}</span>
+        </div>
+      );
+    }
+    if (props.x === 329) {
+      return <div className={"_1cig _1vd7 _4h2r"} id={undefined}></div>;
+    }
+    if (props.x === 340) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Campaign Name"}</span>
+        </div>
+      );
+    }
+    if (props.x === 346) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined} data-tooltip-content={"Changed"} data-hover={"tooltip"}>
+          <ReactImage0 x={345} />
+          {null}
         </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell193 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":40,"width":972,"left":788}}>
-        {undefined}
-        <TransitionCell192 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader194 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _1vd7 _4h2r"}>
-        {null}
-        <span className={"_1cid"}>{"Creative Assets"}</span>
-      </div>
-    );
-  },
-});
-
-var TransitionCell195 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={"Creative Assets"} dataKey={4} groupHeaderRenderer={function() {}} groupHeaderLabels={{}} groupHeaderData={{}} columnKey={undefined} height={40} width={514} rowIndex={0} className={"_4lgc _4h2u"} style={{"height":40,"width":514}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <AdsPETableHeader194 />
-          </div>
+      );
+    }
+    if (props.x === 352) {
+      return (
+        <div className={"_1cig _25fg"} id={"ads_pe_table_error_header"} data-tooltip-content={"Errors"} data-hover={"tooltip"}>
+          <ReactImage0 x={351} />
+          {null}
         </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell196 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":40,"width":514,"left":1760}}>
-        {undefined}
-        <TransitionCell195 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader197 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _1vd7 _4h2r"}>
-        {null}
-        <span className={"_1cid"}>{"Toplines"}</span>
-      </div>
-    );
-  },
-});
-
-var TransitionCell198 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={"Toplines"} dataKey={5} groupHeaderRenderer={function() {}} groupHeaderLabels={{}} groupHeaderData={{}} columnKey={undefined} height={40} width={0} rowIndex={0} className={"_4lgc _4h2u"} style={{"height":40,"width":0}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <AdsPETableHeader197 />
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell199 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":40,"width":0,"left":2274}}>
-        {undefined}
-        <TransitionCell198 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader200 = React.createClass({
-  render: function() {
-    return <div className={"_1cig _1vd7 _4h2r"}></div>;
-  },
-});
-
-var TransitionCell201 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={""} dataKey={6} groupHeaderRenderer={function() {}} groupHeaderLabels={{}} groupHeaderData={{}} columnKey={undefined} height={40} width={25} rowIndex={0} className={"_4lgc _4h2u"} style={{"height":40,"width":25}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <AdsPETableHeader200 />
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell202 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":40,"width":25,"left":2274}}>
-        {undefined}
-        <TransitionCell201 />
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCellGroupImpl203 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_3pzj"} style={{"height":40,"position":"absolute","width":2299,"zIndex":0,"transform":"translate3d(0px,0px,0)","backfaceVisibility":"hidden"}}>
-        <FixedDataTableCell187 key={"cell_0"} />
-        <FixedDataTableCell190 key={"cell_1"} />
-        <FixedDataTableCell193 key={"cell_2"} />
-        <FixedDataTableCell196 key={"cell_3"} />
-        <FixedDataTableCell199 key={"cell_4"} />
-        <FixedDataTableCell202 key={"cell_5"} />
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCellGroup204 = React.createClass({
-  render: function() {
-    return (
-      <div style={{"height":40,"left":521}} className={"_3pzk"}>
-        <FixedDataTableCellGroupImpl203 />
-      </div>
-    );
-  },
-});
-
-var FixedDataTableRowImpl205 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1gd4 _4li _52no _3h1a _1mib"} onClick={null} onDoubleClick={null} onMouseDown={null} onMouseEnter={null} onMouseLeave={null} style={{"width":1083,"height":40}}>
-        <div className={"_1gd5"}>
-          <FixedDataTableCellGroup184 key={"fixed_cells"} />
-          <FixedDataTableCellGroup204 key={"scrollable_cells"} />
-          <div className={"_1gd6 _1gd8"} style={{"left":521,"height":40}}></div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableRow206 = React.createClass({
-  render: function() {
-    return (
-      <div style={{"width":1083,"height":40,"zIndex":1,"transform":"translate3d(0px,0px,0)","backfaceVisibility":"hidden"}} className={"_1gda"}>
-        <FixedDataTableRowImpl205 />
-      </div>
-    );
-  },
-});
-
-var AbstractCheckboxInput207 = React.createClass({
-  render: function() {
-    return (
-      <label className={"_4h2r _55sg _kv1"}>
-        <input checked={undefined} onChange={function() {}} className={null} type={"checkbox"}></input>
-        <span data-hover={null} aria-label={undefined}></span>
-      </label>
-    );
-  },
-});
-
-var XUICheckboxInput208 = React.createClass({
-  render: function() {
-    return <AbstractCheckboxInput207 />;
-  },
-});
-
-var TransitionCell209 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={undefined} width={42} dataKey={"common.id"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"common.id"} height={25} style={{"height":25,"width":42}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <XUICheckboxInput208 />
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell210 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4lg6 _4h2m"} style={{"height":25,"width":42,"left":0}}>
-        {undefined}
-        <TransitionCell209 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader211 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _25fg"}>
-        {null}
-        <span className={"_1cid"}>{"Ad Name"}</span>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableAbstractSortableHeader212 = React.createClass({
-  render: function() {
-    return (
-      <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
-        <div className={"_2eq6"}>
+      );
+    }
+    if (props.x === 357) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
           {null}
-          <AdsPETableHeader211 />
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableSortableHeader213 = React.createClass({
-  render: function() {
-    return <FixedDataTableAbstractSortableHeader212 />;
-  },
-});
-
-var TransitionCell214 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={"Ad Name"} width={200} dataKey={"ad.name"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"ad.name"} height={25} style={{"height":25,"width":200}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <FixedDataTableSortableHeader213 />
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell215 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":25,"width":200,"left":42}}>
-        <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
-          <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          <span className={"_1cid"}>{"Status"}</span>
         </div>
-        <TransitionCell214 />
-      </div>
-    );
-  },
-});
-
-var ReactImage216 = React.createClass({
-  render: function() {
-    return <i className={"_1cie img sp_UuU9HmrQ397 sx_844e7d"} src={null}></i>;
-  },
-});
-
-var AdsPETableHeader217 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _25fg"}>
-        <ReactImage216 />
-        {null}
-      </div>
-    );
-  },
-});
-
-var FixedDataTableAbstractSortableHeader218 = React.createClass({
-  render: function() {
-    return (
-      <div onClick={function() {}} className={"_54_8 _1kst _4h2r _2wzx"}>
-        <div className={"_2eq6"}>
+      );
+    }
+    if (props.x === 362) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
           {null}
-          <AdsPETableHeader217 />
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableSortableHeader219 = React.createClass({
-  render: function() {
-    return <FixedDataTableAbstractSortableHeader218 />;
-  },
-});
-
-var TransitionCell220 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={undefined} width={33} dataKey={"edit_status"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"edit_status"} height={25} style={{"height":25,"width":33}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <FixedDataTableSortableHeader219 />
-          </div>
+          <span className={"_1cid"}>{"Delivery"}</span>
         </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell221 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":25,"width":33,"left":242}}>
-        {undefined}
-        <TransitionCell220 />
-      </div>
-    );
-  },
-});
-
-var ReactImage222 = React.createClass({
-  render: function() {
-    return <i className={"_1cie img sp_UuU9HmrQ397 sx_36dc45"} src={null}></i>;
-  },
-});
-
-var AdsPETableHeader223 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _25fg"}>
-        <ReactImage222 />
-        {null}
-      </div>
-    );
-  },
-});
-
-var FixedDataTableAbstractSortableHeader224 = React.createClass({
-  render: function() {
-    return (
-      <div onClick={function() {}} className={"_54_8 _1kst _4h2r _2wzx"}>
-        <div className={"_2eq6"}>
+      );
+    }
+    if (props.x === 369) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
           {null}
-          <AdsPETableHeader223 />
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableSortableHeader225 = React.createClass({
-  render: function() {
-    return <FixedDataTableAbstractSortableHeader224 />;
-  },
-});
-
-var TransitionCell226 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={undefined} width={36} dataKey={"errors"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"errors"} height={25} style={{"height":25,"width":36}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <FixedDataTableSortableHeader225 />
-          </div>
+          <span className={"_1cid"}>{"Results"}</span>
         </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell227 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":25,"width":36,"left":275}}>
-        {undefined}
-        <TransitionCell226 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader228 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _25fg"}>
-        {null}
-        <span className={"_1cid"}>{"Status"}</span>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableAbstractSortableHeader229 = React.createClass({
-  render: function() {
-    return (
-      <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
-        <div className={"_2eq6"}>
+      );
+    }
+    if (props.x === 374) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
           {null}
-          <AdsPETableHeader228 />
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableSortableHeader230 = React.createClass({
-  render: function() {
-    return <FixedDataTableAbstractSortableHeader229 />;
-  },
-});
-
-var TransitionCell231 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={"Status"} width={60} dataKey={"ad.adgroup_status"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"ad.adgroup_status"} height={25} style={{"height":25,"width":60}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <FixedDataTableSortableHeader230 />
-          </div>
+          <span className={"_1cid"}>{"Cost"}</span>
         </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell232 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":25,"width":60,"left":311}}>
-        {undefined}
-        <TransitionCell231 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader233 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _25fg"}>
-        {null}
-        <span className={"_1cid"}>{"Delivery"}</span>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableAbstractSortableHeader234 = React.createClass({
-  render: function() {
-    return (
-      <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
-        <div className={"_2eq6"}>
+      );
+    }
+    if (props.x === 379) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
           {null}
-          <AdsPETableHeader233 />
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableSortableHeader235 = React.createClass({
-  render: function() {
-    return <FixedDataTableAbstractSortableHeader234 />;
-  },
-});
-
-var TransitionCell236 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={"Delivery"} width={150} dataKey={"ukiAdData.computed_activity_status"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"ukiAdData.computed_activity_status"} height={25} style={{"height":25,"width":150}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <FixedDataTableSortableHeader235 />
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell237 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":25,"width":150,"left":371}}>
-        <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
-          <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          <span className={"_1cid"}>{"Reach"}</span>
         </div>
-        <TransitionCell236 />
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCellGroupImpl238 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_3pzj"} style={{"height":25,"position":"absolute","width":521,"zIndex":2,"transform":"translate3d(0px,0px,0)","backfaceVisibility":"hidden"}}>
-        <FixedDataTableCell210 key={"cell_0"} />
-        <FixedDataTableCell215 key={"cell_1"} />
-        <FixedDataTableCell221 key={"cell_2"} />
-        <FixedDataTableCell227 key={"cell_3"} />
-        <FixedDataTableCell232 key={"cell_4"} />
-        <FixedDataTableCell237 key={"cell_5"} />
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCellGroup239 = React.createClass({
-  render: function() {
-    return (
-      <div style={{"height":25,"left":0}} className={"_3pzk"}>
-        <FixedDataTableCellGroupImpl238 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader240 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _25fg"}>
-        {null}
-        <span className={"_1cid"}>{"Reach"}</span>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableAbstractSortableHeader241 = React.createClass({
-  render: function() {
-    return (
-      <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
-        <div className={"_2eq6"}>
+      );
+    }
+    if (props.x === 384) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
           {null}
-          <AdsPETableHeader240 />
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableSortableHeader242 = React.createClass({
-  render: function() {
-    return <FixedDataTableAbstractSortableHeader241 />;
-  },
-});
-
-var TransitionCell243 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={"Reach"} width={60} dataKey={"stats.unique_impressions"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"stats.unique_impressions"} height={25} style={{"height":25,"width":60}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <FixedDataTableSortableHeader242 />
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell244 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":25,"width":60,"left":0}}>
-        <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
-          <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          <span className={"_1cid"}>{"Impressions"}</span>
         </div>
-        <TransitionCell243 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader245 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _25fg"}>
-        {null}
-        <span className={"_1cid"}>{"Ad Impressions"}</span>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableAbstractSortableHeader246 = React.createClass({
-  render: function() {
-    return (
-      <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
-        <div className={"_2eq6"}>
+      );
+    }
+    if (props.x === 389) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
           {null}
-          <AdsPETableHeader245 />
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableSortableHeader247 = React.createClass({
-  render: function() {
-    return <FixedDataTableAbstractSortableHeader246 />;
-  },
-});
-
-var TransitionCell248 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={"Ad Impressions"} width={80} dataKey={"stats.impressions"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"stats.impressions"} height={25} style={{"height":25,"width":80}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <FixedDataTableSortableHeader247 />
-          </div>
+          <span className={"_1cid"}>{"Clicks"}</span>
         </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell249 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":25,"width":80,"left":60}}>
-        <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
-          <div className={"_4lga _4lgb"} style={{"height":25}}></div>
-        </div>
-        <TransitionCell248 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader250 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _25fg"}>
-        {null}
-        <span className={"_1cid"}>{"Avg. CPM"}</span>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableAbstractSortableHeader251 = React.createClass({
-  render: function() {
-    return (
-      <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
-        <div className={"_2eq6"}>
+      );
+    }
+    if (props.x === 394) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
           {null}
-          <AdsPETableHeader250 />
+          <span className={"_1cid"}>{"Avg. CPM"}</span>
         </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableSortableHeader252 = React.createClass({
-  render: function() {
-    return <FixedDataTableAbstractSortableHeader251 />;
-  },
-});
-
-var TransitionCell253 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={"Avg. CPM"} width={80} dataKey={"stats.avg_cpm"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"stats.avg_cpm"} height={25} style={{"height":25,"width":80}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <FixedDataTableSortableHeader252 />
-          </div>
+      );
+    }
+    if (props.x === 399) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Avg. CPC"}</span>
         </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell254 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":25,"width":80,"left":140}}>
-        <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
-          <div className={"_4lga _4lgb"} style={{"height":25}}></div>
-        </div>
-        <TransitionCell253 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader255 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _25fg"}>
-        {null}
-        <span className={"_1cid"}>{"Avg. CPC"}</span>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableAbstractSortableHeader256 = React.createClass({
-  render: function() {
-    return (
-      <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
-        <div className={"_2eq6"}>
-          {null}
-          <AdsPETableHeader255 />
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableSortableHeader257 = React.createClass({
-  render: function() {
-    return <FixedDataTableAbstractSortableHeader256 />;
-  },
-});
-
-var TransitionCell258 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={"Avg. CPC"} width={78} dataKey={"stats.avg_cpc"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"stats.avg_cpc"} height={25} style={{"height":25,"width":78}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <FixedDataTableSortableHeader257 />
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell259 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":25,"width":78,"left":220}}>
-        <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
-          <div className={"_4lga _4lgb"} style={{"height":25}}></div>
-        </div>
-        <TransitionCell258 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader260 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _25fg _4h2r"}>
-        {null}
-        <span className={"_1cid"}>{"Results"}</span>
-      </div>
-    );
-  },
-});
-
-var TransitionCell261 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={"Results"} width={140} dataKey={"stats.actions"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"stats.actions"} height={25} style={{"height":25,"width":140}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <AdsPETableHeader260 />
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell262 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":25,"width":140,"left":298}}>
-        <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
-          <div className={"_4lga _4lgb"} style={{"height":25}}></div>
-        </div>
-        <TransitionCell261 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader263 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _25fg _4h2r"}>
-        {null}
-        <span className={"_1cid"}>{"Cost"}</span>
-      </div>
-    );
-  },
-});
-
-var TransitionCell264 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={"Cost"} width={140} dataKey={"stats.cpa"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"stats.cpa"} height={25} style={{"height":25,"width":140}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <AdsPETableHeader263 />
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell265 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":25,"width":140,"left":438}}>
-        <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
-          <div className={"_4lga _4lgb"} style={{"height":25}}></div>
-        </div>
-        <TransitionCell264 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader266 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _25fg"}>
-        {null}
-        <span className={"_1cid"}>{"Clicks"}</span>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableAbstractSortableHeader267 = React.createClass({
-  render: function() {
-    return (
-      <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
-        <div className={"_2eq6"}>
-          {null}
-          <AdsPETableHeader266 />
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableSortableHeader268 = React.createClass({
-  render: function() {
-    return <FixedDataTableAbstractSortableHeader267 />;
-  },
-});
-
-var TransitionCell269 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={"Clicks"} width={60} dataKey={"stats.clicks"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"stats.clicks"} height={25} style={{"height":25,"width":60}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <FixedDataTableSortableHeader268 />
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell270 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":25,"width":60,"left":578}}>
-        <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
-          <div className={"_4lga _4lgb"} style={{"height":25}}></div>
-        </div>
-        <TransitionCell269 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader271 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _25fg"}>
-        {null}
-        <span className={"_1cid"}>{"CTR %"}</span>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableAbstractSortableHeader272 = React.createClass({
-  render: function() {
-    return (
-      <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
-        <div className={"_2eq6"}>
-          {null}
-          <AdsPETableHeader271 />
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableSortableHeader273 = React.createClass({
-  render: function() {
-    return <FixedDataTableAbstractSortableHeader272 />;
-  },
-});
-
-var TransitionCell274 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={"CTR %"} width={70} dataKey={"stats.ctr"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"stats.ctr"} height={25} style={{"height":25,"width":70}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <FixedDataTableSortableHeader273 />
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell275 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":25,"width":70,"left":638}}>
-        <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
-          <div className={"_4lga _4lgb"} style={{"height":25}}></div>
-        </div>
-        <TransitionCell274 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader276 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _25fg"}>
-        {null}
-        <span className={"_1cid"}>{"Social %"}</span>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableAbstractSortableHeader277 = React.createClass({
-  render: function() {
-    return (
-      <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
-        <div className={"_2eq6"}>
-          {null}
-          <AdsPETableHeader276 />
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableSortableHeader278 = React.createClass({
-  render: function() {
-    return <FixedDataTableAbstractSortableHeader277 />;
-  },
-});
-
-var TransitionCell279 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={"Social %"} width={80} dataKey={"stats.social_percent"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"stats.social_percent"} height={25} style={{"height":25,"width":80}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <FixedDataTableSortableHeader278 />
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell280 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":25,"width":80,"left":708}}>
-        <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
-          <div className={"_4lga _4lgb"} style={{"height":25}}></div>
-        </div>
-        <TransitionCell279 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader281 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _25fg"}>
-        {null}
-        <span className={"_1cid"}>{"Ad Set Name"}</span>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableAbstractSortableHeader282 = React.createClass({
-  render: function() {
-    return (
-      <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
-        <div className={"_2eq6"}>
-          {null}
-          <AdsPETableHeader281 />
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableSortableHeader283 = React.createClass({
-  render: function() {
-    return <FixedDataTableAbstractSortableHeader282 />;
-  },
-});
-
-var TransitionCell284 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={"Ad Set Name"} width={100} dataKey={"campaign.name"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"campaign.name"} height={25} style={{"height":25,"width":100}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <FixedDataTableSortableHeader283 />
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell285 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":25,"width":100,"left":788}}>
-        <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
-          <div className={"_4lga _4lgb"} style={{"height":25}}></div>
-        </div>
-        <TransitionCell284 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader286 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _25fg"}>
-        {null}
-        <span className={"_1cid"}>{"Campaign Name"}</span>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableAbstractSortableHeader287 = React.createClass({
-  render: function() {
-    return (
-      <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
-        <div className={"_2eq6"}>
-          {null}
-          <AdsPETableHeader286 />
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableSortableHeader288 = React.createClass({
-  render: function() {
-    return <FixedDataTableAbstractSortableHeader287 />;
-  },
-});
-
-var TransitionCell289 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={"Campaign Name"} width={150} dataKey={"campaignGroup.name"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"campaignGroup.name"} height={25} style={{"height":25,"width":150}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <FixedDataTableSortableHeader288 />
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell290 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":25,"width":150,"left":888}}>
-        <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
-          <div className={"_4lga _4lgb"} style={{"height":25}}></div>
-        </div>
-        <TransitionCell289 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader291 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _25fg"}>
-        {null}
-        <span className={"_1cid"}>{"Ad ID"}</span>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableAbstractSortableHeader292 = React.createClass({
-  render: function() {
-    return (
-      <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
-        <div className={"_2eq6"}>
-          {null}
-          <AdsPETableHeader291 />
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableSortableHeader293 = React.createClass({
-  render: function() {
-    return <FixedDataTableAbstractSortableHeader292 />;
-  },
-});
-
-var TransitionCell294 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={"Ad ID"} width={120} dataKey={"ad.id"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"ad.id"} height={25} style={{"height":25,"width":120}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <FixedDataTableSortableHeader293 />
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell295 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":25,"width":120,"left":1038}}>
-        <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
-          <div className={"_4lga _4lgb"} style={{"height":25}}></div>
-        </div>
-        <TransitionCell294 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader296 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _25fg"}>
-        {null}
-        <span className={"_1cid"}>{"Objective"}</span>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableAbstractSortableHeader297 = React.createClass({
-  render: function() {
-    return (
-      <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
-        <div className={"_2eq6"}>
-          {null}
-          <AdsPETableHeader296 />
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableSortableHeader298 = React.createClass({
-  render: function() {
-    return <FixedDataTableAbstractSortableHeader297 />;
-  },
-});
-
-var TransitionCell299 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={"Objective"} width={80} dataKey={"campaignGroup.objective"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"campaignGroup.objective"} height={25} style={{"height":25,"width":80}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <FixedDataTableSortableHeader298 />
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell300 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":25,"width":80,"left":1158}}>
-        <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
-          <div className={"_4lga _4lgb"} style={{"height":25}}></div>
-        </div>
-        <TransitionCell299 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader301 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _25fg"}>
-        {null}
-        <span className={"_1cid"}>{"Spent"}</span>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableAbstractSortableHeader302 = React.createClass({
-  render: function() {
-    return (
-      <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
-        <div className={"_2eq6"}>
-          {null}
-          <AdsPETableHeader301 />
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableSortableHeader303 = React.createClass({
-  render: function() {
-    return <FixedDataTableAbstractSortableHeader302 />;
-  },
-});
-
-var TransitionCell304 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={"Spent"} width={70} dataKey={"stats.spent_100"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"stats.spent_100"} height={25} style={{"height":25,"width":70}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <FixedDataTableSortableHeader303 />
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell305 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":25,"width":70,"left":1238}}>
-        <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
-          <div className={"_4lga _4lgb"} style={{"height":25}}></div>
-        </div>
-        <TransitionCell304 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader306 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _25fg"}>
-        {null}
-        <span className={"_1cid"}>{"Start"}</span>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableAbstractSortableHeader307 = React.createClass({
-  render: function() {
-    return (
-      <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
-        <div className={"_2eq6"}>
-          {null}
-          <AdsPETableHeader306 />
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableSortableHeader308 = React.createClass({
-  render: function() {
-    return <FixedDataTableAbstractSortableHeader307 />;
-  },
-});
-
-var TransitionCell309 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={"Start"} width={113} dataKey={"derivedCampaign.startDate"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"derivedCampaign.startDate"} height={25} style={{"height":25,"width":113}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <FixedDataTableSortableHeader308 />
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell310 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":25,"width":113,"left":1308}}>
-        <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
-          <div className={"_4lga _4lgb"} style={{"height":25}}></div>
-        </div>
-        <TransitionCell309 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader311 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _25fg"}>
-        {null}
-        <span className={"_1cid"}>{"End"}</span>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableAbstractSortableHeader312 = React.createClass({
-  render: function() {
-    return (
-      <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
-        <div className={"_2eq6"}>
-          {null}
-          <AdsPETableHeader311 />
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableSortableHeader313 = React.createClass({
-  render: function() {
-    return <FixedDataTableAbstractSortableHeader312 />;
-  },
-});
-
-var TransitionCell314 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={"End"} width={113} dataKey={"derivedCampaign.endDate"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"derivedCampaign.endDate"} height={25} style={{"height":25,"width":113}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <FixedDataTableSortableHeader313 />
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell315 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":25,"width":113,"left":1421}}>
-        <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
-          <div className={"_4lga _4lgb"} style={{"height":25}}></div>
-        </div>
-        <TransitionCell314 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader316 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _25fg"}>
-        {null}
-        <span className={"_1cid"}>{"Date created"}</span>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableAbstractSortableHeader317 = React.createClass({
-  render: function() {
-    return (
-      <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
-        <div className={"_2eq6"}>
-          {null}
-          <AdsPETableHeader316 />
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableSortableHeader318 = React.createClass({
-  render: function() {
-    return <FixedDataTableAbstractSortableHeader317 />;
-  },
-});
-
-var TransitionCell319 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={"Date created"} width={113} dataKey={"ad.created_time"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"ad.created_time"} height={25} style={{"height":25,"width":113}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <FixedDataTableSortableHeader318 />
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell320 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":25,"width":113,"left":1534}}>
-        <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
-          <div className={"_4lga _4lgb"} style={{"height":25}}></div>
-        </div>
-        <TransitionCell319 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader321 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _25fg"}>
-        {null}
-        <span className={"_1cid"}>{"Date last edited"}</span>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableAbstractSortableHeader322 = React.createClass({
-  render: function() {
-    return (
-      <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
-        <div className={"_2eq6"}>
-          {null}
-          <AdsPETableHeader321 />
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableSortableHeader323 = React.createClass({
-  render: function() {
-    return <FixedDataTableAbstractSortableHeader322 />;
-  },
-});
-
-var TransitionCell324 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={"Date last edited"} width={113} dataKey={"ad.updated_time"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"ad.updated_time"} height={25} style={{"height":25,"width":113}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <FixedDataTableSortableHeader323 />
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell325 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":25,"width":113,"left":1647}}>
-        <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
-          <div className={"_4lga _4lgb"} style={{"height":25}}></div>
-        </div>
-        <TransitionCell324 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader326 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _25fg"}>
-        {null}
-        <span className={"_1cid"}>{"Title"}</span>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableAbstractSortableHeader327 = React.createClass({
-  render: function() {
-    return (
-      <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
-        <div className={"_2eq6"}>
-          {null}
-          <AdsPETableHeader326 />
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableSortableHeader328 = React.createClass({
-  render: function() {
-    return <FixedDataTableAbstractSortableHeader327 />;
-  },
-});
-
-var TransitionCell329 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={"Title"} width={80} dataKey={"ad.title"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"ad.title"} height={25} style={{"height":25,"width":80}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <FixedDataTableSortableHeader328 />
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell330 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":25,"width":80,"left":1760}}>
-        <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
-          <div className={"_4lga _4lgb"} style={{"height":25}}></div>
-        </div>
-        <TransitionCell329 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader331 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _25fg"}>
-        {null}
-        <span className={"_1cid"}>{"Body"}</span>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableAbstractSortableHeader332 = React.createClass({
-  render: function() {
-    return (
-      <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
-        <div className={"_2eq6"}>
-          {null}
-          <AdsPETableHeader331 />
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableSortableHeader333 = React.createClass({
-  render: function() {
-    return <FixedDataTableAbstractSortableHeader332 />;
-  },
-});
-
-var TransitionCell334 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={"Body"} width={80} dataKey={"ad.creative.body"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"ad.creative.body"} height={25} style={{"height":25,"width":80}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <FixedDataTableSortableHeader333 />
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell335 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":25,"width":80,"left":1840}}>
-        <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
-          <div className={"_4lga _4lgb"} style={{"height":25}}></div>
-        </div>
-        <TransitionCell334 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader336 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _25fg"}>
-        {null}
-        <span className={"_1cid"}>{"Destination"}</span>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableAbstractSortableHeader337 = React.createClass({
-  render: function() {
-    return (
-      <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
-        <div className={"_2eq6"}>
-          {null}
-          <AdsPETableHeader336 />
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableSortableHeader338 = React.createClass({
-  render: function() {
-    return <FixedDataTableAbstractSortableHeader337 />;
-  },
-});
-
-var TransitionCell339 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={"Destination"} width={92} dataKey={"destination"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"destination"} height={25} style={{"height":25,"width":92}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <FixedDataTableSortableHeader338 />
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell340 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":25,"width":92,"left":1920}}>
-        <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
-          <div className={"_4lga _4lgb"} style={{"height":25}}></div>
-        </div>
-        <TransitionCell339 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader341 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _25fg"}>
-        {null}
-        <span className={"_1cid"}>{"Link"}</span>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableAbstractSortableHeader342 = React.createClass({
-  render: function() {
-    return (
-      <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
-        <div className={"_2eq6"}>
-          {null}
-          <AdsPETableHeader341 />
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableSortableHeader343 = React.createClass({
-  render: function() {
-    return <FixedDataTableAbstractSortableHeader342 />;
-  },
-});
-
-var TransitionCell344 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={"Link"} width={70} dataKey={"ad.creative.link_url"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"ad.creative.link_url"} height={25} style={{"height":25,"width":70}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <FixedDataTableSortableHeader343 />
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell345 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":25,"width":70,"left":2012}}>
-        <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
-          <div className={"_4lga _4lgb"} style={{"height":25}}></div>
-        </div>
-        <TransitionCell344 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader346 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _25fg"}>
-        {null}
-        <span className={"_1cid"}>{"Related Page"}</span>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableAbstractSortableHeader347 = React.createClass({
-  render: function() {
-    return (
-      <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
-        <div className={"_2eq6"}>
-          {null}
-          <AdsPETableHeader346 />
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableSortableHeader348 = React.createClass({
-  render: function() {
-    return <FixedDataTableAbstractSortableHeader347 />;
-  },
-});
-
-var TransitionCell349 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={"Related Page"} width={92} dataKey={"page"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"page"} height={25} style={{"height":25,"width":92}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <FixedDataTableSortableHeader348 />
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell350 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":25,"width":92,"left":2082}}>
-        <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
-          <div className={"_4lga _4lgb"} style={{"height":25}}></div>
-        </div>
-        <TransitionCell349 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader351 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1cig _25fg _4h2r"}>
-        {null}
-        <span className={"_1cid"}>{"Preview Link"}</span>
-      </div>
-    );
-  },
-});
-
-var TransitionCell352 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={"Preview Link"} width={100} dataKey={"ad.demolink_hash"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"ad.demolink_hash"} height={25} style={{"height":25,"width":100}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <AdsPETableHeader351 />
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell353 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":25,"width":100,"left":2174}}>
-        <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
-          <div className={"_4lga _4lgb"} style={{"height":25}}></div>
-        </div>
-        <TransitionCell352 />
-      </div>
-    );
-  },
-});
-
-var AdsPETableHeader354 = React.createClass({
-  render: function() {
-    return <div className={"_1cig _25fg _4h2r"}></div>;
-  },
-});
-
-var TransitionCell355 = React.createClass({
-  render: function() {
-    return (
-      <div isHeaderCell={true} label={""} width={25} dataKey={"scrollbar_spacer"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"scrollbar_spacer"} height={25} style={{"height":25,"width":25}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <AdsPETableHeader354 />
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell356 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":25,"width":25,"left":2274}}>
-        {undefined}
-        <TransitionCell355 />
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCellGroupImpl357 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_3pzj"} style={{"height":25,"position":"absolute","width":2299,"zIndex":0,"transform":"translate3d(0px,0px,0)","backfaceVisibility":"hidden"}}>
-        <FixedDataTableCell244 key={"cell_0"} />
-        <FixedDataTableCell249 key={"cell_1"} />
-        <FixedDataTableCell254 key={"cell_2"} />
-        <FixedDataTableCell259 key={"cell_3"} />
-        <FixedDataTableCell262 key={"cell_4"} />
-        <FixedDataTableCell265 key={"cell_5"} />
-        <FixedDataTableCell270 key={"cell_6"} />
-        <FixedDataTableCell275 key={"cell_7"} />
-        <FixedDataTableCell280 key={"cell_8"} />
-        <FixedDataTableCell285 key={"cell_9"} />
-        <FixedDataTableCell290 key={"cell_10"} />
-        <FixedDataTableCell295 key={"cell_11"} />
-        <FixedDataTableCell300 key={"cell_12"} />
-        <FixedDataTableCell305 key={"cell_13"} />
-        <FixedDataTableCell310 key={"cell_14"} />
-        <FixedDataTableCell315 key={"cell_15"} />
-        <FixedDataTableCell320 key={"cell_16"} />
-        <FixedDataTableCell325 key={"cell_17"} />
-        <FixedDataTableCell330 key={"cell_18"} />
-        <FixedDataTableCell335 key={"cell_19"} />
-        <FixedDataTableCell340 key={"cell_20"} />
-        <FixedDataTableCell345 key={"cell_21"} />
-        <FixedDataTableCell350 key={"cell_22"} />
-        <FixedDataTableCell353 key={"cell_23"} />
-        <FixedDataTableCell356 key={"cell_24"} />
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCellGroup358 = React.createClass({
-  render: function() {
-    return (
-      <div style={{"height":25,"left":521}} className={"_3pzk"}>
-        <FixedDataTableCellGroupImpl357 />
-      </div>
-    );
-  },
-});
-
-var FixedDataTableRowImpl359 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1gd4 _4li _3h1a _1mib"} onClick={null} onDoubleClick={null} onMouseDown={null} onMouseEnter={null} onMouseLeave={null} style={{"width":1083,"height":25}}>
-        <div className={"_1gd5"}>
-          <FixedDataTableCellGroup239 key={"fixed_cells"} />
-          <FixedDataTableCellGroup358 key={"scrollable_cells"} />
-          <div className={"_1gd6 _1gd8"} style={{"left":521,"height":25}}></div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableRow360 = React.createClass({
-  render: function() {
-    return (
-      <div style={{"width":1083,"height":25,"zIndex":1,"transform":"translate3d(0px,40px,0)","backfaceVisibility":"hidden"}} className={"_1gda"}>
-        <FixedDataTableRowImpl359 />
-      </div>
-    );
-  },
-});
-
-var AbstractCheckboxInput361 = React.createClass({
-  render: function() {
-    return (
-      <label className={"_5hhv _55sg _kv1"}>
-        <input className={null} disabled={false} inline={true} checked={true} value={undefined} onChange={function() {}} type={"checkbox"}></input>
-        <span data-hover={null} aria-label={undefined}></span>
-      </label>
-    );
-  },
-});
-
-var XUICheckboxInput362 = React.createClass({
-  render: function() {
-    return <AbstractCheckboxInput361 />;
-  },
-});
-
-var TransitionCell363 = React.createClass({
-  render: function() {
-    return (
-      <div dataKey={"common.id"} className={"_4lgc _4h2u"} rowGetter={function() {}} width={42} columnData={{}} cellDataGetter={function() {}} cellRenderer={function() {}} columnKey={"common.id"} height={32} rowIndex={0} style={{"height":32,"width":42}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <span className={"_5hhu _4h2r"} onMouseDown={function() {}}>
-              <XUICheckboxInput362 />
-            </span>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell364 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4lg6 _4h2m"} style={{"height":32,"width":42,"left":0}}>
-        {undefined}
-        <TransitionCell363 />
-      </div>
-    );
-  },
-});
-
-var AdsEditableTextCellDisplay365 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_vew"} onDoubleClick={function() {}} onMouseEnter={function() {}} onMouseLeave={function() {}}>
-        <div className={"_vex _5w6k"}>
-          <div className={"_vey"}>{"Test Ad"}</div>
-          <div className={"_5w6_"}></div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var AdsEditableCell366 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_2d6h _2-ev _4h2r _5abb"}>
-        <AdsEditableTextCellDisplay365 />
-      </div>
-    );
-  },
-});
-
-var TransitionCell367 = React.createClass({
-  render: function() {
-    return (
-      <div dataKey={"ad.name"} className={"_4lgc _4h2u"} rowGetter={function() {}} width={200} columnData={{}} cellDataGetter={function() {}} cellRenderer={function() {}} columnKey={"ad.name"} height={32} rowIndex={0} style={{"height":32,"width":200}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <AdsEditableCell366 />
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell368 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":32,"width":200,"left":42}}>
-        {undefined}
-        <TransitionCell367 />
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCellDefault369 = React.createClass({
-  render: function() {
-    return (
-      <div dataKey={"edit_status"} className={"_4lgc _4h2u"} rowGetter={function() {}} width={33} columnData={{}} cellDataGetter={function() {}} cellRenderer={function() {}} columnKey={"edit_status"} height={32} rowIndex={0} style={{"height":32,"width":33}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <div className={"_4h2r"}>{""}</div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var TransitionCell370 = React.createClass({
-  render: function() {
-    return <FixedDataTableCellDefault369 />;
-  },
-});
-
-var FixedDataTableCell371 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":32,"width":33,"left":242}}>
-        {undefined}
-        <TransitionCell370 />
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCellDefault372 = React.createClass({
-  render: function() {
-    return (
-      <div dataKey={"errors"} className={"_4lgc _4h2u"} rowGetter={function() {}} width={36} columnData={{}} cellDataGetter={function() {}} cellRenderer={function() {}} columnKey={"errors"} height={32} rowIndex={0} style={{"height":32,"width":36}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <div className={"_4h2r"}></div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var TransitionCell373 = React.createClass({
-  render: function() {
-    return <FixedDataTableCellDefault372 />;
-  },
-});
-
-var FixedDataTableCell374 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":32,"width":36,"left":275}}>
-        {undefined}
-        <TransitionCell373 />
-      </div>
-    );
-  },
-});
-
-var BUISwitch375 = React.createClass({
-  render: function() {
-    return (
-      <div value={true} disabled={true} onToggle={function() {}} data-hover={"tooltip"} data-tooltip-position={"below"} aria-label={"Currently active and you can not deactivate it."} animate={true} className={"_128j _128k _128m _128n"} role={"checkbox"} aria-checked={"true"}>
-        <div className={"_128o"} onClick={function() {}} onKeyDown={function() {}} onMouseDown={function() {}} tabIndex={"-1"}>
-          <div className={"_128p"}></div>
-        </div>
-        {null}
-      </div>
-    );
-  },
-});
-
-var AdsStatusSwitchInternal376 = React.createClass({
-  render: function() {
-    return <BUISwitch375 />;
-  },
-});
-
-var AdsStatusSwitch377 = React.createClass({
-  render: function() {
-    return <AdsStatusSwitchInternal376 />;
-  },
-});
-
-var TransitionCell378 = React.createClass({
-  render: function() {
-    return (
-      <div dataKey={"ad.adgroup_status"} className={"_4lgc _4h2u"} rowGetter={function() {}} width={60} columnData={{}} cellDataGetter={function() {}} cellRenderer={function() {}} columnKey={"ad.adgroup_status"} height={32} rowIndex={0} style={{"height":32,"width":60}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <div className={"_15si _4h2r"}>
-              <AdsStatusSwitch377 />
-            </div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell379 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":32,"width":60,"left":311}}>
-        {undefined}
-        <TransitionCell378 />
-      </div>
-    );
-  },
-});
-
-var ReactImage380 = React.createClass({
-  render: function() {
-    return <i aria-label={"Pending Review"} data-hover={"tooltip"} className={"_4ms8 img sp_UuU9HmrQ397 sx_ced63f"} src={null} width={"7"} height={"7"}></i>;
-  },
-});
-
-var AdsPEActivityStatusIndicator381 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_k4-"}>
-        <ReactImage380 />
-        {"Pending Review"}
-        {undefined}
-      </div>
-    );
-  },
-});
-
-var TransitionCell382 = React.createClass({
-  render: function() {
-    return (
-      <div dataKey={"ukiAdData.computed_activity_status"} className={"_4lgc _4h2u"} rowGetter={function() {}} width={150} columnData={{}} cellDataGetter={function() {}} cellRenderer={function() {}} columnKey={"ukiAdData.computed_activity_status"} height={32} rowIndex={0} style={{"height":32,"width":150}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <div className={"_2d6h _4h2r"}>
-              <AdsPEActivityStatusIndicator381 />
-            </div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell383 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":32,"width":150,"left":371}}>
-        {undefined}
-        <TransitionCell382 />
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCellGroupImpl384 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_3pzj"} style={{"height":32,"position":"absolute","width":521,"zIndex":2,"transform":"translate3d(0px,0px,0)","backfaceVisibility":"hidden"}}>
-        <FixedDataTableCell364 key={"cell_0"} />
-        <FixedDataTableCell368 key={"cell_1"} />
-        <FixedDataTableCell371 key={"cell_2"} />
-        <FixedDataTableCell374 key={"cell_3"} />
-        <FixedDataTableCell379 key={"cell_4"} />
-        <FixedDataTableCell383 key={"cell_5"} />
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCellGroup385 = React.createClass({
-  render: function() {
-    return (
-      <div style={{"height":32,"left":0}} className={"_3pzk"}>
-        <FixedDataTableCellGroupImpl384 />
-      </div>
-    );
-  },
-});
-
-var TransitionCell386 = React.createClass({
-  render: function() {
-    return (
-      <div dataKey={"stats.unique_impressions"} className={"_4lgc _4h2u"} rowGetter={function() {}} width={60} columnData={{}} cellDataGetter={function() {}} cellRenderer={function() {}} columnKey={"stats.unique_impressions"} height={32} rowIndex={0} style={{"height":32,"width":60}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <div className={"_2d6h _2g7x _4h2r"}>{" — "}</div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell387 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":32,"width":60,"left":0}}>
-        {undefined}
-        <TransitionCell386 />
-      </div>
-    );
-  },
-});
-
-var TransitionCell388 = React.createClass({
-  render: function() {
-    return (
-      <div dataKey={"stats.impressions"} className={"_4lgc _4h2u"} rowGetter={function() {}} width={80} columnData={{}} cellDataGetter={function() {}} cellRenderer={function() {}} columnKey={"stats.impressions"} height={32} rowIndex={0} style={{"height":32,"width":80}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <div className={"_2d6h _2g7x _4h2r"}>{" — "}</div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell389 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":32,"width":80,"left":60}}>
-        {undefined}
-        <TransitionCell388 />
-      </div>
-    );
-  },
-});
-
-var TransitionCell390 = React.createClass({
-  render: function() {
-    return (
-      <div dataKey={"stats.avg_cpm"} className={"_4lgc _4h2u"} rowGetter={function() {}} width={80} columnData={{}} cellDataGetter={function() {}} cellRenderer={function() {}} columnKey={"stats.avg_cpm"} height={32} rowIndex={0} style={{"height":32,"width":80}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <div className={"_2d6h _2g7x _4h2r"}>{" — "}</div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell391 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":32,"width":80,"left":140}}>
-        {undefined}
-        <TransitionCell390 />
-      </div>
-    );
-  },
-});
-
-var TransitionCell392 = React.createClass({
-  render: function() {
-    return (
-      <div dataKey={"stats.avg_cpc"} className={"_4lgc _4h2u"} rowGetter={function() {}} width={78} columnData={{}} cellDataGetter={function() {}} cellRenderer={function() {}} columnKey={"stats.avg_cpc"} height={32} rowIndex={0} style={{"height":32,"width":78}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <div className={"_2d6h _2g7x _4h2r"}>{" — "}</div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell393 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":32,"width":78,"left":220}}>
-        {undefined}
-        <TransitionCell392 />
-      </div>
-    );
-  },
-});
-
-var TransitionCell394 = React.createClass({
-  render: function() {
-    return (
-      <div dataKey={"stats.actions"} className={"_4lgc _4h2u"} rowGetter={function() {}} width={140} columnData={{}} cellDataGetter={function() {}} cellRenderer={function() {}} columnKey={"stats.actions"} height={32} rowIndex={0} style={{"height":32,"width":140}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <div className={"_2d6h _2g7x _4h2r"}>{" — "}</div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell395 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":32,"width":140,"left":298}}>
-        {undefined}
-        <TransitionCell394 />
-      </div>
-    );
-  },
-});
-
-var TransitionCell396 = React.createClass({
-  render: function() {
-    return (
-      <div dataKey={"stats.cpa"} className={"_4lgc _4h2u"} rowGetter={function() {}} width={140} columnData={{}} cellDataGetter={function() {}} cellRenderer={function() {}} columnKey={"stats.cpa"} height={32} rowIndex={0} style={{"height":32,"width":140}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <div className={"_2d6h _2g7x _4h2r"}>{" — "}</div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell397 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":32,"width":140,"left":438}}>
-        {undefined}
-        <TransitionCell396 />
-      </div>
-    );
-  },
-});
-
-var TransitionCell398 = React.createClass({
-  render: function() {
-    return (
-      <div dataKey={"stats.clicks"} className={"_4lgc _4h2u"} rowGetter={function() {}} width={60} columnData={{}} cellDataGetter={function() {}} cellRenderer={function() {}} columnKey={"stats.clicks"} height={32} rowIndex={0} style={{"height":32,"width":60}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <div className={"_2d6h _2g7x _4h2r"}>{" — "}</div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell399 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":32,"width":60,"left":578}}>
-        {undefined}
-        <TransitionCell398 />
-      </div>
-    );
-  },
-});
-
-var TransitionCell400 = React.createClass({
-  render: function() {
-    return (
-      <div dataKey={"stats.ctr"} className={"_4lgc _4h2u"} rowGetter={function() {}} width={70} columnData={{}} cellDataGetter={function() {}} cellRenderer={function() {}} columnKey={"stats.ctr"} height={32} rowIndex={0} style={{"height":32,"width":70}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <div className={"_2d6h _2g7x _4h2r"}>{" — "}</div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell401 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":32,"width":70,"left":638}}>
-        {undefined}
-        <TransitionCell400 />
-      </div>
-    );
-  },
-});
-
-var TransitionCell402 = React.createClass({
-  render: function() {
-    return (
-      <div dataKey={"stats.social_percent"} className={"_4lgc _4h2u"} rowGetter={function() {}} width={80} columnData={{}} cellDataGetter={function() {}} cellRenderer={function() {}} columnKey={"stats.social_percent"} height={32} rowIndex={0} style={{"height":32,"width":80}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <div className={"_2d6h _2g7x _4h2r"}>{" — "}</div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell403 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":32,"width":80,"left":708}}>
-        {undefined}
-        <TransitionCell402 />
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCellDefault404 = React.createClass({
-  render: function() {
-    return (
-      <div dataKey={"campaign.name"} className={"_4lgc _4h2u"} rowGetter={function() {}} width={100} columnData={{}} cellDataGetter={function() {}} cellRenderer={undefined} columnKey={"campaign.name"} height={32} rowIndex={0} style={{"height":32,"width":100}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <div className={"_4h2r"}>{"Test Ad Set"}</div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var TransitionCell405 = React.createClass({
-  render: function() {
-    return <FixedDataTableCellDefault404 />;
-  },
-});
-
-var FixedDataTableCell406 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":32,"width":100,"left":788}}>
-        {undefined}
-        <TransitionCell405 />
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCellDefault407 = React.createClass({
-  render: function() {
-    return (
-      <div dataKey={"campaignGroup.name"} className={"_4lgc _4h2u"} rowGetter={function() {}} width={150} columnData={{}} cellDataGetter={function() {}} cellRenderer={undefined} columnKey={"campaignGroup.name"} height={32} rowIndex={0} style={{"height":32,"width":150}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <div className={"_4h2r"}>{"Test Campaign"}</div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var TransitionCell408 = React.createClass({
-  render: function() {
-    return <FixedDataTableCellDefault407 />;
-  },
-});
-
-var FixedDataTableCell409 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":32,"width":150,"left":888}}>
-        {undefined}
-        <TransitionCell408 />
-      </div>
-    );
-  },
-});
-
-var TransitionCell410 = React.createClass({
-  render: function() {
-    return (
-      <div dataKey={"ad.id"} className={"_4lgc _4h2u"} rowGetter={function() {}} width={120} columnData={{}} cellDataGetter={function() {}} cellRenderer={function() {}} columnKey={"ad.id"} height={32} rowIndex={0} style={{"height":32,"width":120}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <div className={"_2d6h _4h2r"}>{"98010048849345"}</div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell411 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":32,"width":120,"left":1038}}>
-        {undefined}
-        <TransitionCell410 />
-      </div>
-    );
-  },
-});
-
-var TransitionCell412 = React.createClass({
-  render: function() {
-    return (
-      <div dataKey={"campaignGroup.objective"} className={"_4lgc _4h2u"} rowGetter={function() {}} width={80} columnData={{}} cellDataGetter={function() {}} cellRenderer={function() {}} columnKey={"campaignGroup.objective"} height={32} rowIndex={0} style={{"height":32,"width":80}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <div className={"_2d6h _4h2r"}>{"Clicks to Website"}</div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell413 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":32,"width":80,"left":1158}}>
-        {undefined}
-        <TransitionCell412 />
-      </div>
-    );
-  },
-});
-
-var TransitionCell414 = React.createClass({
-  render: function() {
-    return (
-      <div dataKey={"stats.spent_100"} className={"_4lgc _4h2u"} rowGetter={function() {}} width={70} columnData={{}} cellDataGetter={function() {}} cellRenderer={function() {}} columnKey={"stats.spent_100"} height={32} rowIndex={0} style={{"height":32,"width":70}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <div className={"_2d6h _2g7x _4h2r"}>{" — "}</div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell415 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":32,"width":70,"left":1238}}>
-        {undefined}
-        <TransitionCell414 />
-      </div>
-    );
-  },
-});
-
-var ReactDate416 = React.createClass({
-  render: function() {
-    return <span>{"10/24/2015"}</span>;
-  },
-});
-
-var TransitionCell417 = React.createClass({
-  render: function() {
-    return (
-      <div dataKey={"derivedCampaign.startDate"} className={"_4lgc _4h2u"} rowGetter={function() {}} width={113} columnData={{}} cellDataGetter={function() {}} cellRenderer={function() {}} columnKey={"derivedCampaign.startDate"} height={32} rowIndex={0} style={{"height":32,"width":113}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <div className={"_2d6h _4h2r"}>
-              <ReactDate416 />
-            </div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell418 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":32,"width":113,"left":1308}}>
-        {undefined}
-        <TransitionCell417 />
-      </div>
-    );
-  },
-});
-
-var TransitionCell419 = React.createClass({
-  render: function() {
-    return (
-      <div dataKey={"derivedCampaign.endDate"} className={"_4lgc _4h2u"} rowGetter={function() {}} width={113} columnData={{}} cellDataGetter={function() {}} cellRenderer={function() {}} columnKey={"derivedCampaign.endDate"} height={32} rowIndex={0} style={{"height":32,"width":113}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <div className={"_2d6h _4h2r"}>{"Ongoing"}</div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell420 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":32,"width":113,"left":1421}}>
-        {undefined}
-        <TransitionCell419 />
-      </div>
-    );
-  },
-});
-
-var ReactDate421 = React.createClass({
-  render: function() {
-    return <span>{"10/24/2015"}</span>;
-  },
-});
-
-var TransitionCell422 = React.createClass({
-  render: function() {
-    return (
-      <div dataKey={"ad.created_time"} className={"_4lgc _4h2u"} rowGetter={function() {}} width={113} columnData={{}} cellDataGetter={function() {}} cellRenderer={function() {}} columnKey={"ad.created_time"} height={32} rowIndex={0} style={{"height":32,"width":113}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <div className={"_2d6h _4h2r"}>
-              <ReactDate421 />
-            </div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell423 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":32,"width":113,"left":1534}}>
-        {undefined}
-        <TransitionCell422 />
-      </div>
-    );
-  },
-});
-
-var ReactDate424 = React.createClass({
-  render: function() {
-    return <span>{"10/24/2015"}</span>;
-  },
-});
-
-var TransitionCell425 = React.createClass({
-  render: function() {
-    return (
-      <div dataKey={"ad.updated_time"} className={"_4lgc _4h2u"} rowGetter={function() {}} width={113} columnData={{}} cellDataGetter={function() {}} cellRenderer={function() {}} columnKey={"ad.updated_time"} height={32} rowIndex={0} style={{"height":32,"width":113}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <div className={"_2d6h _4h2r"}>
-              <ReactDate424 />
-            </div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell426 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":32,"width":113,"left":1647}}>
-        {undefined}
-        <TransitionCell425 />
-      </div>
-    );
-  },
-});
-
-var TransitionCell427 = React.createClass({
-  render: function() {
-    return (
-      <div dataKey={"ad.title"} className={"_4lgc _4h2u"} rowGetter={function() {}} width={80} columnData={{}} cellDataGetter={function() {}} cellRenderer={function() {}} columnKey={"ad.title"} height={32} rowIndex={0} style={{"height":32,"width":80}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <div className={"_2d6h _4h2r"}>{"Example"}</div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell428 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":32,"width":80,"left":1760}}>
-        {undefined}
-        <TransitionCell427 />
-      </div>
-    );
-  },
-});
-
-var TransitionCell429 = React.createClass({
-  render: function() {
-    return (
-      <div dataKey={"ad.creative.body"} className={"_4lgc _4h2u"} rowGetter={function() {}} width={80} columnData={{}} cellDataGetter={function() {}} cellRenderer={function() {}} columnKey={"ad.creative.body"} height={32} rowIndex={0} style={{"height":32,"width":80}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <div className={"_2d6h _4h2r"}>{"It's an example."}</div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell430 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":32,"width":80,"left":1840}}>
-        {undefined}
-        <TransitionCell429 />
-      </div>
-    );
-  },
-});
-
-var TransitionCell431 = React.createClass({
-  render: function() {
-    return (
-      <div dataKey={"destination"} className={"_4lgc _4h2u"} rowGetter={function() {}} width={92} columnData={{}} cellDataGetter={function() {}} cellRenderer={function() {}} columnKey={"destination"} height={32} rowIndex={0} style={{"height":32,"width":92}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <div className={"_2d6h _4h2r"}></div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell432 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":32,"width":92,"left":1920}}>
-        {undefined}
-        <TransitionCell431 />
-      </div>
-    );
-  },
-});
-
-var TransitionCell433 = React.createClass({
-  render: function() {
-    return (
-      <div dataKey={"ad.creative.link_url"} className={"_4lgc _4h2u"} rowGetter={function() {}} width={70} columnData={{}} cellDataGetter={function() {}} cellRenderer={function() {}} columnKey={"ad.creative.link_url"} height={32} rowIndex={0} style={{"height":32,"width":70}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <div className={"_2d6h _4h2r"}>{"http://www.example.com/"}</div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell434 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":32,"width":70,"left":2012}}>
-        {undefined}
-        <TransitionCell433 />
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCellDefault435 = React.createClass({
-  render: function() {
-    return (
-      <div dataKey={"page"} className={"_4lgc _4h2u"} rowGetter={function() {}} width={92} columnData={{}} cellDataGetter={function() {}} cellRenderer={function() {}} columnKey={"page"} height={32} rowIndex={0} style={{"height":32,"width":92}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <div className={"_4h2r"}></div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var TransitionCell436 = React.createClass({
-  render: function() {
-    return <FixedDataTableCellDefault435 />;
-  },
-});
-
-var FixedDataTableCell437 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":32,"width":92,"left":2082}}>
-        {undefined}
-        <TransitionCell436 />
-      </div>
-    );
-  },
-});
-
-var Link438 = React.createClass({
-  render: function() {
-    return <a href={"https://www.facebook.com/?demo_ad=98010048849345&h=AQA24w3temAtB-5f#pagelet_ego_pane"} target={"_blank"} rel={undefined} onClick={function() {}}>{"Preview Ad"}</a>;
-  },
-});
-
-var ReactImage439 = React.createClass({
-  render: function() {
-    return <i src={null} className={"_541d img sp_R48dKBxiJkP sx_dc2cdb"}></i>;
-  },
-});
-
-var AdsPopoverLink440 = React.createClass({
-  render: function() {
-    return (
-      <span ref={"tipIcon"} onMouseEnter={function() {}} onMouseLeave={function() {}}>
-        <span className={"_3o_j"}></span>
-        <ReactImage439 />
-      </span>
-    );
-  },
-});
-
-var AdsHelpLink441 = React.createClass({
-  render: function() {
-    return <AdsPopoverLink440 />;
-  },
-});
-
-var TransitionCell442 = React.createClass({
-  render: function() {
-    return (
-      <div dataKey={"ad.demolink_hash"} className={"_4lgc _4h2u"} rowGetter={function() {}} width={100} columnData={{}} cellDataGetter={function() {}} cellRenderer={function() {}} columnKey={"ad.demolink_hash"} height={32} rowIndex={0} style={{"height":32,"width":100}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <div className={"_4h2r"}>
-              <Link438 />
-              <AdsHelpLink441 />
-            </div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell443 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":32,"width":100,"left":2174}}>
-        {undefined}
-        <TransitionCell442 />
-      </div>
-    );
-  },
-});
-
-var TransitionCell444 = React.createClass({
-  render: function() {
-    return (
-      <div dataKey={"scrollbar_spacer"} className={"_4lgc _4h2u"} rowGetter={function() {}} width={25} columnData={{}} cellDataGetter={function() {}} cellRenderer={function() {}} columnKey={"scrollbar_spacer"} height={32} rowIndex={0} style={{"height":32,"width":25}}>
-        <div className={"_4lgd _4h2w"}>
-          <div className={"_4lge _4h2x"}>
-            <div className={"_2d6h _4h2r"}></div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCell445 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_4lg0 _4h2m"} style={{"height":32,"width":25,"left":2274}}>
-        {undefined}
-        <TransitionCell444 />
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCellGroupImpl446 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_3pzj"} style={{"height":32,"position":"absolute","width":2299,"zIndex":0,"transform":"translate3d(0px,0px,0)","backfaceVisibility":"hidden"}}>
-        <FixedDataTableCell387 key={"cell_0"} />
-        <FixedDataTableCell389 key={"cell_1"} />
-        <FixedDataTableCell391 key={"cell_2"} />
-        <FixedDataTableCell393 key={"cell_3"} />
-        <FixedDataTableCell395 key={"cell_4"} />
-        <FixedDataTableCell397 key={"cell_5"} />
-        <FixedDataTableCell399 key={"cell_6"} />
-        <FixedDataTableCell401 key={"cell_7"} />
-        <FixedDataTableCell403 key={"cell_8"} />
-        <FixedDataTableCell406 key={"cell_9"} />
-        <FixedDataTableCell409 key={"cell_10"} />
-        <FixedDataTableCell411 key={"cell_11"} />
-        <FixedDataTableCell413 key={"cell_12"} />
-        <FixedDataTableCell415 key={"cell_13"} />
-        <FixedDataTableCell418 key={"cell_14"} />
-        <FixedDataTableCell420 key={"cell_15"} />
-        <FixedDataTableCell423 key={"cell_16"} />
-        <FixedDataTableCell426 key={"cell_17"} />
-        <FixedDataTableCell428 key={"cell_18"} />
-        <FixedDataTableCell430 key={"cell_19"} />
-        <FixedDataTableCell432 key={"cell_20"} />
-        <FixedDataTableCell434 key={"cell_21"} />
-        <FixedDataTableCell437 key={"cell_22"} />
-        <FixedDataTableCell443 key={"cell_23"} />
-        <FixedDataTableCell445 key={"cell_24"} />
-      </div>
-    );
-  },
-});
-
-var FixedDataTableCellGroup447 = React.createClass({
-  render: function() {
-    return (
-      <div style={{"height":32,"left":521}} className={"_3pzk"}>
-        <FixedDataTableCellGroupImpl446 />
-      </div>
-    );
-  },
-});
-
-var FixedDataTableRowImpl448 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_1gd4 _4li _52no _35m0 _35m1 _3c7k _4efq _4efs"} onClick={null} onDoubleClick={null} onMouseDown={function() {}} onMouseEnter={null} onMouseLeave={null} style={{"width":1083,"height":32}}>
-        <div className={"_1gd5"}>
-          <FixedDataTableCellGroup385 key={"fixed_cells"} />
-          <FixedDataTableCellGroup447 key={"scrollable_cells"} />
-          <div className={"_1gd6 _1gd8"} style={{"left":521,"height":32}}></div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTableRow449 = React.createClass({
-  render: function() {
-    return (
-      <div style={{"width":1083,"height":32,"zIndex":0,"transform":"translate3d(0px,0px,0)","backfaceVisibility":"hidden"}} className={"_1gda"}>
-        <FixedDataTableRowImpl448 />
-      </div>
-    );
-  },
-});
-
-var FixedDataTableBufferedRows450 = React.createClass({
-  render: function() {
-    return (
-      <div style={{"position":"absolute","pointerEvents":"auto","transform":"translate3d(0px,65px,0)","backfaceVisibility":"hidden"}}>
-        <FixedDataTableRow449 key={"0"} />
-      </div>
-    );
-  },
-});
-
-var Scrollbar451 = React.createClass({
-  render: function() {
-    return (
-      <div onFocus={function() {}} onBlur={function() {}} onKeyDown={function() {}} onMouseDown={function() {}} onWheel={function() {}} className={"_1t0r _1t0t _4jdr _1t0u"} style={{"width":1083,"zIndex":99}} tabIndex={0}>
-        <div ref={"face"} className={"_1t0w _1t0y _1t0_"} style={{"width":407.918085106383,"transform":"translate3d(4px,0px,0)","backfaceVisibility":"hidden"}}></div>
-      </div>
-    );
-  },
-});
-
-var HorizontalScrollbar452 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_3h1k _3h1m"} style={{"height":15,"width":1083}}>
-        <div style={{"height":15,"position":"absolute","overflow":"hidden","width":1083,"transform":"translate3d(0px,0px,0)","backfaceVisibility":"hidden"}}>
-          <Scrollbar451 />
-        </div>
-      </div>
-    );
-  },
-});
-
-var FixedDataTable453 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_3h1i _1mie"} onWheel={function() {}} style={{"height":532,"width":1083}}>
-        <div className={"_3h1j"} style={{"height":515,"width":1083}}>
-          <FixedDataTableColumnResizeHandle178 />
-          <FixedDataTableRow206 key={"group_header"} />
-          <FixedDataTableRow360 key={"header"} />
-          <FixedDataTableBufferedRows450 />
-          {null}
-          {undefined}
-          {undefined}
-        </div>
-        {undefined}
-        <HorizontalScrollbar452 />
-      </div>
-    );
-  },
-});
-
-var TransitionTable454 = React.createClass({
-  render: function() {
-    return <FixedDataTable453 />;
-  },
-});
-
-var AdsSelectableFixedDataTable455 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_5hht"}>
-        <TransitionTable454 />
-      </div>
-    );
-  },
-});
-
-var AdsDataTableKeyboardSupportDecorator456 = React.createClass({
-  render: function() {
-    return (
-      <div ref={"tableContainer"} className={"_5d6f"} tabIndex={"0"} onKeyDown={function() {}}>
-        <AdsSelectableFixedDataTable455 />
-      </div>
-    );
-  },
-});
-
-var AdsEditableDataTableDecorator457 = React.createClass({
-  render: function() {
-    return (
-      <div onCopy={function() {}}>
-        <AdsDataTableKeyboardSupportDecorator456 ref={"decoratedTable"} />
-      </div>
-    );
-  },
-});
-
-var AdsPEDataTableContainer458 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_35l_"}>
-        {null}
-        {null}
-        <AdsEditableDataTableDecorator457 />
-      </div>
-    );
-  },
-});
-
-var ResponsiveBlock459 = React.createClass({
-  render: function() {
-    return (
-      <div onResize={function() {}} className={"_4u-c"}>
-        <AdsPEDataTableContainer458 />
-        <div key={"sensor"} className={"_4u-f"}>
-          <iframe ref={"sensorNode"} aria-hidden={"true"} className={"_4u-g"} tabIndex={"-1"}></iframe>
-        </div>
-      </div>
-    );
-  },
-});
-
-var AdsPEAdTableContainer460 = React.createClass({
-  render: function() {
-    return <ResponsiveBlock459 />;
-  },
-});
-
-var AdsPEManageAdsPaneContainer461 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_2utw"}>
-        {null}
-        <div className={"_2utx _41tt"}>
-          <AdsPEFilterContainer104 />
-          <AdsPECampaignTimeLimitNoticeContainer106 />
-          {null}
-        </div>
-        <div className={" _41ts"}>
-          <AdsPEAdgroupToolbarContainer169 />
-        </div>
-        <div className={"_2utz"}>
-          <div className={"_2ut-"}>
-            <AdsPEOrganizerContainer177 />
-          </div>
-          <div className={"_2ut_"}>
-            <AdsPEAdTableContainer460 />
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var AdsPEContentContainer462 = React.createClass({
-  render: function() {
-    return <AdsPEManageAdsPaneContainer461 />;
-  },
-});
-
-var FluxContainer_r_463 = React.createClass({
-  render: function() {
-    return (
-      <div className={"mainWrapper"} style={{"width":1192}}>
-        <FluxContainer_r_69 />
-        <AdsPEContentContainer462 />
-        {null}
-      </div>
-    );
-  },
-});
-
-var FluxContainer_q_464 = React.createClass({
-  render: function() {
-    return null;
-  },
-});
-
-var AdsPEUploadDialog465 = React.createClass({
-  render: function() {
-    return null;
-  },
-});
-
-var FluxContainer_y_466 = React.createClass({
-  render: function() {
-    return <AdsPEUploadDialog465 />;
-  },
-});
-
-var ReactImage467 = React.createClass({
-  render: function() {
-    return <i className={"_1-lx img sp_UuU9HmrQ397 sx_990b54"} src={null}></i>;
-  },
-});
-
-var AdsPESideTrayTabButton468 = React.createClass({
-  render: function() {
-    return (
-      <div onClick={function() {}} className={"_1-ly _59j9 _d9a"}>
-        <ReactImage467 />
-        <div className={"_vf7"}></div>
-        <div className={"_vf8"}></div>
-      </div>
-    );
-  },
-});
-
-var AdsPEEditorTrayTabButton469 = React.createClass({
-  render: function() {
-    return <AdsPESideTrayTabButton468 />;
-  },
-});
-
-var ReactImage470 = React.createClass({
-  render: function() {
-    return <i className={"_1-lx img sp_UuU9HmrQ397 sx_94017f"} src={null}></i>;
-  },
-});
-
-var AdsPESideTrayTabButton471 = React.createClass({
-  render: function() {
-    return (
-      <div onClick={function() {}} className={" _1-lz _d9a"}>
-        <ReactImage470 />
-        <div className={"_vf7"}></div>
-        <div className={"_vf8"}></div>
-      </div>
-    );
-  },
-});
-
-var AdsPEInsightsTrayTabButton472 = React.createClass({
-  render: function() {
-    return <AdsPESideTrayTabButton471 />;
-  },
-});
-
-var AdsPESideTrayTabButton473 = React.createClass({
-  render: function() {
-    return null;
-  },
-});
-
-var AdsPENekoDebuggerTrayTabButton474 = React.createClass({
-  render: function() {
-    return <AdsPESideTrayTabButton473 />;
-  },
-});
-
-var FBDragHandle475 = React.createClass({
-  render: function() {
-    return <div style={{"height":550}} className={"_4a2j _2ciy _2ciz"} horizontal={true} onStart={function() {}} onEnd={function() {}} onChange={function() {}} initialData={function() {}} vertical={false} throttle={25} delay={0} threshold={0} onMouseDown={function() {}} onMouseUp={function() {}} onMouseLeave={function() {}}></div>;
-  },
-});
-
-var XUIText476 = React.createClass({
-  render: function() {
-    return <span size={"large"} weight={"bold"} className={"_2x9f  _50f5 _50f7"} display={"inline"}>{"Editing Ad"}</span>;
-  },
-});
-
-var XUIText477 = React.createClass({
-  render: function() {
-    return <span size={"large"} weight={"bold"} display={"inline"} className={" _50f5 _50f7"}>{"Test Ad"}</span>;
-  },
-});
-
-var AdsPEEditorChildLink478 = React.createClass({
-  render: function() {
-    return null;
-  },
-});
-
-var AdsPEEditorChildLinkContainer479 = React.createClass({
-  render: function() {
-    return <AdsPEEditorChildLink478 />;
-  },
-});
-
-var AdsPEHeaderSection480 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_yke"}>
-        <div className={"_2x9d _pry"}></div>
-        <XUIText476 />
-        <div className={"_3a-a"}>
-          <div className={"_3a-b"}>
-            <XUIText477 />
-          </div>
-        </div>
-        {null}
-        <AdsPEEditorChildLinkContainer479 />
-      </div>
-    );
-  },
-});
-
-var AdsPEAdgroupHeaderSectionContainer481 = React.createClass({
-  render: function() {
-    return <AdsPEHeaderSection480 />;
-  },
-});
-
-var AdsPEAdgroupDisapprovalMessage482 = React.createClass({
-  render: function() {
-    return null;
-  },
-});
-
-var FluxContainer_r_483 = React.createClass({
-  render: function() {
-    return <AdsPEAdgroupDisapprovalMessage482 />;
-  },
-});
-
-var AdsPEAdgroupAutoNamingConfirmationContainer484 = React.createClass({
-  render: function() {
-    return null;
-  },
-});
-
-var AdsLabeledField485 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_5ir9 _3bvz"} label={"Ad Name"} labelSize={"small"}>
-        <label className={"_4el4 _3qwj _3hy-"} htmlFor={undefined}>
-          {"Ad Name"}
-          {" "}
-          {undefined}
-        </label>
-        {null}
-        <div className={"_3bv-"}></div>
-      </div>
-    );
-  },
-});
-
-var ReactXUIError486 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_5ira _2vl4 _1h18"}>
-        {null}
-        {null}
-        <div className={"_2vl9 _1h1f"} style={{"backgroundColor":"#fff"}}>
-          <div className={"_2vla _1h1g"}>
-            <div>
-              {null}
-              <textarea ref={"input"} id={undefined} disabled={undefined} onKeyDown={function() {}} onFocus={function() {}} onBlur={function() {}} onChange={function() {}} dir={"auto"} maxLength={null} className={"_2vli _2vlj _1h26 _1h27"} value={"Test Ad"}></textarea>
-              {null}
-            </div>
-            <div ref={"shadowText"} aria-hidden={"true"} className={"_2vlk"}></div>
-          </div>
-        </div>
-        {null}
-      </div>
-    );
-  },
-});
-
-var AdsTextInput487 = React.createClass({
-  render: function() {
-    return <ReactXUIError486 />;
-  },
-});
-
-var Link488 = React.createClass({
-  render: function() {
-    return <a className={"_5ir9"} label={"Rename using available fields"} onMouseDown={function() {}} href={"#"} rel={undefined} onClick={function() {}}>{"Rename using available fields"}</a>;
-  },
-});
-
-var AdsAutoNamingTemplateDialog489 = React.createClass({
-  render: function() {
-    return <Link488 ref={"link"} />;
-  },
-});
-
-var AdsPEAmbientNUXMegaphone490 = React.createClass({
-  render: function() {
-    return (
-      <span ref={"mainChild"}>
-        <AdsAutoNamingTemplateDialog489 />
-      </span>
-    );
-  },
-});
-
-var AdsLabeledField491 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_5ir9 _3bvz"} label={"Status"} labelSize={"small"}>
-        <label className={"_4el4 _3qwj _3hy-"} htmlFor={undefined}>
-          {"Status"}
-          {" "}
-          {undefined}
-        </label>
-        {null}
-        <div className={"_3bv-"}></div>
-      </div>
-    );
-  },
-});
-
-var BUISwitch492 = React.createClass({
-  render: function() {
-    return (
-      <div value={true} disabled={true} onToggle={function() {}} data-hover={"tooltip"} data-tooltip-position={"below"} aria-label={"Currently active and you can not deactivate it."} animate={true} className={"_128j _128k _128m _128n"} role={"checkbox"} aria-checked={"true"}>
-        <div className={"_128o"} onClick={function() {}} onKeyDown={function() {}} onMouseDown={function() {}} tabIndex={"-1"}>
-          <div className={"_128p"}></div>
-        </div>
-        {null}
-      </div>
-    );
-  },
-});
-
-var AdsStatusSwitchInternal493 = React.createClass({
-  render: function() {
-    return <BUISwitch492 />;
-  },
-});
-
-var AdsStatusSwitch494 = React.createClass({
-  render: function() {
-    return <AdsStatusSwitchInternal493 />;
-  },
-});
-
-var LeftRight495 = React.createClass({
-  render: function() {
-    return (
-      <div className={"clearfix"}>
-        <div key={"left"} className={"_ohe lfloat"}>
-          <div>
-            <AdsLabeledField485 />
-            <span className={"_5irl"}>
-              <AdsTextInput487 key={"nameEditor98010048849345"} ref={"nameTextInput"} />
-              <AdsPEAmbientNUXMegaphone490 />
-            </span>
-          </div>
-        </div>
-        <div key={"right"} className={"_ohf rfloat"}>
-          <div>
-            <AdsLabeledField491 />
-            <div className={"_5irp"}>
-              <AdsStatusSwitch494 />
-            </div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var XUICard496 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_5ir8 _12k2 _4-u2  _4-u8"} xuiErrorPosition={"above"} background={"white"}>
-        <LeftRight495 />
-      </div>
-    );
-  },
-});
-
-var ReactXUIError497 = React.createClass({
-  render: function() {
-    return <XUICard496 />;
-  },
-});
-
-var AdsCard498 = React.createClass({
-  render: function() {
-    return <ReactXUIError497 />;
-  },
-});
-
-var AdsPENameSection499 = React.createClass({
-  render: function() {
-    return <AdsCard498 />;
-  },
-});
-
-var AdsPEAdgroupNameSectionContainer500 = React.createClass({
-  render: function() {
-    return <AdsPENameSection499 />;
-  },
-});
-
-var XUICardHeaderTitle501 = React.createClass({
-  render: function() {
-    return (
-      <span itemComponent={"span"} className={"_38my"}>
-        {"Ad Links"}
-        {null}
-        <span className={"_c1c"}></span>
-      </span>
-    );
-  },
-});
-
-var XUICardSection502 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_5dw9 _5dwa _4-u3"} background={"transparent"}>
-        {[
-          <XUICardHeaderTitle501 key={"/.0"} />,
-        ]}
-        {undefined}
-        {undefined}
-        <div className={"_3s3-"}></div>
-      </div>
-    );
-  },
-});
-
-var XUICardHeader503 = React.createClass({
-  render: function() {
-    return <XUICardSection502 />;
-  },
-});
-
-var AdsCardHeader504 = React.createClass({
-  render: function() {
-    return <XUICardHeader503 />;
-  },
-});
-
-var XUIText505 = React.createClass({
-  render: function() {
-    return <div className={"_502s"} display={"block"} size={"inherit"} weight={"inherit"}>{"Ad ID 98010048849345"}</div>;
-  },
-});
-
-var Link506 = React.createClass({
-  render: function() {
-    return <a target={"_blank"} href={"/ads/manager/ad/?ids=98010048849345"} onClick={function() {}} rel={undefined}>{"Open in Ads Manager"}</a>;
-  },
-});
-
-var Link507 = React.createClass({
-  render: function() {
-    return <a target={"_blank"} href={"#"} onClick={function() {}} rel={undefined}>{"Open in Ads Reporting"}</a>;
-  },
-});
-
-var Link508 = React.createClass({
-  render: function() {
-    return <a target={"_blank"} href={"https://www.facebook.com/?demo_ad=98010048849345&h=AQA24w3temAtB-5f#pagelet_ego_pane"} onClick={function() {}} rel={undefined}>{"View on Desktop Right Column"}</a>;
-  },
-});
-
-var Link509 = React.createClass({
-  render: function() {
-    return <a target={"_blank"} href={"/ads/manage/powereditor/?act=10149999073643408&adgroup=98010048849345"} onClick={function() {}} rel={undefined}>{"Open Power Editor with this ad selected"}</a>;
-  },
-});
-
-var List510 = React.createClass({
-  render: function() {
-    return (
-      <ul spacing={"small"} border={"none"} direction={"vertical"} valign={"top"} className={"uiList _4kg _6-i _6-h _704"}>
-        {null}
-        <li key={"/ads/manager/ad/?ids=98010048849345"}>
-          <Link506 />
-        </li>
-        <li key={"#"}>
-          <Link507 />
-        </li>
-        {null}
-        <li key={"https://www.facebook.com/?demo_ad=98010048849345&h=AQA24w3temAtB-5f#pagelet_ego_pane"}>
-          <Link508 />
-        </li>
-        {null}
-        {null}
-        {null}
-        <li key={"/ads/manage/powereditor/?act=10149999073643408&adgroup=98010048849345"}>
-          <Link509 />
-        </li>
-        {null}
-      </ul>
-    );
-  },
-});
-
-var XUICardSection511 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_12jy _4-u3"} background={"transparent"}>
-        <div className={"_3-8j"}>
-          <XUIText505 />
-          <List510 />
-        </div>
-      </div>
-    );
-  },
-});
-
-var AdsCardSection512 = React.createClass({
-  render: function() {
-    return <XUICardSection511 />;
-  },
-});
-
-var XUICard513 = React.createClass({
-  render: function() {
-    return (
-      <div xuiErrorPosition={"above"} className={"_12k2 _4-u2  _4-u8"} background={"white"}>
-        <AdsCardHeader504 />
-        <AdsCardSection512 />
-      </div>
-    );
-  },
-});
-
-var ReactXUIError514 = React.createClass({
-  render: function() {
-    return <XUICard513 />;
-  },
-});
-
-var AdsCard515 = React.createClass({
-  render: function() {
-    return <ReactXUIError514 />;
-  },
-});
-
-var AdsPELinkList516 = React.createClass({
-  render: function() {
-    return <AdsCard515 />;
-  },
-});
-
-var AdsPEAdgroupLinksSection517 = React.createClass({
-  render: function() {
-    return <AdsPELinkList516 />;
-  },
-});
-
-var AdsPEAdgroupLinksSectionContainer518 = React.createClass({
-  render: function() {
-    return (
-      <div>
-        <AdsPEAdgroupLinksSection517 />
-        {null}
-      </div>
-    );
-  },
-});
-
-var XUICardHeaderTitle519 = React.createClass({
-  render: function() {
-    return (
-      <span itemComponent={"span"} className={"_38my"}>
-        {"Preview"}
-        {null}
-        <span className={"_c1c"}></span>
-      </span>
-    );
-  },
-});
-
-var XUICardSection520 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_5dw9 _5dwa _4-u3"} background={"transparent"}>
-        {[
-          <XUICardHeaderTitle519 key={"/.0"} />,
-        ]}
-        {undefined}
-        {undefined}
-        <div className={"_3s3-"}></div>
-      </div>
-    );
-  },
-});
-
-var XUICardHeader521 = React.createClass({
-  render: function() {
-    return <XUICardSection520 />;
-  },
-});
-
-var AdsCardHeader522 = React.createClass({
-  render: function() {
-    return <XUICardHeader521 />;
-  },
-});
-
-var PillButton523 = React.createClass({
-  render: function() {
-    return <a label={null} selected={true} onClick={function() {}} href={"#"} className={"uiPillButton uiPillButtonSelected"}>{"Desktop Right Column"}</a>;
-  },
-});
-
-var List524 = React.createClass({
-  render: function() {
-    return (
-      <ul className={"uiList  _4ki _509- _6-i _6-h _704"} border={"none"} direction={"horizontal"} spacing={"small"} valign={"top"}>
-        <li key={"0/.$RIGHT_COLUMN_STANDARD"}>
-          <PillButton523 key={"RIGHT_COLUMN_STANDARD"} />
-        </li>
-      </ul>
-    );
-  },
-});
-
-var PillList525 = React.createClass({
-  render: function() {
-    return <List524 />;
-  },
-});
-
-var XUICardSection526 = React.createClass({
-  render: function() {
-    return (
-      <div background={"light-wash"} className={"_14p9 _12jy _4-u3  _57d8"}>
-        <div className={"_3-8j"}>
-          <PillList525 />
-        </div>
-      </div>
-    );
-  },
-});
-
-var AdsCardSection527 = React.createClass({
-  render: function() {
-    return <XUICardSection526 />;
-  },
-});
-
-var AdsPEPreviewPillList528 = React.createClass({
-  render: function() {
-    return <AdsCardSection527 />;
-  },
-});
-
-var XUISpinner529 = React.createClass({
-  render: function() {
-    return <span size={"large"} className={"hidden_elem img _55ym _55yq _55yo"} showOnAsync={false} background={"light"} aria-label={"Loading..."} aria-busy={true}></span>;
-  },
-});
-
-var ReactImage530 = React.createClass({
-  render: function() {
-    return (
-      <i alt={"Warning"} className={"_585p img sp_R48dKBxiJkP sx_aed870"} src={null}>
-        <u>{"Warning"}</u>
-      </i>
-    );
-  },
-});
-
-var XUINotice531 = React.createClass({
-  render: function() {
-    return (
-      <div size={"medium"} className={"_585n _585o"}>
-        <ReactImage530 />
-        {null}
-        <div className={"_585r _50f4"}>{"Unable to display a preview for this ad."}</div>
-      </div>
-    );
-  },
-});
-
-var AdPreview532 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_2hm6"}>
-        <div className={undefined}>
-          <div className={"_3akw"}>
-            <XUISpinner529 />
-          </div>
-          <div className={"hidden_elem"}>
-            <XUINotice531 />
-          </div>
-          <div ref={"pageletContainer"} className={""}></div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var XUICardSection533 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_3m4g _12jy _4-u3"} style={{"maxHeight":"425px"}} background={"transparent"}>
-        <div className={"_3-8j"}>
-          <div className={"_14p7"}>
-            <div className={"_14p8"}>
-              <AdPreview532 />
-            </div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var AdsCardSection534 = React.createClass({
-  render: function() {
-    return <XUICardSection533 />;
-  },
-});
-
-var AdsPEPreview535 = React.createClass({
-  render: function() {
-    return (
-      <div>
-        <AdsPEPreviewPillList528 ref={"pillList"} />
-        {undefined}
-        <AdsCardSection534 />
-      </div>
-    );
-  },
-});
-
-var AdsPEStandardPreview536 = React.createClass({
-  render: function() {
-    return <AdsPEPreview535 />;
-  },
-});
-
-var AdsPEStandardPreviewContainer537 = React.createClass({
-  render: function() {
-    return <AdsPEStandardPreview536 />;
-  },
-});
-
-var XUICard538 = React.createClass({
-  render: function() {
-    return (
-      <div xuiErrorPosition={"above"} className={"_12k2 _4-u2  _4-u8"} background={"white"}>
-        <AdsCardHeader522 />
-        {null}
-        <AdsPEStandardPreviewContainer537 />
-      </div>
-    );
-  },
-});
-
-var ReactXUIError539 = React.createClass({
-  render: function() {
-    return <XUICard538 />;
-  },
-});
-
-var AdsCard540 = React.createClass({
-  render: function() {
-    return <ReactXUIError539 />;
-  },
-});
-
-var AdsPEAdgroupPreviewSection541 = React.createClass({
-  render: function() {
-    return <AdsCard540 />;
-  },
-});
-
-var AdsPEAdgroupPreviewSectionContainer542 = React.createClass({
-  render: function() {
-    return <AdsPEAdgroupPreviewSection541 />;
-  },
-});
-
-var AdsPEStickyArea543 = React.createClass({
-  render: function() {
-    return (
-      <div>
-        {null}
-        <div ref={"sticky"}>
-          <AdsPEAdgroupPreviewSectionContainer542 />
-        </div>
-      </div>
-    );
-  },
-});
-
-var XUICardHeaderTitle544 = React.createClass({
-  render: function() {
-    return (
-      <span itemComponent={"span"} className={"_38my"}>
-        {"Facebook Page"}
-        {null}
-        <span className={"_c1c"}></span>
-      </span>
-    );
-  },
-});
-
-var XUICardSection545 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_5dw9 _5dwa _4-u3"} background={"transparent"}>
-        {[
-          <XUICardHeaderTitle544 key={"/.0"} />,
-        ]}
-        {undefined}
-        {undefined}
-        <div className={"_3s3-"}></div>
-      </div>
-    );
-  },
-});
-
-var XUICardHeader546 = React.createClass({
-  render: function() {
-    return <XUICardSection545 />;
-  },
-});
-
-var AdsCardHeader547 = React.createClass({
-  render: function() {
-    return <XUICardHeader546 />;
-  },
-});
-
-var Link548 = React.createClass({
-  render: function() {
-    return <a className={"fwb"} onClick={function() {}} href={"#"} rel={undefined}>{"Connect a Facebook Page"}</a>;
-  },
-});
-
-var AdsPEWebsiteNoPageDestinationSection549 = React.createClass({
-  render: function() {
-    return (
-      <div>
-        <div className={"_3-95"}>{"This ad is not connected to a Facebook Page. It will not show in News Feed."}</div>
-        <Link548 />
-      </div>
-    );
-  },
-});
-
-var AdsPEWebsiteNoPageDestinationSectionContainer550 = React.createClass({
-  render: function() {
-    return <AdsPEWebsiteNoPageDestinationSection549 />;
-  },
-});
-
-var XUICardSection551 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_12jy _4-u3"} background={"transparent"}>
-        <div className={"_3-8j"}>
-          <AdsPEWebsiteNoPageDestinationSectionContainer550 />
-        </div>
-      </div>
-    );
-  },
-});
-
-var AdsCardSection552 = React.createClass({
-  render: function() {
-    return <XUICardSection551 />;
-  },
-});
-
-var XUICard553 = React.createClass({
-  render: function() {
-    return (
-      <div xuiErrorPosition={"above"} className={"_12k2 _4-u2  _4-u8"} background={"white"}>
-        <AdsCardHeader547 />
-        <AdsCardSection552 />
-      </div>
-    );
-  },
-});
-
-var ReactXUIError554 = React.createClass({
-  render: function() {
-    return <XUICard553 />;
-  },
-});
-
-var AdsCard555 = React.createClass({
-  render: function() {
-    return <ReactXUIError554 />;
-  },
-});
-
-var AdsPEAdgroupDestinationSection556 = React.createClass({
-  render: function() {
-    return <AdsCard555 />;
-  },
-});
-
-var AdsPEAdgroupDestinationSectionContainer557 = React.createClass({
-  render: function() {
-    return <AdsPEAdgroupDestinationSection556 />;
-  },
-});
-
-var XUICardHeaderTitle558 = React.createClass({
-  render: function() {
-    return (
-      <span itemComponent={"span"} className={"_38my"}>
-        {"Creative"}
-        {null}
-        <span className={"_c1c"}></span>
-      </span>
-    );
-  },
-});
-
-var XUICardSection559 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_5dw9 _5dwa _4-u3"} background={"transparent"}>
-        {[
-          <XUICardHeaderTitle558 key={"/.0"} />,
-        ]}
-        {undefined}
-        {undefined}
-        <div className={"_3s3-"}></div>
-      </div>
-    );
-  },
-});
-
-var XUICardHeader560 = React.createClass({
-  render: function() {
-    return <XUICardSection559 />;
-  },
-});
-
-var AdsCardHeader561 = React.createClass({
-  render: function() {
-    return <XUICardHeader560 />;
-  },
-});
-
-var ReactImage562 = React.createClass({
-  render: function() {
-    return <i src={null} className={"_541d img sp_R48dKBxiJkP sx_dc2cdb"}></i>;
-  },
-});
-
-var AdsPopoverLink563 = React.createClass({
-  render: function() {
-    return (
-      <span ref={"tipIcon"} onMouseEnter={function() {}} onMouseLeave={function() {}}>
-        <span className={"_3o_j"}></span>
-        <ReactImage562 />
-      </span>
-    );
-  },
-});
-
-var AdsHelpLink564 = React.createClass({
-  render: function() {
-    return <AdsPopoverLink563 />;
-  },
-});
-
-var AdsLabeledField565 = React.createClass({
-  render: function() {
-    return (
-      <div htmlFor={undefined} label={"Website URL"} helpText={"Enter the website URL you want to promote. Ex: http://www.example.com/page"} helpLinger={undefined} optional={undefined} labelSize={"small"} className={"_3bvz"}>
-        <label className={"_4el4 _3qwj _3hy-"} htmlFor={undefined}>
-          {"Website URL"}
-          {" "}
-          {undefined}
-        </label>
-        <AdsHelpLink564 />
-        <div className={"_3bv-"}></div>
-      </div>
-    );
-  },
-});
-
-var ReactXUIError566 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_gon _2vl4 _1h18"}>
-        <div className={"_2vln"}>{1001}</div>
-        <AdsLabeledField565 />
-        <div className={"_2vl9 _1h1f"} style={{"backgroundColor":"#fff"}}>
-          <div className={"_2vla _1h1g"}>
-            <div>
-              {null}
-              <textarea ref={"input"} id={undefined} disabled={undefined} onKeyDown={function() {}} onFocus={function() {}} onBlur={function() {}} onChange={function() {}} dir={"auto"} maxLength={null} className={"_2vli _2vlj _1h26 _1h27"} value={"http://www.example.com/"}></textarea>
-              {null}
-            </div>
-            <div ref={"shadowText"} aria-hidden={"true"} className={"_2vlk"}></div>
-          </div>
-        </div>
-        {null}
-      </div>
-    );
-  },
-});
-
-var AdsTextInput567 = React.createClass({
-  render: function() {
-    return <ReactXUIError566 />;
-  },
-});
-
-var AdsBulkTextInput568 = React.createClass({
-  render: function() {
-    return <AdsTextInput567 />;
-  },
-});
-
-var AdsPEWebsiteURLField569 = React.createClass({
-  render: function() {
-    return <AdsBulkTextInput568 />;
-  },
-});
-
-var ReactImage570 = React.createClass({
-  render: function() {
-    return <i src={null} className={"_541d img sp_R48dKBxiJkP sx_dc2cdb"}></i>;
-  },
-});
-
-var AdsPopoverLink571 = React.createClass({
-  render: function() {
-    return (
-      <span ref={"tipIcon"} onMouseEnter={function() {}} onMouseLeave={function() {}}>
-        <span className={"_3o_j"}></span>
-        <ReactImage570 />
-      </span>
-    );
-  },
-});
-
-var AdsHelpLink572 = React.createClass({
-  render: function() {
-    return <AdsPopoverLink571 />;
-  },
-});
-
-var AdsLabeledField573 = React.createClass({
-  render: function() {
-    return (
-      <div htmlFor={undefined} label={"Headline"} helpText={"Your headline text will appear differently depending on the placement of your ad. Check the previews to make sure your headline looks the way you want in the placements it appears in."} helpLinger={undefined} optional={undefined} labelSize={"small"} className={"_3bvz"}>
-        <label className={"_4el4 _3qwj _3hy-"} htmlFor={undefined}>
-          {"Headline"}
-          {" "}
-          {undefined}
-        </label>
-        <AdsHelpLink572 />
-        <div className={"_3bv-"}></div>
-      </div>
-    );
-  },
-});
-
-var ReactXUIError574 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_gon _2vl4 _1h18"}>
-        <div className={"_2vln"}>{18}</div>
-        <AdsLabeledField573 />
-        <div className={"_2vl9 _1h1f"} style={{"backgroundColor":"#fff"}}>
-          <div className={"_2vla _1h1g"}>
-            <div>
-              {null}
-              <textarea ref={"input"} id={undefined} disabled={undefined} onKeyDown={function() {}} onFocus={function() {}} onBlur={function() {}} onChange={function() {}} dir={"auto"} maxLength={null} className={"_2vli _2vlj _1h26 _1h27"} value={"Example"}></textarea>
-              {null}
-            </div>
-            <div ref={"shadowText"} aria-hidden={"true"} className={"_2vlk"}></div>
-          </div>
-        </div>
-        {null}
-      </div>
-    );
-  },
-});
-
-var AdsTextInput575 = React.createClass({
-  render: function() {
-    return <ReactXUIError574 />;
-  },
-});
-
-var AdsBulkTextInput576 = React.createClass({
-  render: function() {
-    return <AdsTextInput575 />;
-  },
-});
-
-var AdsPEHeadlineField577 = React.createClass({
-  render: function() {
-    return <AdsBulkTextInput576 />;
-  },
-});
-
-var AdsLabeledField578 = React.createClass({
-  render: function() {
-    return (
-      <div htmlFor={undefined} label={"Text"} helpText={undefined} helpLinger={undefined} optional={undefined} labelSize={"small"} className={"_3bvz"}>
-        <label className={"_4el4 _3qwj _3hy-"} htmlFor={undefined}>
-          {"Text"}
-          {" "}
-          {undefined}
-        </label>
-        {null}
-        <div className={"_3bv-"}></div>
-      </div>
-    );
-  },
-});
-
-var ReactXUIError579 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_gon _2vl4 _2vl6 _1h18 _1h1a"}>
-        <div className={"_2vln"}>{74}</div>
-        <AdsLabeledField578 />
-        <div className={"_2vl9 _1h1f"} style={{"backgroundColor":"#fff"}}>
-          <div className={"_2vla _1h1g"}>
-            <div>
-              {null}
-              <textarea ref={"input"} id={undefined} disabled={undefined} onKeyDown={function() {}} onFocus={function() {}} onBlur={function() {}} onChange={function() {}} dir={"auto"} maxLength={null} className={"_2vli _2vlj _1h26 _1h27"} value={"It's an example."}></textarea>
-              {null}
-            </div>
-            <div ref={"shadowText"} aria-hidden={"true"} className={"_2vlk"}></div>
-          </div>
-        </div>
-        {null}
-      </div>
-    );
-  },
-});
-
-var AdsTextInput580 = React.createClass({
-  render: function() {
-    return <ReactXUIError579 />;
-  },
-});
-
-var AdsBulkTextInput581 = React.createClass({
-  render: function() {
-    return <AdsTextInput580 />;
-  },
-});
-
-var AdsPEMessageField582 = React.createClass({
-  render: function() {
-    return (
-      <div>
-        <AdsBulkTextInput581 />
-        {null}
-      </div>
-    );
-  },
-});
-
-var AbstractButton583 = React.createClass({
-  render: function() {
-    return (
-      <button label={null} onClick={function() {}} size={"large"} use={"default"} borderShade={"light"} suppressed={false} className={"_4jy0 _4jy4 _517h _51sy _42ft"} type={"submit"} value={"1"}>
-        {undefined}
-        {"Change Image"}
-        {undefined}
-      </button>
-    );
-  },
-});
-
-var XUIButton584 = React.createClass({
-  render: function() {
-    return <AbstractButton583 />;
-  },
-});
-
-var BackgroundImage585 = React.createClass({
-  render: function() {
-    return (
-      <div src={"https://scontent.xx.fbcdn.net/hads-xap1/t45.1600-4/12124737_98010048849339_1665004369_n.png"} width={114.6} height={60} backgroundSize={"contain"} optimizeResizeSpeed={false} loadingIndicatorStyle={"none"} className={"_5f0d"} style={{"width":"114.6px","height":"60px"}} onContextMenu={undefined}>
-        <img alt={""} className={"_5i4g"} style={{"width":"90px","height":"60px","left":"12px","top":"0px"}} src={"https://scontent.xx.fbcdn.net/hads-xap1/t45.1600-4/12124737_98010048849339_1665004369_n.png"}></img>
-        {undefined}
-        {null}
-      </div>
-    );
-  },
-});
-
-var XUIText586 = React.createClass({
-  render: function() {
-    return <span shade={"light"} className={"_50f8"} size={"inherit"} weight={"inherit"} display={"inline"}>{"1000 × 667"}</span>;
-  },
-});
-
-var XUIGrayText587 = React.createClass({
-  render: function() {
-    return <XUIText586 />;
-  },
-});
-
-var XUIText588 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_3-95  _50f7"} display={"block"} weight={"bold"} size={"inherit"}>
-        {"untitled – "}
-        <XUIGrayText587 />
-        {""}
-      </div>
-    );
-  },
-});
-
-var CenteredContainer589 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_50vi"} horizontal={false} vertical={true} fullHeight={false}>
-        <div className={"_3bwv"}>
-          <div className={"_3bwy"}>
-            <div key={"/.0"} className={"_3bwx"}>
-              <XUIText588 />
-            </div>
-            <div key={"/.1"} className={"_3bwx"}></div>
-          </div>
-        </div>
-      </div>
-    );
-  },
-});
-
-var Link590 = React.createClass({
-  render: function() {
-    return <a href={"/business/ads-guide/"} target={"_blank"} rel={undefined} onClick={function() {}}>{"Facebook Ad Guidelines"}</a>;
-  },
-});
-
-var XUIText591 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_3-96"} display={"block"} size={"inherit"} weight={"inherit"}>
-        {"For questions and more information, see the "}
-        <Link590 />
-        {"."}
-      </div>
-    );
-  },
-});
-
-var AdsImageInput592 = React.createClass({
-  render: function() {
-    return (
-      <div>
-        <div>
-          <XUIButton584 />
-          {undefined}
-        </div>
-        {null}
-        <div className={"_50vh _3-8n _2ph_"}>
-          <div className={"_37xq"}>
-            <div className={"_3-90"}>
-              <div className={" _1yi2"} onContextMenu={undefined}>
-                <BackgroundImage585 />
-              </div>
-            </div>
-            <CenteredContainer589 />
-          </div>
-          {null}
-        </div>
-        <XUIText591 />
-        {null}
-      </div>
-    );
-  },
-});
-
-var AdsBulkImageInput593 = React.createClass({
-  render: function() {
-    return <AdsImageInput592 />;
-  },
-});
-
-var AdsLabeledField594 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_3-96 _3bvz"} label={"Image"} labelSize={"small"}>
-        <label className={"_4el4 _3qwj _3hy-"} htmlFor={undefined}>
-          {"Image"}
-          {" "}
-          {undefined}
-        </label>
-        {null}
-        <div className={"_3bv-"}>
-          <AdsBulkImageInput593 />
-        </div>
-      </div>
-    );
-  },
-});
-
-var AdsPEImageSelector595 = React.createClass({
-  render: function() {
-    return <AdsLabeledField594 />;
-  },
-});
-
-var AdsPEImageSelectorContainer596 = React.createClass({
-  render: function() {
-    return <AdsPEImageSelector595 />;
-  },
-});
-
-var AdsPEWebsiteNoPageCreative597 = React.createClass({
-  render: function() {
-    return (
-      <div>
-        <AdsPEWebsiteURLField569 />
-        <AdsPEHeadlineField577 />
-        <AdsPEMessageField582 />
-        <AdsPEImageSelectorContainer596 />
-      </div>
-    );
-  },
-});
-
-var AdsPEWebsiteNoPageCreativeContainer598 = React.createClass({
-  render: function() {
-    return <AdsPEWebsiteNoPageCreative597 />;
-  },
-});
-
-var XUICardSection599 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_12jy _4-u3"} background={"transparent"}>
-        <div className={"_3-8j"}>
-          <div></div>
-          <AdsPEWebsiteNoPageCreativeContainer598 />
-        </div>
-      </div>
-    );
-  },
-});
-
-var AdsCardSection600 = React.createClass({
-  render: function() {
-    return <XUICardSection599 />;
-  },
-});
-
-var XUICard601 = React.createClass({
-  render: function() {
-    return (
-      <div xuiErrorPosition={"above"} className={"_12k2 _4-u2  _4-u8"} background={"white"}>
-        <AdsCardHeader561 />
-        <AdsCardSection600 />
-      </div>
-    );
-  },
-});
-
-var ReactXUIError602 = React.createClass({
-  render: function() {
-    return <XUICard601 />;
-  },
-});
-
-var AdsCard603 = React.createClass({
-  render: function() {
-    return <ReactXUIError602 />;
-  },
-});
-
-var AdsPEAdgroupCreativeSection604 = React.createClass({
-  render: function() {
-    return <AdsCard603 />;
-  },
-});
-
-var AdsPEAdgroupCreativeSectionContainer605 = React.createClass({
-  render: function() {
-    return <AdsPEAdgroupCreativeSection604 />;
-  },
-});
-
-var AdsPELeadGenFormSection606 = React.createClass({
-  render: function() {
-    return null;
-  },
-});
-
-var AdsPELeadGenFormContainer607 = React.createClass({
-  render: function() {
-    return <AdsPELeadGenFormSection606 />;
-  },
-});
-
-var XUICardHeaderTitle608 = React.createClass({
-  render: function() {
-    return (
-      <span itemComponent={"span"} className={"_38my"}>
-        {"Tracking"}
-        {null}
-        <span className={"_c1c"}></span>
-      </span>
-    );
-  },
-});
-
-var XUICardSection609 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_5dw9 _5dwa _4-u3"} background={"transparent"}>
-        {[
-          <XUICardHeaderTitle608 key={"/.0"} />,
-        ]}
-        {undefined}
-        {undefined}
-        <div className={"_3s3-"}></div>
-      </div>
-    );
-  },
-});
-
-var XUICardHeader610 = React.createClass({
-  render: function() {
-    return <XUICardSection609 />;
-  },
-});
-
-var AdsCardHeader611 = React.createClass({
-  render: function() {
-    return <XUICardHeader610 />;
-  },
-});
-
-var XUIText612 = React.createClass({
-  render: function() {
-    return <span weight={"bold"} className={"_3ga-  _50f7"} size={"inherit"} display={"inline"}>{"Conversion Tracking"}</span>;
-  },
-});
-
-var ReactImage613 = React.createClass({
-  render: function() {
-    return <i src={null} className={"_5s_w _541d img sp_R48dKBxiJkP sx_dc2cdb"}></i>;
-  },
-});
-
-var AdsPopoverLink614 = React.createClass({
-  render: function() {
-    return (
-      <span ref={"tipIcon"} onMouseEnter={function() {}} onMouseLeave={function() {}}>
-        <span className={"_3o_j"}></span>
-        <ReactImage613 />
-      </span>
-    );
-  },
-});
-
-var AdsHelpLink615 = React.createClass({
-  render: function() {
-    return <AdsPopoverLink614 />;
-  },
-});
-
-var AdsCFHelpLink616 = React.createClass({
-  render: function() {
-    return <AdsHelpLink615 />;
-  },
-});
-
-var AdsPixelTrackingLabel617 = React.createClass({
-  render: function() {
-    return (
-      <div className={"_3gay"}>
-        <XUIText612 />
-        <AdsCFHelpLink616 />
-      </div>
-    );
-  },
-});
-
-var ReactImage618 = React.createClass({
-  render: function() {
-    return <i src={null} className={"img _8o _8r img sp_UuU9HmrQ397 sx_ad67ef"}></i>;
-  },
-});
-
-var XUIText619 = React.createClass({
-  render: function() {
-    return <div size={"medium"} weight={"bold"} shade={"medium"} display={"block"} className={"_3-8m  _c24  _50f4 _50f7"}>{"Facebook Pixel"}</div>;
-  },
-});
-
-var XUIGrayText620 = React.createClass({
-  render: function() {
-    return <XUIText619 />;
-  },
-});
-
-var XUIText621 = React.createClass({
-  render: function() {
-    return <span size={"medium"} weight={"inherit"} display={"inline"} className={" _50f4"}>{"Learn More"}</span>;
-  },
-});
-
-var Link622 = React.createClass({
-  render: function() {
-    return (
-      <a href={"/help/336923339852238"} target={"_blank"} rel={undefined} onClick={function() {}}>
-        <XUIText621 />
-      </a>
-    );
-  },
-});
-
-var XUIText623 = React.createClass({
-  render: function() {
-    return (
-      <span shade={"medium"} size={"medium"} className={" _c24  _50f4"} weight={"inherit"} display={"inline"}>
-        {"You can now create one pixel for tracking, optimization and remarketing."}
-        <span className={"_3-99"}>
-          <Link622 />
-        </span>
-      </span>
-    );
-  },
-});
-
-var XUIGrayText624 = React.createClass({
-  render: function() {
-    return <XUIText623 />;
-  },
-});
-
-var AbstractButton625 = React.createClass({
-  render: function() {
-    return (
-      <button className={"_23ng _4jy0 _4jy4 _4jy1 _51sy selected _42ft"} label={null} onClick={function() {}} size={"large"} use={"confirm"} borderShade={"light"} suppressed={false} type={"submit"} value={"1"}>
-        {undefined}
-        {"Create a Pixel"}
-        {undefined}
-      </button>
-    );
-  },
-});
-
-var XUIButton626 = React.createClass({
-  render: function() {
-    return <AbstractButton625 />;
-  },
-});
-
-var AdsPixelCreateButton627 = React.createClass({
-  render: function() {
-    return <XUIButton626 />;
+      );
+    }
+    if (props.x === 404) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"CTR %"}</span>
+        </div>
+      );
+    }
+    if (props.x === 409) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Spent"}</span>
+        </div>
+      );
+    }
+    if (props.x === 414) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Objective"}</span>
+        </div>
+      );
+    }
+    if (props.x === 419) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Buying Type"}</span>
+        </div>
+      );
+    }
+    if (props.x === 424) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Campaign ID"}</span>
+        </div>
+      );
+    }
+    if (props.x === 429) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Start"}</span>
+        </div>
+      );
+    }
+    if (props.x === 434) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"End"}</span>
+        </div>
+      );
+    }
+    if (props.x === 439) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Date created"}</span>
+        </div>
+      );
+    }
+    if (props.x === 444) {
+      return (
+        <div className={"_1cig _25fg"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Date last edited"}</span>
+        </div>
+      );
+    }
+    if (props.x === 449) {
+      return (
+        <div className={"_1cig _25fg _4h2r"} id={undefined}>
+          {null}
+          <span className={"_1cid"}>{"Tags"}</span>
+        </div>
+      );
+    }
+    if (props.x === 452) {
+      return <div className={"_1cig _25fg _4h2r"} id={undefined}></div>;
+    }
   },
 });
 
-var LeftRight628 = React.createClass({
+var TransitionCell142 = React.createClass({
   render: function() {
-    return (
-      <div className={"_23nf clearfix"} direction={"left"}>
-        <div key={"left"} className={"_ohe lfloat"}>
-          <ReactImage618 />
+    var props = this.props;
+    if (props.x === 316) {
+      return (
+        <div isHeaderCell={true} label={"Campaigns"} dataKey={0} groupHeaderRenderer={function() {}} groupHeaderLabels={{}} groupHeaderData={{}} columnKey={undefined} height={40} width={721} rowIndex={0} className={"_4lgc _4h2u"} style={{"height":40,"width":721}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <AdsPETableHeader141 x={315} />
+            </div>
+          </div>
         </div>
-        <div key={"right"} className={""}>
-          <div className={"_42ef _8u"}>
-            <div>
-              <XUIGrayText620 />
-              <XUIGrayText624 />
-              <div className={"_3-8x"}>
-                <AdsPixelCreateButton627 />
-              </div>
+      );
+    }
+    if (props.x === 321) {
+      return (
+        <div isHeaderCell={true} label={"Performance"} dataKey={1} groupHeaderRenderer={function() {}} groupHeaderLabels={{}} groupHeaderData={{}} columnKey={undefined} height={40} width={798} rowIndex={0} className={"_4lgc _4h2u"} style={{"height":40,"width":798}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <AdsPETableHeader141 x={320} />
             </div>
           </div>
         </div>
-      </div>
-    );
-  },
-});
-
-var ImageBlock629 = React.createClass({
-  render: function() {
-    return <LeftRight628 />;
+      );
+    }
+    if (props.x === 324) {
+      return (
+        <div isHeaderCell={true} label={"Overview"} dataKey={2} groupHeaderRenderer={function() {}} groupHeaderLabels={{}} groupHeaderData={{}} columnKey={undefined} height={40} width={1022} rowIndex={0} className={"_4lgc _4h2u"} style={{"height":40,"width":1022}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <AdsPETableHeader141 x={323} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 327) {
+      return (
+        <div isHeaderCell={true} label={"Toplines"} dataKey={3} groupHeaderRenderer={function() {}} groupHeaderLabels={{}} groupHeaderData={{}} columnKey={undefined} height={40} width={0} rowIndex={0} className={"_4lgc _4h2u"} style={{"height":40,"width":0}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <AdsPETableHeader141 x={326} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 330) {
+      return (
+        <div isHeaderCell={true} label={""} dataKey={4} groupHeaderRenderer={function() {}} groupHeaderLabels={{}} groupHeaderData={{}} columnKey={undefined} height={40} width={25} rowIndex={0} className={"_4lgc _4h2u"} style={{"height":40,"width":25}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <AdsPETableHeader141 x={329} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 338) {
+      return (
+        <div isHeaderCell={true} label={undefined} width={42} dataKey={"common.id"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"common.id"} height={25} style={{"height":25,"width":42}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <XUICheckboxInput60 x={337} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 343) {
+      return (
+        <div isHeaderCell={true} label={"Campaign Name"} width={400} dataKey={"campaignGroup.name"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"campaignGroup.name"} height={25} style={{"height":25,"width":400}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={342} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 349) {
+      return (
+        <div isHeaderCell={true} label={undefined} width={33} dataKey={"edit_status"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"edit_status"} height={25} style={{"height":25,"width":33}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={348} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 355) {
+      return (
+        <div isHeaderCell={true} label={undefined} width={36} dataKey={"errors"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"errors"} height={25} style={{"height":25,"width":36}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={354} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 360) {
+      return (
+        <div isHeaderCell={true} label={"Status"} width={60} dataKey={"campaignGroup.status"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"campaignGroup.status"} height={25} style={{"height":25,"width":60}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={359} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 365) {
+      return (
+        <div isHeaderCell={true} label={"Delivery"} width={150} dataKey={"derivedCampaignGroup.activity_status"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"derivedCampaignGroup.activity_status"} height={25} style={{"height":25,"width":150}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={364} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 372) {
+      return (
+        <div isHeaderCell={true} label={"Results"} width={140} dataKey={"stats.actions"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"stats.actions"} height={25} style={{"height":25,"width":140}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={371} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 377) {
+      return (
+        <div isHeaderCell={true} label={"Cost"} width={140} dataKey={"stats.cpa"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"stats.cpa"} height={25} style={{"height":25,"width":140}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={376} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 382) {
+      return (
+        <div isHeaderCell={true} label={"Reach"} width={80} dataKey={"stats.unique_impressions"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"stats.unique_impressions"} height={25} style={{"height":25,"width":80}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={381} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 387) {
+      return (
+        <div isHeaderCell={true} label={"Impressions"} width={80} dataKey={"stats.impressions"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"stats.impressions"} height={25} style={{"height":25,"width":80}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={386} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 392) {
+      return (
+        <div isHeaderCell={true} label={"Clicks"} width={60} dataKey={"stats.clicks"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"stats.clicks"} height={25} style={{"height":25,"width":60}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={391} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 397) {
+      return (
+        <div isHeaderCell={true} label={"Avg. CPM"} width={80} dataKey={"stats.avg_cpm"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"stats.avg_cpm"} height={25} style={{"height":25,"width":80}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={396} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 402) {
+      return (
+        <div isHeaderCell={true} label={"Avg. CPC"} width={78} dataKey={"stats.avg_cpc"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"stats.avg_cpc"} height={25} style={{"height":25,"width":78}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={401} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 407) {
+      return (
+        <div isHeaderCell={true} label={"CTR %"} width={70} dataKey={"stats.ctr"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"stats.ctr"} height={25} style={{"height":25,"width":70}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={406} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 412) {
+      return (
+        <div isHeaderCell={true} label={"Spent"} width={70} dataKey={"stats.spent_100"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"stats.spent_100"} height={25} style={{"height":25,"width":70}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={411} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 417) {
+      return (
+        <div isHeaderCell={true} label={"Objective"} width={200} dataKey={"campaignGroup.objective"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"campaignGroup.objective"} height={25} style={{"height":25,"width":200}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={416} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 422) {
+      return (
+        <div isHeaderCell={true} label={"Buying Type"} width={100} dataKey={"campaignGroup.buying_type"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"campaignGroup.buying_type"} height={25} style={{"height":25,"width":100}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={421} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 427) {
+      return (
+        <div isHeaderCell={true} label={"Campaign ID"} width={120} dataKey={"campaignGroup.id"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"campaignGroup.id"} height={25} style={{"height":25,"width":120}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={426} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 432) {
+      return (
+        <div isHeaderCell={true} label={"Start"} width={113} dataKey={"derivedCampaignGroup.startDate"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"derivedCampaignGroup.startDate"} height={25} style={{"height":25,"width":113}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={431} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 437) {
+      return (
+        <div isHeaderCell={true} label={"End"} width={113} dataKey={"derivedCampaignGroup.stopDate"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"derivedCampaignGroup.stopDate"} height={25} style={{"height":25,"width":113}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={436} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 442) {
+      return (
+        <div isHeaderCell={true} label={"Date created"} width={113} dataKey={"derivedCampaignGroup.createdDate"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"derivedCampaignGroup.createdDate"} height={25} style={{"height":25,"width":113}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={441} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 447) {
+      return (
+        <div isHeaderCell={true} label={"Date last edited"} width={113} dataKey={"derivedCampaignGroup.updatedDate"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"derivedCampaignGroup.updatedDate"} height={25} style={{"height":25,"width":113}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <FixedDataTableSortableHeader149 x={446} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 450) {
+      return (
+        <div isHeaderCell={true} label={"Tags"} width={150} dataKey={"labels"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"labels"} height={25} style={{"height":25,"width":150}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <AdsPETableHeader141 x={449} />
+            </div>
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 453) {
+      return (
+        <div isHeaderCell={true} label={""} width={25} dataKey={"scrollbar_spacer"} className={"_4lgc _4h2u"} columnData={{}} cellRenderer={function() {}} headerDataGetter={function() {}} columnKey={"scrollbar_spacer"} height={25} style={{"height":25,"width":25}}>
+          <div className={"_4lgd _4h2w"}>
+            <div className={"_4lge _4h2x"}>
+              <AdsPETableHeader141 x={452} />
+            </div>
+          </div>
+        </div>
+      );
+    }
   },
 });
 
-var AdsPixelCreationCard630 = React.createClass({
+var FixedDataTableCell143 = React.createClass({
   render: function() {
-    return (
-      <div className={"_2pie"} horizontal={true}>
-        <div className={"_23ne _4fsl"}>
-          <ImageBlock629 />
+    var props = this.props;
+    if (props.x === 317) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":40,"width":721,"left":0}}>
+          {undefined}
+          <TransitionCell142 x={316} />
+        </div>
+      );
+    }
+    if (props.x === 322) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":40,"width":798,"left":0}}>
+          {undefined}
+          <TransitionCell142 x={321} />
+        </div>
+      );
+    }
+    if (props.x === 325) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":40,"width":1022,"left":798}}>
+          {undefined}
+          <TransitionCell142 x={324} />
+        </div>
+      );
+    }
+    if (props.x === 328) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":40,"width":0,"left":1820}}>
+          {undefined}
+          <TransitionCell142 x={327} />
+        </div>
+      );
+    }
+    if (props.x === 331) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":40,"width":25,"left":1820}}>
+          {undefined}
+          <TransitionCell142 x={330} />
+        </div>
+      );
+    }
+    if (props.x === 339) {
+      return (
+        <div className={"_4lg0 _4lg6 _4h2m"} style={{"height":25,"width":42,"left":0}}>
+          {undefined}
+          <TransitionCell142 x={338} />
+        </div>
+      );
+    }
+    if (props.x === 344) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":25,"width":400,"left":42}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={343} />
+        </div>
+      );
+    }
+    if (props.x === 350) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":25,"width":33,"left":442}}>
+          {undefined}
+          <TransitionCell142 x={349} />
+        </div>
+      );
+    }
+    if (props.x === 356) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":25,"width":36,"left":475}}>
+          {undefined}
+          <TransitionCell142 x={355} />
+        </div>
+      );
+    }
+    if (props.x === 361) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":25,"width":60,"left":511}}>
+          {undefined}
+          <TransitionCell142 x={360} />
+        </div>
+      );
+    }
+    if (props.x === 366) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":25,"width":150,"left":571}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={365} />
+        </div>
+      );
+    }
+    if (props.x === 373) {
+      return (
+        <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":25,"width":140,"left":0}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={372} />
+        </div>
+      );
+    }
+    if (props.x === 378) {
+      return (
+        <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":25,"width":140,"left":140}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={377} />
+        </div>
+      );
+    }
+    if (props.x === 383) {
+      return (
+        <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":25,"width":80,"left":280}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={382} />
+        </div>
+      );
+    }
+    if (props.x === 388) {
+      return (
+        <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":25,"width":80,"left":360}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={387} />
+        </div>
+      );
+    }
+    if (props.x === 393) {
+      return (
+        <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":25,"width":60,"left":440}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={392} />
+        </div>
+      );
+    }
+    if (props.x === 398) {
+      return (
+        <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":25,"width":80,"left":500}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={397} />
+        </div>
+      );
+    }
+    if (props.x === 403) {
+      return (
+        <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":25,"width":78,"left":580}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={402} />
+        </div>
+      );
+    }
+    if (props.x === 408) {
+      return (
+        <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":25,"width":70,"left":658}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={407} />
+        </div>
+      );
+    }
+    if (props.x === 413) {
+      return (
+        <div className={"_4lg0 _4lg5 _4h2p _4h2m"} style={{"height":25,"width":70,"left":728}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={412} />
+        </div>
+      );
+    }
+    if (props.x === 418) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":25,"width":200,"left":798}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={417} />
+        </div>
+      );
+    }
+    if (props.x === 423) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":25,"width":100,"left":998}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={422} />
+        </div>
+      );
+    }
+    if (props.x === 428) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":25,"width":120,"left":1098}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={427} />
+        </div>
+      );
+    }
+    if (props.x === 433) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":25,"width":113,"left":1218}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={432} />
+        </div>
+      );
+    }
+    if (props.x === 438) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":25,"width":113,"left":1331}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={437} />
+        </div>
+      );
+    }
+    if (props.x === 443) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":25,"width":113,"left":1444}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={442} />
+        </div>
+      );
+    }
+    if (props.x === 448) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":25,"width":113,"left":1557}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={447} />
+        </div>
+      );
+    }
+    if (props.x === 451) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":25,"width":150,"left":1670}}>
+          <div className={"_4lg9"} style={{"height":25}} onMouseDown={function() {}}>
+            <div className={"_4lga _4lgb"} style={{"height":25}}></div>
+          </div>
+          <TransitionCell142 x={450} />
+        </div>
+      );
+    }
+    if (props.x === 454) {
+      return (
+        <div className={"_4lg0 _4h2m"} style={{"height":25,"width":25,"left":1820}}>
+          {undefined}
+          <TransitionCell142 x={453} />
+        </div>
+      );
+    }
+  },
+});
+
+var FixedDataTableCellGroupImpl144 = React.createClass({
+  render: function() {
+    var props = this.props;
+    if (props.x === 318) {
+      return (
+        <div className={"_3pzj"} style={{"height":40,"position":"absolute","width":721,"zIndex":2,"transform":"translate3d(0px,0px,0)","backfaceVisibility":"hidden"}}>
+          <FixedDataTableCell143 x={317} key={"cell_0"} />
+        </div>
+      );
+    }
+    if (props.x === 332) {
+      return (
+        <div className={"_3pzj"} style={{"height":40,"position":"absolute","width":1845,"zIndex":0,"transform":"translate3d(0px,0px,0)","backfaceVisibility":"hidden"}}>
+          <FixedDataTableCell143 x={322} key={"cell_0"} />
+          <FixedDataTableCell143 x={325} key={"cell_1"} />
+          <FixedDataTableCell143 x={328} key={"cell_2"} />
+          <FixedDataTableCell143 x={331} key={"cell_3"} />
+        </div>
+      );
+    }
+    if (props.x === 367) {
+      return (
+        <div className={"_3pzj"} style={{"height":25,"position":"absolute","width":721,"zIndex":2,"transform":"translate3d(0px,0px,0)","backfaceVisibility":"hidden"}}>
+          <FixedDataTableCell143 x={339} key={"cell_0"} />
+          <FixedDataTableCell143 x={344} key={"cell_1"} />
+          <FixedDataTableCell143 x={350} key={"cell_2"} />
+          <FixedDataTableCell143 x={356} key={"cell_3"} />
+          <FixedDataTableCell143 x={361} key={"cell_4"} />
+          <FixedDataTableCell143 x={366} key={"cell_5"} />
+        </div>
+      );
+    }
+    if (props.x === 455) {
+      return (
+        <div className={"_3pzj"} style={{"height":25,"position":"absolute","width":1845,"zIndex":0,"transform":"translate3d(0px,0px,0)","backfaceVisibility":"hidden"}}>
+          <FixedDataTableCell143 x={373} key={"cell_0"} />
+          <FixedDataTableCell143 x={378} key={"cell_1"} />
+          <FixedDataTableCell143 x={383} key={"cell_2"} />
+          <FixedDataTableCell143 x={388} key={"cell_3"} />
+          <FixedDataTableCell143 x={393} key={"cell_4"} />
+          <FixedDataTableCell143 x={398} key={"cell_5"} />
+          <FixedDataTableCell143 x={403} key={"cell_6"} />
+          <FixedDataTableCell143 x={408} key={"cell_7"} />
+          <FixedDataTableCell143 x={413} key={"cell_8"} />
+          <FixedDataTableCell143 x={418} key={"cell_9"} />
+          <FixedDataTableCell143 x={423} key={"cell_10"} />
+          <FixedDataTableCell143 x={428} key={"cell_11"} />
+          <FixedDataTableCell143 x={433} key={"cell_12"} />
+          <FixedDataTableCell143 x={438} key={"cell_13"} />
+          <FixedDataTableCell143 x={443} key={"cell_14"} />
+          <FixedDataTableCell143 x={448} key={"cell_15"} />
+          <FixedDataTableCell143 x={451} key={"cell_16"} />
+          <FixedDataTableCell143 x={454} key={"cell_17"} />
+        </div>
+      );
+    }
+  },
+});
+
+var FixedDataTableCellGroup145 = React.createClass({
+  render: function() {
+    var props = this.props;
+    if (props.x === 319) {
+      return (
+        <div style={{"height":40,"left":0}} className={"_3pzk"}>
+          <FixedDataTableCellGroupImpl144 x={318} />
+        </div>
+      );
+    }
+    if (props.x === 333) {
+      return (
+        <div style={{"height":40,"left":721}} className={"_3pzk"}>
+          <FixedDataTableCellGroupImpl144 x={332} />
+        </div>
+      );
+    }
+    if (props.x === 368) {
+      return (
+        <div style={{"height":25,"left":0}} className={"_3pzk"}>
+          <FixedDataTableCellGroupImpl144 x={367} />
+        </div>
+      );
+    }
+    if (props.x === 456) {
+      return (
+        <div style={{"height":25,"left":721}} className={"_3pzk"}>
+          <FixedDataTableCellGroupImpl144 x={455} />
+        </div>
+      );
+    }
+  },
+});
+
+var FixedDataTableRowImpl146 = React.createClass({
+  render: function() {
+    var props = this.props;
+    if (props.x === 334) {
+      return (
+        <div className={"_1gd4 _4li _52no _3h1a _1mib"} onClick={null} onDoubleClick={null} onMouseDown={null} onMouseEnter={null} onMouseLeave={null} style={{"width":1209,"height":40}}>
+          <div className={"_1gd5"}>
+            <FixedDataTableCellGroup145 x={319} key={"fixed_cells"} />
+            <FixedDataTableCellGroup145 x={333} key={"scrollable_cells"} />
+            <div className={"_1gd6 _1gd8"} style={{"left":721,"height":40}}></div>
+          </div>
         </div>
-      </div>
-    );
+      );
+    }
+    if (props.x === 457) {
+      return (
+        <div className={"_1gd4 _4li _3h1a _1mib"} onClick={null} onDoubleClick={null} onMouseDown={null} onMouseEnter={null} onMouseLeave={null} style={{"width":1209,"height":25}}>
+          <div className={"_1gd5"}>
+            <FixedDataTableCellGroup145 x={368} key={"fixed_cells"} />
+            <FixedDataTableCellGroup145 x={456} key={"scrollable_cells"} />
+            <div className={"_1gd6 _1gd8"} style={{"left":721,"height":25}}></div>
+          </div>
+        </div>
+      );
+    }
   },
 });
 
-var AdsPixelTrackingSelector631 = React.createClass({
+var FixedDataTableRow147 = React.createClass({
   render: function() {
-    return (
-      <div className={"_3-8x _4fsk"}>
-        <AdsPixelCreationCard630 key={"FacebookPixelNUX"} />
-      </div>
-    );
+    var props = this.props;
+    if (props.x === 335) {
+      return (
+        <div style={{"width":1209,"height":40,"zIndex":1,"transform":"translate3d(0px,0px,0)","backfaceVisibility":"hidden"}} className={"_1gda"}>
+          <FixedDataTableRowImpl146 x={334} />
+        </div>
+      );
+    }
+    if (props.x === 458) {
+      return (
+        <div style={{"width":1209,"height":25,"zIndex":1,"transform":"translate3d(0px,40px,0)","backfaceVisibility":"hidden"}} className={"_1gda"}>
+          <FixedDataTableRowImpl146 x={457} />
+        </div>
+      );
+    }
   },
 });
 
-var AdsPixelTracking632 = React.createClass({
+var FixedDataTableAbstractSortableHeader148 = React.createClass({
   render: function() {
-    return (
-      <div className={undefined}>
-        <AdsPixelTrackingLabel617 />
-        <div className={"_3-8x"}>
-          <div></div>
+    var props = this.props;
+    if (props.x === 341) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={340} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 347) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _1kst _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={346} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 353) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _1kst _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={352} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 358) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={357} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 363) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _54_9 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={362} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 370) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={369} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 375) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={374} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 380) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={379} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 385) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={384} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 390) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={389} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 395) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={394} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 400) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={399} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 405) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={404} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 410) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={409} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 415) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={414} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 420) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={419} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 425) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={424} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 430) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={429} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 435) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={434} />
+          </div>
         </div>
-        <AdsPixelTrackingSelector631 />
-      </div>
-    );
+      );
+    }
+    if (props.x === 440) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={439} />
+          </div>
+        </div>
+      );
+    }
+    if (props.x === 445) {
+      return (
+        <div onClick={function() {}} className={"_54_8 _4h2r _2wzx"}>
+          <div className={"_2eq6"}>
+            {null}
+            <AdsPETableHeader141 x={444} />
+          </div>
+        </div>
+      );
+    }
+  },
+});
+
+var FixedDataTableSortableHeader149 = React.createClass({
+  render: function() {
+    var props = this.props;
+    if (props.x === 342) {
+      return <FixedDataTableAbstractSortableHeader148 x={341} />;
+    }
+    if (props.x === 348) {
+      return <FixedDataTableAbstractSortableHeader148 x={347} />;
+    }
+    if (props.x === 354) {
+      return <FixedDataTableAbstractSortableHeader148 x={353} />;
+    }
+    if (props.x === 359) {
+      return <FixedDataTableAbstractSortableHeader148 x={358} />;
+    }
+    if (props.x === 364) {
+      return <FixedDataTableAbstractSortableHeader148 x={363} />;
+    }
+    if (props.x === 371) {
+      return <FixedDataTableAbstractSortableHeader148 x={370} />;
+    }
+    if (props.x === 376) {
+      return <FixedDataTableAbstractSortableHeader148 x={375} />;
+    }
+    if (props.x === 381) {
+      return <FixedDataTableAbstractSortableHeader148 x={380} />;
+    }
+    if (props.x === 386) {
+      return <FixedDataTableAbstractSortableHeader148 x={385} />;
+    }
+    if (props.x === 391) {
+      return <FixedDataTableAbstractSortableHeader148 x={390} />;
+    }
+    if (props.x === 396) {
+      return <FixedDataTableAbstractSortableHeader148 x={395} />;
+    }
+    if (props.x === 401) {
+      return <FixedDataTableAbstractSortableHeader148 x={400} />;
+    }
+    if (props.x === 406) {
+      return <FixedDataTableAbstractSortableHeader148 x={405} />;
+    }
+    if (props.x === 411) {
+      return <FixedDataTableAbstractSortableHeader148 x={410} />;
+    }
+    if (props.x === 416) {
+      return <FixedDataTableAbstractSortableHeader148 x={415} />;
+    }
+    if (props.x === 421) {
+      return <FixedDataTableAbstractSortableHeader148 x={420} />;
+    }
+    if (props.x === 426) {
+      return <FixedDataTableAbstractSortableHeader148 x={425} />;
+    }
+    if (props.x === 431) {
+      return <FixedDataTableAbstractSortableHeader148 x={430} />;
+    }
+    if (props.x === 436) {
+      return <FixedDataTableAbstractSortableHeader148 x={435} />;
+    }
+    if (props.x === 441) {
+      return <FixedDataTableAbstractSortableHeader148 x={440} />;
+    }
+    if (props.x === 446) {
+      return <FixedDataTableAbstractSortableHeader148 x={445} />;
+    }
+  },
+});
+
+var FixedDataTableBufferedRows150 = React.createClass({
+  render: function() {
+    var props = this.props;
+    if (props.x === 459) {
+      return <div style={{"position":"absolute","pointerEvents":"auto","transform":"translate3d(0px,65px,0)","backfaceVisibility":"hidden"}}></div>;
+    }
+  },
+});
+
+var Scrollbar151 = React.createClass({
+  render: function() {
+    var props = this.props;
+    if (props.x === 460) {
+      return null;
+    }
+    if (props.x === 461) {
+      return (
+        <div onFocus={function() {}} onBlur={function() {}} onKeyDown={function() {}} onMouseDown={function() {}} onWheel={function() {}} className={"_1t0r _1t0t _4jdr _1t0u"} style={{"width":1209,"zIndex":99}} tabIndex={0}>
+          <div ref={"face"} className={"_1t0w _1t0y _1t0_"} style={{"width":561.6340607950117,"transform":"translate3d(4px,0px,0)","backfaceVisibility":"hidden"}}></div>
+        </div>
+      );
+    }
+  },
+});
+
+var HorizontalScrollbar152 = React.createClass({
+  render: function() {
+    var props = this.props;
+    if (props.x === 462) {
+      return (
+        <div className={"_3h1k _3h1m"} style={{"height":15,"width":1209}}>
+          <div style={{"height":15,"position":"absolute","overflow":"hidden","width":1209,"transform":"translate3d(0px,0px,0)","backfaceVisibility":"hidden"}}>
+            <Scrollbar151 x={461} />
+          </div>
+        </div>
+      );
+    }
   },
 });
 
-var AdsPEPixelTracking633 = React.createClass({
+var FixedDataTable153 = React.createClass({
   render: function() {
-    return <AdsPixelTracking632 key={"tracking"} />;
+    var props = this.props;
+    if (props.x === 463) {
+      return (
+        <div className={"_3h1i _1mie"} onWheel={function() {}} style={{"height":25,"width":1209}}>
+          <div className={"_3h1j"} style={{"height":8,"width":1209}}>
+            <FixedDataTableColumnResizeHandle140 x={313} />
+            <FixedDataTableRow147 x={335} key={"group_header"} />
+            <FixedDataTableRow147 x={458} key={"header"} />
+            <FixedDataTableBufferedRows150 x={459} />
+            {null}
+            {undefined}
+            <div className={"_3h1e _3h1h"} style={{"top":8}}></div>
+          </div>
+          <Scrollbar151 x={460} />
+          <HorizontalScrollbar152 x={462} />
+        </div>
+      );
+    }
   },
 });
 
-var AdsPEPixelTrackingContainer634 = React.createClass({
+var TransitionTable154 = React.createClass({
   render: function() {
-    return <AdsPEPixelTracking633 />;
+    var props = this.props;
+    if (props.x === 464) {
+      return <FixedDataTable153 x={463} ref={"fixedDataTable"} />;
+    }
   },
 });
 
-var AdsPEAdgroupAppTrackingSelectorContainer635 = React.createClass({
+var AdsSelectableFixedDataTable155 = React.createClass({
   render: function() {
-    return null;
+    var props = this.props;
+    if (props.x === 465) {
+      return (
+        <div className={"_5hht"}>
+          <TransitionTable154 x={464} />
+        </div>
+      );
+    }
   },
 });
 
-var AdsPEStandardTrackingSection636 = React.createClass({
+var AdsDataTableKeyboardSupportDecorator156 = React.createClass({
   render: function() {
-    return (
-      <div>
-        {null}
-        <div className={"_3-96"}>
-          <AdsPEPixelTrackingContainer634 />
+    var props = this.props;
+    if (props.x === 466) {
+      return (
+        <div ref={"tableContainer"} className={"_5d6f"} tabIndex={"0"} onKeyDown={function() {}}>
+          <AdsSelectableFixedDataTable155 x={465} />
         </div>
-        <div className={"_3-96"}>
-          <AdsPEAdgroupAppTrackingSelectorContainer635 />
-        </div>
-        {null}
-      </div>
-    );
+      );
+    }
   },
 });
 
-var AdsPEStandardTrackingContainer637 = React.createClass({
+var AdsEditableDataTableDecorator157 = React.createClass({
   render: function() {
-    return <AdsPEStandardTrackingSection636 />;
+    var props = this.props;
+    if (props.x === 467) {
+      return (
+        <div onCopy={function() {}}>
+          <AdsDataTableKeyboardSupportDecorator156 x={466} ref={"decoratedTable"} />
+        </div>
+      );
+    }
   },
 });
 
-var XUICardSection638 = React.createClass({
+var AdsPEDataTableContainer158 = React.createClass({
   render: function() {
-    return (
-      <div className={"_12jy _4-u3"} background={"transparent"}>
-        <div className={"_3-8j"}>
-          <AdsPEStandardTrackingContainer637 />
+    var props = this.props;
+    if (props.x === 468) {
+      return (
+        <div className={"_35l_ _1hr clearfix"}>
+          {null}
+          {null}
+          {null}
+          <AdsEditableDataTableDecorator157 x={467} />
         </div>
-      </div>
-    );
+      );
+    }
   },
 });
 
-var AdsCardSection639 = React.createClass({
+var AdsPECampaignGroupTableContainer159 = React.createClass({
   render: function() {
-    return <XUICardSection638 />;
+    var props = this.props;
+    if (props.x === 470) {
+      return <ResponsiveBlock37 x={469} />;
+    }
   },
 });
 
-var XUICard640 = React.createClass({
+var AdsPEManageAdsPaneContainer160 = React.createClass({
   render: function() {
-    return (
-      <div xuiErrorPosition={"above"} className={"_12k2 _4-u2  _4-u8"} background={"white"}>
-        <AdsCardHeader611 />
-        <AdsCardSection639 />
-      </div>
-    );
+    var props = this.props;
+    if (props.x === 473) {
+      return (
+        <div>
+          <AdsErrorBoundary10 x={65} />
+          <div className={"_2uty"}>
+            <AdsErrorBoundary10 x={125} />
+          </div>
+          <div className={"_2utx _21oc"}>
+            <AdsErrorBoundary10 x={171} />
+            <div className={"_41tu"}>
+              <AdsErrorBoundary10 x={176} />
+              <AdsErrorBoundary10 x={194} />
+            </div>
+          </div>
+          <div className={"_2utz"} style={{"height":25}}>
+            <AdsErrorBoundary10 x={302} />
+            <div className={"_2ut-"}>
+              <AdsErrorBoundary10 x={312} />
+            </div>
+            <div className={"_2ut_"}>
+              <AdsErrorBoundary10 x={472} />
+            </div>
+          </div>
+        </div>
+      );
+    }
   },
 });
 
-var ReactXUIError641 = React.createClass({
+var AdsPEContentContainer161 = React.createClass({
   render: function() {
-    return <XUICard640 />;
+    var props = this.props;
+    if (props.x === 474) {
+      return <AdsPEManageAdsPaneContainer160 x={473} />;
+    }
   },
 });
 
-var AdsCard642 = React.createClass({
+var FluxContainer_AdsPEWorkspaceContainer_162 = React.createClass({
   render: function() {
-    return <ReactXUIError641 />;
+    var props = this.props;
+    if (props.x === 477) {
+      return (
+        <div className={"_49wu"} style={{"height":177,"top":43,"width":1306}}>
+          <ResponsiveBlock37 x={62} />
+          <AdsErrorBoundary10 x={476} />
+          {null}
+        </div>
+      );
+    }
   },
 });
 
-var AdsPEAdgroupTrackingSection643 = React.createClass({
+var FluxContainer_AdsSessionExpiredDialogContainer_163 = React.createClass({
   render: function() {
-    return <AdsCard642 />;
+    var props = this.props;
+    if (props.x === 478) {
+      return null;
+    }
   },
 });
 
-var AdsPEAdgroupTrackingSectionContainer644 = React.createClass({
+var FluxContainer_AdsPEUploadDialogLazyContainer_164 = React.createClass({
   render: function() {
-    return <AdsPEAdgroupTrackingSection643 />;
+    var props = this.props;
+    if (props.x === 479) {
+      return null;
+    }
   },
 });
 
-var AdsPEAdgroupIOSection645 = React.createClass({
+var FluxContainer_DialogContainer_165 = React.createClass({
   render: function() {
-    return null;
+    var props = this.props;
+    if (props.x === 480) {
+      return null;
+    }
   },
 });
 
-var AdsPEAdgroupIOSectionContainer646 = React.createClass({
+var AdsBugReportContainer166 = React.createClass({
   render: function() {
-    return <AdsPEAdgroupIOSection645 />;
+    var props = this.props;
+    if (props.x === 481) {
+      return <span></span>;
+    }
   },
 });
 
-var LeftRight647 = React.createClass({
+var AdsPEAudienceSplittingDialog167 = React.createClass({
   render: function() {
-    return (
-      <div flex={"left"} direction={"right"} className={"clearfix"}>
-        <div key={"right"} className={"_ohf rfloat"}>
-          <div className={"_20ro _20rp"}>
-            <div>
-              {null}
-              <AdsPEAdgroupLinksSectionContainer518 />
-              <AdsPEStickyArea543 />
-            </div>
-          </div>
-        </div>
-        <div key={"left"} className={""}>
-          <div className={"_42ef"}>
-            <div>
-              <AdsPEAdgroupDestinationSectionContainer557 />
-              <AdsPEAdgroupCreativeSectionContainer605 />
-              <AdsPELeadGenFormContainer607 />
-              <AdsPEAdgroupTrackingSectionContainer644 />
-              <AdsPEAdgroupIOSectionContainer646 />
-            </div>
-          </div>
-        </div>
-      </div>
-    );
+    var props = this.props;
+    if (props.x === 482) {
+      return null;
+    }
   },
 });
 
-var FlexibleBlock648 = React.createClass({
+var AdsPEAudienceSplittingDialogContainer168 = React.createClass({
   render: function() {
-    return <LeftRight647 />;
+    var props = this.props;
+    if (props.x === 483) {
+      return (
+        <div>
+          <AdsPEAudienceSplittingDialog167 x={482} />
+        </div>
+      );
+    }
   },
 });
 
-var AdsPEMultiColumnEditor649 = React.createClass({
+var FluxContainer_AdsRuleDialogBootloadContainer_169 = React.createClass({
   render: function() {
-    return (
-      <div className={"_2j_c _ykd"}>
-        <div>
-          <FluxContainer_r_483 />
-          {null}
-          <AdsPEAdgroupAutoNamingConfirmationContainer484 />
-          <AdsPEAdgroupNameSectionContainer500 />
-        </div>
-        <FlexibleBlock648 />
-      </div>
-    );
+    var props = this.props;
+    if (props.x === 484) {
+      return null;
+    }
   },
 });
 
-var AdsPEAdgroupEditor650 = React.createClass({
+var FluxContainer_AdsPECFTrayContainer_170 = React.createClass({
   render: function() {
-    return (
-      <div>
-        <AdsPEAdgroupHeaderSectionContainer481 />
-        <AdsPEMultiColumnEditor649 />
-      </div>
-    );
+    var props = this.props;
+    if (props.x === 485) {
+      return null;
+    }
   },
 });
 
-var AdsPEAdgroupEditorContainer651 = React.createClass({
+var FluxContainer_AdsPEDeleteDraftContainer_171 = React.createClass({
   render: function() {
-    return <AdsPEAdgroupEditor650 key={"98010048849345"} />;
+    var props = this.props;
+    if (props.x === 486) {
+      return null;
+    }
   },
 });
 
-var AdsPESideTrayTabContent652 = React.createClass({
+var FluxContainer_AdsPEInitialDraftPublishDialogContainer_172 = React.createClass({
   render: function() {
-    return (
-      <div className={"_1o_8 _44ra _5cyn"}>
-        <AdsPEAdgroupEditorContainer651 />
-      </div>
-    );
+    var props = this.props;
+    if (props.x === 487) {
+      return null;
+    }
   },
 });
 
-var AdsPEEditorTrayTabContent653 = React.createClass({
+var FluxContainer_AdsPEReachFrequencyStatusTransitionDialogBootloadContainer_173 = React.createClass({
   render: function() {
-    return <AdsPESideTrayTabContent652 />;
+    var props = this.props;
+    if (props.x === 488) {
+      return null;
+    }
   },
 });
 
-var AdsPEMultiTabDrawer654 = React.createClass({
+var FluxContainer_AdsPEPurgeArchiveDialogContainer_174 = React.createClass({
   render: function() {
-    return (
-      <div style={{"height":550,"width":1027}} tabButtons={{}} tabContentPanes={{}} enableAnimation={true} showButton={true} className={"_2kev _2kew _2kex"}>
-        <div className={"_2kf0"}>
-          <AdsPEEditorTrayTabButton469 key={"editor_tray_button"} />
-          <AdsPEInsightsTrayTabButton472 key={"insights_tray_button"} />
-          <AdsPENekoDebuggerTrayTabButton474 key={"neko_debugger_tray_button"} />
-        </div>
-        <div className={"_2kf1"}>
-          <FBDragHandle475 />
-          <AdsPEEditorTrayTabContent653 key={"EDITOR_DRAWER"} />
-          {null}
-        </div>
-      </div>
-    );
+    var props = this.props;
+    if (props.x === 489) {
+      return null;
+    }
   },
 });
 
-var FluxContainer_x_655 = React.createClass({
+var AdsPECreateDialogContainer175 = React.createClass({
   render: function() {
-    return <AdsPEMultiTabDrawer654 />;
+    var props = this.props;
+    if (props.x === 490) {
+      return <span></span>;
+    }
   },
 });
 
-var AdsBugReportContainer656 = React.createClass({
+var FluxContainer_AdsPEModalStatusContainer_176 = React.createClass({
   render: function() {
-    return null;
+    var props = this.props;
+    if (props.x === 491) {
+      return null;
+    }
   },
 });
 
-var AdsPEAudienceSplittingDialog657 = React.createClass({
+var FluxContainer_AdsBrowserExtensionErrorDialogContainer_177 = React.createClass({
   render: function() {
-    return null;
+    var props = this.props;
+    if (props.x === 492) {
+      return null;
+    }
   },
 });
 
-var AdsPEAudienceSplittingDialogContainer658 = React.createClass({
+var FluxContainer_AdsPESortByErrorTipContainer_178 = React.createClass({
   render: function() {
-    return (
-      <div>
-        <AdsPEAudienceSplittingDialog657 />
-      </div>
-    );
+    var props = this.props;
+    if (props.x === 493) {
+      return null;
+    }
   },
 });
 
-var FluxContainer_p_659 = React.createClass({
+var LeadDownloadDialogSelector179 = React.createClass({
   render: function() {
-    return null;
+    var props = this.props;
+    if (props.x === 494) {
+      return null;
+    }
   },
 });
 
-var AdsPECreateDialogContainer660 = React.createClass({
+var FluxContainer_AdsPELeadDownloadDialogContainerClass_180 = React.createClass({
   render: function() {
-    return null;
+    var props = this.props;
+    if (props.x === 495) {
+      return <LeadDownloadDialogSelector179 x={494} />;
+    }
   },
 });
 
-var AdsPEContainer661 = React.createClass({
+var AdsPEContainer181 = React.createClass({
   render: function() {
-    return (
-      <div id={"ads_pe_container"}>
-        {null}
-        <FluxContainer_ja_26 />
-        <FluxContainer_w_56 />
-        <FluxContainer_r_463 />
-        <FluxContainer_q_464 />
-        <FluxContainer_y_466 />
-        {null}
-        <FluxContainer_x_655 />
-        <AdsBugReportContainer656 />
-        {null}
-        <AdsPEAudienceSplittingDialogContainer658 />
-        {null}
-        {null}
-        {null}
-        <FluxContainer_p_659 />
-        <AdsPECreateDialogContainer660 />
-      </div>
-    );
+    var props = this.props;
+    if (props.x === 496) {
+      return (
+        <div id={"ads_pe_container"}>
+          <FluxContainer_AdsPETopNavContainer_26 x={41} />
+          {null}
+          <FluxContainer_AdsPEWorkspaceContainer_162 x={477} />
+          <FluxContainer_AdsSessionExpiredDialogContainer_163 x={478} />
+          <FluxContainer_AdsPEUploadDialogLazyContainer_164 x={479} />
+          <FluxContainer_DialogContainer_165 x={480} />
+          <AdsBugReportContainer166 x={481} />
+          <AdsPEAudienceSplittingDialogContainer168 x={483} />
+          <FluxContainer_AdsRuleDialogBootloadContainer_169 x={484} />
+          <FluxContainer_AdsPECFTrayContainer_170 x={485} />
+          <span>
+            <FluxContainer_AdsPEDeleteDraftContainer_171 x={486} />
+            <FluxContainer_AdsPEInitialDraftPublishDialogContainer_172 x={487} />
+            <FluxContainer_AdsPEReachFrequencyStatusTransitionDialogBootloadContainer_173 x={488} />
+          </span>
+          <FluxContainer_AdsPEPurgeArchiveDialogContainer_174 x={489} />
+          <AdsPECreateDialogContainer175 x={490} />
+          <FluxContainer_AdsPEModalStatusContainer_176 x={491} />
+          <FluxContainer_AdsBrowserExtensionErrorDialogContainer_177 x={492} />
+          <FluxContainer_AdsPESortByErrorTipContainer_178 x={493} />
+          <FluxContainer_AdsPELeadDownloadDialogContainerClass_180 x={495} />
+          <div id={"web_ads_guidance_tips"}></div>
+        </div>
+      );
+    }
   },
 });
 
 var Benchmark = React.createClass({
   render: function() {
-    return <AdsPEContainer661 />;
+    var props = this.props;
+    if (props.x === undefined) {
+      return <AdsPEContainer181 x={496} />;
+    }
   },
 });
 
diff --git a/scripts/bench/extract-component.js b/scripts/bench/extract-component.js
index 3dfda0c25268..9cfab989cccb 100644
--- a/scripts/bench/extract-component.js
+++ b/scripts/bench/extract-component.js
@@ -2,11 +2,18 @@
 /*eslint-disable no-debugger */
 
 // Copy and paste this file into your (Chrome) browser console after changing
-// the React root ID. Works on facebook.com as of 10/28/15 (use a test user).
+// the React root ID. Works on facebook.com as of 7/6/16 (use a test user).
+// Then run this to convert the JSX:
+//
+//   ../../node_modules/.bin/babel \
+//     --presets ../../node_modules/babel-preset-react \
+//     --no-babelrc --compact=false \
+//     bench-foo.js -o bench-foo-es5.js
 
 'use strict';
 
-var rootID = '.0';
+var rootID = 5;
+var outputStatelessFunctional = false;
 
 var React = require('React');
 var ReactMount = require('ReactMount');
@@ -28,18 +35,50 @@ function elementMeta(element) {
 }
 
 function print(outerComponent) {
-  function addComposite(name, child) {
-    output += 'var ' + name + ' = React.createClass({\n';
-    output += '  render: function() {\n';
-    if (child.indexOf('\n') !== -1) {
-      output += '    return (\n';
-      output += child.replace(/^|\n/g, '$&      ') + '\n';
-      output += '    );\n';
+  var typeCounter = 0;
+  var elementCounter = 0;
+  var composites = new Map();
+
+  function addComposite(type, child) {
+    var info = composites.get(type);
+    if (!info) {
+      var name = (type.displayName || type.name || 'Component').replace(/(?:^[^a-z]|\W)+/gi, '_') + typeCounter++;
+      if (!/^[A-Z]/.test(name)) {
+        name = '_' + name;
+      }
+      info = {name: name, values: new Map()};
+      composites.set(type, info);
+    }
+    var c = elementCounter++;
+    info.values.set(c, child);
+    return '<' + info.name + ' x={' + c + '} />';
+  }
+
+  function printComposite(info) {
+    if (outputStatelessFunctional) {
+      output += 'var ' + info.name + ' = function(props) {\n';
+    } else {
+      output += 'var ' + info.name + ' = React.createClass({\n';
+      output += '  render: function() {\n';
+      output += '    var props = this.props;\n';
+    }
+    for (var [c, child] of info.values) {
+      output += '    if (props.x === ' + c + ') {\n';
+      if (child.indexOf('\n') !== -1) {
+        output += '      return (\n';
+        output += child.replace(/^|\n/g, '$&        ') + '\n';
+        output += '      );\n';
+      } else {
+        output += '      return ' + child + ';\n';
+      }
+      output += '    }\n';
+    }
+    if (outputStatelessFunctional) {
+      output += '};\n';
     } else {
-      output += '    return ' + child + ';\n';
+      output += '  },\n';
+      output += '});\n';
     }
-    output += '  },\n';
-    output += '});\n';
     output += '\n';
   }
 
@@ -59,15 +98,8 @@ function print(outerComponent) {
     // Composite component
     if (typeof element.type === 'function') {
       var rendered = printImpl(component._renderedComponent);
-      var name = (component.getName() || 'Component').replace(/(?:^[^a-z]|\W)+/gi, '_') + counter++;
-      if (!/^[A-Z]/.test(name)) {
-        name = '_' + name;
-      }
-      addComposite(name, rendered);
-      var compositeMarkup = '<' + name;
-      compositeMarkup += elementMeta(component._currentElement);
-      compositeMarkup += ' />';
-      return compositeMarkup;
+      return addComposite(component._currentElement.type, rendered)
+        .replace(/(?= \/>$)/, elementMeta(component._currentElement));
     }
 
     // Native component
@@ -112,10 +144,14 @@ function print(outerComponent) {
         var values = keys.map((childKey) => renderedChildren[childKey]);
 
         if (keys.length) {
-          function dump(children) {
+          var dump = function(children) {
             if (typeof children === 'boolean' || children == null) {
               return '' + children;
             }
+            if (typeof children === 'object' && !Array.isArray(children) && children[Symbol.iterator]) {
+              // TODO: Not quite right.
+              children = Array.from(children);
+            }
             if (Array.isArray(children)) {
               return children.length ? (
                 '[\n' +
@@ -130,7 +166,7 @@ function print(outerComponent) {
               debugger;
               throw new Error('hmm');
             }
-          }
+          };
 
           markup += '\n';
           var children = element.props.children;
@@ -159,10 +195,12 @@ function print(outerComponent) {
   }
 
   var output = '(function() {\n\n';
-  var counter = 0;
 
   var tail = printImpl(outerComponent);
-  addComposite('Benchmark', tail);
+  for (var info of composites.values()) {
+    printComposite(info);
+  }
+  printComposite({name: 'Benchmark', values: new Map([[undefined, tail]])});
   output += 'this.Benchmark = Benchmark;\n';
   output += '\n})(this);\n';
   return output;
diff --git a/scripts/bench/measure.py b/scripts/bench/measure.py
index 8c9296b5b39e..613cb98e4e11 100755
--- a/scripts/bench/measure.py
+++ b/scripts/bench/measure.py
@@ -9,12 +9,13 @@
 import functools
 import json
 import os
+import random
 import subprocess
 import sys
 
 
 def _run_js_in_jsc(jit, js, env):
-    return subprocess.check_call(
+    return subprocess.check_output(
         ['jsc', '-e', """
             function now() {
                 return preciseTime() * 1000;
@@ -41,7 +42,7 @@ def _run_js_in_jsc(jit, js, env):
 
 
 def _run_js_in_node(js, env):
-    return subprocess.check_call(
+    return subprocess.check_output(
         ['node', '-e', """
             function now() {
                 var hrTime = process.hrtime();
@@ -70,13 +71,16 @@ def _run_js_in_node(js, env):
 
 
 def _measure_ssr_ms(engine, react_path, bench_name, bench_path, measure_warm):
-    engine(
+    return engine(
         """
-            var reactCode = readFile(ENV.react_path);
+            var reactCode = readFile(ENV.react_path + '/react.min.js');
+            var reactDOMServerCode = readFile(ENV.react_path + '/react-dom-server.min.js');
             var START = now();
             globalEval(reactCode);
+            globalEval(reactDOMServerCode);
             var END = now();
-            if (typeof React !== 'object') throw new Error('React not laoded');
+            if (typeof React !== 'object') throw new Error('React not loaded');
+            if (typeof ReactDOMServer !== 'object') throw new Error('ReactDOMServer not loaded');
             report('factory_ms', END - START);
 
             globalEval(readFile(ENV.bench_path));
@@ -84,7 +88,7 @@ def _measure_ssr_ms(engine, react_path, bench_name, bench_path, measure_warm):
               throw new Error('benchmark not loaded');
             }
             var START = now();
-            var html = React.renderToString(React.createElement(Benchmark));
+            var html = ReactDOMServer.renderToString(React.createElement(Benchmark));
             html.charCodeAt(0);  // flatten ropes
             var END = now();
             report('ssr_' + ENV.bench_name + '_cold_ms', END - START);
@@ -93,12 +97,12 @@ def _measure_ssr_ms(engine, react_path, bench_name, bench_path, measure_warm):
             var trials = ENV.measure_warm ? 40 : 0;
 
             for (var i = 0; i < warmup; i++) {
-                React.renderToString(React.createElement(Benchmark));
+                ReactDOMServer.renderToString(React.createElement(Benchmark));
             }
 
             for (var i = 0; i < trials; i++) {
                 var START = now();
-                var html = React.renderToString(React.createElement(Benchmark));
+                var html = ReactDOMServer.renderToString(React.createElement(Benchmark));
                 html.charCodeAt(0);  // flatten ropes
                 var END = now();
                 report('ssr_' + ENV.bench_name + '_warm_ms', END - START);
@@ -114,36 +118,56 @@ def _measure_ssr_ms(engine, react_path, bench_name, bench_path, measure_warm):
 
 
 def _main():
-    if len(sys.argv) != 2:
-        sys.stderr.write("usage: measure.py react.min.js >out.txt\n")
+    if len(sys.argv) < 2 or len(sys.argv) % 2 == 0:
+        sys.stderr.write("usage: measure.py build-folder-a a.txt build-folder-b b.txt\n")
         return 1
-    react_path = sys.argv[1]
+    # [(react_path, out_path)]
+    react_paths = sys.argv[1::2]
+    files = [open(out_path, 'w') for out_path in sys.argv[2::2]]
 
     trials = 30
     sys.stderr.write("Measuring SSR for PE benchmark (%d trials)\n" % trials)
+    sys.stderr.write("_" * trials + "\n")
     for i in range(trials):
         for engine in [
             _run_js_in_jsc_jit,
             _run_js_in_jsc_nojit,
             _run_js_in_node
         ]:
-            _measure_ssr_ms(engine, react_path, 'pe', 'bench-pe-es5.js', False)
+            engines = range(len(react_paths))
+            random.shuffle(engines)
+            for i in engines:
+                out = _measure_ssr_ms(engine, react_paths[i], 'pe', 'bench-pe-es5.js', False)
+                files[i].write(out)
         sys.stderr.write(".")
         sys.stderr.flush()
     sys.stderr.write("\n")
+    sys.stderr.flush()
+
+    # You can set this to a number of trials you want to do with warm JIT.
+    # They are disabled by default because they are slower.
+    trials = 0
 
-    trials = 3
     sys.stderr.write("Measuring SSR for PE with warm JIT (%d slow trials)\n" % trials)
+    sys.stderr.write("_" * trials + "\n")
     for i in range(trials):
         for engine in [
             _run_js_in_jsc_jit,
             _run_js_in_jsc_nojit,
             _run_js_in_node
         ]:
-            _measure_ssr_ms(engine, react_path, 'pe', 'bench-pe-es5.js', True)
+            engines = range(len(react_paths))
+            random.shuffle(engines)
+            for i in engines:
+                out = _measure_ssr_ms(engine, react_paths[i], 'pe', 'bench-pe-es5.js', True)
+                files[i].write(out)
         sys.stderr.write(".")
         sys.stderr.flush()
     sys.stderr.write("\n")
+    sys.stderr.flush()
+
+    for f in files:
+        f.close()
 
 
 if __name__ == '__main__':
diff --git a/scripts/circleci/build_gh_pages.sh b/scripts/circleci/build_gh_pages.sh
new file mode 100755
index 000000000000..c0ecc81e35da
--- /dev/null
+++ b/scripts/circleci/build_gh_pages.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+set -e
+
+if [ "$CIRCLE_BRANCH" = "$REACT_WEBSITE_BRANCH" ]; then
+
+  GH_PAGES_DIR=`pwd`/../react-gh-pages
+
+  # check if directory exists (restored from cache)
+  if [ -d $GH_PAGES_DIR ]; then
+    pushd $GH_PAGES_DIR
+    git pull origin gh-pages
+    popd
+  else
+    git clone --branch gh-pages --depth=1 \
+      https://reactjs-bot@github.com/facebook/react.git \
+      $GH_PAGES_DIR
+  fi
+
+  pushd docs
+  bundle exec rake release
+  cd $GH_PAGES_DIR
+  git status
+  git --no-pager diff
+  if ! git diff-index --quiet HEAD --; then
+    git add -A .
+    git commit -m "Rebuild website"
+    git push origin gh-pages
+  fi
+  popd
+else
+  echo "Not building website"
+fi
diff --git a/scripts/circleci/set_up_github_keys.sh b/scripts/circleci/set_up_github_keys.sh
new file mode 100755
index 000000000000..302c40eef0e2
--- /dev/null
+++ b/scripts/circleci/set_up_github_keys.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+set -e
+
+if [ -n $GITHUB_TOKEN ]; then
+
+  GH_PAGES_DIR=`pwd`/../react-gh-pages
+  echo "machine github.com login reactjs-bot password $GITHUB_TOKEN" >~/.netrc
+  git config --global user.name "Circle CI"
+  git config --global user.email "circle@reactjs.org"
+
+fi
diff --git a/scripts/circleci/test_coverage.sh b/scripts/circleci/test_coverage.sh
new file mode 100755
index 000000000000..05a717c2a413
--- /dev/null
+++ b/scripts/circleci/test_coverage.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+set -e
+
+./node_modules/.bin/grunt jest:coverage
+if [ -z $CI_PULL_REQUEST ]; then
+  cat ./coverage/lcov.info | ./node_modules/.bin/coveralls
+fi
diff --git a/scripts/circleci/test_entry_point.sh b/scripts/circleci/test_entry_point.sh
new file mode 100755
index 000000000000..1c0e03add1c5
--- /dev/null
+++ b/scripts/circleci/test_entry_point.sh
@@ -0,0 +1,64 @@
+#!/bin/bash
+
+set -e
+
+COMMANDS_TO_RUN=()
+
+# We split these to be approximately equal chunks of four. As of this writing,
+# times were around:
+# - 3:30 test_coverage.sh
+# - 2:00 test_fiber.sh
+# - 1:15 test_html_generation.sh
+# - 1:15 grunt build
+# with everything else < 0:30.
+
+if [ $((1 % CIRCLE_NODE_TOTAL)) -eq "$CIRCLE_NODE_INDEX" ]; then
+  COMMANDS_TO_RUN+=('./scripts/circleci/test_coverage.sh')
+fi
+
+if [ $((2 % CIRCLE_NODE_TOTAL)) -eq "$CIRCLE_NODE_INDEX" ]; then
+  COMMANDS_TO_RUN+=('./scripts/circleci/test_html_generation.sh')
+fi
+
+# These seem out of order but extract-errors must be run after jest.
+if [ $((0 % CIRCLE_NODE_TOTAL)) -eq "$CIRCLE_NODE_INDEX" ]; then
+  COMMANDS_TO_RUN+=('./node_modules/.bin/gulp lint')
+  COMMANDS_TO_RUN+=('node ./scripts/prettier/index')
+  COMMANDS_TO_RUN+=('./node_modules/.bin/gulp flow')
+  COMMANDS_TO_RUN+=('./node_modules/.bin/grunt build')
+  COMMANDS_TO_RUN+=('./scripts/circleci/test_extract_errors.sh')
+  COMMANDS_TO_RUN+=('./scripts/circleci/track_stats.sh')
+  COMMANDS_TO_RUN+=('node ./addons/test')
+fi
+
+RETURN_CODES=()
+FAILURE=0
+
+printf "Node #%s (%s total). " "$CIRCLE_NODE_INDEX" "$CIRCLE_NODE_TOTAL"
+if [ -n "${COMMANDS_TO_RUN[0]}" ]; then
+  echo "Preparing to run commands:"
+  for cmd in "${COMMANDS_TO_RUN[@]}"; do
+    echo "- $cmd"
+  done
+
+  for cmd in "${COMMANDS_TO_RUN[@]}"; do
+    echo
+    echo "$ $cmd"
+    set +e
+    $cmd
+    rc=$?
+    set -e
+    RETURN_CODES+=($rc)
+    if [ $rc -ne 0 ]; then
+      FAILURE=$rc
+    fi
+  done
+
+  echo
+  for i in "${!COMMANDS_TO_RUN[@]}"; do
+    echo "Received return code ${RETURN_CODES[i]} from: ${COMMANDS_TO_RUN[i]}"
+  done
+  exit $FAILURE
+else
+  echo "No commands to run."
+fi
diff --git a/scripts/circleci/test_extract_errors.sh b/scripts/circleci/test_extract_errors.sh
new file mode 100755
index 000000000000..5169752509e9
--- /dev/null
+++ b/scripts/circleci/test_extract_errors.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+set -e
+
+./node_modules/.bin/gulp react:extract-errors
+git checkout -- scripts/error-codes/codes.json
diff --git a/scripts/circleci/test_html_generation.sh b/scripts/circleci/test_html_generation.sh
new file mode 100755
index 000000000000..0bedb26aea4e
--- /dev/null
+++ b/scripts/circleci/test_html_generation.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+set -e
+
+echo 'Testing in server-render (HTML generation) mode...'
+printf '\nmodule.exports.useCreateElement = false;\n' \
+  >> src/renderers/dom/shared/ReactDOMFeatureFlags.js
+./node_modules/.bin/grunt jest:normal
+git checkout -- src/renderers/dom/shared/ReactDOMFeatureFlags.js
diff --git a/scripts/circleci/track_stats.sh b/scripts/circleci/track_stats.sh
new file mode 100755
index 000000000000..a8a3eae1fad2
--- /dev/null
+++ b/scripts/circleci/track_stats.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+set -e
+
+ALL_FILES=`find src -name '*.js' | grep -v umd/ | grep -v __tests__ | grep -v __mocks__`
+COUNT_ALL_FILES=`echo "$ALL_FILES" | wc -l`
+COUNT_WITH_FLOW=`grep '@flow' $ALL_FILES | perl -pe 's/:.+//' | wc -l`
+node scripts/facts-tracker/index.js "flow-files" "$COUNT_WITH_FLOW/$COUNT_ALL_FILES"
diff --git a/scripts/circleci/upload_build.sh b/scripts/circleci/upload_build.sh
new file mode 100755
index 000000000000..0558ba8dd057
--- /dev/null
+++ b/scripts/circleci/upload_build.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+set -e
+
+if [ -z $CI_PULL_REQUEST ] && [ -n "$BUILD_SERVER_ENDPOINT" ]; then
+  curl \
+    -F "react=@build/react.js" \
+    -F "react.min=@build/react.min.js" \
+    -F "react-with-addons=@build/react-with-addons.js" \
+    -F "react-with-addons.min=@build/react-with-addons.min.js" \
+    -F "react-dom=@build/react-dom.js" \
+    -F "react-dom.min=@build/react-dom.min.js" \
+    -F "react-dom-server=@build/react-dom-server.js" \
+    -F "react-dom-server.min=@build/react-dom-server.min.js" \
+    -F "npm-react=@build/packages/react.tgz" \
+    -F "npm-react-dom=@build/packages/react-dom.tgz" \
+    -F "commit=$CIRCLE_SHA1" \
+    -F "date=`git log --format='%ct' -1`" \
+    -F "pull_request=false" \
+    -F "token=$BUILD_SERVER_TOKEN" \
+    -F "branch=$CIRCLE_BRANCH" \
+    $BUILD_SERVER_ENDPOINT
+fi
diff --git a/scripts/error-codes/README.md b/scripts/error-codes/README.md
new file mode 100644
index 000000000000..aefb87b6fd9e
--- /dev/null
+++ b/scripts/error-codes/README.md
@@ -0,0 +1,14 @@
+The error code system substitutes React's invariant error messages with error IDs to provide a better debugging support in production. Check out the blog post [here](https://facebook.github.io/react/blog/2016/07/11/introducing-reacts-error-code-system.html).
+
+## Note for cutting a new React release
+1. For each release, we run `gulp react:extract-errors` to update the error codes before calling `npm run build`. The build process uses `codes.json` for a production (minified) build; there should be no warning like `Error message "foo" cannot be found` for a successful release.
+2. The updated `codes.json` file should be synced back to the master branch. The error decoder page in our documentation site uses `codes.json` from master; if the json file has been updated, the docs site should also be rebuilt (`rake copy_error_codes` is included in the default `rake release` task).
+3. It's not recommended to run `gulp react:extract-errors` directly in master since it may contain commits that are not cherry-picked to a release branch. These error messages might be changed/removed before cutting a new release, and we don't want to add intermediate/temporary error messages to `codes.json`. However, if a PR changes an existing error message and there's a specific production test (which is rare), it's ok to update `codes.json` for that. Please use `gulp react:extract-errors` and don't edit the file manually.
+
+## Structure
+The error code system consists of 5 parts:
+- [`codes.json`](https://github.com/facebook/react/blob/master/scripts/error-codes/codes.json) contains the mapping from IDs to error messages. This file is generated by the Gulp plugin and is used by both the Babel plugin and the error decoder page in our documentation. This file is append-only, which means an existing code in the file will never be changed/removed.
+- [`gulp-extract-errors.js`](https://github.com/facebook/react/blob/master/scripts/error-codes/gulp-extract-errors.js) is a gulp plugin that traverses our codebase and updates `codes.json`. Use it by calling `gulp react:extract-errors`.
+- [`dev-expression-with-codes.js`](https://github.com/facebook/react/blob/master/scripts/error-codes/dev-expression-with-codes.js) is a Babel pass that rewrites error messages to IDs for a production (minified) build. Notice that this plugin is not in `.babelrc`; it's being used in the [`gulpfile.js`](https://github.com/facebook/react/blob/master/gulpfile.js#L21) and it has to be run before [`rewrite-modules`](https://github.com/facebook/fbjs/blob/master/packages/babel-preset-fbjs/plugins/rewrite-modules.js) since we search for `require('invariant')` but not `require('./invariant')`.
+- [`reactProdInvariant.js`](https://github.com/facebook/react/blob/master/src/shared/utils/reactProdInvariant.js) is the replacement for `invariant` in production. This file gets imported by the Babel plugin and should _not_ be used manually.
+- [`ErrorDecoderComponent`](https://github.com/facebook/react/blob/master/docs/_js/ErrorDecoderComponent.js) is a React component that lives at https://facebook.github.io/react/docs/error-decoder.html. This page takes parameters like `?invariant=109&args[]=Foo` and displays a corresponding error message. Our documentation site's [`Rakefile`](https://github.com/facebook/react/blob/master/docs/Rakefile#L64-L69) has a task (`bundle exec rake copy_error_codes`) for adding the latest `codes.json` to the error decoder page. This task is included in the default `bundle exec rake release` task.
diff --git a/scripts/error-codes/Types.js b/scripts/error-codes/Types.js
new file mode 100644
index 000000000000..5f7fe7f0062c
--- /dev/null
+++ b/scripts/error-codes/Types.js
@@ -0,0 +1,13 @@
+/**
+ * Copyright (c) 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.
+ *
+ * @flow
+ */
+'use strict';
+
+/*:: export type ErrorMap = { [id: string]: string; }; */
diff --git a/scripts/error-codes/__tests__/dev-expression-with-codes-test.js b/scripts/error-codes/__tests__/dev-expression-with-codes-test.js
new file mode 100644
index 000000000000..4a459a550829
--- /dev/null
+++ b/scripts/error-codes/__tests__/dev-expression-with-codes-test.js
@@ -0,0 +1,145 @@
+/**
+ * Copyright (c) 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.
+ */
+/* eslint-disable quotes */
+'use strict';
+
+let babel = require('babel-core');
+let devExpressionWithCodes = require('../dev-expression-with-codes');
+
+function transform(input) {
+  return babel.transform(input, {
+    plugins: [devExpressionWithCodes],
+  }).code;
+}
+
+function compare(input, output) {
+  var compiled = transform(input);
+  expect(compiled).toEqual(output);
+}
+
+var oldEnv;
+
+describe('dev-expression', () => {
+  beforeEach(() => {
+    oldEnv = process.env.NODE_ENV;
+    process.env.NODE_ENV = '';
+  });
+
+  afterEach(() => {
+    process.env.NODE_ENV = oldEnv;
+  });
+
+  it('should replace __DEV__ in if', () => {
+    compare(
+`
+if (__DEV__) {
+  console.log('foo')
+}`,
+`
+if (process.env.NODE_ENV !== 'production') {
+  console.log('foo');
+}`
+    );
+  });
+
+  it('should replace warning calls', () => {
+    compare(
+      "warning(condition, 'a %s b', 'c');",
+      "process.env.NODE_ENV !== 'production' ? warning(condition, 'a %s b', 'c') : void 0;"
+    );
+  });
+
+  it("should add `reactProdInvariant` when it finds `require('invariant')`", () => {
+    compare(
+"var invariant = require('invariant');",
+
+`var _prodInvariant = require('reactProdInvariant');
+
+var invariant = require('invariant');`
+    );
+  });
+
+  it('should replace simple invariant calls', () => {
+    compare(
+      "invariant(condition, 'Do not override existing functions.');",
+      "var _prodInvariant = require('reactProdInvariant');\n\n" +
+      "!condition ? " +
+      "process.env.NODE_ENV !== 'production' ? " +
+      "invariant(false, 'Do not override existing functions.') : " +
+      `_prodInvariant('16') : void 0;`
+    );
+  });
+
+  it("should only add `reactProdInvariant` once", () => {
+    var expectedInvariantTransformResult = (
+      "!condition ? " +
+      "process.env.NODE_ENV !== 'production' ? " +
+      "invariant(false, 'Do not override existing functions.') : " +
+      `_prodInvariant('16') : void 0;`
+    );
+
+    compare(
+`var invariant = require('invariant');
+invariant(condition, 'Do not override existing functions.');
+invariant(condition, 'Do not override existing functions.');`,
+
+`var _prodInvariant = require('reactProdInvariant');
+
+var invariant = require('invariant');
+${expectedInvariantTransformResult}
+${expectedInvariantTransformResult}`
+    );
+  });
+
+  it('should support invariant calls with args', () => {
+    compare(
+      "invariant(condition, 'Expected %s target to be an array; got %s', 'foo', 'bar');",
+      "var _prodInvariant = require('reactProdInvariant');\n\n" +
+      "!condition ? " +
+      "process.env.NODE_ENV !== 'production' ? " +
+      "invariant(false, 'Expected %s target to be an array; got %s', 'foo', 'bar') : " +
+      `_prodInvariant('7', 'foo', 'bar') : void 0;`
+    );
+  });
+
+  it('should support invariant calls with a concatenated template string and args', () => {
+    compare(
+      "invariant(condition, 'Expected a component class, ' + 'got %s.' + '%s', 'Foo', 'Bar');",
+      "var _prodInvariant = require('reactProdInvariant');\n\n" +
+      "!condition ? " +
+      "process.env.NODE_ENV !== 'production' ? " +
+      "invariant(false, 'Expected a component class, got %s.%s', 'Foo', 'Bar') : " +
+      `_prodInvariant('18', 'Foo', 'Bar') : void 0;`
+    );
+  });
+
+  it('should warn in non-test envs if the error message cannot be found', () => {
+    spyOn(console, 'warn');
+    transform("invariant(condition, 'a %s b', 'c');");
+
+    expect(console.warn.calls.count()).toBe(1);
+    expect(console.warn.calls.argsFor(0)[0]).toBe(
+      'Error message "a %s b" ' +
+      'cannot be found. The current React version ' +
+      'and the error map are probably out of sync. ' +
+      'Please run `gulp react:extract-errors` before building React.'
+    );
+  });
+
+  it('should not warn in test env if the error message cannot be found', () => {
+    process.env.NODE_ENV = 'test';
+
+    spyOn(console, 'warn');
+    transform("invariant(condition, 'a %s b', 'c');");
+
+    expect(console.warn.calls.count()).toBe(0);
+
+    process.env.NODE_ENV = '';
+  });
+});
diff --git a/scripts/error-codes/__tests__/evalToString-test.js b/scripts/error-codes/__tests__/evalToString-test.js
new file mode 100644
index 000000000000..efc6b4bb6958
--- /dev/null
+++ b/scripts/error-codes/__tests__/evalToString-test.js
@@ -0,0 +1,36 @@
+/**
+ * Copyright (c) 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.
+ */
+'use strict';
+
+var evalToString = require('../evalToString');
+var babylon = require('babylon');
+
+var parse = (source) => babylon.parse(
+  `(${source});`
+).program.body[0].expression; // quick way to get an exp node
+
+var parseAndEval = (source) => evalToString(parse(source));
+
+describe('evalToString', () => {
+  it('should support StringLiteral', () => {
+    expect(parseAndEval(`'foobar'`)).toBe('foobar');
+    expect(parseAndEval(`'yowassup'`)).toBe('yowassup');
+  });
+
+  it('should support string concat (`+`)', () => {
+    expect(parseAndEval(`'foo ' + 'bar'`)).toBe('foo bar');
+  });
+
+  it('should throw when it finds other types', () => {
+    expect(() => parseAndEval(`'foo ' + true`)).toThrowError(/Unsupported type/);
+    expect(() => parseAndEval(`'foo ' + 3`)).toThrowError(/Unsupported type/);
+    expect(() => parseAndEval(`'foo ' + null`)).toThrowError(/Unsupported type/);
+    expect(() => parseAndEval(`'foo ' + undefined`)).toThrowError(/Unsupported type/);
+  });
+});
diff --git a/scripts/error-codes/__tests__/invertObject-test.js b/scripts/error-codes/__tests__/invertObject-test.js
new file mode 100644
index 000000000000..1b8c35c6febb
--- /dev/null
+++ b/scripts/error-codes/__tests__/invertObject-test.js
@@ -0,0 +1,54 @@
+/**
+ * Copyright (c) 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.
+ */
+'use strict';
+
+var invertObject = require('../invertObject');
+
+var objectValues = (target) => Object.keys(target).map((key) => target[key]);
+
+describe('invertObject', () => {
+  it('should return an empty object for an empty input', () => {
+    expect(invertObject({})).toEqual({});
+  });
+
+  it('should invert key-values', () => {
+    expect(invertObject({
+      a: '3',
+      b: '4',
+    })).toEqual({
+      3: 'a',
+      4: 'b',
+    });
+  });
+
+  it('should take the last value when there\'re duplications in vals', () => {
+    expect(invertObject({
+      a: '3',
+      b: '4',
+      c: '3',
+    })).toEqual({
+      4: 'b',
+      3: 'c',
+    });
+  });
+
+  it('should perserve the original order', () => {
+    expect(Object.keys(invertObject({
+      a: '3',
+      b: '4',
+      c: '3',
+    }))).toEqual(['3', '4']);
+
+    expect(objectValues(invertObject({
+      a: '3',
+      b: '4',
+      c: '3',
+    }))).toEqual(['c', 'b']);
+  });
+});
diff --git a/scripts/error-codes/codes.json b/scripts/error-codes/codes.json
new file mode 100644
index 000000000000..d29e8bd0435a
--- /dev/null
+++ b/scripts/error-codes/codes.json
@@ -0,0 +1,148 @@
+{
+  "0": "React.addons.createFragment(...): Encountered an invalid child; DOM elements are not valid children of React components.",
+  "1": "update(): expected target of %s to be an array; got %s.",
+  "2": "update(): expected spec of %s to be an array; got %s. Did you forget to wrap your parameter in an array?",
+  "3": "update(): You provided a key path to update() that did not contain one of %s. Did you forget to include {%s: ...}?",
+  "4": "Cannot have more than one key in an object with %s",
+  "5": "update(): %s expects a spec of type 'object'; got %s",
+  "6": "update(): %s expects a target of type 'object'; got %s",
+  "7": "Expected %s target to be an array; got %s",
+  "8": "update(): expected spec of %s to be an array of arrays; got %s. Did you forget to wrap your parameters in an array?",
+  "9": "update(): expected spec of %s to be a function; got %s.",
+  "10": "findAllInRenderedTree(...): instance must be a composite component",
+  "11": "TestUtils.scryRenderedDOMComponentsWithClass expects a className as a second argument.",
+  "12": "ReactShallowRenderer render(): Invalid component element.%s",
+  "13": "ReactShallowRenderer render(): Shallow rendering works only with custom components, not primitives (%s). Instead of calling `.render(el)` and inspecting the rendered output, look at `el.props` directly instead.",
+  "14": "TestUtils.Simulate expects a component instance and not a ReactElement.TestUtils.Simulate will not work if you are using shallow rendering.",
+  "15": "reactComponentExpect(...): instance must be a composite component",
+  "16": "Do not override existing functions.",
+  "17": "All native instances should have a tag.",
+  "18": "Expected a component class, got %s.%s",
+  "19": "Expect a native root tag, instead got %s",
+  "20": "RawText \"%s\" must be wrapped in an explicit <Text> component.",
+  "21": "findNodeHandle(...): Argument is not a component (type: %s, keys: %s)",
+  "22": "findNodeHandle(...): Unable to find node handle for unmounted component.",
+  "23": "onlyChild must be passed a children with exactly one child.",
+  "24": "Mismatched list of contexts in callback queue",
+  "25": "Trying to release an instance into a pool of a different type.",
+  "26": "Unexpected node: %s",
+  "27": "Transaction.perform(...): Cannot initialize a transaction when there is already an outstanding transaction.",
+  "28": "Transaction.closeAll(): Cannot close transaction when none are open.",
+  "29": "accumulate(...): Accumulated items must be not be null or undefined.",
+  "30": "accumulateInto(...): Accumulated items must not be null or undefined.",
+  "31": "Objects are not valid as a React child (found: %s).%s",
+  "32": "Unable to find element with ID %s.",
+  "33": "getNodeFromInstance: Invalid argument.",
+  "34": "React DOM tree root should always have a node reference.",
+  "35": "isAncestor: Invalid argument.",
+  "36": "getParentInstance: Invalid argument.",
+  "37": "_registerComponent(...): Target container is not a DOM element.",
+  "38": "parentComponent must be a valid React Component",
+  "39": "ReactDOM.render(): Invalid component element.%s",
+  "40": "unmountComponentAtNode(...): Target container is not a DOM element.",
+  "41": "mountComponentIntoNode(...): Target container is not valid.",
+  "42": "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",
+  "43": "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.",
+  "44": "findDOMNode was called on an unmounted component.",
+  "45": "Element appears to be neither ReactComponent nor DOMNode (keys: %s)",
+  "46": "renderToString(): You must pass a valid ReactElement.",
+  "47": "renderToStaticMarkup(): You must pass a valid ReactElement.",
+  "48": "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.",
+  "49": "DOMProperty: Properties that have side effects must use property: %s",
+  "50": "DOMProperty: Value can be one of boolean, overloaded boolean, or numeric value, but not a combination: %s",
+  "51": "dangerouslyRenderMarkup(...): 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.",
+  "52": "dangerouslyRenderMarkup(...): Missing markup.",
+  "53": "Danger: Assigning to an already-occupied result index.",
+  "54": "Danger: Did not assign to every index of resultList.",
+  "55": "Danger: Expected markup to render %s nodes, but rendered %s.",
+  "56": "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.",
+  "57": "dangerouslyReplaceNodeWithMarkup(...): Missing markup.",
+  "58": "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().",
+  "59": "%s is a void element tag and must not have `children` or use `props.dangerouslySetInnerHTML`.%s",
+  "60": "Can only set one of `children` or `props.dangerouslySetInnerHTML`.",
+  "61": "`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. Please visit https://fb.me/react-invariant-dangerously-set-inner-html for more information.",
+  "62": "The `style` prop expects a mapping from style properties to values, not a string. For example, style={{marginRight: spacing + 'em'}} when using JSX.%s",
+  "63": "Must be mounted to trap events",
+  "64": "trapBubbledEvent(...): Requires node to be rendered.",
+  "65": "Invalid tag: %s",
+  "66": "<%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.",
+  "67": "Missing closing comment for text component %s",
+  "68": "Expected devtool events to fire for the child before its parent includes it in onSetChildren().",
+  "69": "Expected onSetDisplayName() to fire for the child before its parent includes it in onSetChildren().",
+  "70": "Expected onSetChildren() or onSetText() to fire for the child before its parent includes it in onSetChildren().",
+  "71": "Expected onMountComponent() to fire for the child before its parent includes it in onSetChildren().",
+  "72": "Expected onSetParent() and onSetChildren() to be consistent (%s has parents %s and %s).",
+  "73": "ReactClassInterface: You are attempting to override `%s` from your class specification. Ensure that your method names do not overlap with React methods.",
+  "74": "ReactClassInterface: You are attempting to define `%s` on your component more than once. This conflict may be due to a mixin.",
+  "75": "ReactClass: You're attempting to use a component class or function as a mixin. Instead, just use a regular object.",
+  "76": "ReactClass: You're attempting to use a component as a mixin. Instead, just use a regular object.",
+  "77": "ReactClass: Unexpected spec policy %s for key %s when mixing in component specs.",
+  "78": "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.",
+  "79": "ReactClass: You are attempting to define `%s` on your component more than once. This conflict may be due to a mixin.",
+  "80": "mergeIntoWithNoDuplicateKeys(): Cannot merge non-objects.",
+  "81": "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.",
+  "82": "%s.getInitialState(): must return an object or null",
+  "83": "createClass(...): Class specification must implement a `render` method.",
+  "84": "%s: %s type `%s` is invalid; it must be a function, usually from React.PropTypes.",
+  "85": "setState(...): takes an object of state variables to update or a function which returns an object of state variables.",
+  "86": "SimpleEventPlugin: Unhandled event type, `%s`.",
+  "87": "Cannot provide a checkedLink and a valueLink. If you want to use checkedLink, you probably don't want to use valueLink and vice versa.",
+  "88": "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.",
+  "89": "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",
+  "90": "ReactDOMInput: Mixing React and non-React radio inputs with the same `name` is not supported.",
+  "91": "`dangerouslySetInnerHTML` does not make sense on <textarea>.",
+  "92": "If you supply `defaultValue` on a <textarea>, do not pass children.",
+  "93": "<textarea> can only have at most one child.",
+  "94": "Expected %s listener to be a function, instead got type %s",
+  "95": "processEventQueue(): Additional events were enqueued while processing an event queue. Support for this has not yet been implemented.",
+  "96": "EventPluginRegistry: Cannot inject event plugins that do not exist in the plugin ordering, `%s`.",
+  "97": "EventPluginRegistry: Event plugins must implement an `extractEvents` method, but `%s` does not.",
+  "98": "EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.",
+  "99": "EventPluginHub: More than one plugin attempted to publish the same event name, `%s`.",
+  "100": "EventPluginHub: More than one plugin attempted to publish the same registration name, `%s`.",
+  "101": "EventPluginRegistry: Cannot inject event plugin ordering more than once. You are likely trying to load more than one copy of React.",
+  "102": "EventPluginRegistry: Cannot inject two different event plugins using the same name, `%s`.",
+  "103": "executeDirectDispatch(...): Invalid `event`.",
+  "104": "ReactCompositeComponent: injectEnvironment() can only be called once.",
+  "105": "%s(...): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.",
+  "106": "%s.state: must be set to an object or null",
+  "107": "%s.getChildContext(): childContextTypes must be defined in order to use getChildContext().",
+  "108": "%s.getChildContext(): key \"%s\" is not defined in childContextTypes.",
+  "109": "%s.render(): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.",
+  "110": "Stateless function components cannot have refs.",
+  "111": "There is no registered component for the tag %s",
+  "112": "getNextDescendantID(%s, %s): Received an invalid React DOM ID.",
+  "113": "getNextDescendantID(...): React has made an invalid assumption about the DOM hierarchy. Expected `%s` to be an ancestor of `%s`.",
+  "114": "getFirstCommonAncestorID(%s, %s): Expected a valid React DOM ID: %s",
+  "115": "traverseParentPath(...): Cannot traverse from and to the same ID, `%s`.",
+  "116": "traverseParentPath(%s, %s, ...): Cannot traverse from two IDs that do not have a parent path.",
+  "117": "traverseParentPath(%s, %s, ...): Detected an infinite loop while traversing the React DOM ID tree. This may be due to malformed IDs: %s",
+  "118": "updateTextContent called on non-empty component.",
+  "119": "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).",
+  "120": "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).",
+  "121": "performUpdateIfNecessary: Unexpected batch number (current %s, pending %s)",
+  "122": "%s(...): Expected the last optional `callback` argument to be a function. Instead received: %s.",
+  "123": "ReactUpdates: must inject a reconcile transaction class and batching strategy",
+  "124": "Expected flush transaction's stored dirty-components length (%s) to match dirty-components array length (%s).",
+  "125": "ReactUpdates.asap: Can't enqueue an asap callback in a context whereupdates are not being batched.",
+  "126": "ReactUpdates: must provide a reconcile transaction class",
+  "127": "ReactUpdates: must provide a batching strategy",
+  "128": "ReactUpdates: must provide a batchedUpdates() function",
+  "129": "ReactUpdates: must provide an isBatchingUpdates boolean attribute",
+  "130": "Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: %s.%s",
+  "131": "Encountered invalid React node of type %s",
+  "132": "Ended a touch event which was not counted in trackedTouchCount.",
+  "133": "Touch object is missing identifier",
+  "134": "Touch data should have been recorded on start",
+  "135": "Cannot find single active touch",
+  "136": "Attempted to update component `%s` that has already been unmounted (or failed to mount).",
+  "137": "%s is a void element tag and must neither have `children` nor use `dangerouslySetInnerHTML`.%s",
+  "138": "Touch object is missing identifier.",
+  "139": "ReactTestRenderer: .update() can't be called after unmount.",
+  "140": "Expected hook events to fire for the child before its parent includes it in onSetChildren().",
+  "141": "Expected onSetChildren() to fire for a container child before its parent includes it in onSetChildren().",
+  "142": "Expected onBeforeMountComponent() parent and onSetChildren() to be consistent (%s has parents %s and %s).",
+  "143": "React.Children.only expected to receive a single React element child.",
+  "144": "Item must have been set",
+  "145": "hostContainerInfo should be populated before getPublicInstance is called."
+}
diff --git a/scripts/error-codes/dev-expression-with-codes.js b/scripts/error-codes/dev-expression-with-codes.js
new file mode 100644
index 000000000000..9862a20f51a7
--- /dev/null
+++ b/scripts/error-codes/dev-expression-with-codes.js
@@ -0,0 +1,190 @@
+/**
+ * Copyright (c) 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.
+ */
+'use strict';
+
+var evalToString = require('./evalToString');
+var existingErrorMap = require('./codes.json');
+var invertObject = require('./invertObject');
+
+var errorMap = invertObject(existingErrorMap);
+
+module.exports = function(babel) {
+  var t = babel.types;
+
+  var SEEN_SYMBOL = Symbol('dev-expression-with-codes.seen');
+
+  // Generate a hygienic identifier
+  function getProdInvariantIdentifier(path, localState) {
+    if (!localState.prodInvariantIdentifier) {
+      localState.prodInvariantIdentifier = path.scope.generateUidIdentifier('prodInvariant');
+      path.scope.getProgramParent().push({
+        id: localState.prodInvariantIdentifier,
+        init: t.callExpression(
+          t.identifier('require'),
+          [t.stringLiteral('reactProdInvariant')]
+        ),
+      });
+    }
+    return localState.prodInvariantIdentifier;
+  }
+
+  var DEV_EXPRESSION = t.binaryExpression(
+    '!==',
+    t.memberExpression(
+      t.memberExpression(
+        t.identifier('process'),
+        t.identifier('env'),
+        false
+      ),
+      t.identifier('NODE_ENV'),
+      false
+    ),
+    t.stringLiteral('production')
+  );
+
+  return {
+    pre: function() {
+      this.prodInvariantIdentifier = null;
+    },
+
+    visitor: {
+      Identifier: {
+        enter: function(path) {
+          // Do nothing when testing
+          if (process.env.NODE_ENV === 'test') {
+            return;
+          }
+          // Replace __DEV__ with process.env.NODE_ENV !== 'production'
+          if (path.isIdentifier({name: '__DEV__'})) {
+            path.replaceWith(DEV_EXPRESSION);
+          }
+        },
+      },
+      CallExpression: {
+        exit: function(path) {
+          var node = path.node;
+          // Ignore if it's already been processed
+          if (node[SEEN_SYMBOL]) {
+            return;
+          }
+          // Insert `var PROD_INVARIANT = require('reactProdInvariant');`
+          // before all `require('invariant')`s.
+          // NOTE it doesn't support ES6 imports yet.
+          if (
+            path.get('callee').isIdentifier({name: 'require'}) &&
+            path.get('arguments')[0] &&
+            path.get('arguments')[0].isStringLiteral({value: 'invariant'})
+          ) {
+            node[SEEN_SYMBOL] = true;
+            getProdInvariantIdentifier(path, this);
+          } else if (path.get('callee').isIdentifier({name: 'invariant'})) {
+            // Turns this code:
+            //
+            // invariant(condition, argument, 'foo', 'bar');
+            //
+            // into this:
+            //
+            // if (!condition) {
+            //   if ("production" !== process.env.NODE_ENV) {
+            //     invariant(false, argument, 'foo', 'bar');
+            //   } else {
+            //     PROD_INVARIANT('XYZ', 'foo', 'bar');
+            //   }
+            // }
+            //
+            // where
+            // - `XYZ` is an error code: a unique identifier (a number string)
+            //   that references a verbose error message.
+            //   The mapping is stored in `scripts/error-codes/codes.json`.
+            // - `PROD_INVARIANT` is the `reactProdInvariant` function that always throws with an error URL like
+            //   http://facebook.github.io/react/docs/error-decoder.html?invariant=XYZ&args[]=foo&args[]=bar
+            //
+            // Specifically this does 3 things:
+            // 1. Checks the condition first, preventing an extra function call.
+            // 2. Adds an environment check so that verbose error messages aren't
+            //    shipped to production.
+            // 3. Rewrites the call to `invariant` in production to `reactProdInvariant`
+            //   - `reactProdInvariant` is always renamed to avoid shadowing
+            // The generated code is longer than the original code but will dead
+            // code removal in a minifier will strip that out.
+            var condition = node.arguments[0];
+            var errorMsgLiteral = evalToString(node.arguments[1]);
+
+            var prodErrorId = errorMap[errorMsgLiteral];
+            if (prodErrorId === undefined) {
+              // The error cannot be found in the map.
+              node[SEEN_SYMBOL] = true;
+              if (process.env.NODE_ENV !== 'test') {
+                console.warn(
+                  'Error message "' + errorMsgLiteral +
+                  '" cannot be found. The current React version ' +
+                  'and the error map are probably out of sync. ' +
+                  'Please run `gulp react:extract-errors` before building React.'
+                );
+              }
+              return;
+            }
+
+            var devInvariant = t.callExpression(node.callee, [
+              t.booleanLiteral(false),
+              t.stringLiteral(errorMsgLiteral),
+            ].concat(node.arguments.slice(2)));
+
+            devInvariant[SEEN_SYMBOL] = true;
+
+            var localInvariantId = getProdInvariantIdentifier(path, this);
+            var prodInvariant = t.callExpression(localInvariantId, [
+              t.stringLiteral(prodErrorId),
+            ].concat(node.arguments.slice(2)));
+
+            prodInvariant[SEEN_SYMBOL] = true;
+            path.replaceWith(t.ifStatement(
+              t.unaryExpression('!', condition),
+              t.blockStatement([
+                t.ifStatement(
+                  DEV_EXPRESSION,
+                  t.blockStatement([
+                    t.expressionStatement(devInvariant),
+                  ]),
+                  t.blockStatement([
+                    t.expressionStatement(prodInvariant),
+                  ])
+                ),
+              ])
+            ));
+          } else if (path.get('callee').isIdentifier({name: 'warning'})) {
+            // Turns this code:
+            //
+            // warning(condition, argument, argument);
+            //
+            // into this:
+            //
+            // if ("production" !== process.env.NODE_ENV) {
+            //   warning(condition, argument, argument);
+            // }
+            //
+            // The goal is to strip out warning calls entirely in production. We
+            // don't need the same optimizations for conditions that we use for
+            // invariant because we don't care about an extra call in __DEV__
+
+            node[SEEN_SYMBOL] = true;
+            path.replaceWith(t.ifStatement(
+              DEV_EXPRESSION,
+              t.blockStatement([
+                t.expressionStatement(
+                  node
+                ),
+              ])
+            ));
+          }
+        },
+      },
+    },
+  };
+};
diff --git a/scripts/error-codes/evalToString.js b/scripts/error-codes/evalToString.js
new file mode 100644
index 000000000000..a8a0b9c6b1df
--- /dev/null
+++ b/scripts/error-codes/evalToString.js
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 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.
+ *
+ * @flow
+ */
+'use strict';
+
+function evalToString(ast/* : Object */)/* : string */ {
+  switch (ast.type) {
+    case 'StringLiteral':
+      return ast.value;
+    case 'BinaryExpression': // `+`
+      if (ast.operator !== '+') {
+        throw new Error('Unsupported binary operator ' + ast.operator);
+      }
+      return evalToString(ast.left) + evalToString(ast.right);
+    default:
+      throw new Error('Unsupported type ' + ast.type);
+  }
+}
+
+module.exports = evalToString;
diff --git a/scripts/error-codes/gulp-extract-errors.js b/scripts/error-codes/gulp-extract-errors.js
new file mode 100644
index 000000000000..cc873db9d4b0
--- /dev/null
+++ b/scripts/error-codes/gulp-extract-errors.js
@@ -0,0 +1,117 @@
+/**
+ * Copyright (c) 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.
+ */
+'use strict';
+
+var babylon = require('babylon');
+var fs = require('fs');
+var gutil = require('gulp-util');
+var path = require('path');
+var through = require('through2');
+var traverse = require('babel-traverse').default;
+
+var evalToString = require('./evalToString');
+var invertObject = require('./invertObject');
+
+var PLUGIN_NAME = 'extract-errors';
+
+var babylonOptions = {
+  sourceType: 'module',
+  // As a parser, babylon has its own options and we can't directly
+  // import/require a babel preset. It should be kept **the same** as
+  // the `babel-plugin-syntax-*` ones specified in
+  // https://github.com/facebook/fbjs/blob/master/babel-preset/configure.js
+  plugins: [
+    'classProperties',
+    'flow',
+    'jsx',
+    'trailingFunctionCommas',
+    'objectRestSpread',
+  ],
+};
+
+module.exports = function(opts) {
+  if (!opts || !('errorMapFilePath' in opts)) {
+    throw new gutil.PluginError(
+      PLUGIN_NAME,
+      'Missing options. Ensure you pass an object with `errorMapFilePath`.'
+    );
+  }
+
+  var errorMapFilePath = opts.errorMapFilePath;
+  var existingErrorMap;
+  try {
+    existingErrorMap = require(
+      path.join(__dirname, path.basename(errorMapFilePath))
+    );
+  } catch (e) {
+    existingErrorMap = {};
+  }
+
+  var allErrorIDs = Object.keys(existingErrorMap);
+  var currentID;
+
+  if (allErrorIDs.length === 0) { // Map is empty
+    currentID = 0;
+  } else {
+    currentID = Math.max.apply(null, allErrorIDs) + 1;
+  }
+
+  // Here we invert the map object in memory for faster error code lookup
+  existingErrorMap = invertObject(existingErrorMap);
+
+  function transform(file, enc, cb) {
+    if (file.isNull()) {
+      cb(null, file);
+      return;
+    }
+
+    if (file.isStream()) {
+      cb(new gutil.PluginError(PLUGIN_NAME, 'Streaming not supported'));
+      return;
+    }
+
+    var source = file.contents.toString();
+    var ast = babylon.parse(source, babylonOptions);
+
+    traverse(ast, {
+      CallExpression: {
+        exit: function(astPath) {
+          if (astPath.get('callee').isIdentifier({name: 'invariant'})) {
+            var node = astPath.node;
+
+            // error messages can be concatenated (`+`) at runtime, so here's a
+            // trivial partial evaluator that interprets the literal value
+            var errorMsgLiteral = evalToString(node.arguments[1]);
+            if (existingErrorMap.hasOwnProperty(errorMsgLiteral)) {
+              return;
+            }
+
+            existingErrorMap[errorMsgLiteral] = '' + (currentID++);
+          }
+        },
+      },
+    });
+
+    cb();
+  }
+
+  function flush(cb) {
+    fs.writeFile(
+      errorMapFilePath,
+      JSON.stringify(invertObject(existingErrorMap), null, 2) + '\n',
+      'utf-8',
+      function() {
+        // avoid calling cb with fs.write callback data
+        cb();
+      }
+    );
+  }
+
+  return through.obj(transform, flush);
+};
diff --git a/scripts/error-codes/invertObject.js b/scripts/error-codes/invertObject.js
new file mode 100644
index 000000000000..ddf72aac1c30
--- /dev/null
+++ b/scripts/error-codes/invertObject.js
@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) 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.
+ *
+ * @flow
+ */
+'use strict';
+
+/*:: import type { ErrorMap } from './Types' */
+
+/**
+ * turns
+ *   { 'MUCH ERROR': '0', 'SUCH WRONG': '1' }
+ * into
+ *   { 0: 'MUCH ERROR', 1: 'SUCH WRONG' }
+ */
+function invertObject(targetObj/* : ErrorMap */)/* : ErrorMap */ {
+  var result = {};
+  var mapKeys = Object.keys(targetObj);
+
+  for (let i = 0; i < mapKeys.length; i++) {
+    var originalKey = mapKeys[i];
+    var originalVal = targetObj[originalKey];
+
+    result[originalVal] = originalKey;
+  }
+
+  return result;
+}
+
+module.exports = invertObject;
diff --git a/scripts/facts-tracker/index.js b/scripts/facts-tracker/index.js
new file mode 100644
index 000000000000..70fa9e20061d
--- /dev/null
+++ b/scripts/facts-tracker/index.js
@@ -0,0 +1,178 @@
+#!/usr/bin/env node
+
+/**
+ * Copyright (c) 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.
+ */
+
+'use strict';
+
+var fs = require('fs');
+var path = require('path');
+var execSync = require('child_process').execSync;
+
+function escape(value) {
+  return '\'' + value.replace(/'/g, "'\\''") + '\'';
+}
+
+var cwd = null;
+function exec(command) {
+  console.error('>', command.replace(process.env.GITHUB_TOKEN, '************'));
+  return execSync(command, cwd ? {cwd: cwd} : undefined).toString();
+}
+
+var isInsideOfTravis = !!process.env.TRAVIS_REPO_SLUG;
+
+if (isInsideOfTravis) {
+  if (process.env.TRAVIS_BRANCH !== 'master') {
+    console.error('facts-tracker: Branch is not master, exiting...');
+    process.exit(0);
+  }
+
+  if (process.env.TRAVIS_PULL_REQUEST !== 'false') {
+    console.error('facts-tracker: This is a pull request, exiting...');
+    process.exit(0);
+  }
+
+  if (!process.env.GITHUB_USER || !process.env.GITHUB_TOKEN) {
+    console.error(
+      'In order to use facts-tracker, you need to configure a ' +
+      'few environment variables in order to be able to commit to the ' +
+      'repository. Follow those steps to get you setup:\n' +
+      '\n' +
+      'Go to https://github.com/settings/tokens/new\n' +
+      ' - Fill "Token description" with "facts-tracker for ' +
+        process.env.TRAVIS_REPO_SLUG + '"\n' +
+      ' - Check "public_repo"\n' +
+      ' - Press "Generate Token"\n' +
+      '\n' +
+      'In a different tab, go to https://travis-ci.org/' +
+        process.env.TRAVIS_REPO_SLUG + '/settings\n' +
+      ' - Make sure "Build only if .travis.yml is present" is ON\n' +
+      ' - Fill "Name" with "GITHUB_TOKEN" and "Value" with the token you ' +
+        'just generated. Press "Add"\n' +
+      ' - Fill "Name" with "GITHUB_USER" and "Value" with the name of the ' +
+        'account you generated the token with. Press "Add"\n' +
+      '\n' +
+      'Once this is done, commit anything to the repository to restart ' +
+        'Travis and it should work :)'
+    );
+    process.exit(1);
+  }
+
+  exec(
+    'echo "machine github.com login $GITHUB_USER password $GITHUB_TOKEN"' +
+    '> ~/.netrc'
+  );
+  exec(
+    'git config --global user.name ' +
+    escape(process.env.GITHUB_USER_NAME || 'facts-tracker')
+  );
+  exec(
+    'git config --global user.email ' +
+    escape(process.env.GITHUB_USER_EMAIL || 'facts-tracker@no-reply.github.com')
+  );
+}
+
+if (process.argv.length <= 2) {
+  console.error('Usage: facts-tracker <name1> <value1> <name2> <value2>...');
+  process.exit(1);
+}
+
+function getRepoSlug() {
+  if (isInsideOfTravis) {
+    return process.env.TRAVIS_REPO_SLUG;
+  }
+
+  var remotes = exec('git remote -v').split('\n');
+  for (var i = 0; i < remotes.length; ++i) {
+    var match = remotes[i].match(/^origin\t[^:]+:([^\.]+).+\(fetch\)/);
+    if (match) {
+      return match[1];
+    }
+  }
+  
+  console.error('Cannot find repository slug, sorry.');
+  process.exit(1);
+}
+
+var repoSlug = getRepoSlug();
+var currentCommitHash = exec('git rev-parse HEAD').trim();
+var currentTimestamp = new Date().toISOString()
+  .replace('T', ' ')
+  .replace(/\..+/, '');
+
+function checkoutFactsFolder() {
+  var factsFolder = '../' + repoSlug.split('/')[1] + '-facts';
+  if (!fs.existsSync(factsFolder)) {
+    var escapedRepoURL;
+    if (isInsideOfTravis) {
+      escapedRepoURL = 'https://$GITHUB_TOKEN@github.com/' + escape(repoSlug) + '.git';
+    } else {
+      escapedRepoURL = escape('git@github.com:' + repoSlug + '.git');
+    }
+
+    exec(
+      'git clone ' +
+      '--branch facts ' +
+      '--depth=5 ' +
+      escapedRepoURL + ' ' +
+      escape(factsFolder)
+    );
+  }
+
+  cwd = path.resolve(factsFolder);
+  exec('git fetch');
+  if (exec('git status --porcelain')) {
+    console.error('facts-tracker: `git status` is not clean, aborting.');
+    process.exit(1);
+  }
+  exec('git rebase origin/facts');
+}
+checkoutFactsFolder();
+
+for (var i = 2; i < process.argv.length; i += 2) {
+  var name = process.argv[i].trim();
+  var value = process.argv[i + 1];
+  if (value.indexOf('\n') !== -1) {
+    console.error(
+      'facts-tracker: skipping', name,
+      'as the value contains new lines:', value
+    );
+    continue;
+  }
+
+  var filename = name + '.txt';
+  try {
+    var lastLine = exec('tail -n 1 ' + escape(filename));
+  } catch (e) {
+    // ignore error
+  }
+  var lastValue = lastLine && lastLine
+    .replace(/^[^\t]+\t[^\t]+\t/, '') // commit hash \t timestamp \t
+    .slice(0, -1); // trailing \n
+
+  if (value !== lastValue) {
+    fs.appendFileSync(
+      path.resolve(cwd, filename),
+      currentCommitHash + '\t' + currentTimestamp + '\t' + value + '\n'
+    );    
+  }
+
+  console.log(name);
+  console.log(lastValue);
+  console.log(value);
+}
+
+if (exec('git status --porcelain')) {
+  exec('git add --all');
+  exec('git commit -m ' + escape('Adding facts for ' + currentCommitHash));
+  exec('git push origin facts');
+} else {
+  console.error('facts-tracker: nothing to update');
+}
+cwd = null;
diff --git a/scripts/jest/environment.js b/scripts/jest/environment.js
index edc810072c56..6b0c38fe49d7 100644
--- a/scripts/jest/environment.js
+++ b/scripts/jest/environment.js
@@ -1,2 +1,11 @@
 /* eslint-disable */
 global.__DEV__ = true;
+
+// For testing DOM Fiber, we synchronously invoke all the scheduling.
+global.requestAnimationFrame = function(callback) {
+  callback();
+};
+
+global.requestIdleCallback = function(callback) {
+  callback({ timeRemaining() { return Infinity; } });
+};
diff --git a/scripts/jest/jest.d.ts b/scripts/jest/jest.d.ts
index 31fcc07dfcff..c3e69596f804 100644
--- a/scripts/jest/jest.d.ts
+++ b/scripts/jest/jest.d.ts
@@ -17,6 +17,7 @@ declare function xit(name: string, fn: any): void;
 interface Expect {
   not: Expect
   toThrow(message?: string): void
+  toThrowError(message?: string): void
   toBe(value: any): void
   toEqual(value: any): void
   toBeFalsy(): void
diff --git a/scripts/jest/preprocessor.js b/scripts/jest/preprocessor.js
index 29f0d03b0697..3a60dfd051e6 100644
--- a/scripts/jest/preprocessor.js
+++ b/scripts/jest/preprocessor.js
@@ -20,13 +20,14 @@ var createCacheKeyFunction = require('fbjs-scripts/jest/createCacheKeyFunction')
 // Use require.resolve to be resilient to file moves, npm updates, etc
 var pathToBabel = path.join(require.resolve('babel-core'), '..', 'package.json');
 var pathToModuleMap = require.resolve('fbjs/module-map');
-var pathToBabelPluginDev = require.resolve('fbjs-scripts/babel-6/dev-expression');
+var pathToBabelPluginDevWithCode = require.resolve('../error-codes/dev-expression-with-codes');
 var pathToBabelPluginModules = require.resolve('fbjs-scripts/babel-6/rewrite-modules');
 var pathToBabelrc = path.join(__dirname, '..', '..', '.babelrc');
 
 // TODO: make sure this stays in sync with gulpfile
 var babelOptions = {
   plugins: [
+    pathToBabelPluginDevWithCode, // this pass has to run before `rewrite-modules`
     [babelPluginModules, {
       map: Object.assign(
         {},
@@ -54,7 +55,10 @@ module.exports = {
     ) {
       return babel.transform(
         src,
-        Object.assign({filename: filePath}, babelOptions)
+        Object.assign(
+          {filename: path.relative(process.cwd(), filePath)},
+          babelOptions
+        )
       ).code;
     }
     return src;
@@ -65,7 +69,7 @@ module.exports = {
     pathToBabel,
     pathToBabelrc,
     pathToModuleMap,
-    pathToBabelPluginDev,
+    pathToBabelPluginDevWithCode,
     pathToBabelPluginModules,
   ]),
 };
diff --git a/scripts/jest/setupSpecEquivalenceReporter.js b/scripts/jest/setupSpecEquivalenceReporter.js
new file mode 100644
index 000000000000..90e430f4c7fe
--- /dev/null
+++ b/scripts/jest/setupSpecEquivalenceReporter.js
@@ -0,0 +1,31 @@
+/*!
+ * Copyright 2015-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.
+ */
+
+'use strict';
+
+var expect = global.expect;
+
+var numExpectations = 0;
+
+global.expect = function() {
+  numExpectations += 1;
+  return expect.apply(this, arguments);
+};
+
+beforeEach(() => numExpectations = 0);
+
+jasmine.currentEnv_.addReporter({
+  specDone: (spec) => {
+    console.log(
+      `EQUIVALENCE: ${spec.description}, ` +
+      `status: ${spec.status}, ` +
+      `numExpectations: ${numExpectations}`
+    );
+  },
+});
diff --git a/scripts/jest/test-framework-setup.js b/scripts/jest/test-framework-setup.js
index 107f6a8d43ac..f90d4cbe4895 100644
--- a/scripts/jest/test-framework-setup.js
+++ b/scripts/jest/test-framework-setup.js
@@ -1,35 +1,54 @@
 'use strict';
 
+// We want to globally mock this but jest doesn't let us do that by default
+// for a file that already exists. So we have to explicitly mock it.
+jest.mock('ReactDOM');
+
 var env = jasmine.getEnv();
 
+var callCount = 0;
 var oldError = console.error;
 var newError = function() {
+  callCount++;
   oldError.apply(this, arguments);
-  var spec = env.currentSpec;
-  if (spec) {
-    var expectationResult = new jasmine.ExpectationResult({
-      passed: false,
-      message:
-        'Expected test not to warn. If the warning is expected, mock it ' +
-        'out using spyOn(console, \'error\'); and test that the warning ' +
-        'occurs.',
-    });
-    spec.addMatcherResult(expectationResult);
-  }
 };
-console.error = newError;
 
-// Make sure console.error is set back at the end of each test, or else the
-// above logic won't work
-afterEach(function() {
-  // TODO: Catch test cases that call spyOn() but don't inspect the mock
-  // properly.
+console.error = newError;
 
-  if (console.error !== newError && !console.error.isSpy) {
-    var expectationResult = new jasmine.ExpectationResult({
-      passed: false,
-      message: 'Test did not tear down console.error mock properly.',
-    });
-    env.currentSpec.addMatcherResult(expectationResult);
-  }
+env.beforeEach(() => {
+  callCount = 0;
+  jasmine.addMatchers({
+    toBeReset() {
+      return {
+        compare(actual) {
+          // TODO: Catch test cases that call spyOn() but don't inspect the mock
+          // properly.
+          if (actual !== newError && !jasmine.isSpy(actual)) {
+            return {
+              pass: false,
+              message: 'Test did not tear down console.error mock properly.',
+            };
+          }
+          return {pass: true};
+        },
+      };
+    },
+    toNotHaveBeenCalled() {
+      return {
+        compare(actual) {
+          return {
+            pass: callCount === 0,
+            message:
+              'Expected test not to warn. If the warning is expected, mock ' +
+              'it out using spyOn(console, \'error\'); and test that the ' +
+              'warning occurs.',
+          };
+        },
+      };
+    },
+  });
+});
+env.afterEach(() => {
+  expect(console.error).toBeReset();
+  expect(console.error).toNotHaveBeenCalled();
 });
diff --git a/scripts/jest/ts-preprocessor.js b/scripts/jest/ts-preprocessor.js
index 760b57345fb4..e6b298f5f06a 100644
--- a/scripts/jest/ts-preprocessor.js
+++ b/scripts/jest/ts-preprocessor.js
@@ -4,12 +4,15 @@ var fs = require('fs');
 var path = require('path');
 var ts = require('typescript');
 
-var tsOptions = {module: 'commonjs'};
+var tsOptions = {
+  module: ts.ModuleKind.CommonJS,
+  jsx: ts.JsxEmit.React,
+};
 
 function formatErrorMessage(error) {
   return (
     error.file.filename + '(' +
-    error.file.getLineAndCharacterFromPosition(error.start).line +
+    error.file.getLineAndCharacterOfPosition(error.start).line +
     '): ' +
     error.messageText
   );
@@ -18,21 +21,23 @@ function formatErrorMessage(error) {
 function compile(content, contentFilename) {
   var output = null;
   var compilerHost = {
-    getSourceFile: function(filename, languageVersion) {
+    getSourceFile(filename, languageVersion) {
       var source;
 
       // `path.normalize` and `path.join` are used to turn forward slashes in
       // the file path into backslashes on Windows.
       filename = path.normalize(filename);
       var reactRegex = new RegExp(
-        path.join('/', '(?:React|ReactDOM)(?:\.d)?\.ts$')
+        path.join('/', '(?:React|ReactDOM|PropTypes)(?:\.d)?\.ts$')
       );
 
+      var jestRegex = /jest\.d\.ts/;
+
       if (filename === 'lib.d.ts') {
         source = fs.readFileSync(
-          require.resolve('typescript/bin/lib.d.ts')
+          require.resolve('typescript/lib/lib.d.ts')
         ).toString();
-      } else if (filename === 'jest.d.ts') {
+      } else if (filename.match(jestRegex)) {
         source = fs.readFileSync(
           path.join(__dirname, 'jest.d.ts')
         ).toString();
@@ -55,34 +60,36 @@ function compile(content, contentFilename) {
       }
       return ts.createSourceFile(filename, source, 'ES5', '0');
     },
-    writeFile: function(name, text, writeByteOrderMark) {
+    writeFile(name, text, writeByteOrderMark) {
       if (output === null) {
         output = text;
       } else {
         throw new Error('Expected only one dependency.');
       }
     },
-    getCanonicalFileName: function(filename) {
+    getCanonicalFileName(filename) {
       return filename;
     },
-    getCurrentDirectory: function() {
+    getCurrentDirectory() {
       return '';
     },
-    getNewLine: function() {
+    getNewLine() {
       return '\n';
     },
+    fileExists(filename) {
+      return ts.sys.fileExists(filename);
+    },
+    useCaseSensitiveFileNames() {
+      return ts.sys.useCaseSensitiveFileNames;
+    },
   };
   var program = ts.createProgram([
     'lib.d.ts',
     'jest.d.ts',
     contentFilename,
   ], tsOptions, compilerHost);
-  var errors = program.getDiagnostics();
-  if (!errors.length) {
-    var checker = program.getTypeChecker(true);
-    errors = checker.getDiagnostics();
-    checker.emitFiles();
-  }
+  var emitResult = program.emit();
+  var errors = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics);
   if (errors.length) {
     throw new Error(errors.map(formatErrorMessage).join('\n'));
   }
diff --git a/scripts/prettier/index.js b/scripts/prettier/index.js
new file mode 100644
index 000000000000..55a9affb81a3
--- /dev/null
+++ b/scripts/prettier/index.js
@@ -0,0 +1,89 @@
+/**
+ * Copyright (c) 2014-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.
+ */
+'use strict';
+
+// Based on similar script in Jest
+// https://github.com/facebook/jest/blob/master/scripts/prettier.js
+
+const chalk = require('chalk');
+const glob = require('glob');
+const path = require('path');
+const execFileSync = require('child_process').execFileSync;
+
+const shouldWrite = process.argv[2] === 'write';
+const isWindows = process.platform === 'win32';
+const prettier = isWindows ? 'prettier.cmd' : 'prettier';
+const prettierCmd = path.resolve(__dirname, '../../node_modules/.bin/' + prettier);
+const defaultOptions = {
+  'bracket-spacing': 'false',
+  'single-quote': 'true',
+  'jsx-bracket-same-line': 'true',
+  'trailing-comma': 'all',
+  'print-width': 80,
+};
+const config = {
+  default: {
+    patterns: ['src/**/*.js'],
+    ignore: [
+      '**/third_party/**',
+      '**/node_modules/**',
+    ],
+  },
+  addons: {
+    patterns: ['addons/**/*.js'],
+    ignore: [
+      '**/node_modules/**',
+    ],
+    options: {
+      // We don't compile them with Babel, and
+      // trailing commas break GCC.
+      'trailing-comma': 'none',
+    },
+  },
+};
+
+function exec(command, args) {
+  console.log('> ' + [command].concat(args).join(' '));
+  var options = {};
+  return execFileSync(command, args, options).toString();
+}
+
+Object.keys(config).forEach(key => {
+  const patterns = config[key].patterns;
+  const options = config[key].options;
+  const ignore = config[key].ignore;
+
+  const globPattern = patterns.length > 1
+    ? `{${patterns.join(',')}}`
+    : `${patterns.join(',')}`;
+  const files = glob.sync(globPattern, {ignore});
+
+  const args = Object.keys(defaultOptions).map(
+    k => `--${k}=${(options && options[k]) || defaultOptions[k]}`
+  );
+  args.push(`--${shouldWrite ? 'write' : 'l'}`);
+
+  try {
+    exec(prettierCmd, [...args, ...files]);
+  } catch (e) {
+    if (!shouldWrite) {
+      console.log(
+        '\n' +
+        chalk.red(
+          `  This project uses prettier to format all JavaScript code.\n`
+        ) +
+          chalk.dim(`    Please run `) +
+          chalk.reset('yarn prettier') +
+          chalk.dim(` and add changes to files listed above to your commit.`) +
+          `\n`
+      );
+      process.exit(1);
+    }
+    throw e;
+  }
+});
diff --git a/src/ReactVersion.js b/src/ReactVersion.js
index d62569be00d3..cf91b4c58bd9 100644
--- a/src/ReactVersion.js
+++ b/src/ReactVersion.js
@@ -11,4 +11,4 @@
 
 'use strict';
 
-module.exports = '15.0.0-rc.2';
+module.exports = '15.6.1';
diff --git a/src/addons/ReactAddonsDOMDependencies.js b/src/addons/ReactAddonsDOMDependencies.js
new file mode 100644
index 000000000000..70856ec6c5fe
--- /dev/null
+++ b/src/addons/ReactAddonsDOMDependencies.js
@@ -0,0 +1,37 @@
+/**
+ * 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 ReactAddonsDOMDependencies
+ */
+
+'use strict';
+
+var ReactDOM = require('ReactDOM');
+
+exports.getReactDOM = function() {
+  return ReactDOM;
+};
+
+if (__DEV__) {
+  var ReactPerf;
+  var ReactTestUtils;
+
+  exports.getReactPerf = function() {
+    if (!ReactPerf) {
+      ReactPerf = require('ReactPerf');
+    }
+    return ReactPerf;
+  };
+
+  exports.getReactTestUtils = function() {
+    if (!ReactTestUtils) {
+      ReactTestUtils = require('ReactTestUtils');
+    }
+    return ReactTestUtils;
+  };
+}
diff --git a/src/addons/ReactComponentWithPureRenderMixin.js b/src/addons/ReactComponentWithPureRenderMixin.js
index afafbdaa763a..cf00d7cb3deb 100644
--- a/src/addons/ReactComponentWithPureRenderMixin.js
+++ b/src/addons/ReactComponentWithPureRenderMixin.js
@@ -36,6 +36,8 @@ var shallowCompare = require('shallowCompare');
  * complex data structures this mixin may have false-negatives for deeper
  * differences. Only mixin to components which have simple props and state, or
  * use `forceUpdate()` when you know deep data structures have changed.
+ *
+ * See https://facebook.github.io/react/docs/pure-render-mixin.html
  */
 var ReactComponentWithPureRenderMixin = {
   shouldComponentUpdate: function(nextProps, nextState) {
diff --git a/src/addons/ReactDOMFactories.js b/src/addons/ReactDOMFactories.js
new file mode 100644
index 000000000000..f1f82c3a0152
--- /dev/null
+++ b/src/addons/ReactDOMFactories.js
@@ -0,0 +1,169 @@
+/**
+ * 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 ReactDOMFactories
+ */
+
+'use strict';
+
+var ReactElement = require('ReactElement');
+
+/**
+ * Create a factory that creates HTML tag elements.
+ *
+ * @private
+ */
+var createDOMFactory = ReactElement.createFactory;
+if (__DEV__) {
+  var ReactElementValidator = require('ReactElementValidator');
+  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;
diff --git a/src/addons/ReactFragment.js b/src/addons/ReactFragment.js
index f16ccf8bc029..0ed35d4ae621 100644
--- a/src/addons/ReactFragment.js
+++ b/src/addons/ReactFragment.js
@@ -31,14 +31,17 @@ var numericPropertyRegex = /^\d+$/;
 var warnedAboutNumeric = false;
 
 var ReactFragment = {
-  // Wrap a keyed object in an opaque proxy that warns you if you access any
-  // of its properties.
+  /**
+   * Wrap a keyed object in an opaque proxy that warns you if you access any
+   * of its properties.
+   * See https://facebook.github.io/react/docs/create-fragment.html
+   */
   create: function(object) {
     if (typeof object !== 'object' || !object || Array.isArray(object)) {
       warning(
         false,
         'React.addons.createFragment only accepts a single object. Got: %s',
-        object
+        object,
       );
       return object;
     }
@@ -46,7 +49,7 @@ var ReactFragment = {
       warning(
         false,
         'React.addons.createFragment does not accept a ReactElement ' +
-        'without a wrapper object.'
+          'without a wrapper object.',
       );
       return object;
     }
@@ -54,7 +57,7 @@ var ReactFragment = {
     invariant(
       object.nodeType !== 1,
       'React.addons.createFragment(...): Encountered an invalid child; DOM ' +
-      'elements are not valid children of React components.'
+        'elements are not valid children of React components.',
     );
 
     var result = [];
@@ -65,7 +68,7 @@ var ReactFragment = {
           warning(
             false,
             'React.addons.createFragment(...): Child objects should have ' +
-            'non-numeric keys so ordering is preserved.'
+              'non-numeric keys so ordering is preserved.',
           );
           warnedAboutNumeric = true;
         }
@@ -74,7 +77,7 @@ var ReactFragment = {
         object[key],
         result,
         key,
-        emptyFunction.thatReturnsArgument
+        emptyFunction.thatReturnsArgument,
       );
     }
 
diff --git a/src/addons/ReactWithAddons.js b/src/addons/ReactWithAddons.js
index bd13ea495f99..8cf081c98220 100644
--- a/src/addons/ReactWithAddons.js
+++ b/src/addons/ReactWithAddons.js
@@ -13,8 +13,8 @@
 
 var LinkedStateMixin = require('LinkedStateMixin');
 var React = require('React');
-var ReactComponentWithPureRenderMixin =
-  require('ReactComponentWithPureRenderMixin');
+var ReactAddonsDOMDependencies = require('ReactAddonsDOMDependencies');
+var ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin');
 var ReactCSSTransitionGroup = require('ReactCSSTransitionGroup');
 var ReactFragment = require('ReactFragment');
 var ReactTransitionGroup = require('ReactTransitionGroup');
@@ -34,8 +34,20 @@ React.addons = {
 };
 
 if (__DEV__) {
-  React.addons.Perf = require('ReactDefaultPerf');
-  React.addons.TestUtils = require('ReactTestUtils');
+  // For the UMD build we get these lazily from the global since they're tied
+  // to the DOM renderer and it hasn't loaded yet.
+  Object.defineProperty(React.addons, 'Perf', {
+    enumerable: true,
+    get: function() {
+      return ReactAddonsDOMDependencies.getReactPerf();
+    },
+  });
+  Object.defineProperty(React.addons, 'TestUtils', {
+    enumerable: true,
+    get: function() {
+      return ReactAddonsDOMDependencies.getReactTestUtils();
+    },
+  });
 }
 
 module.exports = React;
diff --git a/src/addons/__tests__/ReactComponentWithPureRenderMixin-test.js b/src/addons/__tests__/ReactComponentWithPureRenderMixin-test.js
deleted file mode 100644
index 2c9581994cce..000000000000
--- a/src/addons/__tests__/ReactComponentWithPureRenderMixin-test.js
+++ /dev/null
@@ -1,145 +0,0 @@
-/**
- * Copyright 2015-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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-var React;
-var ReactComponentWithPureRenderMixin;
-var ReactTestUtils;
-
-describe('ReactComponentWithPureRenderMixin', function() {
-
-  beforeEach(function() {
-    React = require('React');
-    ReactComponentWithPureRenderMixin =
-      require('ReactComponentWithPureRenderMixin');
-    ReactTestUtils = require('ReactTestUtils');
-  });
-
-  it('provides a default shouldComponentUpdate implementation', function() {
-    var renderCalls = 0;
-    class PlasticWrap extends React.Component {
-      constructor(props, context) {
-        super(props, context);
-        this.state = {
-          color: 'green',
-        };
-      }
-
-      render() {
-        return (
-          <Apple
-            color={this.state.color}
-            ref="apple"
-          />
-        );
-      }
-    }
-
-    var Apple = React.createClass({
-      mixins: [ReactComponentWithPureRenderMixin],
-
-      getInitialState: function() {
-        return {
-          cut: false,
-          slices: 1,
-        };
-      },
-
-      cut: function() {
-        this.setState({
-          cut: true,
-          slices: 10,
-        });
-      },
-
-      eatSlice: function() {
-        this.setState({
-          slices: this.state.slices - 1,
-        });
-      },
-
-      render: function() {
-        renderCalls++;
-        return <div />;
-      },
-    });
-
-    var instance = ReactTestUtils.renderIntoDocument(<PlasticWrap />);
-    expect(renderCalls).toBe(1);
-
-    // Do not re-render based on props
-    instance.setState({color: 'green'});
-    expect(renderCalls).toBe(1);
-
-    // Re-render based on props
-    instance.setState({color: 'red'});
-    expect(renderCalls).toBe(2);
-
-    // Re-render base on state
-    instance.refs.apple.cut();
-    expect(renderCalls).toBe(3);
-
-    // No re-render based on state
-    instance.refs.apple.cut();
-    expect(renderCalls).toBe(3);
-
-    // Re-render based on state again
-    instance.refs.apple.eatSlice();
-    expect(renderCalls).toBe(4);
-  });
-
-  it('does not do a deep comparison', function() {
-    function getInitialState() {
-      return {
-        foo: [1, 2, 3],
-        bar: {a: 4, b: 5, c: 6},
-      };
-    }
-
-    var renderCalls = 0;
-    var initialSettings = getInitialState();
-
-    var Component = React.createClass({
-      mixins: [ReactComponentWithPureRenderMixin],
-
-      getInitialState: function() {
-        return initialSettings;
-      },
-
-      render: function() {
-        renderCalls++;
-        return <div />;
-      },
-    });
-
-    var instance = ReactTestUtils.renderIntoDocument(<Component />);
-    expect(renderCalls).toBe(1);
-
-    // Do not re-render if state is equal
-    var settings = {
-      foo: initialSettings.foo,
-      bar: initialSettings.bar,
-    };
-    instance.setState(settings);
-    expect(renderCalls).toBe(1);
-
-    // Re-render because one field changed
-    initialSettings.foo = [1, 2, 3];
-    instance.setState(initialSettings);
-    expect(renderCalls).toBe(2);
-
-    // Re-render because the object changed
-    instance.setState(getInitialState());
-    expect(renderCalls).toBe(3);
-  });
-
-});
diff --git a/src/addons/__tests__/ReactDOMFactories-test.js b/src/addons/__tests__/ReactDOMFactories-test.js
new file mode 100644
index 000000000000..641faa3f003d
--- /dev/null
+++ b/src/addons/__tests__/ReactDOMFactories-test.js
@@ -0,0 +1,41 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var React = require('React');
+var {div} = require('ReactDOMFactories');
+
+describe('ReactDOMFactories', () => {
+  it('allow factories to be called without warnings', () => {
+    spyOn(console, 'error');
+    spyOn(console, 'warn');
+    var element = div();
+    expect(element.type).toBe('div');
+    expect(console.error).not.toHaveBeenCalled();
+    expect(console.warn).not.toHaveBeenCalled();
+  });
+
+  it('warns once when accessing React.DOM methods', () => {
+    spyOn(console, 'warn');
+
+    var a = React.DOM.a();
+    var p = React.DOM.p();
+
+    expect(a.type).toBe('a');
+    expect(p.type).toBe('p');
+
+    expect(console.warn).toHaveBeenCalledTimes(1);
+    expect(console.warn.calls.first().args[0]).toContain(
+      'Warning: Accessing factories like React.DOM.a has been deprecated',
+    );
+  });
+});
diff --git a/src/addons/__tests__/ReactFragment-test.js b/src/addons/__tests__/ReactFragment-test.js
index 4a1b9775d62a..1fc6f03d2a51 100644
--- a/src/addons/__tests__/ReactFragment-test.js
+++ b/src/addons/__tests__/ReactFragment-test.js
@@ -15,15 +15,14 @@ var React;
 var ReactDOM;
 var ReactFragment;
 
-describe('ReactFragment', function() {
-
-  beforeEach(function() {
+describe('ReactFragment', () => {
+  beforeEach(() => {
     React = require('React');
     ReactDOM = require('ReactDOM');
     ReactFragment = require('ReactFragment');
   });
 
-  it('should throw if a plain object is used as a child', function() {
+  it('should throw if a plain object is used as a child', () => {
     var children = {
       x: <span />,
       y: <span />,
@@ -31,15 +30,15 @@ describe('ReactFragment', function() {
     };
     var element = <div>{[children]}</div>;
     var container = document.createElement('div');
-    expect(() => ReactDOM.render(element, container)).toThrow(
+    expect(() => ReactDOM.render(element, container)).toThrowError(
       'Objects are not valid as a React child (found: object with keys ' +
-      '{x, y, z}). 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.'
+        '{x, y, z}). 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.',
     );
   });
 
-  it('should throw if a plain object even if it is in an owner', function() {
+  it('should throw if a plain object even if it is in an owner', () => {
     class Foo extends React.Component {
       render() {
         var children = {
@@ -51,62 +50,61 @@ describe('ReactFragment', function() {
       }
     }
     var container = document.createElement('div');
-    expect(() => ReactDOM.render(<Foo />, container)).toThrow(
+    expect(() => ReactDOM.render(<Foo />, container)).toThrowError(
       'Objects are not valid as a React child (found: object with keys ' +
-      '{a, b, c}). 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. Check the render method of `Foo`.'
+        '{a, b, c}). 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. Check the render method of `Foo`.',
     );
   });
 
-  it('should throw if a plain object looks like an old element', function() {
+  it('should throw if a plain object looks like an old element', () => {
     var oldEl = {_isReactElement: true, type: 'span', props: {}};
     var container = document.createElement('div');
-    expect(() => ReactDOM.render(<div>{oldEl}</div>, container)).toThrow(
+    expect(() => ReactDOM.render(<div>{oldEl}</div>, container)).toThrowError(
       'Objects are not valid as a React child (found: object with keys ' +
-      '{_isReactElement, type, props}). It looks like you\'re using an ' +
-      'element created by a different version of React. Make sure to use ' +
-      'only one copy of React.'
+        "{_isReactElement, type, props}). It looks like you're using an " +
+        'element created by a different version of React. Make sure to use ' +
+        'only one copy of React.',
     );
   });
 
-  it('warns for numeric keys on objects as children', function() {
+  it('warns for numeric keys on objects as children', () => {
     spyOn(console, 'error');
 
     ReactFragment.create({1: <span />, 2: <span />});
 
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
-      'Child objects should have non-numeric keys so ordering is preserved.'
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'Child objects should have non-numeric keys so ordering is preserved.',
     );
   });
 
-  it('should warn if passing null to createFragment', function() {
+  it('should warn if passing null to createFragment', () => {
     spyOn(console, 'error');
     ReactFragment.create(null);
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
-      'React.addons.createFragment only accepts a single object.'
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'React.addons.createFragment only accepts a single object.',
     );
   });
 
-  it('should warn if passing an array to createFragment', function() {
+  it('should warn if passing an array to createFragment', () => {
     spyOn(console, 'error');
     ReactFragment.create([]);
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
-      'React.addons.createFragment only accepts a single object.'
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'React.addons.createFragment only accepts a single object.',
     );
   });
 
-  it('should warn if passing a ReactElement to createFragment', function() {
+  it('should warn if passing a ReactElement to createFragment', () => {
     spyOn(console, 'error');
     ReactFragment.create(<div />);
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
       'React.addons.createFragment does not accept a ReactElement without a ' +
-      'wrapper object.'
+        'wrapper object.',
     );
   });
-
 });
diff --git a/src/addons/__tests__/renderSubtreeIntoContainer-test.js b/src/addons/__tests__/renderSubtreeIntoContainer-test.js
index de67b7ee4794..0af5d796250d 100644
--- a/src/addons/__tests__/renderSubtreeIntoContainer-test.js
+++ b/src/addons/__tests__/renderSubtreeIntoContainer-test.js
@@ -11,85 +11,190 @@
 
 'use strict';
 
+var PropTypes = require('prop-types');
 var React = require('React');
+var ReactDOM = require('ReactDOM');
 var ReactTestUtils = require('ReactTestUtils');
 var renderSubtreeIntoContainer = require('renderSubtreeIntoContainer');
 
-describe('renderSubtreeIntoContainer', function() {
-
-  it('should pass context when rendering subtree elsewhere', function() {
-
+describe('renderSubtreeIntoContainer', () => {
+  it('should pass context when rendering subtree elsewhere', () => {
     var portal = document.createElement('div');
 
-    var Component = React.createClass({
-      contextTypes: {
-        foo: React.PropTypes.string.isRequired,
-      },
+    class Component extends React.Component {
+      static contextTypes = {
+        foo: PropTypes.string.isRequired,
+      };
 
-      render: function() {
+      render() {
         return <div>{this.context.foo}</div>;
-      },
-    });
+      }
+    }
 
-    var Parent = React.createClass({
-      childContextTypes: {
-        foo: React.PropTypes.string.isRequired,
-      },
+    class Parent extends React.Component {
+      static childContextTypes = {
+        foo: PropTypes.string.isRequired,
+      };
 
-      getChildContext: function() {
+      getChildContext() {
         return {
           foo: 'bar',
         };
-      },
+      }
 
-      render: function() {
+      render() {
         return null;
-      },
+      }
 
-      componentDidMount: function() {
-        expect(function() {
-          renderSubtreeIntoContainer(this, <Component />, portal);
-        }.bind(this)).not.toThrow();
-      },
-    });
+      componentDidMount() {
+        expect(
+          function() {
+            renderSubtreeIntoContainer(this, <Component />, portal);
+          }.bind(this),
+        ).not.toThrow();
+      }
+    }
 
     ReactTestUtils.renderIntoDocument(<Parent />);
     expect(portal.firstChild.innerHTML).toBe('bar');
   });
 
-  it('should throw if parentComponent is invalid', function() {
+  it('should throw if parentComponent is invalid', () => {
     var portal = document.createElement('div');
 
-    var Component = React.createClass({
-      contextTypes: {
-        foo: React.PropTypes.string.isRequired,
-      },
+    class Component extends React.Component {
+      static contextTypes = {
+        foo: PropTypes.string.isRequired,
+      };
 
-      render: function() {
+      render() {
         return <div>{this.context.foo}</div>;
-      },
-    });
-
-    var Parent = React.createClass({
-      childContextTypes: {
-        foo: React.PropTypes.string.isRequired,
-      },
-
-      getChildContext: function() {
+      }
+    }
+
+    // ESLint is confused here and thinks Parent is unused, presumably because
+    // it is only used inside of the class body?
+    // eslint-disable-next-line no-unused-vars
+    class Parent extends React.Component {
+      static childContextTypes = {
+        foo: PropTypes.string.isRequired,
+      };
+
+      getChildContext() {
         return {
           foo: 'bar',
         };
-      },
+      }
 
-      render: function() {
+      render() {
         return null;
-      },
+      }
 
-      componentDidMount: function() {
+      componentDidMount() {
         expect(function() {
           renderSubtreeIntoContainer(<Parent />, <Component />, portal);
-        }).toThrow('parentComponentmust be a valid React Component');
-      },
-    });
+        }).toThrowError('parentComponentmust be a valid React Component');
+      }
+    }
+  });
+
+  it('should update context if it changes due to setState', () => {
+    var container = document.createElement('div');
+    document.body.appendChild(container);
+    var portal = document.createElement('div');
+
+    class Component extends React.Component {
+      static contextTypes = {
+        foo: PropTypes.string.isRequired,
+        getFoo: PropTypes.func.isRequired,
+      };
+
+      render() {
+        return <div>{this.context.foo + '-' + this.context.getFoo()}</div>;
+      }
+    }
+
+    class Parent extends React.Component {
+      static childContextTypes = {
+        foo: PropTypes.string.isRequired,
+        getFoo: PropTypes.func.isRequired,
+      };
+
+      state = {
+        bar: 'initial',
+      };
+
+      getChildContext() {
+        return {
+          foo: this.state.bar,
+          getFoo: () => this.state.bar,
+        };
+      }
+
+      render() {
+        return null;
+      }
+
+      componentDidMount() {
+        renderSubtreeIntoContainer(this, <Component />, portal);
+      }
+
+      componentDidUpdate() {
+        renderSubtreeIntoContainer(this, <Component />, portal);
+      }
+    }
+
+    var instance = ReactDOM.render(<Parent />, container);
+    expect(portal.firstChild.innerHTML).toBe('initial-initial');
+    instance.setState({bar: 'changed'});
+    expect(portal.firstChild.innerHTML).toBe('changed-changed');
+  });
+
+  it('should update context if it changes due to re-render', () => {
+    var container = document.createElement('div');
+    document.body.appendChild(container);
+    var portal = document.createElement('div');
+
+    class Component extends React.Component {
+      static contextTypes = {
+        foo: PropTypes.string.isRequired,
+        getFoo: PropTypes.func.isRequired,
+      };
+
+      render() {
+        return <div>{this.context.foo + '-' + this.context.getFoo()}</div>;
+      }
+    }
+
+    class Parent extends React.Component {
+      static childContextTypes = {
+        foo: PropTypes.string.isRequired,
+        getFoo: PropTypes.func.isRequired,
+      };
+
+      getChildContext() {
+        return {
+          foo: this.props.bar,
+          getFoo: () => this.props.bar,
+        };
+      }
+
+      render() {
+        return null;
+      }
+
+      componentDidMount() {
+        renderSubtreeIntoContainer(this, <Component />, portal);
+      }
+
+      componentDidUpdate() {
+        renderSubtreeIntoContainer(this, <Component />, portal);
+      }
+    }
+
+    ReactDOM.render(<Parent bar="initial" />, container);
+    expect(portal.firstChild.innerHTML).toBe('initial-initial');
+    ReactDOM.render(<Parent bar="changed" />, container);
+    expect(portal.firstChild.innerHTML).toBe('changed-changed');
   });
 });
diff --git a/src/addons/__tests__/update-test.js b/src/addons/__tests__/update-test.js
index 05a6578ee897..15cf7ff75d5f 100644
--- a/src/addons/__tests__/update-test.js
+++ b/src/addons/__tests__/update-test.js
@@ -13,150 +13,154 @@
 
 var update = require('update');
 
-describe('update', function() {
-
-  describe('$push', function() {
-    it('pushes', function() {
+describe('update', () => {
+  describe('$push', () => {
+    it('pushes', () => {
       expect(update([1], {$push: [7]})).toEqual([1, 7]);
     });
-    it('does not mutate the original object', function() {
+    it('does not mutate the original object', () => {
       var obj = [1];
       update(obj, {$push: [7]});
       expect(obj).toEqual([1]);
     });
-    it('only pushes an array', function() {
-      expect(update.bind(null, [], {$push: 7})).toThrow(
+    it('only pushes an array', () => {
+      expect(update.bind(null, [], {$push: 7})).toThrowError(
         'update(): expected spec of $push to be an array; got 7. Did you ' +
-        'forget to wrap your parameter in an array?'
+          'forget to wrap your parameter in an array?',
       );
     });
-    it('only pushes unto an array', function() {
-      expect(update.bind(null, 1, {$push: 7})).toThrow(
-        'update(): expected target of $push to be an array; got 1.'
+    it('only pushes unto an array', () => {
+      expect(update.bind(null, 1, {$push: 7})).toThrowError(
+        'update(): expected target of $push to be an array; got 1.',
       );
     });
   });
 
-  describe('$unshift', function() {
-    it('unshifts', function() {
+  describe('$unshift', () => {
+    it('unshifts', () => {
       expect(update([1], {$unshift: [7]})).toEqual([7, 1]);
     });
-    it('does not mutate the original object', function() {
+    it('does not mutate the original object', () => {
       var obj = [1];
       update(obj, {$unshift: [7]});
       expect(obj).toEqual([1]);
     });
-    it('only unshifts an array', function() {
-      expect(update.bind(null, [], {$unshift: 7})).toThrow(
+    it('only unshifts an array', () => {
+      expect(update.bind(null, [], {$unshift: 7})).toThrowError(
         'update(): expected spec of $unshift to be an array; got 7. Did you ' +
-        'forget to wrap your parameter in an array?'
+          'forget to wrap your parameter in an array?',
       );
     });
-    it('only unshifts unto an array', function() {
-      expect(update.bind(null, 1, {$unshift: 7})).toThrow(
-        'update(): expected target of $unshift to be an array; got 1.'
+    it('only unshifts unto an array', () => {
+      expect(update.bind(null, 1, {$unshift: 7})).toThrowError(
+        'update(): expected target of $unshift to be an array; got 1.',
       );
     });
   });
 
-  describe('$splice', function() {
-    it('splices', function() {
+  describe('$splice', () => {
+    it('splices', () => {
       expect(update([1, 4, 3], {$splice: [[1, 1, 2]]})).toEqual([1, 2, 3]);
     });
-    it('does not mutate the original object', function() {
+    it('does not mutate the original object', () => {
       var obj = [1, 4, 3];
       update(obj, {$splice: [[1, 1, 2]]});
       expect(obj).toEqual([1, 4, 3]);
     });
-    it('only splices an array of arrays', function() {
-      expect(update.bind(null, [], {$splice: 1})).toThrow(
+    it('only splices an array of arrays', () => {
+      expect(update.bind(null, [], {$splice: 1})).toThrowError(
         'update(): expected spec of $splice to be an array of arrays; got 1. ' +
-        'Did you forget to wrap your parameters in an array?'
+          'Did you forget to wrap your parameters in an array?',
       );
-      expect(update.bind(null, [], {$splice: [1]})).toThrow(
+      expect(update.bind(null, [], {$splice: [1]})).toThrowError(
         'update(): expected spec of $splice to be an array of arrays; got 1. ' +
-        'Did you forget to wrap your parameters in an array?'
+          'Did you forget to wrap your parameters in an array?',
       );
     });
-    it('only splices unto an array', function() {
-      expect(update.bind(null, 1, {$splice: 7})).toThrow(
-        'Expected $splice target to be an array; got 1'
+    it('only splices unto an array', () => {
+      expect(update.bind(null, 1, {$splice: 7})).toThrowError(
+        'Expected $splice target to be an array; got 1',
       );
     });
   });
 
-  describe('$merge', function() {
-    it('merges', function() {
+  describe('$merge', () => {
+    it('merges', () => {
       expect(update({a: 'b'}, {$merge: {c: 'd'}})).toEqual({a: 'b', c: 'd'});
     });
-    it('does not mutate the original object', function() {
+    it('does not mutate the original object', () => {
       var obj = {a: 'b'};
       update(obj, {$merge: {c: 'd'}});
       expect(obj).toEqual({a: 'b'});
     });
-    it('only merges with an object', function() {
-      expect(update.bind(null, {}, {$merge: 7})).toThrow(
-        'update(): $merge expects a spec of type \'object\'; got 7'
+    it('only merges with an object', () => {
+      expect(update.bind(null, {}, {$merge: 7})).toThrowError(
+        "update(): $merge expects a spec of type 'object'; got 7",
       );
     });
-    it('only merges with an object', function() {
-      expect(update.bind(null, 7, {$merge: {a: 'b'}})).toThrow(
-        'update(): $merge expects a target of type \'object\'; got 7'
+    it('only merges with an object', () => {
+      expect(update.bind(null, 7, {$merge: {a: 'b'}})).toThrowError(
+        "update(): $merge expects a target of type 'object'; got 7",
       );
     });
   });
 
-  describe('$set', function() {
-    it('sets', function() {
+  describe('$set', () => {
+    it('sets', () => {
       expect(update({a: 'b'}, {$set: {c: 'd'}})).toEqual({c: 'd'});
     });
-    it('does not mutate the original object', function() {
+    it('does not mutate the original object', () => {
       var obj = {a: 'b'};
       update(obj, {$set: {c: 'd'}});
       expect(obj).toEqual({a: 'b'});
     });
   });
 
-  describe('$apply', function() {
+  describe('$apply', () => {
     var applier = function(node) {
       return {v: node.v * 2};
     };
-    it('applies', function() {
+    it('applies', () => {
       expect(update({v: 2}, {$apply: applier})).toEqual({v: 4});
     });
-    it('does not mutate the original object', function() {
+    it('does not mutate the original object', () => {
       var obj = {v: 2};
       update(obj, {$apply: applier});
       expect(obj).toEqual({v: 2});
     });
-    it('only applies a function', function() {
-      expect(update.bind(null, 2, {$apply: 123})).toThrow(
-        'update(): expected spec of $apply to be a function; got 123.'
+    it('only applies a function', () => {
+      expect(update.bind(null, 2, {$apply: 123})).toThrowError(
+        'update(): expected spec of $apply to be a function; got 123.',
       );
     });
   });
 
-  it('should support deep updates', function() {
-    expect(update({
-      a: 'b',
-      c: {
-        d: 'e',
-        f: [1],
-        g: [2],
-        h: [3],
-        i: {j: 'k'},
-        l: 4,
-      },
-    }, {
-      c: {
-        d: {$set: 'm'},
-        f: {$push: [5]},
-        g: {$unshift: [6]},
-        h: {$splice: [[0, 1, 7]]},
-        i: {$merge: {n: 'o'}},
-        l: {$apply: (x) => x * 2},
-      },
-    })).toEqual({
+  it('should support deep updates', () => {
+    expect(
+      update(
+        {
+          a: 'b',
+          c: {
+            d: 'e',
+            f: [1],
+            g: [2],
+            h: [3],
+            i: {j: 'k'},
+            l: 4,
+          },
+        },
+        {
+          c: {
+            d: {$set: 'm'},
+            f: {$push: [5]},
+            g: {$unshift: [6]},
+            h: {$splice: [[0, 1, 7]]},
+            i: {$merge: {n: 'o'}},
+            l: {$apply: x => x * 2},
+          },
+        },
+      ),
+    ).toEqual({
       a: 'b',
       c: {
         d: 'm',
@@ -169,17 +173,17 @@ describe('update', function() {
     });
   });
 
-  it('should require a command', function() {
-    expect(update.bind(null, {a: 'b'}, {a: 'c'})).toThrow(
+  it('should require a command', () => {
+    expect(update.bind(null, {a: 'b'}, {a: 'c'})).toThrowError(
       'update(): You provided a key path to update() that did not contain ' +
-      'one of $push, $unshift, $splice, $set, $merge, $apply. Did you ' +
-      'forget to include {$set: ...}?'
+        'one of $push, $unshift, $splice, $set, $merge, $apply. Did you ' +
+        'forget to include {$set: ...}?',
     );
   });
 
-  it('should perform safe hasOwnProperty check', function() {
-    expect(update({}, {'hasOwnProperty': {$set: 'a'}})).toEqual({
-      'hasOwnProperty': 'a',
+  it('should perform safe hasOwnProperty check', () => {
+    expect(update({}, {hasOwnProperty: {$set: 'a'}})).toEqual({
+      hasOwnProperty: 'a',
     });
   });
 });
diff --git a/src/addons/link/LinkedStateMixin.js b/src/addons/link/LinkedStateMixin.js
index c45a79faad9e..4a646095df24 100644
--- a/src/addons/link/LinkedStateMixin.js
+++ b/src/addons/link/LinkedStateMixin.js
@@ -16,6 +16,7 @@ var ReactStateSetters = require('ReactStateSetters');
 
 /**
  * A simple mixin around ReactLink.forState().
+ * See https://facebook.github.io/react/docs/two-way-binding-helpers.html
  */
 var LinkedStateMixin = {
   /**
@@ -23,14 +24,13 @@ var LinkedStateMixin = {
    * ReactLink will have the current value of this.state[key] and will call
    * setState() when a change is requested.
    *
-   * @param {string} key state key to update. Note: you may want to use keyOf()
-   * if you're using Google Closure Compiler advanced mode.
+   * @param {string} key state key to update.
    * @return {ReactLink} ReactLink instance linking to the state.
    */
   linkState: function(key) {
     return new ReactLink(
       this.state[key],
-      ReactStateSetters.createStateKeySetter(this, key)
+      ReactStateSetters.createStateKeySetter(this, key),
     );
   },
 };
diff --git a/src/addons/link/ReactLink.js b/src/addons/link/ReactLink.js
index ea6435c92b7b..d91345e6970d 100644
--- a/src/addons/link/ReactLink.js
+++ b/src/addons/link/ReactLink.js
@@ -34,9 +34,10 @@
  * consumption of ReactLink easier; see LinkedValueUtils and LinkedStateMixin.
  */
 
-var React = require('React');
-
 /**
+ * Deprecated: An an easy way to express two-way binding with React. 
+ * See https://facebook.github.io/react/docs/two-way-binding-helpers.html
+ *
  * @param {*} value current value of the link
  * @param {function} requestChange callback to request a change
  */
@@ -45,26 +46,4 @@ function ReactLink(value, requestChange) {
   this.requestChange = requestChange;
 }
 
-/**
- * Creates a PropType that enforces the ReactLink API and optionally checks the
- * type of the value being passed inside the link. Example:
- *
- * MyComponent.propTypes = {
- *   tabIndexLink: ReactLink.PropTypes.link(React.PropTypes.number)
- * }
- */
-function createLinkTypeChecker(linkType) {
-  var shapes = {
-    value: linkType === undefined ?
-      React.PropTypes.any.isRequired :
-      linkType.isRequired,
-    requestChange: React.PropTypes.func.isRequired,
-  };
-  return React.PropTypes.shape(shapes);
-}
-
-ReactLink.PropTypes = {
-  link: createLinkTypeChecker,
-};
-
 module.exports = ReactLink;
diff --git a/src/renderers/shared/reconciler/ReactStateSetters.js b/src/addons/link/ReactStateSetters.js
similarity index 100%
rename from src/renderers/shared/reconciler/ReactStateSetters.js
rename to src/addons/link/ReactStateSetters.js
diff --git a/src/addons/link/__tests__/LinkedStateMixin-test.js b/src/addons/link/__tests__/LinkedStateMixin-test.js
deleted file mode 100644
index 01b82351c8cf..000000000000
--- a/src/addons/link/__tests__/LinkedStateMixin-test.js
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * 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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-
-describe('LinkedStateMixin', function() {
-  var LinkedStateMixin;
-  var React;
-  var ReactTestUtils;
-
-  beforeEach(function() {
-    LinkedStateMixin = require('LinkedStateMixin');
-    React = require('React');
-    ReactTestUtils = require('ReactTestUtils');
-  });
-
-  it('should create a ReactLink for state', function() {
-    var Component = React.createClass({
-      mixins: [LinkedStateMixin],
-
-      getInitialState: function() {
-        return {value: 'initial value'};
-      },
-
-      render: function() {
-        return <span>value is {this.state.value}</span>;
-      },
-    });
-    var component = ReactTestUtils.renderIntoDocument(<Component />);
-    var link = component.linkState('value');
-    expect(component.state.value).toBe('initial value');
-    expect(link.value).toBe('initial value');
-    link.requestChange('new value');
-    expect(component.state.value).toBe('new value');
-    expect(component.linkState('value').value).toBe('new value');
-  });
-});
diff --git a/src/addons/link/__tests__/ReactLinkPropTypes-test.js b/src/addons/link/__tests__/ReactLinkPropTypes-test.js
deleted file mode 100644
index 6ade13777036..000000000000
--- a/src/addons/link/__tests__/ReactLinkPropTypes-test.js
+++ /dev/null
@@ -1,154 +0,0 @@
-/**
- * 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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-var emptyFunction = require('emptyFunction');
-var LinkPropTypes = require('ReactLink').PropTypes;
-var React = require('React');
-var ReactPropTypeLocations = require('ReactPropTypeLocations');
-
-var invalidMessage = 'Invalid prop `testProp` supplied to `testComponent`.';
-var requiredMessage =
-  'Required prop `testProp` was not specified in `testComponent`.';
-
-function typeCheckFail(declaration, value, message) {
-  var props = {testProp: value};
-  var error = declaration(
-    props,
-    'testProp',
-    'testComponent',
-    ReactPropTypeLocations.prop
-  );
-  expect(error instanceof Error).toBe(true);
-  expect(error.message).toBe(message);
-}
-
-function typeCheckPass(declaration, value) {
-  var props = {testProp: value};
-  var error = declaration(
-    props,
-    'testProp',
-    'testComponent',
-    ReactPropTypeLocations.prop
-  );
-  expect(error).toBe(null);
-}
-
-describe('ReactLink', function() {
-  it('should fail if the argument does not implement the Link API', function() {
-    typeCheckFail(
-      LinkPropTypes.link(React.PropTypes.any),
-      {},
-      'Required prop `testProp.value` was not specified in `testComponent`.'
-    );
-    typeCheckFail(
-      LinkPropTypes.link(React.PropTypes.any),
-      {value: 123},
-      'Required prop `testProp.requestChange` was not specified in `testComponent`.'
-    );
-    typeCheckFail(
-      LinkPropTypes.link(React.PropTypes.any),
-      {requestChange: emptyFunction},
-      'Required prop `testProp.value` was not specified in `testComponent`.'
-    );
-    typeCheckFail(
-      LinkPropTypes.link(React.PropTypes.any),
-      {value: null, requestChange: null},
-      'Required prop `testProp.value` was not specified in `testComponent`.'
-    );
-  });
-
-  it('should allow valid links even if no type was specified', function() {
-    typeCheckPass(
-      LinkPropTypes.link(),
-      {value: 42, requestChange: emptyFunction}
-    );
-    typeCheckPass(
-      LinkPropTypes.link(),
-      {value: {}, requestChange: emptyFunction,
-    });
-  });
-
-  it('should allow no link to be passed at all', function() {
-    typeCheckPass(
-      LinkPropTypes.link(React.PropTypes.string),
-      undefined
-    );
-  });
-
-  it('should allow valid links with correct value format', function() {
-    typeCheckPass(
-      LinkPropTypes.link(React.PropTypes.any),
-      {value: 42, requestChange: emptyFunction}
-    );
-    typeCheckPass(
-      LinkPropTypes.link(React.PropTypes.number),
-      {value: 42, requestChange: emptyFunction}
-    );
-    typeCheckPass(
-      LinkPropTypes.link(React.PropTypes.node),
-      {value: 42, requestChange: emptyFunction}
-    );
-  });
-
-  it('should fail if the link`s value type does not match', function() {
-    typeCheckFail(
-      LinkPropTypes.link(React.PropTypes.string),
-      {value: 123, requestChange: emptyFunction},
-      'Invalid prop `testProp.value` of type `number` supplied to `testComponent`,' +
-      ' expected `string`.'
-    );
-  });
-
-  it('should be implicitly optional and not warn without values', function() {
-    typeCheckPass(LinkPropTypes.link(), null);
-    typeCheckPass(LinkPropTypes.link(), undefined);
-    typeCheckPass(LinkPropTypes.link(React.PropTypes.string), null);
-    typeCheckPass(LinkPropTypes.link(React.PropTypes.string), undefined);
-  });
-
-  it('should warn for missing required values', function() {
-    typeCheckFail(LinkPropTypes.link().isRequired, null, requiredMessage);
-    typeCheckFail(LinkPropTypes.link().isRequired, undefined, requiredMessage);
-    typeCheckFail(
-      LinkPropTypes.link(React.PropTypes.string).isRequired,
-      null,
-      requiredMessage
-    );
-    typeCheckFail(
-      LinkPropTypes.link(React.PropTypes.string).isRequired,
-      undefined,
-      requiredMessage
-    );
-  });
-
-  it('should be compatible with React.PropTypes.oneOfType', function() {
-    typeCheckPass(
-      React.PropTypes.oneOfType([LinkPropTypes.link(React.PropTypes.number)]),
-      {value: 123, requestChange: emptyFunction}
-    );
-    typeCheckFail(
-      React.PropTypes.oneOfType([LinkPropTypes.link(React.PropTypes.number)]),
-      123,
-      invalidMessage
-    );
-    typeCheckPass(
-      LinkPropTypes.link(React.PropTypes.oneOfType([React.PropTypes.number])),
-      {value: 123, requestChange: emptyFunction}
-    );
-    typeCheckFail(
-      LinkPropTypes.link(React.PropTypes.oneOfType([React.PropTypes.number])),
-      {value: 'imastring', requestChange: emptyFunction},
-      'Invalid prop `testProp.value` supplied to `testComponent`.'
-    );
-  });
-});
diff --git a/src/addons/shallowCompare.js b/src/addons/shallowCompare.js
index 33e4591ba89b..334f7a2db66c 100644
--- a/src/addons/shallowCompare.js
+++ b/src/addons/shallowCompare.js
@@ -6,8 +6,8 @@
  * LICENSE file in the root directory of this source tree. An additional grant
  * of patent rights can be found in the PATENTS file in the same directory.
  *
-* @providesModule shallowCompare
-*/
+ * @providesModule shallowCompare
+ */
 
 'use strict';
 
@@ -16,6 +16,7 @@ var shallowEqual = require('shallowEqual');
 /**
  * Does a shallow comparison for props and state.
  * See ReactComponentWithPureRenderMixin
+ * See also https://facebook.github.io/react/docs/shallow-compare.html
  */
 function shallowCompare(instance, nextProps, nextState) {
   return (
diff --git a/src/addons/transitions/ReactCSSTransitionGroup.js b/src/addons/transitions/ReactCSSTransitionGroup.js
index 4177ec790b2e..4c1fb3b6e489 100644
--- a/src/addons/transitions/ReactCSSTransitionGroup.js
+++ b/src/addons/transitions/ReactCSSTransitionGroup.js
@@ -12,6 +12,8 @@
 'use strict';
 
 var React = require('React');
+var propTypesFactory = require('prop-types/factory');
+var PropTypes = propTypesFactory(React.isValidElement);
 
 var ReactTransitionGroup = require('ReactTransitionGroup');
 var ReactCSSTransitionGroupChild = require('ReactCSSTransitionGroupChild');
@@ -26,44 +28,50 @@ function createTransitionTimeoutPropValidator(transitionType) {
       // If no timeout duration is provided
       if (props[timeoutPropName] == null) {
         return new Error(
-          timeoutPropName + ' wasn\'t supplied to ReactCSSTransitionGroup: ' +
-          'this can cause unreliable animations and won\'t be supported in ' +
-          'a future version of React. See ' +
-          'https://fb.me/react-animation-transition-group-timeout for more ' +
-          'information.'
+          timeoutPropName +
+            " wasn't supplied to ReactCSSTransitionGroup: " +
+            "this can cause unreliable animations and won't be supported in " +
+            'a future version of React. See ' +
+            'https://fb.me/react-animation-transition-group-timeout for more ' +
+            'information.',
         );
 
-      // If the duration isn't a number
+        // If the duration isn't a number
       } else if (typeof props[timeoutPropName] !== 'number') {
-        return new Error(timeoutPropName + ' must be a number (in milliseconds)');
+        return new Error(
+          timeoutPropName + ' must be a number (in milliseconds)',
+        );
       }
     }
   };
 }
 
-var ReactCSSTransitionGroup = React.createClass({
-  displayName: 'ReactCSSTransitionGroup',
+/**
+ * An easy way to perform CSS transitions and animations when a React component
+ * enters or leaves the DOM.
+ * See https://facebook.github.io/react/docs/animation.html#high-level-api-reactcsstransitiongroup
+ */
+class ReactCSSTransitionGroup extends React.Component {
+  static displayName = 'ReactCSSTransitionGroup';
 
-  propTypes: {
+  static propTypes = {
     transitionName: ReactCSSTransitionGroupChild.propTypes.name,
 
-    transitionAppear: React.PropTypes.bool,
-    transitionEnter: React.PropTypes.bool,
-    transitionLeave: React.PropTypes.bool,
+    transitionAppear: PropTypes.bool,
+    transitionEnter: PropTypes.bool,
+    transitionLeave: PropTypes.bool,
     transitionAppearTimeout: createTransitionTimeoutPropValidator('Appear'),
     transitionEnterTimeout: createTransitionTimeoutPropValidator('Enter'),
     transitionLeaveTimeout: createTransitionTimeoutPropValidator('Leave'),
-  },
+  };
 
-  getDefaultProps: function() {
-    return {
-      transitionAppear: false,
-      transitionEnter: true,
-      transitionLeave: true,
-    };
-  },
+  static defaultProps = {
+    transitionAppear: false,
+    transitionEnter: true,
+    transitionLeave: true,
+  };
 
-  _wrapChild: function(child) {
+  _wrapChild = child => {
     // We need to provide this childFactory so that
     // ReactCSSTransitionGroupChild can receive updates to name, enter, and
     // leave while it is leaving.
@@ -78,16 +86,16 @@ var ReactCSSTransitionGroup = React.createClass({
         enterTimeout: this.props.transitionEnterTimeout,
         leaveTimeout: this.props.transitionLeaveTimeout,
       },
-      child
+      child,
     );
-  },
+  };
 
-  render: function() {
+  render() {
     return React.createElement(
       ReactTransitionGroup,
-      Object.assign({}, this.props, {childFactory: this._wrapChild})
+      Object.assign({}, this.props, {childFactory: this._wrapChild}),
     );
-  },
-});
+  }
+}
 
 module.exports = ReactCSSTransitionGroup;
diff --git a/src/addons/transitions/ReactCSSTransitionGroupChild.js b/src/addons/transitions/ReactCSSTransitionGroupChild.js
index 170cb9d87d67..94bf1fd6f019 100644
--- a/src/addons/transitions/ReactCSSTransitionGroupChild.js
+++ b/src/addons/transitions/ReactCSSTransitionGroupChild.js
@@ -12,7 +12,10 @@
 'use strict';
 
 var React = require('React');
-var ReactDOM = require('ReactDOM');
+var ReactAddonsDOMDependencies = require('ReactAddonsDOMDependencies');
+
+var propTypesFactory = require('prop-types/factory');
+var PropTypes = propTypesFactory(React.isValidElement);
 
 var CSSCore = require('CSSCore');
 var ReactTransitionEvents = require('ReactTransitionEvents');
@@ -21,40 +24,40 @@ var onlyChild = require('onlyChild');
 
 var TICK = 17;
 
-var ReactCSSTransitionGroupChild = React.createClass({
-  displayName: 'ReactCSSTransitionGroupChild',
-
-  propTypes: {
-    name: React.PropTypes.oneOfType([
-      React.PropTypes.string,
-      React.PropTypes.shape({
-        enter: React.PropTypes.string,
-        leave: React.PropTypes.string,
-        active: React.PropTypes.string,
+class ReactCSSTransitionGroupChild extends React.Component {
+  static propTypes = {
+    name: PropTypes.oneOfType([
+      PropTypes.string,
+      PropTypes.shape({
+        enter: PropTypes.string,
+        leave: PropTypes.string,
+        active: PropTypes.string,
       }),
-      React.PropTypes.shape({
-        enter: React.PropTypes.string,
-        enterActive: React.PropTypes.string,
-        leave: React.PropTypes.string,
-        leaveActive: React.PropTypes.string,
-        appear: React.PropTypes.string,
-        appearActive: React.PropTypes.string,
+      PropTypes.shape({
+        enter: PropTypes.string,
+        enterActive: PropTypes.string,
+        leave: PropTypes.string,
+        leaveActive: PropTypes.string,
+        appear: PropTypes.string,
+        appearActive: PropTypes.string,
       }),
     ]).isRequired,
 
     // Once we require timeouts to be specified, we can remove the
     // boolean flags (appear etc.) and just accept a number
     // or a bool for the timeout flags (appearTimeout etc.)
-    appear: React.PropTypes.bool,
-    enter: React.PropTypes.bool,
-    leave: React.PropTypes.bool,
-    appearTimeout: React.PropTypes.number,
-    enterTimeout: React.PropTypes.number,
-    leaveTimeout: React.PropTypes.number,
-  },
+    appear: PropTypes.bool,
+    enter: PropTypes.bool,
+    leave: PropTypes.bool,
+    appearTimeout: PropTypes.number,
+    enterTimeout: PropTypes.number,
+    leaveTimeout: PropTypes.number,
+  };
 
-  transition: function(animationType, finishCallback, userSpecifiedDelay) {
-    var node = ReactDOM.findDOMNode(this);
+  _isMounted = false;
+
+  transition = (animationType, finishCallback, userSpecifiedDelay) => {
+    var node = ReactAddonsDOMDependencies.getReactDOM().findDOMNode(this);
 
     if (!node) {
       if (finishCallback) {
@@ -63,8 +66,10 @@ var ReactCSSTransitionGroupChild = React.createClass({
       return;
     }
 
-    var className = this.props.name[animationType] || this.props.name + '-' + animationType;
-    var activeClassName = this.props.name[animationType + 'Active'] || className + '-active';
+    var className =
+      this.props.name[animationType] || this.props.name + '-' + animationType;
+    var activeClassName =
+      this.props.name[animationType + 'Active'] || className + '-active';
     var timeout = null;
 
     var endListener = function(e) {
@@ -89,7 +94,7 @@ var ReactCSSTransitionGroupChild = React.createClass({
     CSSCore.addClass(node, className);
 
     // Need to do this to actually trigger a transition.
-    this.queueClass(activeClassName);
+    this.queueClassAndNode(activeClassName, node);
 
     // If the user specified a timeout delay.
     if (userSpecifiedDelay) {
@@ -100,67 +105,78 @@ var ReactCSSTransitionGroupChild = React.createClass({
       // DEPRECATED: this listener will be removed in a future version of react
       ReactTransitionEvents.addEndEventListener(node, endListener);
     }
-  },
+  };
 
-  queueClass: function(className) {
-    this.classNameQueue.push(className);
+  queueClassAndNode = (className, node) => {
+    this.classNameAndNodeQueue.push({
+      className: className,
+      node: node,
+    });
 
     if (!this.timeout) {
-      this.timeout = setTimeout(this.flushClassNameQueue, TICK);
+      this.timeout = setTimeout(this.flushClassNameAndNodeQueue, TICK);
     }
-  },
+  };
 
-  flushClassNameQueue: function() {
-    if (this.isMounted()) {
-      this.classNameQueue.forEach(
-        CSSCore.addClass.bind(CSSCore, ReactDOM.findDOMNode(this))
-      );
+  flushClassNameAndNodeQueue = () => {
+    if (this._isMounted) {
+      this.classNameAndNodeQueue.forEach(function(obj) {
+        CSSCore.addClass(obj.node, obj.className);
+      });
     }
-    this.classNameQueue.length = 0;
+    this.classNameAndNodeQueue.length = 0;
     this.timeout = null;
-  },
+  };
 
-  componentWillMount: function() {
-    this.classNameQueue = [];
+  componentWillMount() {
+    this.classNameAndNodeQueue = [];
     this.transitionTimeouts = [];
-  },
+  }
+
+  componentDidMount() {
+    this._isMounted = true;
+  }
+
+  componentWillUnmount() {
+    this._isMounted = false;
 
-  componentWillUnmount: function() {
     if (this.timeout) {
       clearTimeout(this.timeout);
     }
     this.transitionTimeouts.forEach(function(timeout) {
       clearTimeout(timeout);
     });
-  },
 
-  componentWillAppear: function(done) {
+    this.classNameAndNodeQueue.length = 0;
+  }
+
+  componentWillAppear = done => {
     if (this.props.appear) {
       this.transition('appear', done, this.props.appearTimeout);
     } else {
       done();
     }
-  },
+  };
 
-  componentWillEnter: function(done) {
+  componentWillEnter = done => {
     if (this.props.enter) {
       this.transition('enter', done, this.props.enterTimeout);
     } else {
       done();
     }
-  },
+  };
 
-  componentWillLeave: function(done) {
+  componentWillLeave = done => {
     if (this.props.leave) {
       this.transition('leave', done, this.props.leaveTimeout);
     } else {
       done();
     }
-  },
+  };
 
-  render: function() {
+  render() {
     return onlyChild(this.props.children);
-  },
-});
+  }
+}
 
 module.exports = ReactCSSTransitionGroupChild;
diff --git a/src/addons/transitions/ReactTransitionChildMapping.js b/src/addons/transitions/ReactTransitionChildMapping.js
index 28583432403d..4ba6795dfce9 100644
--- a/src/addons/transitions/ReactTransitionChildMapping.js
+++ b/src/addons/transitions/ReactTransitionChildMapping.js
@@ -19,12 +19,18 @@ var ReactTransitionChildMapping = {
    * simple syntactic sugar around flattenChildren().
    *
    * @param {*} children `this.props.children`
+   * @param {number=} selfDebugID Optional debugID of the current internal instance.
    * @return {object} Mapping of key to child
    */
-  getChildMapping: function(children) {
+  getChildMapping: function(children, selfDebugID) {
     if (!children) {
       return children;
     }
+
+    if (__DEV__) {
+      return flattenChildren(children, selfDebugID);
+    }
+
     return flattenChildren(children);
   },
 
@@ -80,7 +86,7 @@ var ReactTransitionChildMapping = {
         for (i = 0; i < nextKeysPending[nextKey].length; i++) {
           var pendingNextKey = nextKeysPending[nextKey][i];
           childMapping[nextKeysPending[nextKey][i]] = getValueForKey(
-            pendingNextKey
+            pendingNextKey,
           );
         }
       }
diff --git a/src/addons/transitions/ReactTransitionGroup.js b/src/addons/transitions/ReactTransitionGroup.js
index 6d6df1a80b60..cd576aa852ce 100644
--- a/src/addons/transitions/ReactTransitionGroup.js
+++ b/src/addons/transitions/ReactTransitionGroup.js
@@ -14,54 +14,59 @@
 var React = require('React');
 var ReactTransitionChildMapping = require('ReactTransitionChildMapping');
 
+var propTypesFactory = require('prop-types/factory');
+var PropTypes = propTypesFactory(React.isValidElement);
+
 var emptyFunction = require('emptyFunction');
 
-var ReactTransitionGroup = React.createClass({
-  displayName: 'ReactTransitionGroup',
+/**
+ * A basis for animations. When children are declaratively added or removed,
+ * special lifecycle hooks are called.
+ * See https://facebook.github.io/react/docs/animation.html#low-level-api-reacttransitiongroup
+ */
+class ReactTransitionGroup extends React.Component {
+  static displayName = 'ReactTransitionGroup';
 
-  propTypes: {
-    component: React.PropTypes.any,
-    childFactory: React.PropTypes.func,
-  },
+  static propTypes = {
+    component: PropTypes.any,
+    childFactory: PropTypes.func,
+  };
 
-  getDefaultProps: function() {
-    return {
-      component: 'span',
-      childFactory: emptyFunction.thatReturnsArgument,
-    };
-  },
+  static defaultProps = {
+    component: 'span',
+    childFactory: emptyFunction.thatReturnsArgument,
+  };
 
-  getInitialState: function() {
-    return {
-      children: ReactTransitionChildMapping.getChildMapping(this.props.children),
-    };
-  },
+  state = {
+    // TODO: can we get useful debug information to show at this point?
+    children: ReactTransitionChildMapping.getChildMapping(this.props.children),
+  };
 
-  componentWillMount: function() {
+  componentWillMount() {
     this.currentlyTransitioningKeys = {};
     this.keysToEnter = [];
     this.keysToLeave = [];
-  },
+  }
 
-  componentDidMount: function() {
+  componentDidMount() {
     var initialChildMapping = this.state.children;
     for (var key in initialChildMapping) {
       if (initialChildMapping[key]) {
         this.performAppear(key);
       }
     }
-  },
+  }
 
-  componentWillReceiveProps: function(nextProps) {
+  componentWillReceiveProps(nextProps) {
     var nextChildMapping = ReactTransitionChildMapping.getChildMapping(
-      nextProps.children
+      nextProps.children,
     );
     var prevChildMapping = this.state.children;
 
     this.setState({
       children: ReactTransitionChildMapping.mergeChildMappings(
         prevChildMapping,
-        nextChildMapping
+        nextChildMapping,
       ),
     });
 
@@ -69,24 +74,30 @@ var ReactTransitionGroup = React.createClass({
 
     for (key in nextChildMapping) {
       var hasPrev = prevChildMapping && prevChildMapping.hasOwnProperty(key);
-      if (nextChildMapping[key] && !hasPrev &&
-          !this.currentlyTransitioningKeys[key]) {
+      if (
+        nextChildMapping[key] &&
+        !hasPrev &&
+        !this.currentlyTransitioningKeys[key]
+      ) {
         this.keysToEnter.push(key);
       }
     }
 
     for (key in prevChildMapping) {
       var hasNext = nextChildMapping && nextChildMapping.hasOwnProperty(key);
-      if (prevChildMapping[key] && !hasNext &&
-          !this.currentlyTransitioningKeys[key]) {
+      if (
+        prevChildMapping[key] &&
+        !hasNext &&
+        !this.currentlyTransitioningKeys[key]
+      ) {
         this.keysToLeave.push(key);
       }
     }
 
     // If we want to someday check for reordering, we could do it here.
-  },
+  }
 
-  componentDidUpdate: function() {
+  componentDidUpdate() {
     var keysToEnter = this.keysToEnter;
     this.keysToEnter = [];
     keysToEnter.forEach(this.performEnter);
@@ -94,23 +105,21 @@ var ReactTransitionGroup = React.createClass({
     var keysToLeave = this.keysToLeave;
     this.keysToLeave = [];
     keysToLeave.forEach(this.performLeave);
-  },
+  }
 
-  performAppear: function(key) {
+  performAppear = key => {
     this.currentlyTransitioningKeys[key] = true;
 
     var component = this.refs[key];
 
     if (component.componentWillAppear) {
-      component.componentWillAppear(
-        this._handleDoneAppearing.bind(this, key)
-      );
+      component.componentWillAppear(this._handleDoneAppearing.bind(this, key));
     } else {
       this._handleDoneAppearing(key);
     }
-  },
+  };
 
-  _handleDoneAppearing: function(key) {
+  _handleDoneAppearing = key => {
     var component = this.refs[key];
     if (component.componentDidAppear) {
       component.componentDidAppear();
@@ -119,30 +128,28 @@ var ReactTransitionGroup = React.createClass({
     delete this.currentlyTransitioningKeys[key];
 
     var currentChildMapping = ReactTransitionChildMapping.getChildMapping(
-      this.props.children
+      this.props.children,
     );
 
     if (!currentChildMapping || !currentChildMapping.hasOwnProperty(key)) {
       // This was removed before it had fully appeared. Remove it.
       this.performLeave(key);
     }
-  },
+  };
 
-  performEnter: function(key) {
+  performEnter = key => {
     this.currentlyTransitioningKeys[key] = true;
 
     var component = this.refs[key];
 
     if (component.componentWillEnter) {
-      component.componentWillEnter(
-        this._handleDoneEntering.bind(this, key)
-      );
+      component.componentWillEnter(this._handleDoneEntering.bind(this, key));
     } else {
       this._handleDoneEntering(key);
     }
-  },
+  };
 
-  _handleDoneEntering: function(key) {
+  _handleDoneEntering = key => {
     var component = this.refs[key];
     if (component.componentDidEnter) {
       component.componentDidEnter();
@@ -151,16 +158,16 @@ var ReactTransitionGroup = React.createClass({
     delete this.currentlyTransitioningKeys[key];
 
     var currentChildMapping = ReactTransitionChildMapping.getChildMapping(
-      this.props.children
+      this.props.children,
     );
 
     if (!currentChildMapping || !currentChildMapping.hasOwnProperty(key)) {
       // This was removed before it had fully entered. Remove it.
       this.performLeave(key);
     }
-  },
+  };
 
-  performLeave: function(key) {
+  performLeave = key => {
     this.currentlyTransitioningKeys[key] = true;
 
     var component = this.refs[key];
@@ -172,9 +179,9 @@ var ReactTransitionGroup = React.createClass({
       // is done.
       this._handleDoneLeaving(key);
     }
-  },
+  };
 
-  _handleDoneLeaving: function(key) {
+  _handleDoneLeaving = key => {
     var component = this.refs[key];
 
     if (component.componentDidLeave) {
@@ -184,7 +191,7 @@ var ReactTransitionGroup = React.createClass({
     delete this.currentlyTransitioningKeys[key];
 
     var currentChildMapping = ReactTransitionChildMapping.getChildMapping(
-      this.props.children
+      this.props.children,
     );
 
     if (currentChildMapping && currentChildMapping.hasOwnProperty(key)) {
@@ -197,9 +204,9 @@ var ReactTransitionGroup = React.createClass({
         return {children: newChildren};
       });
     }
-  },
+  };
 
-  render: function() {
+  render() {
     // TODO: we could get rid of the need for the wrapper node
     // by cloning a single child
     var childrenToRender = [];
@@ -211,18 +218,29 @@ var ReactTransitionGroup = React.createClass({
         // already been removed. In case you need this behavior you can provide
         // a childFactory function to wrap every child, even the ones that are
         // leaving.
-        childrenToRender.push(React.cloneElement(
-          this.props.childFactory(child),
-          {ref: key, key: key}
-        ));
+        childrenToRender.push(
+          React.cloneElement(this.props.childFactory(child), {
+            ref: key,
+            key: key,
+          }),
+        );
       }
     }
-    return React.createElement(
-      this.props.component,
-      this.props,
-      childrenToRender
-    );
-  },
-});
+
+    // Do not forward ReactTransitionGroup props to primitive DOM nodes
+    var props = Object.assign({}, this.props);
+    delete props.transitionLeave;
+    delete props.transitionName;
+    delete props.transitionAppear;
+    delete props.transitionEnter;
+    delete props.childFactory;
+    delete props.transitionLeaveTimeout;
+    delete props.transitionEnterTimeout;
+    delete props.transitionAppearTimeout;
+    delete props.component;
+
+    return React.createElement(this.props.component, props, childrenToRender);
+  }
+}
 
 module.exports = ReactTransitionGroup;
diff --git a/src/addons/transitions/__tests__/ReactCSSTransitionGroup-test.js b/src/addons/transitions/__tests__/ReactCSSTransitionGroup-test.js
deleted file mode 100644
index 0bf8c6bb2ff7..000000000000
--- a/src/addons/transitions/__tests__/ReactCSSTransitionGroup-test.js
+++ /dev/null
@@ -1,294 +0,0 @@
-/**
- * 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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-var CSSCore = require('CSSCore');
-
-var React;
-var ReactDOM;
-var ReactCSSTransitionGroup;
-
-// Most of the real functionality is covered in other unit tests, this just
-// makes sure we're wired up correctly.
-describe('ReactCSSTransitionGroup', function() {
-  var container;
-
-  beforeEach(function() {
-    jest.resetModuleRegistry();
-    React = require('React');
-    ReactDOM = require('ReactDOM');
-    ReactCSSTransitionGroup = require('ReactCSSTransitionGroup');
-
-    container = document.createElement('div');
-    spyOn(console, 'error');
-  });
-
-  it('should warn if timeouts aren\'t specified', function() {
-    ReactDOM.render(
-      <ReactCSSTransitionGroup
-        transitionName="yolo"
-        transitionEnter={false}
-        transitionLeave={true}
-      >
-        <span key="one" id="one" />
-      </ReactCSSTransitionGroup>,
-      container
-    );
-
-    // Warning about the missing transitionLeaveTimeout prop
-    expect(console.error.argsForCall.length).toBe(1);
-  });
-
-  it('should not warn if timeouts is zero', function() {
-    ReactDOM.render(
-      <ReactCSSTransitionGroup
-        transitionName="yolo"
-        transitionEnter={false}
-        transitionLeave={true}
-        transitionLeaveTimeout={0}
-      >
-        <span key="one" id="one" />
-      </ReactCSSTransitionGroup>,
-      container
-    );
-
-    expect(console.error.argsForCall.length).toBe(0);
-  });
-
-  it('should clean-up silently after the timeout elapses', function() {
-    var a = ReactDOM.render(
-      <ReactCSSTransitionGroup
-        transitionName="yolo"
-        transitionEnter={false}
-        transitionLeaveTimeout={200}
-      >
-        <span key="one" id="one" />
-      </ReactCSSTransitionGroup>,
-      container
-    );
-    expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(1);
-
-    setTimeout.mock.calls.length = 0;
-
-    ReactDOM.render(
-      <ReactCSSTransitionGroup
-        transitionName="yolo"
-        transitionEnter={false}
-        transitionLeaveTimeout={200}
-      >
-        <span key="two" id="two" />
-      </ReactCSSTransitionGroup>,
-      container
-    );
-    expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(2);
-    expect(ReactDOM.findDOMNode(a).childNodes[0].id).toBe('two');
-    expect(ReactDOM.findDOMNode(a).childNodes[1].id).toBe('one');
-
-    // For some reason jst is adding extra setTimeout()s and grunt test isn't,
-    // so we need to do this disgusting hack.
-    for (var i = 0; i < setTimeout.mock.calls.length; i++) {
-      if (setTimeout.mock.calls[i][1] === 200) {
-        setTimeout.mock.calls[i][0]();
-        break;
-      }
-    }
-
-    // No warnings
-    expect(console.error.argsForCall.length).toBe(0);
-
-    // The leaving child has been removed
-    expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(1);
-    expect(ReactDOM.findDOMNode(a).childNodes[0].id).toBe('two');
-  });
-
-  it('should keep both sets of DOM nodes around', function() {
-    var a = ReactDOM.render(
-      <ReactCSSTransitionGroup transitionName="yolo">
-        <span key="one" id="one" />
-      </ReactCSSTransitionGroup>,
-      container
-    );
-    expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(1);
-    ReactDOM.render(
-      <ReactCSSTransitionGroup transitionName="yolo">
-        <span key="two" id="two" />
-      </ReactCSSTransitionGroup>,
-      container
-    );
-    expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(2);
-    expect(ReactDOM.findDOMNode(a).childNodes[0].id).toBe('two');
-    expect(ReactDOM.findDOMNode(a).childNodes[1].id).toBe('one');
-  });
-
-  it('should switch transitionLeave from false to true', function() {
-    var a = ReactDOM.render(
-      <ReactCSSTransitionGroup
-          transitionName="yolo"
-          transitionEnter={false}
-          transitionLeave={false}>
-        <span key="one" id="one" />
-      </ReactCSSTransitionGroup>,
-      container
-    );
-    expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(1);
-    ReactDOM.render(
-      <ReactCSSTransitionGroup
-          transitionName="yolo"
-          transitionEnter={false}
-          transitionLeave={false}>
-        <span key="two" id="two" />
-      </ReactCSSTransitionGroup>,
-      container
-    );
-    expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(1);
-    ReactDOM.render(
-      <ReactCSSTransitionGroup
-          transitionName="yolo"
-          transitionEnter={false}
-          transitionLeave={true}>
-        <span key="three" id="three" />
-      </ReactCSSTransitionGroup>,
-      container
-    );
-    expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(2);
-    expect(ReactDOM.findDOMNode(a).childNodes[0].id).toBe('three');
-    expect(ReactDOM.findDOMNode(a).childNodes[1].id).toBe('two');
-  });
-
-  it('should work with no children', function() {
-    ReactDOM.render(
-      <ReactCSSTransitionGroup transitionName="yolo" />,
-      container
-    );
-  });
-
-  it('should work with a null child', function() {
-    ReactDOM.render(
-      <ReactCSSTransitionGroup transitionName="yolo">
-        {[null]}
-      </ReactCSSTransitionGroup>,
-      container
-    );
-  });
-
-  it('should transition from one to null', function() {
-    var a = ReactDOM.render(
-      <ReactCSSTransitionGroup transitionName="yolo">
-        <span key="one" id="one" />
-      </ReactCSSTransitionGroup>,
-      container
-    );
-    expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(1);
-    ReactDOM.render(
-      <ReactCSSTransitionGroup transitionName="yolo">
-        {null}
-      </ReactCSSTransitionGroup>,
-      container
-    );
-    // (Here, we expect the original child to stick around but test that no
-    // exception is thrown)
-    expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(1);
-    expect(ReactDOM.findDOMNode(a).childNodes[0].id).toBe('one');
-  });
-
-  it('should transition from false to one', function() {
-    var a = ReactDOM.render(
-      <ReactCSSTransitionGroup transitionName="yolo">
-        {false}
-      </ReactCSSTransitionGroup>,
-      container
-    );
-    expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(0);
-    ReactDOM.render(
-      <ReactCSSTransitionGroup transitionName="yolo">
-        <span key="one" id="one" />
-      </ReactCSSTransitionGroup>,
-      container
-    );
-    expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(1);
-    expect(ReactDOM.findDOMNode(a).childNodes[0].id).toBe('one');
-  });
-
-  it('should use transition-type specific names when they\'re provided', function() {
-    var customTransitionNames = {
-      enter: 'custom-entering',
-      leave: 'custom-leaving',
-    };
-
-    var a = ReactDOM.render(
-      <ReactCSSTransitionGroup
-        transitionName={customTransitionNames}
-        transitionEnterTimeout={1}
-        transitionLeaveTimeout={1}
-      >
-        <span key="one" id="one" />
-      </ReactCSSTransitionGroup>,
-      container
-    );
-    expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(1);
-
-    // Add an element
-    ReactDOM.render(
-      <ReactCSSTransitionGroup
-        transitionName={customTransitionNames}
-        transitionEnterTimeout={1}
-        transitionLeaveTimeout={1}
-      >
-        <span key="one" id="one" />
-        <span key="two" id="two" />
-      </ReactCSSTransitionGroup>,
-      container
-    );
-    expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(2);
-
-    var enteringNode = ReactDOM.findDOMNode(a).childNodes[1];
-    expect(CSSCore.hasClass(enteringNode, 'custom-entering')).toBe(true);
-
-    // Remove an element
-    ReactDOM.render(
-      <ReactCSSTransitionGroup
-        transitionName={customTransitionNames}
-        transitionEnterTimeout={1}
-        transitionLeaveTimeout={1}
-      >
-        <span key="two" id="two" />
-      </ReactCSSTransitionGroup>,
-      container
-    );
-    expect(ReactDOM.findDOMNode(a).childNodes.length).toBe(2);
-
-    var leavingNode = ReactDOM.findDOMNode(a).childNodes[0];
-    expect(CSSCore.hasClass(leavingNode, 'custom-leaving')).toBe(true);
-  });
-
-  it('should clear transition timeouts when unmounted', function() {
-    var Component = React.createClass({
-      render: function() {
-        return (
-          <ReactCSSTransitionGroup
-            transitionName="yolo"
-            transitionEnterTimeout={500}>
-            {this.props.children}
-          </ReactCSSTransitionGroup>
-        );
-      },
-    });
-
-    ReactDOM.render(<Component/>, container);
-    ReactDOM.render(<Component><span key="yolo" id="yolo"/></Component>, container);
-
-    ReactDOM.unmountComponentAtNode(container);
-
-    // Testing that no exception is thrown here, as the timeout has been cleared.
-    jest.runAllTimers();
-  });
-});
diff --git a/src/addons/transitions/__tests__/ReactTransitionChildMapping-test.js b/src/addons/transitions/__tests__/ReactTransitionChildMapping-test.js
index 7cc3c63a6f11..b6c705898985 100644
--- a/src/addons/transitions/__tests__/ReactTransitionChildMapping-test.js
+++ b/src/addons/transitions/__tests__/ReactTransitionChildMapping-test.js
@@ -14,27 +14,27 @@
 var React;
 var ReactTransitionChildMapping;
 
-describe('ReactTransitionChildMapping', function() {
-  beforeEach(function() {
+describe('ReactTransitionChildMapping', () => {
+  beforeEach(() => {
     React = require('React');
     ReactTransitionChildMapping = require('ReactTransitionChildMapping');
   });
 
-  it('should support getChildMapping', function() {
+  it('should support getChildMapping', () => {
     var oneone = <div key="oneone" />;
     var onetwo = <div key="onetwo" />;
     var one = <div key="one">{oneone}{onetwo}</div>;
     var two = <div key="two" />;
     var component = <div>{one}{two}</div>;
     expect(
-      ReactTransitionChildMapping.getChildMapping(component.props.children)
+      ReactTransitionChildMapping.getChildMapping(component.props.children),
     ).toEqual({
       '.$one': one,
       '.$two': two,
     });
   });
 
-  it('should support mergeChildMappings for adding keys', function() {
+  it('should support mergeChildMappings for adding keys', () => {
     var prev = {
       one: true,
       two: true,
@@ -51,7 +51,7 @@ describe('ReactTransitionChildMapping', function() {
     });
   });
 
-  it('should support mergeChildMappings for removing keys', function() {
+  it('should support mergeChildMappings for removing keys', () => {
     var prev = {
       one: true,
       two: true,
@@ -68,7 +68,7 @@ describe('ReactTransitionChildMapping', function() {
     });
   });
 
-  it('should support mergeChildMappings for adding and removing', function() {
+  it('should support mergeChildMappings for adding and removing', () => {
     var prev = {
       one: true,
       two: true,
@@ -87,7 +87,7 @@ describe('ReactTransitionChildMapping', function() {
     });
   });
 
-  it('should reconcile overlapping insertions and deletions', function() {
+  it('should reconcile overlapping insertions and deletions', () => {
     var prev = {
       one: true,
       two: true,
@@ -109,7 +109,7 @@ describe('ReactTransitionChildMapping', function() {
     });
   });
 
-  it('should support mergeChildMappings with undefined input', function() {
+  it('should support mergeChildMappings with undefined input', () => {
     var prev = {
       one: true,
       two: true,
diff --git a/src/addons/transitions/__tests__/ReactTransitionGroup-test.js b/src/addons/transitions/__tests__/ReactTransitionGroup-test.js
deleted file mode 100644
index f98302be10c6..000000000000
--- a/src/addons/transitions/__tests__/ReactTransitionGroup-test.js
+++ /dev/null
@@ -1,272 +0,0 @@
-/**
- * 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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-var React;
-var ReactDOM;
-var ReactTransitionGroup;
-
-// Most of the real functionality is covered in other unit tests, this just
-// makes sure we're wired up correctly.
-describe('ReactTransitionGroup', function() {
-  var container;
-
-  beforeEach(function() {
-    React = require('React');
-    ReactDOM = require('ReactDOM');
-    ReactTransitionGroup = require('ReactTransitionGroup');
-
-    container = document.createElement('div');
-  });
-
-
-  it('should handle willEnter correctly', function() {
-    var log = [];
-
-    var Child = React.createClass({
-      componentDidMount: function() {
-        log.push('didMount');
-      },
-      componentWillAppear: function(cb) {
-        log.push('willAppear');
-        cb();
-      },
-      componentDidAppear: function() {
-        log.push('didAppear');
-      },
-      componentWillEnter: function(cb) {
-        log.push('willEnter');
-        cb();
-      },
-      componentDidEnter: function() {
-        log.push('didEnter');
-      },
-      componentWillLeave: function(cb) {
-        log.push('willLeave');
-        cb();
-      },
-      componentDidLeave: function() {
-        log.push('didLeave');
-      },
-      componentWillUnmount: function() {
-        log.push('willUnmount');
-      },
-      render: function() {
-        return <span />;
-      },
-    });
-
-    var Component = React.createClass({
-      getInitialState: function() {
-        return {count: 1};
-      },
-      render: function() {
-        var children = [];
-        for (var i = 0; i < this.state.count; i++) {
-          children.push(<Child key={i} />);
-        }
-        return <ReactTransitionGroup>{children}</ReactTransitionGroup>;
-      },
-    });
-
-    var instance = ReactDOM.render(<Component />, container);
-    expect(log).toEqual(['didMount', 'willAppear', 'didAppear']);
-
-    log = [];
-    instance.setState({count: 2}, function() {
-      expect(log).toEqual(['didMount', 'willEnter', 'didEnter']);
-
-      log = [];
-      instance.setState({count: 1}, function() {
-        expect(log).toEqual(['willLeave', 'didLeave', 'willUnmount']);
-      });
-    });
-  });
-
-  it('should handle enter/leave/enter/leave correctly', function() {
-    var log = [];
-    var willEnterCb;
-
-    var Child = React.createClass({
-      componentDidMount: function() {
-        log.push('didMount');
-      },
-      componentWillEnter: function(cb) {
-        log.push('willEnter');
-        willEnterCb = cb;
-      },
-      componentDidEnter: function() {
-        log.push('didEnter');
-      },
-      componentWillLeave: function(cb) {
-        log.push('willLeave');
-        cb();
-      },
-      componentDidLeave: function() {
-        log.push('didLeave');
-      },
-      componentWillUnmount: function() {
-        log.push('willUnmount');
-      },
-      render: function() {
-        return <span />;
-      },
-    });
-
-    var Component = React.createClass({
-      getInitialState: function() {
-        return {count: 1};
-      },
-      render: function() {
-        var children = [];
-        for (var i = 0; i < this.state.count; i++) {
-          children.push(<Child key={i} />);
-        }
-        return <ReactTransitionGroup>{children}</ReactTransitionGroup>;
-      },
-    });
-
-    var instance = ReactDOM.render(<Component />, container);
-    expect(log).toEqual(['didMount']);
-    instance.setState({count: 2});
-    expect(log).toEqual(['didMount', 'didMount', 'willEnter']);
-    for (var k = 0; k < 5; k++) {
-      instance.setState({count: 2});
-      expect(log).toEqual(['didMount', 'didMount', 'willEnter']);
-      instance.setState({count: 1});
-    }
-    // other animations are blocked until willEnterCb is called
-    willEnterCb();
-    expect(log).toEqual([
-      'didMount', 'didMount', 'willEnter',
-      'didEnter', 'willLeave', 'didLeave', 'willUnmount',
-    ]);
-  });
-
-  it('should handle enter/leave/enter correctly', function() {
-    var log = [];
-    var willEnterCb;
-
-    var Child = React.createClass({
-      componentDidMount: function() {
-        log.push('didMount');
-      },
-      componentWillEnter: function(cb) {
-        log.push('willEnter');
-        willEnterCb = cb;
-      },
-      componentDidEnter: function() {
-        log.push('didEnter');
-      },
-      componentWillLeave: function(cb) {
-        log.push('willLeave');
-        cb();
-      },
-      componentDidLeave: function() {
-        log.push('didLeave');
-      },
-      componentWillUnmount: function() {
-        log.push('willUnmount');
-      },
-      render: function() {
-        return <span />;
-      },
-    });
-
-    var Component = React.createClass({
-      getInitialState: function() {
-        return {count: 1};
-      },
-      render: function() {
-        var children = [];
-        for (var i = 0; i < this.state.count; i++) {
-          children.push(<Child key={i} />);
-        }
-        return <ReactTransitionGroup>{children}</ReactTransitionGroup>;
-      },
-    });
-
-    var instance = ReactDOM.render(<Component />, container);
-    expect(log).toEqual(['didMount']);
-    instance.setState({count: 2});
-    expect(log).toEqual(['didMount', 'didMount', 'willEnter']);
-    for (var k = 0; k < 5; k++) {
-      instance.setState({count: 1});
-      expect(log).toEqual(['didMount', 'didMount', 'willEnter']);
-      instance.setState({count: 2});
-    }
-    willEnterCb();
-    expect(log).toEqual([
-      'didMount', 'didMount', 'willEnter', 'didEnter',
-    ]);
-  });
-
-  it('should handle entering/leaving several elements at once', function() {
-    var log = [];
-
-    var Child = React.createClass({
-      componentDidMount: function() {
-        log.push('didMount' + this.props.id);
-      },
-      componentWillEnter: function(cb) {
-        log.push('willEnter' + this.props.id);
-        cb();
-      },
-      componentDidEnter: function() {
-        log.push('didEnter' + this.props.id);
-      },
-      componentWillLeave: function(cb) {
-        log.push('willLeave' + this.props.id);
-        cb();
-      },
-      componentDidLeave: function() {
-        log.push('didLeave' + this.props.id);
-      },
-      componentWillUnmount: function() {
-        log.push('willUnmount' + this.props.id);
-      },
-      render: function() {
-        return <span />;
-      },
-    });
-
-    var Component = React.createClass({
-      getInitialState: function() {
-        return {count: 1};
-      },
-      render: function() {
-        var children = [];
-        for (var i = 0; i < this.state.count; i++) {
-          children.push(<Child key={i} id={i} />);
-        }
-        return <ReactTransitionGroup>{children}</ReactTransitionGroup>;
-      },
-    });
-
-    var instance = ReactDOM.render(<Component />, container);
-    expect(log).toEqual(['didMount0']);
-    log = [];
-
-    instance.setState({count: 3});
-    expect(log).toEqual([
-      'didMount1', 'didMount2', 'willEnter1', 'didEnter1',
-      'willEnter2', 'didEnter2',
-    ]);
-    log = [];
-
-    instance.setState({count: 0});
-    expect(log).toEqual([
-      'willLeave0', 'didLeave0', 'willLeave1', 'didLeave1',
-      'willLeave2', 'didLeave2', 'willUnmount0', 'willUnmount1', 'willUnmount2',
-    ]);
-  });
-});
diff --git a/src/addons/update.js b/src/addons/update.js
index cc2434e2bd30..ce5fa018d168 100644
--- a/src/addons/update.js
+++ b/src/addons/update.js
@@ -9,11 +9,10 @@
  * @providesModule update
  */
 
- /* global hasOwnProperty:true */
+/* global hasOwnProperty:true */
 
 'use strict';
 
-var keyOf = require('keyOf');
 var invariant = require('invariant');
 var hasOwnProperty = {}.hasOwnProperty;
 
@@ -27,12 +26,12 @@ function shallowCopy(x) {
   }
 }
 
-var COMMAND_PUSH = keyOf({$push: null});
-var COMMAND_UNSHIFT = keyOf({$unshift: null});
-var COMMAND_SPLICE = keyOf({$splice: null});
-var COMMAND_SET = keyOf({$set: null});
-var COMMAND_MERGE = keyOf({$merge: null});
-var COMMAND_APPLY = keyOf({$apply: null});
+var COMMAND_PUSH = '$push';
+var COMMAND_UNSHIFT = '$unshift';
+var COMMAND_SPLICE = '$splice';
+var COMMAND_SET = '$set';
+var COMMAND_MERGE = '$merge';
+var COMMAND_APPLY = '$apply';
 
 var ALL_COMMANDS_LIST = [
   COMMAND_PUSH,
@@ -54,32 +53,36 @@ function invariantArrayCase(value, spec, command) {
     Array.isArray(value),
     'update(): expected target of %s to be an array; got %s.',
     command,
-    value
+    value,
   );
   var specValue = spec[command];
   invariant(
     Array.isArray(specValue),
     'update(): expected spec of %s to be an array; got %s. ' +
-    'Did you forget to wrap your parameter in an array?',
+      'Did you forget to wrap your parameter in an array?',
     command,
-    specValue
+    specValue,
   );
 }
 
+/**
+ * Returns a updated shallow copy of an object without mutating the original.
+ * See https://facebook.github.io/react/docs/update.html for details.
+ */
 function update(value, spec) {
   invariant(
     typeof spec === 'object',
     'update(): You provided a key path to update() that did not contain one ' +
-    'of %s. Did you forget to include {%s: ...}?',
+      'of %s. Did you forget to include {%s: ...}?',
     ALL_COMMANDS_LIST.join(', '),
-    COMMAND_SET
+    COMMAND_SET,
   );
 
   if (hasOwnProperty.call(spec, COMMAND_SET)) {
     invariant(
       Object.keys(spec).length === 1,
       'Cannot have more than one key in an object with %s',
-      COMMAND_SET
+      COMMAND_SET,
     );
 
     return spec[COMMAND_SET];
@@ -91,15 +94,15 @@ function update(value, spec) {
     var mergeObj = spec[COMMAND_MERGE];
     invariant(
       mergeObj && typeof mergeObj === 'object',
-      'update(): %s expects a spec of type \'object\'; got %s',
+      "update(): %s expects a spec of type 'object'; got %s",
       COMMAND_MERGE,
-      mergeObj
+      mergeObj,
     );
     invariant(
       nextValue && typeof nextValue === 'object',
-      'update(): %s expects a target of type \'object\'; got %s',
+      "update(): %s expects a target of type 'object'; got %s",
       COMMAND_MERGE,
-      nextValue
+      nextValue,
     );
     Object.assign(nextValue, spec[COMMAND_MERGE]);
   }
@@ -123,22 +126,22 @@ function update(value, spec) {
       Array.isArray(value),
       'Expected %s target to be an array; got %s',
       COMMAND_SPLICE,
-      value
+      value,
     );
     invariant(
       Array.isArray(spec[COMMAND_SPLICE]),
       'update(): expected spec of %s to be an array of arrays; got %s. ' +
-      'Did you forget to wrap your parameters in an array?',
+        'Did you forget to wrap your parameters in an array?',
       COMMAND_SPLICE,
-      spec[COMMAND_SPLICE]
+      spec[COMMAND_SPLICE],
     );
     spec[COMMAND_SPLICE].forEach(function(args) {
       invariant(
         Array.isArray(args),
         'update(): expected spec of %s to be an array of arrays; got %s. ' +
-        'Did you forget to wrap your parameters in an array?',
+          'Did you forget to wrap your parameters in an array?',
         COMMAND_SPLICE,
-        spec[COMMAND_SPLICE]
+        spec[COMMAND_SPLICE],
       );
       nextValue.splice.apply(nextValue, args);
     });
@@ -149,7 +152,7 @@ function update(value, spec) {
       typeof spec[COMMAND_APPLY] === 'function',
       'update(): expected spec of %s to be a function; got %s.',
       COMMAND_APPLY,
-      spec[COMMAND_APPLY]
+      spec[COMMAND_APPLY],
     );
     nextValue = spec[COMMAND_APPLY](nextValue);
   }
diff --git a/src/core/__tests__/ReactErrorBoundaries-test.js b/src/core/__tests__/ReactErrorBoundaries-test.js
deleted file mode 100644
index 0ba37323d552..000000000000
--- a/src/core/__tests__/ReactErrorBoundaries-test.js
+++ /dev/null
@@ -1,239 +0,0 @@
-/**
- * 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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-var React;
-var ReactDOM;
-
-describe('ReactErrorBoundaries', function() {
-
-  beforeEach(function() {
-    ReactDOM = require('ReactDOM');
-    React = require('React');
-  });
-
-  it('does not register event handlers for unmounted children', function() {
-    class Angry extends React.Component {
-      render() {
-        throw new Error('Please, do not render me.');
-      }
-    }
-
-    class Boundary extends React.Component {
-      constructor(props) {
-        super(props);
-        this.state = {error: false};
-      }
-      render() {
-        if (!this.state.error) {
-          return (<div><button onClick={this.onClick}>ClickMe</button><Angry /></div>);
-        } else {
-          return (<div>Happy Birthday!</div>);
-        }
-      }
-      onClick() {
-        /* do nothing */
-      }
-      unstable_handleError() {
-        this.setState({error: true});
-      }
-    }
-
-    var EventPluginHub = require('EventPluginHub');
-    var container = document.createElement('div');
-    EventPluginHub.putListener = jest.genMockFn();
-    ReactDOM.render(<Boundary />, container);
-    expect(EventPluginHub.putListener).not.toBeCalled();
-  });
-
-  it('will catch exceptions in componentWillUnmount', function() {
-    class ErrorBoundary extends React.Component {
-      constructor() {
-        super();
-        this.state = {error: false};
-      }
-      
-      render() {
-        if (!this.state.error) {
-          return <div>{this.props.children}</div>;
-        }
-        return <div>Error has been caught</div>;
-      }
-      
-      unstable_handleError() {
-        this.setState({error: true});
-      }
-    }
-
-    class BrokenRender extends React.Component {
-      render() {
-        throw new Error('Always broken.');
-      }
-    }
-
-    class BrokenUnmount extends React.Component {
-      render() {
-        return <div />;
-      }
-      componentWillUnmount() {
-        throw new Error('Always broken.');
-      }
-    }
-
-    var container = document.createElement('div');
-    ReactDOM.render(
-      <ErrorBoundary>
-        <BrokenUnmount />
-        <BrokenRender />
-        <BrokenUnmount />
-      </ErrorBoundary>,
-      container
-    );
-    ReactDOM.unmountComponentAtNode(container);
-  });
-
-  it('expect uneventful render to succeed', function() {
-    class Boundary extends React.Component {
-      constructor(props) {
-        super(props);
-        this.state = {error: false};
-      }
-      render() {
-        return (<div><button onClick={this.onClick}>ClickMe</button></div>);
-      }
-      onClick() {
-        /* do nothing */
-      }
-      unstable_handleError() {
-        this.setState({error: true});
-      }
-    }
-
-    var EventPluginHub = require('EventPluginHub');
-    var container = document.createElement('div');
-    EventPluginHub.putListener = jest.genMockFn();
-    ReactDOM.render(<Boundary />, container);
-    expect(EventPluginHub.putListener).toBeCalled();
-  });
-
-  it('correctly handles composite siblings', function() {
-    class ErrorBoundary extends React.Component {
-      constructor() {
-        super();
-        this.state = {error: false};
-      }
-      
-      render() {
-        if (!this.state.error) {
-          return <div>{this.props.children}</div>;
-        }
-        return <div>Error has been caught</div>;
-      }
-      
-      unstable_handleError() {
-        this.setState({error: true});
-      }
-    }
-
-    function Broken() {
-      throw new Error('Always broken.');
-    }
-
-    function Composite() {
-      return <div />;
-    }
-
-    var container = document.createElement('div');
-    ReactDOM.render(
-      <ErrorBoundary><Broken /><Composite /></ErrorBoundary>,
-      container
-    );
-    ReactDOM.unmountComponentAtNode(container);
-  });
-
-  it('catches errors from children', function() {
-    var log = [];
-
-    class Box extends React.Component {
-      constructor(props) {
-        super(props);
-        this.state = {errorMessage: null};
-      }
-      render() {
-        if (this.state.errorMessage != null) {
-          log.push('Box renderError');
-          return <div>Error: {this.state.errorMessage}</div>;
-        }
-        log.push('Box render');
-        var ref = function(x) {
-          log.push('Inquisitive ref ' + x);
-        };
-        return (
-          <div>
-            <Inquisitive ref={ref} />
-            <Angry />
-          </div>
-        );
-      }
-      unstable_handleError(e) {
-        this.setState({errorMessage: e.message});
-      }
-      componentDidMount() {
-        log.push('Box componentDidMount');
-      }
-      componentWillUnmount() {
-        log.push('Box componentWillUnmount');
-      }
-    }
-
-    class Inquisitive extends React.Component {
-      render() {
-        log.push('Inquisitive render');
-        return <div>What is love?</div>;
-      }
-      componentDidMount() {
-        log.push('Inquisitive componentDidMount');
-      }
-      componentWillUnmount() {
-        log.push('Inquisitive componentWillUnmount');
-      }
-    }
-
-    class Angry extends React.Component {
-      render() {
-        log.push('Angry render');
-        throw new Error('Please, do not render me.');
-      }
-      componentDidMount() {
-        log.push('Angry componentDidMount');
-      }
-      componentWillUnmount() {
-        log.push('Angry componentWillUnmount');
-      }
-    }
-
-    var container = document.createElement('div');
-    ReactDOM.render(<Box />, container);
-    expect(container.textContent).toBe('Error: Please, do not render me.');
-    ReactDOM.unmountComponentAtNode(container);
-    expect(log).toEqual([
-      'Box render',
-      'Inquisitive render',
-      'Angry render',
-      'Inquisitive ref null',
-      'Inquisitive componentWillUnmount',
-      'Box renderError',
-      'Box componentDidMount',
-      'Box componentWillUnmount',
-    ]);
-  });
-});
diff --git a/src/isomorphic/React.js b/src/isomorphic/React.js
index 551e0a608bb2..ed25972357f9 100644
--- a/src/isomorphic/React.js
+++ b/src/isomorphic/React.js
@@ -11,29 +11,26 @@
 
 'use strict';
 
+var ReactBaseClasses = require('ReactBaseClasses');
 var ReactChildren = require('ReactChildren');
-var ReactComponent = require('ReactComponent');
-var ReactClass = require('ReactClass');
 var ReactDOMFactories = require('ReactDOMFactories');
 var ReactElement = require('ReactElement');
-var ReactElementValidator = require('ReactElementValidator');
 var ReactPropTypes = require('ReactPropTypes');
 var ReactVersion = require('ReactVersion');
 
+var createReactClass = require('createClass');
 var onlyChild = require('onlyChild');
 
 var createElement = ReactElement.createElement;
 var createFactory = ReactElement.createFactory;
 var cloneElement = ReactElement.cloneElement;
 
-if (__DEV__) {
-  createElement = ReactElementValidator.createElement;
-  createFactory = ReactElementValidator.createFactory;
-  cloneElement = ReactElementValidator.cloneElement;
-}
+var __spread = Object.assign;
+var createMixin = function(mixin) {
+  return mixin;
+};
 
 var React = {
-
   // Modern
 
   Children: {
@@ -44,7 +41,8 @@ var React = {
     only: onlyChild,
   },
 
-  Component: ReactComponent,
+  Component: ReactBaseClasses.Component,
+  PureComponent: ReactBaseClasses.PureComponent,
 
   createElement: createElement,
   cloneElement: cloneElement,
@@ -53,18 +51,19 @@ var React = {
   // Classic
 
   PropTypes: ReactPropTypes,
-  createClass: ReactClass.createClass,
+  createClass: createReactClass,
   createFactory: createFactory,
-  createMixin: function(mixin) {
-    // Currently a noop. Will be used to validate and trace mixins.
-    return mixin;
-  },
+  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,
 };
 
+
 module.exports = React;
diff --git a/src/isomorphic/ReactDebugInstanceMap.js b/src/isomorphic/ReactDebugInstanceMap.js
deleted file mode 100644
index 50dddf4ad0e8..000000000000
--- a/src/isomorphic/ReactDebugInstanceMap.js
+++ /dev/null
@@ -1,124 +0,0 @@
-/**
- * Copyright 2016-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 ReactDebugInstanceMap
- */
-
-'use strict';
-
-var warning = require('warning');
-
-function checkValidInstance(internalInstance) {
-  if (!internalInstance) {
-    warning(
-      false,
-      'There is an internal error in the React developer tools integration. ' +
-      'Instead of an internal instance, received %s. ' +
-      'Please report this as a bug in React.',
-      internalInstance
-    );
-    return false;
-  }
-  var isValid = typeof internalInstance.mountComponent === 'function';
-  warning(
-    isValid,
-    'There is an internal error in the React developer tools integration. ' +
-    'Instead of an internal instance, received an object with the following ' +
-    'keys: %s. Please report this as a bug in React.',
-    Object.keys(internalInstance).join(', ')
-  );
-  return isValid;
-}
-
-var idCounter = 1;
-var instancesByIDs = {};
-var instancesToIDs;
-
-function getIDForInstance(internalInstance) {
-  if (!instancesToIDs) {
-    instancesToIDs = new WeakMap();
-  }
-  if (instancesToIDs.has(internalInstance)) {
-    return instancesToIDs.get(internalInstance);
-  } else {
-    var instanceID = (idCounter++).toString();
-    instancesToIDs.set(internalInstance, instanceID);
-    return instanceID;
-  }
-}
-
-function getInstanceByID(instanceID) {
-  return instancesByIDs[instanceID] || null;
-}
-
-function isRegisteredInstance(internalInstance) {
-  var instanceID = getIDForInstance(internalInstance);
-  if (instanceID) {
-    return instancesByIDs.hasOwnProperty(instanceID);
-  } else {
-    return false;
-  }
-}
-
-function registerInstance(internalInstance) {
-  var instanceID = getIDForInstance(internalInstance);
-  if (instanceID) {
-    instancesByIDs[instanceID] = internalInstance;
-  }
-}
-
-function unregisterInstance(internalInstance) {
-  var instanceID = getIDForInstance(internalInstance);
-  if (instanceID) {
-    delete instancesByIDs[instanceID];
-  }
-}
-
-var ReactDebugInstanceMap = {
-  getIDForInstance(internalInstance) {
-    if (!checkValidInstance(internalInstance)) {
-      return null;
-    }
-    return getIDForInstance(internalInstance);
-  },
-  getInstanceByID(instanceID) {
-    return getInstanceByID(instanceID);
-  },
-  isRegisteredInstance(internalInstance) {
-    if (!checkValidInstance(internalInstance)) {
-      return false;
-    }
-    return isRegisteredInstance(internalInstance);
-  },
-  registerInstance(internalInstance) {
-    if (!checkValidInstance(internalInstance)) {
-      return;
-    }
-    warning(
-      !isRegisteredInstance(internalInstance),
-      'There is an internal error in the React developer tools integration. ' +
-      'A registered instance should not be registered again. ' +
-      'Please report this as a bug in React.'
-    );
-    registerInstance(internalInstance);
-  },
-  unregisterInstance(internalInstance) {
-    if (!checkValidInstance(internalInstance)) {
-      return;
-    }
-    warning(
-      isRegisteredInstance(internalInstance),
-      'There is an internal error in the React developer tools integration. ' +
-      'An unregistered instance should not be unregistered again. ' +
-      'Please report this as a bug in React.'
-    );
-    unregisterInstance(internalInstance);
-  },
-};
-
-module.exports = ReactDebugInstanceMap;
diff --git a/src/isomorphic/ReactDebugTool.js b/src/isomorphic/ReactDebugTool.js
deleted file mode 100644
index 4d2c2a3536a5..000000000000
--- a/src/isomorphic/ReactDebugTool.js
+++ /dev/null
@@ -1,77 +0,0 @@
-/**
- * Copyright 2016-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 ReactDebugTool
- */
-
-'use strict';
-
-var ReactInvalidSetStateWarningDevTool = require('ReactInvalidSetStateWarningDevTool');
-var warning = require('warning');
-
-var eventHandlers = [];
-var handlerDoesThrowForEvent = {};
-
-function emitEvent(handlerFunctionName, arg1, arg2, arg3, arg4, arg5) {
-  if (__DEV__) {
-    eventHandlers.forEach(function(handler) {
-      try {
-        if (handler[handlerFunctionName]) {
-          handler[handlerFunctionName](arg1, arg2, arg3, arg4, arg5);
-        }
-      } catch (e) {
-        warning(
-          !handlerDoesThrowForEvent[handlerFunctionName],
-          'exception thrown by devtool while handling %s: %s',
-          handlerFunctionName,
-          e.message
-        );
-        handlerDoesThrowForEvent[handlerFunctionName] = true;
-      }
-    });
-  }
-}
-
-var ReactDebugTool = {
-  addDevtool(devtool) {
-    eventHandlers.push(devtool);
-  },
-  removeDevtool(devtool) {
-    for (var i = 0; i < eventHandlers.length; i++) {
-      if (eventHandlers[i] === devtool) {
-        eventHandlers.splice(i, 1);
-        i--;
-      }
-    }
-  },
-  onBeginProcessingChildContext() {
-    emitEvent('onBeginProcessingChildContext');
-  },
-  onEndProcessingChildContext() {
-    emitEvent('onEndProcessingChildContext');
-  },
-  onSetState() {
-    emitEvent('onSetState');
-  },
-  onMountRootComponent(internalInstance) {
-    emitEvent('onMountRootComponent', internalInstance);
-  },
-  onMountComponent(internalInstance) {
-    emitEvent('onMountComponent', internalInstance);
-  },
-  onUpdateComponent(internalInstance) {
-    emitEvent('onUpdateComponent', internalInstance);
-  },
-  onUnmountComponent(internalInstance) {
-    emitEvent('onUnmountComponent', internalInstance);
-  },
-};
-
-ReactDebugTool.addDevtool(ReactInvalidSetStateWarningDevTool);
-
-module.exports = ReactDebugTool;
diff --git a/src/isomorphic/ReactInstrumentation.js b/src/isomorphic/ReactInstrumentation.js
deleted file mode 100644
index 066da6aaae82..000000000000
--- a/src/isomorphic/ReactInstrumentation.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/**
- * Copyright 2016-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 ReactInstrumentation
- */
-
-'use strict';
-
-var ReactDebugTool = require('ReactDebugTool');
-
-module.exports = {debugTool: ReactDebugTool};
diff --git a/src/isomorphic/__tests__/React-test.js b/src/isomorphic/__tests__/React-test.js
new file mode 100644
index 000000000000..7a2d0c9ac9d6
--- /dev/null
+++ b/src/isomorphic/__tests__/React-test.js
@@ -0,0 +1,71 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+describe('React', () => {
+  var React;
+
+  beforeEach(() => {
+    React = require('React');
+  });
+
+  it('should log a deprecation warning once when using React.__spread', () => {
+    spyOn(console, 'warn');
+    React.__spread({});
+    React.__spread({});
+    expect(console.warn.calls.count()).toBe(1);
+    expect(console.warn.calls.argsFor(0)[0]).toContain(
+      'React.__spread is deprecated and should not be used',
+    );
+  });
+
+  it('should log a deprecation warning once when using React.createMixin', () => {
+    spyOn(console, 'warn');
+    React.createMixin();
+    React.createMixin();
+    expect(console.warn.calls.count()).toBe(1);
+    expect(console.warn.calls.argsFor(0)[0]).toContain(
+      'React.createMixin is deprecated and should not be used',
+    );
+  });
+
+  it('should warn once when attempting to access React.createClass', () => {
+    spyOn(console, 'warn');
+    let createClass = React.createClass;
+    createClass = React.createClass;
+    expect(createClass).not.toBe(undefined);
+    expect(console.warn.calls.count()).toBe(1);
+    expect(console.warn.calls.argsFor(0)[0]).toContain(
+      'Warning: 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',
+    );
+  });
+
+  it('should warn once when attempting to access React.PropTypes', () => {
+    spyOn(console, 'warn');
+    let PropTypes = React.PropTypes;
+    PropTypes = React.PropTypes;
+    expect(PropTypes).not.toBe(undefined);
+    expect(console.warn.calls.count()).toBe(1);
+    expect(console.warn.calls.argsFor(0)[0]).toContain(
+      'Warning: 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',
+    );
+  });
+});
diff --git a/src/isomorphic/__tests__/ReactDebugInstanceMap-test.js b/src/isomorphic/__tests__/ReactDebugInstanceMap-test.js
deleted file mode 100644
index d9a063e2c649..000000000000
--- a/src/isomorphic/__tests__/ReactDebugInstanceMap-test.js
+++ /dev/null
@@ -1,173 +0,0 @@
-/**
- * Copyright 2016-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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-describe('ReactDebugInstanceMap', function() {
-  var React;
-  var ReactDebugInstanceMap;
-  var ReactDOM;
-
-  beforeEach(function() {
-    jest.resetModuleRegistry();
-    React = require('React');
-    ReactDebugInstanceMap = require('ReactDebugInstanceMap');
-    ReactDOM = require('ReactDOM');
-  });
-
-  function createStubInstance() {
-    return { mountComponent: () => {} };
-  }
-
-  it('should register and unregister instances', function() {
-    var inst1 = createStubInstance();
-    var inst2 = createStubInstance();
-
-    expect(ReactDebugInstanceMap.isRegisteredInstance(inst1)).toBe(false);
-    expect(ReactDebugInstanceMap.isRegisteredInstance(inst2)).toBe(false);
-
-    ReactDebugInstanceMap.registerInstance(inst1);
-    expect(ReactDebugInstanceMap.isRegisteredInstance(inst1)).toBe(true);
-    expect(ReactDebugInstanceMap.isRegisteredInstance(inst2)).toBe(false);
-
-    ReactDebugInstanceMap.registerInstance(inst2);
-    expect(ReactDebugInstanceMap.isRegisteredInstance(inst1)).toBe(true);
-    expect(ReactDebugInstanceMap.isRegisteredInstance(inst2)).toBe(true);
-
-    ReactDebugInstanceMap.unregisterInstance(inst2);
-    expect(ReactDebugInstanceMap.isRegisteredInstance(inst1)).toBe(true);
-    expect(ReactDebugInstanceMap.isRegisteredInstance(inst2)).toBe(false);
-
-    ReactDebugInstanceMap.unregisterInstance(inst1);
-    expect(ReactDebugInstanceMap.isRegisteredInstance(inst1)).toBe(false);
-    expect(ReactDebugInstanceMap.isRegisteredInstance(inst2)).toBe(false);
-  });
-
-  it('should assign stable IDs', function() {
-    var inst1 = createStubInstance();
-    var inst2 = createStubInstance();
-
-    var inst1ID = ReactDebugInstanceMap.getIDForInstance(inst1);
-    var inst2ID = ReactDebugInstanceMap.getIDForInstance(inst2);
-    expect(typeof inst1ID).toBe('string');
-    expect(typeof inst2ID).toBe('string');
-    expect(inst1ID).not.toBe(inst2ID);
-
-    ReactDebugInstanceMap.registerInstance(inst1);
-    ReactDebugInstanceMap.registerInstance(inst2);
-    expect(ReactDebugInstanceMap.getIDForInstance(inst1)).toBe(inst1ID);
-    expect(ReactDebugInstanceMap.getIDForInstance(inst2)).toBe(inst2ID);
-
-    ReactDebugInstanceMap.unregisterInstance(inst1);
-    ReactDebugInstanceMap.unregisterInstance(inst2);
-    expect(ReactDebugInstanceMap.getIDForInstance(inst1)).toBe(inst1ID);
-    expect(ReactDebugInstanceMap.getIDForInstance(inst2)).toBe(inst2ID);
-  });
-
-  it('should retrieve registered instance by its ID', function() {
-    var inst1 = createStubInstance();
-    var inst2 = createStubInstance();
-
-    var inst1ID = ReactDebugInstanceMap.getIDForInstance(inst1);
-    var inst2ID = ReactDebugInstanceMap.getIDForInstance(inst2);
-    expect(ReactDebugInstanceMap.getInstanceByID(inst1ID)).toBe(null);
-    expect(ReactDebugInstanceMap.getInstanceByID(inst2ID)).toBe(null);
-
-    ReactDebugInstanceMap.registerInstance(inst1);
-    ReactDebugInstanceMap.registerInstance(inst2);
-    expect(ReactDebugInstanceMap.getInstanceByID(inst1ID)).toBe(inst1);
-    expect(ReactDebugInstanceMap.getInstanceByID(inst2ID)).toBe(inst2);
-
-    ReactDebugInstanceMap.unregisterInstance(inst1);
-    ReactDebugInstanceMap.unregisterInstance(inst2);
-    expect(ReactDebugInstanceMap.getInstanceByID(inst1ID)).toBe(null);
-    expect(ReactDebugInstanceMap.getInstanceByID(inst2ID)).toBe(null);
-  });
-
-  it('should warn when registering an instance twice', function() {
-    spyOn(console, 'error');
-
-    var inst = createStubInstance();
-    ReactDebugInstanceMap.registerInstance(inst);
-    expect(console.error.argsForCall.length).toBe(0);
-
-    ReactDebugInstanceMap.registerInstance(inst);
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
-      'There is an internal error in the React developer tools integration. ' +
-      'A registered instance should not be registered again. ' +
-      'Please report this as a bug in React.'
-    );
-
-    ReactDebugInstanceMap.unregisterInstance(inst);
-    ReactDebugInstanceMap.registerInstance(inst);
-    expect(console.error.argsForCall.length).toBe(1);
-  });
-
-  it('should warn when unregistering an instance twice', function() {
-    spyOn(console, 'error');
-    var inst = createStubInstance();
-
-    ReactDebugInstanceMap.unregisterInstance(inst);
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
-      'There is an internal error in the React developer tools integration. ' +
-      'An unregistered instance should not be unregistered again. ' +
-      'Please report this as a bug in React.'
-    );
-
-    ReactDebugInstanceMap.registerInstance(inst);
-    ReactDebugInstanceMap.unregisterInstance(inst);
-    expect(console.error.argsForCall.length).toBe(1);
-
-    ReactDebugInstanceMap.unregisterInstance(inst);
-    expect(console.error.argsForCall.length).toBe(2);
-    expect(console.error.argsForCall[1][0]).toContain(
-      'There is an internal error in the React developer tools integration. ' +
-      'An unregistered instance should not be unregistered again. ' +
-      'Please report this as a bug in React.'
-    );
-  });
-
-  it('should warn about anything than is not an internal instance', function() {
-    class Foo extends React.Component {
-      render() {
-        return <div />;
-      }
-    }
-
-    spyOn(console, 'error');
-    var warningCount = 0;
-    var div = document.createElement('div');
-    var publicInst = ReactDOM.render(<Foo />, div);
-
-    [false, null, undefined, {}, div, publicInst].forEach(falsyValue => {
-      ReactDebugInstanceMap.registerInstance(falsyValue);
-      warningCount++;
-      expect(ReactDebugInstanceMap.getIDForInstance(falsyValue)).toBe(null);
-      warningCount++;
-      expect(ReactDebugInstanceMap.isRegisteredInstance(falsyValue)).toBe(false);
-      warningCount++;
-      ReactDebugInstanceMap.unregisterInstance(falsyValue);
-      warningCount++;
-    });
-
-    expect(console.error.argsForCall.length).toBe(warningCount);
-    for (var i = 0; i < warningCount.length; i++) {
-      // Ideally we could check for the more detailed error message here
-      // but it depends on the input type and is meant for internal bugs
-      // anyway so I don't think it's worth complicating the test with it.
-      expect(console.error.argsForCall[i][0]).toContain(
-        'There is an internal error in the React developer tools integration.'
-      );
-    }
-  });
-});
diff --git a/src/isomorphic/children/ReactChildren.js b/src/isomorphic/children/ReactChildren.js
index da8848d22913..645c361ff619 100644
--- a/src/isomorphic/children/ReactChildren.js
+++ b/src/isomorphic/children/ReactChildren.js
@@ -20,13 +20,11 @@ var traverseAllChildren = require('traverseAllChildren');
 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.
@@ -55,6 +53,8 @@ function forEachSingleChild(bookKeeping, child, name) {
 /**
  * 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.
  *
@@ -66,13 +66,14 @@ function forEachChildren(children, forEachFunc, forEachContext) {
   if (children == null) {
     return children;
   }
-  var traverseContext =
-    ForEachBookKeeping.getPooled(forEachFunc, forEachContext);
+  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.
@@ -107,7 +108,7 @@ function mapSingleChildIntoContext(bookKeeping, child, childKey) {
       mappedChild,
       result,
       childKey,
-      emptyFunction.thatReturnsArgument
+      emptyFunction.thatReturnsArgument,
     );
   } else if (mappedChild != null) {
     if (ReactElement.isValidElement(mappedChild)) {
@@ -116,12 +117,10 @@ function mapSingleChildIntoContext(bookKeeping, child, childKey) {
         // 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
+          (mappedChild.key && (!child || child.key !== mappedChild.key)
+            ? escapeUserProvidedKey(mappedChild.key) + '/'
+            : '') +
+          childKey,
       );
     }
     result.push(mappedChild);
@@ -137,7 +136,7 @@ function mapIntoWithKeyPrefixInternal(children, array, prefix, func, context) {
     array,
     escapedPrefix,
     func,
-    context
+    context,
   );
   traverseAllChildren(children, mapSingleChildIntoContext, traverseContext);
   MapBookKeeping.release(traverseContext);
@@ -146,6 +145,8 @@ function mapIntoWithKeyPrefixInternal(children, array, prefix, func, context) {
 /**
  * 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.
  *
@@ -163,8 +164,6 @@ function mapChildren(children, func, context) {
   return result;
 }
 
-
-
 function forEachSingleChildDummy(traverseContext, child, name) {
   return null;
 }
@@ -173,6 +172,8 @@ function forEachSingleChildDummy(traverseContext, child, name) {
  * 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.
  */
@@ -180,10 +181,11 @@ 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 = [];
@@ -191,12 +193,11 @@ function toArray(children) {
     children,
     result,
     null,
-    emptyFunction.thatReturnsArgument
+    emptyFunction.thatReturnsArgument,
   );
   return result;
 }
 
-
 var ReactChildren = {
   forEach: forEachChildren,
   map: mapChildren,
diff --git a/src/isomorphic/children/__tests__/ReactChildren-test.js b/src/isomorphic/children/__tests__/ReactChildren-test.js
index e638c68c1022..d6e6a8bfc55a 100644
--- a/src/isomorphic/children/__tests__/ReactChildren-test.js
+++ b/src/isomorphic/children/__tests__/ReactChildren-test.js
@@ -11,19 +11,19 @@
 
 'use strict';
 
-describe('ReactChildren', function() {
+describe('ReactChildren', () => {
   var ReactChildren;
   var React;
   var ReactFragment;
 
-  beforeEach(function() {
+  beforeEach(() => {
     ReactChildren = require('ReactChildren');
     React = require('React');
     ReactFragment = require('ReactFragment');
   });
 
-  it('should support identity for simple', function() {
-    var callback = jasmine.createSpy().andCallFake(function(kid, index) {
+  it('should support identity for simple', () => {
+    var callback = jasmine.createSpy().and.callFake(function(kid, index) {
       return kid;
     });
 
@@ -35,14 +35,14 @@ describe('ReactChildren', function() {
     var instance = <div>{simpleKid}</div>;
     ReactChildren.forEach(instance.props.children, callback);
     expect(callback).toHaveBeenCalledWith(simpleKid, 0);
-    callback.reset();
+    callback.calls.reset();
     var mappedChildren = ReactChildren.map(instance.props.children, callback);
     expect(callback).toHaveBeenCalledWith(simpleKid, 0);
     expect(mappedChildren[0]).toEqual(<span key=".$simple" />);
   });
 
-  it('should treat single arrayless child as being in array', function() {
-    var callback = jasmine.createSpy().andCallFake(function(kid, index) {
+  it('should treat single arrayless child as being in array', () => {
+    var callback = jasmine.createSpy().and.callFake(function(kid, index) {
       return kid;
     });
 
@@ -50,14 +50,14 @@ describe('ReactChildren', function() {
     var instance = <div>{simpleKid}</div>;
     ReactChildren.forEach(instance.props.children, callback);
     expect(callback).toHaveBeenCalledWith(simpleKid, 0);
-    callback.reset();
+    callback.calls.reset();
     var mappedChildren = ReactChildren.map(instance.props.children, callback);
     expect(callback).toHaveBeenCalledWith(simpleKid, 0);
     expect(mappedChildren[0]).toEqual(<span key=".0" />);
   });
 
-  it('should treat single child in array as expected', function() {
-    var callback = jasmine.createSpy().andCallFake(function(kid, index) {
+  it('should treat single child in array as expected', () => {
+    var callback = jasmine.createSpy().and.callFake(function(kid, index) {
       return kid;
     });
 
@@ -65,14 +65,13 @@ describe('ReactChildren', function() {
     var instance = <div>{[simpleKid]}</div>;
     ReactChildren.forEach(instance.props.children, callback);
     expect(callback).toHaveBeenCalledWith(simpleKid, 0);
-    callback.reset();
+    callback.calls.reset();
     var mappedChildren = ReactChildren.map(instance.props.children, callback);
     expect(callback).toHaveBeenCalledWith(simpleKid, 0);
     expect(mappedChildren[0]).toEqual(<span key=".$simple" />);
-
   });
 
-  it('should pass key to returned component', function() {
+  it('should pass key to returned component', () => {
     var mapFn = function(kid, index) {
       return <div>{kid}</div>;
     };
@@ -88,7 +87,7 @@ describe('ReactChildren', function() {
     expect(mappedChildren[0].key).toBe('.$simple');
   });
 
-  it('should invoke callback with the right context', function() {
+  it('should invoke callback with the right context', () => {
     var lastContext;
     var callback = function(kid, index) {
       lastContext = this;
@@ -103,14 +102,17 @@ describe('ReactChildren', function() {
     ReactChildren.forEach(instance.props.children, callback, scopeTester);
     expect(lastContext).toBe(scopeTester);
 
-    var mappedChildren =
-      ReactChildren.map(instance.props.children, callback, scopeTester);
+    var mappedChildren = ReactChildren.map(
+      instance.props.children,
+      callback,
+      scopeTester,
+    );
 
     expect(ReactChildren.count(mappedChildren)).toBe(1);
     expect(mappedChildren[0]).toBe(scopeTester);
   });
 
-  it('should be called for each child', function() {
+  it('should be called for each child', () => {
     var zero = <div key="keyZero" />;
     var one = null;
     var two = <div key="keyTwo" />;
@@ -118,13 +120,13 @@ describe('ReactChildren', function() {
     var four = <div key="keyFour" />;
 
     var mapped = [
-      <div key="giraffe" />,  // Key should be joined to obj key
-      null,  // Key should be added even if we don't supply it!
-      <div />,  // Key should be added even if not supplied!
+      <div key="giraffe" />, // Key should be joined to obj key
+      null, // Key should be added even if we don't supply it!
+      <div />, // Key should be added even if not supplied!
       <span />, // Map from null to something.
       <div key="keyFour" />,
     ];
-    var callback = jasmine.createSpy().andCallFake(function(kid, index) {
+    var callback = jasmine.createSpy().and.callFake(function(kid, index) {
       return mapped[index];
     });
 
@@ -144,11 +146,10 @@ describe('ReactChildren', function() {
     expect(callback).toHaveBeenCalledWith(two, 2);
     expect(callback).toHaveBeenCalledWith(three, 3);
     expect(callback).toHaveBeenCalledWith(four, 4);
-    callback.reset();
+    callback.calls.reset();
 
-    var mappedChildren =
-      ReactChildren.map(instance.props.children, callback);
-    expect(callback.calls.length).toBe(5);
+    var mappedChildren = ReactChildren.map(instance.props.children, callback);
+    expect(callback.calls.count()).toBe(5);
     expect(ReactChildren.count(mappedChildren)).toBe(4);
     // Keys default to indices.
     expect([
@@ -156,9 +157,7 @@ describe('ReactChildren', function() {
       mappedChildren[1].key,
       mappedChildren[2].key,
       mappedChildren[3].key,
-    ]).toEqual(
-      ['giraffe/.$keyZero', '.$keyTwo', '.3', '.$keyFour']
-    );
+    ]).toEqual(['giraffe/.$keyZero', '.$keyTwo', '.3', '.$keyFour']);
 
     expect(callback).toHaveBeenCalledWith(zero, 0);
     expect(callback).toHaveBeenCalledWith(one, 1);
@@ -172,7 +171,7 @@ describe('ReactChildren', function() {
     expect(mappedChildren[3]).toEqual(<div key=".$keyFour" />);
   });
 
-  it('should be called for each child in nested structure', function() {
+  it('should be called for each child in nested structure', () => {
     var zero = <div key="keyZero" />;
     var one = null;
     var two = <div key="keyTwo" />;
@@ -185,15 +184,15 @@ describe('ReactChildren', function() {
     // 1. If grouped in an Object, the object key combined with `key` prop
     // 2. If grouped in an Array, the `key` prop, falling back to array index
 
-    var zeroMapped = <div key="giraffe" />;  // Key should be overridden
-    var twoMapped = <div />;  // Key should be added even if not supplied!
+    var zeroMapped = <div key="giraffe" />; // Key should be overridden
+    var twoMapped = <div />; // Key should be added even if not supplied!
     var fourMapped = <div key="keyFour" />;
     var fiveMapped = <div />;
 
-    var callback = jasmine.createSpy().andCallFake(function(kid, index) {
-      return index === 0 ? zeroMapped :
-        index === 1 ? twoMapped :
-        index === 2 ? fourMapped : fiveMapped;
+    var callback = jasmine.createSpy().and.callFake(function(kid, index) {
+      return index === 0
+        ? zeroMapped
+        : index === 1 ? twoMapped : index === 2 ? fourMapped : fiveMapped;
     });
 
     var frag = ReactFragment.create({
@@ -203,12 +202,7 @@ describe('ReactChildren', function() {
     });
     var instance = <div>{[frag]}</div>;
 
-    expect([
-      frag[0].key,
-      frag[1].key,
-      frag[2].key,
-      frag[3].key,
-    ]).toEqual([
+    expect([frag[0].key, frag[1].key, frag[2].key, frag[3].key]).toEqual([
       'firstHalfKey/.$keyZero',
       'firstHalfKey/.$keyTwo',
       'secondHalfKey/.$keyFour',
@@ -216,15 +210,15 @@ describe('ReactChildren', function() {
     ]);
 
     ReactChildren.forEach(instance.props.children, callback);
-    expect(callback.calls.length).toBe(4);
+    expect(callback.calls.count()).toBe(4);
     expect(callback).toHaveBeenCalledWith(frag[0], 0);
     expect(callback).toHaveBeenCalledWith(frag[1], 1);
     expect(callback).toHaveBeenCalledWith(frag[2], 2);
     expect(callback).toHaveBeenCalledWith(frag[3], 3);
-    callback.reset();
+    callback.calls.reset();
 
     var mappedChildren = ReactChildren.map(instance.props.children, callback);
-    expect(callback.calls.length).toBe(4);
+    expect(callback.calls.count()).toBe(4);
     expect(callback).toHaveBeenCalledWith(frag[0], 0);
     expect(callback).toHaveBeenCalledWith(frag[1], 1);
     expect(callback).toHaveBeenCalledWith(frag[2], 2);
@@ -244,13 +238,17 @@ describe('ReactChildren', function() {
       '.0:$keyFive/.$keyFiveInner',
     ]);
 
-    expect(mappedChildren[0]).toEqual(<div key="giraffe/.0:$firstHalfKey/.$keyZero" />);
+    expect(mappedChildren[0]).toEqual(
+      <div key="giraffe/.0:$firstHalfKey/.$keyZero" />,
+    );
     expect(mappedChildren[1]).toEqual(<div key=".0:$firstHalfKey/.$keyTwo" />);
-    expect(mappedChildren[2]).toEqual(<div key="keyFour/.0:$secondHalfKey/.$keyFour" />);
+    expect(mappedChildren[2]).toEqual(
+      <div key="keyFour/.0:$secondHalfKey/.$keyFour" />,
+    );
     expect(mappedChildren[3]).toEqual(<div key=".0:$keyFive/.$keyFiveInner" />);
   });
 
-  it('should retain key across two mappings', function() {
+  it('should retain key across two mappings', () => {
     var zeroForceKey = <div key="keyZero" />;
     var oneForceKey = <div key="keyOne" />;
 
@@ -271,24 +269,27 @@ describe('ReactChildren', function() {
     );
 
     var expectedForcedKeys = ['giraffe/.$keyZero', '.$keyOne'];
-    var mappedChildrenForcedKeys =
-      ReactChildren.map(forcedKeys.props.children, mapFn);
-    var mappedForcedKeys = mappedChildrenForcedKeys.map((c) => c.key);
+    var mappedChildrenForcedKeys = ReactChildren.map(
+      forcedKeys.props.children,
+      mapFn,
+    );
+    var mappedForcedKeys = mappedChildrenForcedKeys.map(c => c.key);
     expect(mappedForcedKeys).toEqual(expectedForcedKeys);
 
     var expectedRemappedForcedKeys = [
       'giraffe/.$giraffe/.$keyZero',
       '.$.$keyOne',
     ];
-    var remappedChildrenForcedKeys =
-      ReactChildren.map(mappedChildrenForcedKeys, mapFn);
-    expect(
-      remappedChildrenForcedKeys.map((c) => c.key)
-    ).toEqual(expectedRemappedForcedKeys);
-
+    var remappedChildrenForcedKeys = ReactChildren.map(
+      mappedChildrenForcedKeys,
+      mapFn,
+    );
+    expect(remappedChildrenForcedKeys.map(c => c.key)).toEqual(
+      expectedRemappedForcedKeys,
+    );
   });
 
-  it('should not throw if key provided is a dupe with array key', function() {
+  it('should not throw if key provided is a dupe with array key', () => {
     var zero = <div />;
     var one = <div key="0" />;
 
@@ -308,64 +309,56 @@ describe('ReactChildren', function() {
     }).not.toThrow();
   });
 
-  it('should use the same key for a cloned element', function() {
+  it('should use the same key for a cloned element', () => {
     var instance = (
       <div>
         <div />
       </div>
     );
 
-    var mapped = ReactChildren.map(
-      instance.props.children,
-      element => element,
-    );
+    var mapped = ReactChildren.map(instance.props.children, element => element);
 
-    var mappedWithClone = ReactChildren.map(
-      instance.props.children,
-      element => React.cloneElement(element),
+    var mappedWithClone = ReactChildren.map(instance.props.children, element =>
+      React.cloneElement(element),
     );
 
     expect(mapped[0].key).toBe(mappedWithClone[0].key);
   });
 
-  it('should use the same key for a cloned element with key', function() {
+  it('should use the same key for a cloned element with key', () => {
     var instance = (
       <div>
         <div key="unique" />
       </div>
     );
 
-    var mapped = ReactChildren.map(
-      instance.props.children,
-      element => element,
-    );
+    var mapped = ReactChildren.map(instance.props.children, element => element);
 
-    var mappedWithClone = ReactChildren.map(
-      instance.props.children,
-      element => React.cloneElement(element, {key: 'unique'}),
+    var mappedWithClone = ReactChildren.map(instance.props.children, element =>
+      React.cloneElement(element, {key: 'unique'}),
     );
 
     expect(mapped[0].key).toBe(mappedWithClone[0].key);
   });
 
-  it('should return 0 for null children', function() {
+  it('should return 0 for null children', () => {
     var numberOfChildren = ReactChildren.count(null);
     expect(numberOfChildren).toBe(0);
   });
 
-  it('should return 0 for undefined children', function() {
+  it('should return 0 for undefined children', () => {
     var numberOfChildren = ReactChildren.count(undefined);
     expect(numberOfChildren).toBe(0);
   });
 
-  it('should return 1 for single child', function() {
+  it('should return 1 for single child', () => {
     var simpleKid = <span key="simple" />;
     var instance = <div>{simpleKid}</div>;
     var numberOfChildren = ReactChildren.count(instance.props.children);
     expect(numberOfChildren).toBe(1);
   });
 
-  it('should count the number of children in flat structure', function() {
+  it('should count the number of children in flat structure', () => {
     var zero = <div key="keyZero" />;
     var one = null;
     var two = <div key="keyTwo" />;
@@ -385,7 +378,7 @@ describe('ReactChildren', function() {
     expect(numberOfChildren).toBe(5);
   });
 
-  it('should count the number of children in nested structure', function() {
+  it('should count the number of children in nested structure', () => {
     var zero = <div key="keyZero" />;
     var one = null;
     var two = <div key="keyTwo" />;
@@ -399,31 +392,29 @@ describe('ReactChildren', function() {
     // 2. If grouped in an Array, the `key` prop, falling back to array index
 
     var instance = (
-      <div>{
-        [
+      <div>
+        {[
           ReactFragment.create({
             firstHalfKey: [zero, one, two],
             secondHalfKey: [three, four],
             keyFive: five,
           }),
           null,
-        ]
-      }</div>
+        ]}
+      </div>
     );
     var numberOfChildren = ReactChildren.count(instance.props.children);
     expect(numberOfChildren).toBe(5);
   });
 
-  it('should flatten children to an array', function() {
+  it('should flatten children to an array', () => {
     expect(ReactChildren.toArray(undefined)).toEqual([]);
     expect(ReactChildren.toArray(null)).toEqual([]);
 
     expect(ReactChildren.toArray(<div />).length).toBe(1);
     expect(ReactChildren.toArray([<div />]).length).toBe(1);
-    expect(
-      ReactChildren.toArray(<div />)[0].key
-    ).toBe(
-      ReactChildren.toArray([<div />])[0].key
+    expect(ReactChildren.toArray(<div />)[0].key).toBe(
+      ReactChildren.toArray([<div />])[0].key,
     );
 
     var flattened = ReactChildren.toArray([
@@ -447,9 +438,9 @@ describe('ReactChildren', function() {
     expect(flattened[5].key).toBe(reversed[3].key);
 
     // null/undefined/bool are all omitted
-    expect(ReactChildren.toArray([1, 'two', null, undefined, true])).toEqual(
-      [1, 'two']
-    );
+    expect(ReactChildren.toArray([1, 'two', null, undefined, true])).toEqual([
+      1,
+      'two',
+    ]);
   });
-
 });
diff --git a/src/isomorphic/children/__tests__/onlyChild-test.js b/src/isomorphic/children/__tests__/onlyChild-test.js
index 9be5a597588e..0c8870c6d79a 100644
--- a/src/isomorphic/children/__tests__/onlyChild-test.js
+++ b/src/isomorphic/children/__tests__/onlyChild-test.js
@@ -11,87 +11,89 @@
 
 'use strict';
 
-describe('onlyChild', function() {
-
+describe('onlyChild', () => {
   var React;
   var ReactFragment;
   var onlyChild;
   var WrapComponent;
 
-  beforeEach(function() {
+  beforeEach(() => {
     React = require('React');
     ReactFragment = require('ReactFragment');
     onlyChild = require('onlyChild');
-    WrapComponent = React.createClass({
-      render: function() {
+    WrapComponent = class extends React.Component {
+      render() {
         return (
           <div>
             {onlyChild(this.props.children, this.props.mapFn, this)}
           </div>
         );
-      },
-    });
+      }
+    };
   });
 
-  it('should fail when passed two children', function() {
+  it('should fail when passed two children', () => {
     expect(function() {
-      var instance =
+      var instance = (
         <WrapComponent>
           <div />
           <span />
-        </WrapComponent>;
+        </WrapComponent>
+      );
       onlyChild(instance.props.children);
     }).toThrow();
   });
 
-  it('should fail when passed nully values', function() {
+  it('should fail when passed nully values', () => {
     expect(function() {
-      var instance =
+      var instance = (
         <WrapComponent>
           {null}
-        </WrapComponent>;
+        </WrapComponent>
+      );
       onlyChild(instance.props.children);
     }).toThrow();
 
     expect(function() {
-      var instance =
+      var instance = (
         <WrapComponent>
           {undefined}
-        </WrapComponent>;
+        </WrapComponent>
+      );
       onlyChild(instance.props.children);
     }).toThrow();
   });
 
-  it('should fail when key/value objects', function() {
+  it('should fail when key/value objects', () => {
     expect(function() {
-      var instance =
+      var instance = (
         <WrapComponent>
           {ReactFragment.create({oneThing: <span />})}
-        </WrapComponent>;
+        </WrapComponent>
+      );
       onlyChild(instance.props.children);
     }).toThrow();
   });
 
-
-  it('should not fail when passed interpolated single child', function() {
+  it('should not fail when passed interpolated single child', () => {
     expect(function() {
-      var instance =
+      var instance = (
         <WrapComponent>
           {<span />}
-        </WrapComponent>;
+        </WrapComponent>
+      );
       onlyChild(instance.props.children);
     }).not.toThrow();
   });
 
-
-  it('should return the only child', function() {
+  it('should return the only child', () => {
     expect(function() {
-      var instance =
+      var instance = (
         <WrapComponent>
           <span />
-        </WrapComponent>;
+        </WrapComponent>
+      );
       onlyChild(instance.props.children);
     }).not.toThrow();
   });
-
 });
diff --git a/src/isomorphic/children/__tests__/sliceChildren-test.js b/src/isomorphic/children/__tests__/sliceChildren-test.js
index e6d448162a13..d255324a727c 100644
--- a/src/isomorphic/children/__tests__/sliceChildren-test.js
+++ b/src/isomorphic/children/__tests__/sliceChildren-test.js
@@ -11,24 +11,19 @@
 
 'use strict';
 
-describe('sliceChildren', function() {
-
+describe('sliceChildren', () => {
   var React;
 
   var sliceChildren;
 
-  beforeEach(function() {
+  beforeEach(() => {
     React = require('React');
 
     sliceChildren = require('sliceChildren');
   });
 
-  it('should render the whole set if start zero is supplied', function() {
-    var fullSet = [
-      <div key="A" />,
-      <div key="B" />,
-      <div key="C" />,
-    ];
+  it('should render the whole set if start zero is supplied', () => {
+    var fullSet = [<div key="A" />, <div key="B" />, <div key="C" />];
     var children = sliceChildren(fullSet, 0);
     expect(children).toEqual([
       <div key=".$A" />,
@@ -37,20 +32,13 @@ describe('sliceChildren', function() {
     ]);
   });
 
-  it('should render the remaining set if no end index is supplied', function() {
-    var fullSet = [
-      <div key="A" />,
-      <div key="B" />,
-      <div key="C" />,
-    ];
+  it('should render the remaining set if no end index is supplied', () => {
+    var fullSet = [<div key="A" />, <div key="B" />, <div key="C" />];
     var children = sliceChildren(fullSet, 1);
-    expect(children).toEqual([
-      <div key=".$B" />,
-      <div key=".$C" />,
-    ]);
+    expect(children).toEqual([<div key=".$B" />, <div key=".$C" />]);
   });
 
-  it('should exclude everything at or after the end index', function() {
+  it('should exclude everything at or after the end index', () => {
     var fullSet = [
       <div key="A" />,
       <div key="B" />,
@@ -58,36 +46,26 @@ describe('sliceChildren', function() {
       <div key="D" />,
     ];
     var children = sliceChildren(fullSet, 1, 2);
-    expect(children).toEqual([
-      <div key=".$B" />,
-    ]);
+    expect(children).toEqual([<div key=".$B" />]);
   });
 
-  it('should allow static children to be sliced', function() {
+  it('should allow static children to be sliced', () => {
     var a = <a />;
     var b = <b />;
     var c = <i />;
 
     var el = <div>{a}{b}{c}</div>;
     var children = sliceChildren(el.props.children, 1, 2);
-    expect(children).toEqual([
-      <b key=".1" />,
-    ]);
+    expect(children).toEqual([<b key=".1" />]);
   });
 
-  it('should slice nested children', function() {
+  it('should slice nested children', () => {
     var fullSet = [
       <div key="A" />,
-      [
-        <div key="B" />,
-        <div key="C" />,
-      ],
+      [<div key="B" />, <div key="C" />],
       <div key="D" />,
     ];
     var children = sliceChildren(fullSet, 1, 2);
-    expect(children).toEqual([
-      <div key=".1:$B" />,
-    ]);
+    expect(children).toEqual([<div key=".1:$B" />]);
   });
-
 });
diff --git a/src/isomorphic/children/onlyChild.js b/src/isomorphic/children/onlyChild.js
index 0a33ee1801a9..8801fd6dc22d 100644
--- a/src/isomorphic/children/onlyChild.js
+++ b/src/isomorphic/children/onlyChild.js
@@ -16,19 +16,22 @@ var invariant = require('invariant');
 
 /**
  * Returns the first child in a collection of children and verifies that there
- * is only one child in the collection. 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.
+ * 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 {ReactComponent} The first and only `ReactComponent` contained in the
+ * @return {ReactElement} The first and only `ReactElement` contained in the
  * structure.
  */
 function onlyChild(children) {
   invariant(
     ReactElement.isValidElement(children),
-    'onlyChild must be passed a children with exactly one child.'
+    'React.Children.only expected to receive a single React element child.',
   );
   return children;
 }
diff --git a/src/isomorphic/classic/__tests__/ReactContextValidator-test.js b/src/isomorphic/classic/__tests__/ReactContextValidator-test.js
index cc09080f0cc9..29a9ac89138e 100644
--- a/src/isomorphic/classic/__tests__/ReactContextValidator-test.js
+++ b/src/isomorphic/classic/__tests__/ReactContextValidator-test.js
@@ -17,109 +17,115 @@
 
 'use strict';
 
+var PropTypes;
 var React;
 var ReactDOM;
 var ReactTestUtils;
 
 var reactComponentExpect;
 
-describe('ReactContextValidator', function() {
-  beforeEach(function() {
+describe('ReactContextValidator', () => {
+  function normalizeCodeLocInfo(str) {
+    return str.replace(/\(at .+?:\d+\)/g, '(at **)');
+  }
+
+  beforeEach(() => {
     jest.resetModuleRegistry();
 
     React = require('React');
     ReactDOM = require('ReactDOM');
     ReactTestUtils = require('ReactTestUtils');
+    PropTypes = require('prop-types');
     reactComponentExpect = require('reactComponentExpect');
   });
 
   // TODO: This behavior creates a runtime dependency on propTypes. We should
   // ensure that this is not required for ES6 classes with Flow.
 
-  it('should filter out context not in contextTypes', function() {
-    var Component = React.createClass({
-      contextTypes: {
-        foo: React.PropTypes.string,
-      },
-
-      render: function() {
+  it('should filter out context not in contextTypes', () => {
+    class Component extends React.Component {
+      render() {
         return <div />;
-      },
-    });
-
-    var ComponentInFooBarContext = React.createClass({
-      childContextTypes: {
-        foo: React.PropTypes.string,
-        bar: React.PropTypes.number,
-      },
-
-      getChildContext: function() {
+      }
+    }
+    Component.contextTypes = {
+      foo: PropTypes.string,
+    };
+
+    class ComponentInFooBarContext extends React.Component {
+      getChildContext() {
         return {
           foo: 'abc',
           bar: 123,
         };
-      },
+      }
 
-      render: function() {
+      render() {
         return <Component />;
-      },
-    });
-
-    var instance = ReactTestUtils.renderIntoDocument(<ComponentInFooBarContext />);
-    reactComponentExpect(instance).expectRenderedChild().scalarContextEqual({foo: 'abc'});
+      }
+    }
+    ComponentInFooBarContext.childContextTypes = {
+      foo: PropTypes.string,
+      bar: PropTypes.number,
+    };
+
+    var instance = ReactTestUtils.renderIntoDocument(
+      <ComponentInFooBarContext />,
+    );
+    reactComponentExpect(instance)
+      .expectRenderedChild()
+      .scalarContextEqual({foo: 'abc'});
   });
 
-  it('should filter context properly in callbacks', function() {
+  it('should filter context properly in callbacks', () => {
     var actualComponentWillReceiveProps;
     var actualShouldComponentUpdate;
     var actualComponentWillUpdate;
     var actualComponentDidUpdate;
 
-    var Parent = React.createClass({
-      childContextTypes: {
-        foo: React.PropTypes.string.isRequired,
-        bar: React.PropTypes.string.isRequired,
-      },
-
-      getChildContext: function() {
+    class Parent extends React.Component {
+      getChildContext() {
         return {
           foo: this.props.foo,
           bar: 'bar',
         };
-      },
+      }
 
-      render: function() {
+      render() {
         return <Component />;
-      },
-    });
-
-    var Component = React.createClass({
-      contextTypes: {
-        foo: React.PropTypes.string,
-      },
-
-      componentWillReceiveProps: function(nextProps, nextContext) {
+      }
+    }
+    Parent.childContextTypes = {
+      foo: PropTypes.string.isRequired,
+      bar: PropTypes.string.isRequired,
+    };
+
+    class Component extends React.Component {
+      componentWillReceiveProps(nextProps, nextContext) {
         actualComponentWillReceiveProps = nextContext;
         return true;
-      },
+      }
 
-      shouldComponentUpdate: function(nextProps, nextState, nextContext) {
+      shouldComponentUpdate(nextProps, nextState, nextContext) {
         actualShouldComponentUpdate = nextContext;
         return true;
-      },
+      }
 
-      componentWillUpdate: function(nextProps, nextState, nextContext) {
+      componentWillUpdate(nextProps, nextState, nextContext) {
         actualComponentWillUpdate = nextContext;
-      },
+      }
 
-      componentDidUpdate: function(prevProps, prevState, prevContext) {
+      componentDidUpdate(prevProps, prevState, prevContext) {
         actualComponentDidUpdate = prevContext;
-      },
+      }
 
-      render: function() {
+      render() {
         return <div />;
-      },
-    });
+      }
+    }
+    Component.contextTypes = {
+      foo: PropTypes.string,
+    };
 
     var container = document.createElement('div');
     ReactDOM.render(<Parent foo="abc" />, container);
@@ -130,121 +136,122 @@ describe('ReactContextValidator', function() {
     expect(actualComponentDidUpdate).toEqual({foo: 'abc'});
   });
 
-  it('should check context types', function() {
+  it('should check context types', () => {
     spyOn(console, 'error');
 
-    var Component = React.createClass({
-      contextTypes: {
-        foo: React.PropTypes.string.isRequired,
-      },
-
-      render: function() {
+    class Component extends React.Component {
+      render() {
         return <div />;
-      },
-    });
+      }
+    }
+    Component.contextTypes = {
+      foo: PropTypes.string.isRequired,
+    };
 
     ReactTestUtils.renderIntoDocument(<Component />);
 
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: Failed Context Types: ' +
-      'Required context `foo` was not specified in `Component`.'
+    expect(console.error.calls.count()).toBe(1);
+    expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
+      'Warning: Failed context type: ' +
+        'The context `foo` is marked as required in `Component`, but its value ' +
+        'is `undefined`.\n' +
+        '    in Component (at **)',
     );
 
-    var ComponentInFooStringContext = React.createClass({
-      childContextTypes: {
-        foo: React.PropTypes.string,
-      },
-
-      getChildContext: function() {
+    class ComponentInFooStringContext extends React.Component {
+      getChildContext() {
         return {
           foo: this.props.fooValue,
         };
-      },
+      }
 
-      render: function() {
+      render() {
         return <Component />;
-      },
-    });
+      }
+    }
+    ComponentInFooStringContext.childContextTypes = {
+      foo: PropTypes.string,
+    };
 
     ReactTestUtils.renderIntoDocument(
-      <ComponentInFooStringContext fooValue={'bar'} />
+      <ComponentInFooStringContext fooValue={'bar'} />,
     );
 
     // Previous call should not error
-    expect(console.error.argsForCall.length).toBe(1);
-
-    var ComponentInFooNumberContext = React.createClass({
-      childContextTypes: {
-        foo: React.PropTypes.number,
-      },
+    expect(console.error.calls.count()).toBe(1);
 
-      getChildContext: function() {
+    class ComponentInFooNumberContext extends React.Component {
+      getChildContext() {
         return {
           foo: this.props.fooValue,
         };
-      },
+      }
 
-      render: function() {
+      render() {
         return <Component />;
-      },
-    });
+      }
+    }
+    ComponentInFooNumberContext.childContextTypes = {
+      foo: PropTypes.number,
+    };
 
-    ReactTestUtils.renderIntoDocument(<ComponentInFooNumberContext fooValue={123} />);
+    ReactTestUtils.renderIntoDocument(
+      <ComponentInFooNumberContext fooValue={123} />,
+    );
 
-    expect(console.error.argsForCall.length).toBe(2);
-    expect(console.error.argsForCall[1][0]).toBe(
-      'Warning: Failed Context Types: ' +
-      'Invalid context `foo` of type `number` supplied ' +
-      'to `Component`, expected `string`.' +
-      ' Check the render method of `ComponentInFooNumberContext`.'
+    expect(console.error.calls.count()).toBe(2);
+    expect(normalizeCodeLocInfo(console.error.calls.argsFor(1)[0])).toBe(
+      'Warning: Failed context type: ' +
+        'Invalid context `foo` of type `number` supplied ' +
+        'to `Component`, expected `string`.\n' +
+        '    in Component (at **)\n' +
+        '    in ComponentInFooNumberContext (at **)',
     );
   });
 
-  it('should check child context types', function() {
+  it('should check child context types', () => {
     spyOn(console, 'error');
 
-    var Component = React.createClass({
-      childContextTypes: {
-        foo: React.PropTypes.string.isRequired,
-        bar: React.PropTypes.number,
-      },
-
-      getChildContext: function() {
+    class Component extends React.Component {
+      getChildContext() {
         return this.props.testContext;
-      },
+      }
 
-      render: function() {
+      render() {
         return <div />;
-      },
-    });
+      }
+    }
+    Component.childContextTypes = {
+      foo: PropTypes.string.isRequired,
+      bar: PropTypes.number,
+    };
 
     ReactTestUtils.renderIntoDocument(<Component testContext={{bar: 123}} />);
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: Failed Context Types: ' +
-      'Required child context `foo` was not specified in `Component`.'
+    expect(console.error.calls.count()).toBe(1);
+    expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
+      'Warning: Failed child context type: ' +
+        'The child context `foo` is marked as required in `Component`, but its ' +
+        'value is `undefined`.\n' +
+        '    in Component (at **)',
     );
 
     ReactTestUtils.renderIntoDocument(<Component testContext={{foo: 123}} />);
 
-    expect(console.error.argsForCall.length).toBe(2);
-    expect(console.error.argsForCall[1][0]).toBe(
-      'Warning: Failed Context Types: ' +
-      'Invalid child context `foo` of type `number` ' +
-      'supplied to `Component`, expected `string`.'
+    expect(console.error.calls.count()).toBe(2);
+    expect(normalizeCodeLocInfo(console.error.calls.argsFor(1)[0])).toBe(
+      'Warning: Failed child context type: ' +
+        'Invalid child context `foo` of type `number` ' +
+        'supplied to `Component`, expected `string`.\n' +
+        '    in Component (at **)',
     );
 
     ReactTestUtils.renderIntoDocument(
-      <Component testContext={{foo: 'foo', bar: 123}} />
+      <Component testContext={{foo: 'foo', bar: 123}} />,
     );
 
-    ReactTestUtils.renderIntoDocument(
-      <Component testContext={{foo: 'foo'}} />
-    );
+    ReactTestUtils.renderIntoDocument(<Component testContext={{foo: 'foo'}} />);
 
     // Previous calls should not log errors
-    expect(console.error.argsForCall.length).toBe(2);
+    expect(console.error.calls.count()).toBe(2);
   });
-
 });
diff --git a/src/isomorphic/classic/class/ReactClass.js b/src/isomorphic/classic/class/ReactClass.js
deleted file mode 100644
index 56f479a42e99..000000000000
--- a/src/isomorphic/classic/class/ReactClass.js
+++ /dev/null
@@ -1,862 +0,0 @@
-/**
- * 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 ReactClass
- */
-
-'use strict';
-
-var ReactComponent = require('ReactComponent');
-var ReactElement = require('ReactElement');
-var ReactPropTypeLocations = require('ReactPropTypeLocations');
-var ReactPropTypeLocationNames = require('ReactPropTypeLocationNames');
-var ReactNoopUpdateQueue = require('ReactNoopUpdateQueue');
-
-var emptyObject = require('emptyObject');
-var invariant = require('invariant');
-var keyMirror = require('keyMirror');
-var keyOf = require('keyOf');
-var warning = require('warning');
-
-var MIXINS_KEY = keyOf({mixins: null});
-
-/**
- * Policies that describe methods in `ReactClassInterface`.
- */
-var SpecPolicy = keyMirror({
-  /**
-   * These methods may be defined only once by the class specification or mixin.
-   */
-  DEFINE_ONCE: null,
-  /**
-   * These methods may be defined by both the class specification and mixins.
-   * Subsequent definitions will be chained. These methods must return void.
-   */
-  DEFINE_MANY: null,
-  /**
-   * These methods are overriding the base class.
-   */
-  OVERRIDE_BASE: null,
-  /**
-   * These methods are similar to DEFINE_MANY, except we assume they return
-   * objects. We try to merge the keys of the return values of all the mixed in
-   * functions. If there is a key conflict we throw.
-   */
-  DEFINE_MANY_MERGED: null,
-});
-
-
-var injectedMixins = [];
-
-/**
- * Composite components are higher-level components that compose other composite
- * or native 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: SpecPolicy.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: SpecPolicy.DEFINE_MANY,
-
-  /**
-   * Definition of prop types for this component.
-   *
-   * @type {object}
-   * @optional
-   */
-  propTypes: SpecPolicy.DEFINE_MANY,
-
-  /**
-   * Definition of context types for this component.
-   *
-   * @type {object}
-   * @optional
-   */
-  contextTypes: SpecPolicy.DEFINE_MANY,
-
-  /**
-   * Definition of context types this component sets for its children.
-   *
-   * @type {object}
-   * @optional
-   */
-  childContextTypes: SpecPolicy.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: SpecPolicy.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: SpecPolicy.DEFINE_MANY_MERGED,
-
-  /**
-   * @return {object}
-   * @optional
-   */
-  getChildContext: SpecPolicy.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}
-   * @nosideeffects
-   * @required
-   */
-  render: SpecPolicy.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: SpecPolicy.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: SpecPolicy.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: SpecPolicy.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: SpecPolicy.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: SpecPolicy.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: SpecPolicy.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: SpecPolicy.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: SpecPolicy.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 (__DEV__) {
-      validateTypeDef(
-        Constructor,
-        childContextTypes,
-        ReactPropTypeLocations.childContext
-      );
-    }
-    Constructor.childContextTypes = Object.assign(
-      {},
-      Constructor.childContextTypes,
-      childContextTypes
-    );
-  },
-  contextTypes: function(Constructor, contextTypes) {
-    if (__DEV__) {
-      validateTypeDef(
-        Constructor,
-        contextTypes,
-        ReactPropTypeLocations.context
-      );
-    }
-    Constructor.contextTypes = Object.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 (__DEV__) {
-      validateTypeDef(
-        Constructor,
-        propTypes,
-        ReactPropTypeLocations.prop
-      );
-    }
-    Constructor.propTypes = Object.assign(
-      {},
-      Constructor.propTypes,
-      propTypes
-    );
-  },
-  statics: function(Constructor, statics) {
-    mixStaticSpecIntoComponent(Constructor, statics);
-  },
-  autobind: function() {}, // noop
-};
-
-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__
-      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 === 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 === SpecPolicy.DEFINE_MANY ||
-      specPolicy === 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) {
-    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(
-    !ReactElement.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 === SpecPolicy.DEFINE_MANY_MERGED ||
-              specPolicy === 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 === SpecPolicy.DEFINE_MANY_MERGED) {
-            proto[name] = createMergedResultFunction(proto[name], property);
-          } else if (specPolicy === SpecPolicy.DEFINE_MANY) {
-            proto[name] = createChainedFunction(proto[name], property);
-          }
-        } else {
-          proto[name] = property;
-          if (__DEV__) {
-            // 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 (__DEV__) {
-    boundMethod.__reactBoundContext = component;
-    boundMethod.__reactBoundMethod = method;
-    boundMethod.__reactBoundArguments = null;
-    var componentName = component.constructor.displayName;
-    var _bind = boundMethod.bind;
-    boundMethod.bind = function(newThis, ...args) {
-      // 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) {
-        warning(
-          false,
-          'bind(): React component methods may only be bound to the ' +
-          'component instance. See %s',
-          componentName
-        );
-      } else if (!args.length) {
-        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
-    );
-  }
-}
-
-/**
- * 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);
-    if (callback) {
-      this.updater.enqueueCallback(this, callback, 'replaceState');
-    }
-  },
-
-  /**
-   * Checks whether or not this composite component is mounted.
-   * @return {boolean} True if mounted, false otherwise.
-   * @protected
-   * @final
-   */
-  isMounted: function() {
-    return this.updater.isMounted(this);
-  },
-};
-
-var ReactClassComponent = function() {};
-Object.assign(
-  ReactClassComponent.prototype,
-  ReactComponent.prototype,
-  ReactClassMixin
-);
-
-/**
- * Module for creating composite components.
- *
- * @class ReactClass
- */
-var ReactClass = {
-
-  /**
-   * Creates a composite component class given a class specification.
-   *
-   * @param {object} spec Class specification (which must define `render`).
-   * @return {function} Component constructor function.
-   * @public
-   */
-  createClass: function(spec) {
-    var Constructor = function(props, context, updater) {
-      // This constructor gets overridden by mocks. The argument is used
-      // by mocks to assert on what gets mounted.
-
-      if (__DEV__) {
-        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 (__DEV__) {
-        // 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, spec);
-
-    // Initialize the defaultProps property after all mixins have been merged.
-    if (Constructor.getDefaultProps) {
-      Constructor.defaultProps = Constructor.getDefaultProps();
-    }
-
-    if (__DEV__) {
-      // 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 (__DEV__) {
-      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;
-  },
-
-  injection: {
-    injectMixin: function(mixin) {
-      injectedMixins.push(mixin);
-    },
-  },
-
-};
-
-module.exports = ReactClass;
diff --git a/src/isomorphic/classic/class/__tests__/ReactBind-test.js b/src/isomorphic/classic/class/__tests__/ReactBind-test.js
deleted file mode 100644
index 63aa641a9c76..000000000000
--- a/src/isomorphic/classic/class/__tests__/ReactBind-test.js
+++ /dev/null
@@ -1,166 +0,0 @@
-/**
- * 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.
- *
- * @emails react-core
- */
-/*global global:true*/
-'use strict';
-
-var React = require('React');
-var ReactTestUtils = require('ReactTestUtils');
-var reactComponentExpect = require('reactComponentExpect');
-
-// TODO: Test render and all stock methods.
-describe('autobinding', function() {
-
-  it('Holds reference to instance', function() {
-
-    var mouseDidEnter = jest.genMockFn();
-    var mouseDidLeave = jest.genMockFn();
-    var mouseDidClick = jest.genMockFn();
-
-    var TestBindComponent = React.createClass({
-      getInitialState: function() {
-        return {something: 'hi'};
-      },
-      onMouseEnter: mouseDidEnter,
-      onMouseLeave: mouseDidLeave,
-      onClick: mouseDidClick,
-
-      // auto binding only occurs on top level functions in class defs.
-      badIdeas: {
-        badBind: function() {
-          void this.state.something;
-        },
-      },
-
-      render: function() {
-        return (
-          <div
-            onMouseOver={this.onMouseEnter}
-            onMouseOut={this.onMouseLeave}
-            onClick={this.onClick}
-          />
-        );
-      },
-    });
-
-    var instance1 = <TestBindComponent />;
-    var mountedInstance1 = ReactTestUtils.renderIntoDocument(instance1);
-    var rendered1 = reactComponentExpect(mountedInstance1)
-      .expectRenderedChild()
-      .instance();
-
-    var instance2 = <TestBindComponent />;
-    var mountedInstance2 = ReactTestUtils.renderIntoDocument(instance2);
-    var rendered2 = reactComponentExpect(mountedInstance2)
-      .expectRenderedChild()
-      .instance();
-
-    expect(function() {
-      var badIdea = instance1.badIdeas.badBind;
-      badIdea();
-    }).toThrow();
-
-    expect(mountedInstance1.onClick).not.toBe(mountedInstance2.onClick);
-
-    ReactTestUtils.Simulate.click(rendered1);
-    expect(mouseDidClick.mock.instances.length).toBe(1);
-    expect(mouseDidClick.mock.instances[0]).toBe(mountedInstance1);
-
-    ReactTestUtils.Simulate.click(rendered2);
-    expect(mouseDidClick.mock.instances.length).toBe(2);
-    expect(mouseDidClick.mock.instances[1]).toBe(mountedInstance2);
-
-    ReactTestUtils.Simulate.mouseOver(rendered1);
-    expect(mouseDidEnter.mock.instances.length).toBe(1);
-    expect(mouseDidEnter.mock.instances[0]).toBe(mountedInstance1);
-
-    ReactTestUtils.Simulate.mouseOver(rendered2);
-    expect(mouseDidEnter.mock.instances.length).toBe(2);
-    expect(mouseDidEnter.mock.instances[1]).toBe(mountedInstance2);
-
-    ReactTestUtils.Simulate.mouseOut(rendered1);
-    expect(mouseDidLeave.mock.instances.length).toBe(1);
-    expect(mouseDidLeave.mock.instances[0]).toBe(mountedInstance1);
-
-    ReactTestUtils.Simulate.mouseOut(rendered2);
-    expect(mouseDidLeave.mock.instances.length).toBe(2);
-    expect(mouseDidLeave.mock.instances[1]).toBe(mountedInstance2);
-  });
-
-  it('works with mixins', function() {
-    var mouseDidClick = jest.genMockFn();
-
-    var TestMixin = {
-      onClick: mouseDidClick,
-    };
-
-    var TestBindComponent = React.createClass({
-      mixins: [TestMixin],
-
-      render: function() {
-        return <div onClick={this.onClick} />;
-      },
-    });
-
-    var instance1 = <TestBindComponent />;
-    var mountedInstance1 = ReactTestUtils.renderIntoDocument(instance1);
-    var rendered1 = reactComponentExpect(mountedInstance1)
-      .expectRenderedChild()
-      .instance();
-
-    ReactTestUtils.Simulate.click(rendered1);
-    expect(mouseDidClick.mock.instances.length).toBe(1);
-    expect(mouseDidClick.mock.instances[0]).toBe(mountedInstance1);
-  });
-
-  it('warns if you try to bind to this', function() {
-    spyOn(console, 'error');
-
-    var TestBindComponent = React.createClass({
-      handleClick: function() { },
-      render: function() {
-        return <div onClick={this.handleClick.bind(this)} />;
-      },
-    });
-
-    ReactTestUtils.renderIntoDocument(<TestBindComponent />);
-
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: 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 TestBindComponent'
-    );
-  });
-
-  it('does not warn if you pass an auto-bound method to setState', function() {
-    spyOn(console, 'error');
-
-    var TestBindComponent = React.createClass({
-      getInitialState: function() {
-        return {foo: 1};
-      },
-      componentDidMount: function() {
-        this.setState({foo: 2}, this.handleUpdate);
-      },
-      handleUpdate: function() {
-
-      },
-      render: function() {
-        return <div onClick={this.handleClick} />;
-      },
-    });
-
-    ReactTestUtils.renderIntoDocument(<TestBindComponent />);
-
-    expect(console.error.argsForCall.length).toBe(0);
-  });
-
-});
diff --git a/src/isomorphic/classic/class/__tests__/ReactBindOptout-test.js b/src/isomorphic/classic/class/__tests__/ReactBindOptout-test.js
deleted file mode 100644
index 395e34577073..000000000000
--- a/src/isomorphic/classic/class/__tests__/ReactBindOptout-test.js
+++ /dev/null
@@ -1,233 +0,0 @@
-/**
- * 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.
- *
- * @emails react-core
- */
-/*global global:true*/
-'use strict';
-
-var React = require('React');
-var ReactTestUtils = require('ReactTestUtils');
-var reactComponentExpect = require('reactComponentExpect');
-
-// TODO: Test render and all stock methods.
-describe('autobind optout', function() {
-
-  it('should work with manual binding', function() {
-
-    var mouseDidEnter = jest.genMockFn();
-    var mouseDidLeave = jest.genMockFn();
-    var mouseDidClick = jest.genMockFn();
-
-    var TestBindComponent = React.createClass({
-      autobind: false,
-      getInitialState: function() {
-        return {something: 'hi'};
-      },
-      onMouseEnter: mouseDidEnter,
-      onMouseLeave: mouseDidLeave,
-      onClick: mouseDidClick,
-
-      render: function() {
-        return (
-          <div
-            onMouseOver={this.onMouseEnter.bind(this)}
-            onMouseOut={this.onMouseLeave.bind(this)}
-            onClick={this.onClick.bind(this)}
-            />
-        );
-      },
-    });
-
-    var instance1 = <TestBindComponent />;
-    var mountedInstance1 = ReactTestUtils.renderIntoDocument(instance1);
-    var rendered1 = reactComponentExpect(mountedInstance1)
-      .expectRenderedChild()
-      .instance();
-
-    var instance2 = <TestBindComponent />;
-    var mountedInstance2 = ReactTestUtils.renderIntoDocument(instance2);
-    var rendered2 = reactComponentExpect(mountedInstance2)
-      .expectRenderedChild()
-      .instance();
-
-    ReactTestUtils.Simulate.click(rendered1);
-    expect(mouseDidClick.mock.instances.length).toBe(1);
-    expect(mouseDidClick.mock.instances[0]).toBe(mountedInstance1);
-
-    ReactTestUtils.Simulate.click(rendered2);
-    expect(mouseDidClick.mock.instances.length).toBe(2);
-    expect(mouseDidClick.mock.instances[1]).toBe(mountedInstance2);
-
-    ReactTestUtils.Simulate.mouseOver(rendered1);
-    expect(mouseDidEnter.mock.instances.length).toBe(1);
-    expect(mouseDidEnter.mock.instances[0]).toBe(mountedInstance1);
-
-    ReactTestUtils.Simulate.mouseOver(rendered2);
-    expect(mouseDidEnter.mock.instances.length).toBe(2);
-    expect(mouseDidEnter.mock.instances[1]).toBe(mountedInstance2);
-
-    ReactTestUtils.Simulate.mouseOut(rendered1);
-    expect(mouseDidLeave.mock.instances.length).toBe(1);
-    expect(mouseDidLeave.mock.instances[0]).toBe(mountedInstance1);
-
-    ReactTestUtils.Simulate.mouseOut(rendered2);
-    expect(mouseDidLeave.mock.instances.length).toBe(2);
-    expect(mouseDidLeave.mock.instances[1]).toBe(mountedInstance2);
-  });
-
-  it('should not hold reference to instance', function() {
-    var mouseDidClick = function() {
-      void this.state.something;
-    };
-
-    var TestBindComponent = React.createClass({
-      autobind: false,
-      getInitialState: function() {
-        return {something: 'hi'};
-      },
-      onClick: mouseDidClick,
-
-      // auto binding only occurs on top level functions in class defs.
-      badIdeas: {
-        badBind: function() {
-          void this.state.something;
-        },
-      },
-
-      render: function() {
-        return (
-          <div
-            onClick={this.onClick}
-          />
-        );
-      },
-    });
-
-    var instance1 = <TestBindComponent />;
-    var mountedInstance1 = ReactTestUtils.renderIntoDocument(instance1);
-    var rendered1 = reactComponentExpect(mountedInstance1)
-      .expectRenderedChild()
-      .instance();
-
-    var instance2 = <TestBindComponent />;
-    var mountedInstance2 = ReactTestUtils.renderIntoDocument(instance2);
-    var rendered2 = reactComponentExpect(mountedInstance2)
-      .expectRenderedChild()
-      .instance();
-
-    expect(function() {
-      var badIdea = instance1.badIdeas.badBind;
-      badIdea();
-    }).toThrow();
-
-    expect(mountedInstance1.onClick).toBe(mountedInstance2.onClick);
-
-    expect(function() {
-      ReactTestUtils.Simulate.click(rendered1);
-    }).toThrow();
-
-    expect(function() {
-      ReactTestUtils.Simulate.click(rendered2);
-    }).toThrow();
-  });
-
-  it('works with mixins that have not opted out of autobinding', function() {
-    var mouseDidClick = jest.genMockFn();
-
-    var TestMixin = {
-      onClick: mouseDidClick,
-    };
-
-    var TestBindComponent = React.createClass({
-      mixins: [TestMixin],
-
-      render: function() {
-        return <div onClick={this.onClick} />;
-      },
-    });
-
-    var instance1 = <TestBindComponent />;
-    var mountedInstance1 = ReactTestUtils.renderIntoDocument(instance1);
-    var rendered1 = reactComponentExpect(mountedInstance1)
-      .expectRenderedChild()
-      .instance();
-
-    ReactTestUtils.Simulate.click(rendered1);
-    expect(mouseDidClick.mock.instances.length).toBe(1);
-    expect(mouseDidClick.mock.instances[0]).toBe(mountedInstance1);
-  });
-
-  it('works with mixins that have opted out of autobinding', function() {
-    var mouseDidClick = jest.genMockFn();
-
-    var TestMixin = {
-      autobind: false,
-      onClick: mouseDidClick,
-    };
-
-    var TestBindComponent = React.createClass({
-      mixins: [TestMixin],
-
-      render: function() {
-        return <div onClick={this.onClick.bind(this)} />;
-      },
-    });
-
-    var instance1 = <TestBindComponent />;
-    var mountedInstance1 = ReactTestUtils.renderIntoDocument(instance1);
-    var rendered1 = reactComponentExpect(mountedInstance1)
-      .expectRenderedChild()
-      .instance();
-
-    ReactTestUtils.Simulate.click(rendered1);
-    expect(mouseDidClick.mock.instances.length).toBe(1);
-    expect(mouseDidClick.mock.instances[0]).toBe(mountedInstance1);
-  });
-
-  it('does not warn if you try to bind to this', function() {
-    spyOn(console, 'error');
-
-    var TestBindComponent = React.createClass({
-      autobind: false,
-      handleClick: function() { },
-      render: function() {
-        return <div onClick={this.handleClick.bind(this)} />;
-      },
-    });
-
-    ReactTestUtils.renderIntoDocument(<TestBindComponent />);
-
-    expect(console.error.argsForCall.length).toBe(0);
-  });
-
-  it('does not warn if you pass an manually bound method to setState', function() {
-    spyOn(console, 'error');
-
-    var TestBindComponent = React.createClass({
-      autobind: false,
-      getInitialState: function() {
-        return {foo: 1};
-      },
-      componentDidMount: function() {
-        this.setState({foo: 2}, this.handleUpdate.bind(this));
-      },
-      handleUpdate: function() {
-
-      },
-      render: function() {
-        return <div />;
-      },
-    });
-
-    ReactTestUtils.renderIntoDocument(<TestBindComponent />);
-
-    expect(console.error.argsForCall.length).toBe(0);
-  });
-
-});
diff --git a/src/isomorphic/classic/class/__tests__/ReactClass-test.js b/src/isomorphic/classic/class/__tests__/ReactClass-test.js
deleted file mode 100644
index 07a1e4bcb3a7..000000000000
--- a/src/isomorphic/classic/class/__tests__/ReactClass-test.js
+++ /dev/null
@@ -1,353 +0,0 @@
-/**
- * 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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-var React;
-var ReactDOM;
-var ReactTestUtils;
-
-describe('ReactClass-spec', function() {
-
-  beforeEach(function() {
-    React = require('React');
-    ReactDOM = require('ReactDOM');
-    ReactTestUtils = require('ReactTestUtils');
-  });
-
-  it('should throw when `render` is not specified', function() {
-    expect(function() {
-      React.createClass({});
-    }).toThrow(
-      'createClass(...): Class specification must implement a `render` method.'
-    );
-  });
-
-  it('should copy `displayName` onto the Constructor', function() {
-    var TestComponent = React.createClass({
-      render: function() {
-        return <div />;
-      },
-    });
-
-    expect(TestComponent.displayName)
-      .toBe('TestComponent');
-  });
-
-  it('should copy prop types onto the Constructor', function() {
-    var propValidator = jest.genMockFn();
-    var TestComponent = React.createClass({
-      propTypes: {
-        value: propValidator,
-      },
-      render: function() {
-        return <div />;
-      },
-    });
-
-    expect(TestComponent.propTypes).toBeDefined();
-    expect(TestComponent.propTypes.value)
-      .toBe(propValidator);
-  });
-
-  it('should warn on invalid prop types', function() {
-    spyOn(console, 'error');
-    React.createClass({
-      displayName: 'Component',
-      propTypes: {
-        prop: null,
-      },
-      render: function() {
-        return <span>{this.props.prop}</span>;
-      },
-    });
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: Component: prop type `prop` is invalid; ' +
-      'it must be a function, usually from React.PropTypes.'
-    );
-  });
-
-  it('should warn on invalid context types', function() {
-    spyOn(console, 'error');
-    React.createClass({
-      displayName: 'Component',
-      contextTypes: {
-        prop: null,
-      },
-      render: function() {
-        return <span>{this.props.prop}</span>;
-      },
-    });
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: Component: context type `prop` is invalid; ' +
-      'it must be a function, usually from React.PropTypes.'
-    );
-  });
-
-  it('should throw on invalid child context types', function() {
-    spyOn(console, 'error');
-    React.createClass({
-      displayName: 'Component',
-      childContextTypes: {
-        prop: null,
-      },
-      render: function() {
-        return <span>{this.props.prop}</span>;
-      },
-    });
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: Component: child context type `prop` is invalid; ' +
-      'it must be a function, usually from React.PropTypes.'
-    );
-  });
-
-  it('should warn when mispelling shouldComponentUpdate', function() {
-    spyOn(console, 'error');
-
-    React.createClass({
-      componentShouldUpdate: function() {
-        return false;
-      },
-      render: function() {
-        return <div />;
-      },
-    });
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: A component 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.'
-    );
-
-    React.createClass({
-      displayName: 'NamedComponent',
-      componentShouldUpdate: function() {
-        return false;
-      },
-      render: function() {
-        return <div />;
-      },
-    });
-    expect(console.error.argsForCall.length).toBe(2);
-    expect(console.error.argsForCall[1][0]).toBe(
-      'Warning: NamedComponent 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.'
-    );
-  });
-
-  it('should warn when mispelling componentWillReceiveProps', function() {
-    spyOn(console, 'error');
-    React.createClass({
-      componentWillRecieveProps: function() {
-        return false;
-      },
-      render: function() {
-        return <div />;
-      },
-    });
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: A component has a method called componentWillRecieveProps(). Did you ' +
-      'mean componentWillReceiveProps()?'
-    );
-  });
-
-  it('should throw if a reserved property is in statics', function() {
-    expect(function() {
-      React.createClass({
-        statics: {
-          getDefaultProps: function() {
-            return {
-              foo: 0,
-            };
-          },
-        },
-
-        render: function() {
-          return <span />;
-        },
-      });
-    }).toThrow(
-      'ReactClass: You are attempting to define a reserved property, ' +
-      '`getDefaultProps`, that shouldn\'t be on the "statics" key. Define ' +
-      'it as an instance property instead; it will still be accessible on ' +
-      'the constructor.'
-    );
-  });
-
-  // TODO: Consider actually moving these to statics or drop this unit test.
-
-  xit('should warn when using deprecated non-static spec keys', function() {
-    spyOn(console, 'error');
-    React.createClass({
-      mixins: [{}],
-      propTypes: {
-        foo: React.PropTypes.string,
-      },
-      contextTypes: {
-        foo: React.PropTypes.string,
-      },
-      childContextTypes: {
-        foo: React.PropTypes.string,
-      },
-      render: function() {
-        return <div />;
-      },
-    });
-    expect(console.error.argsForCall.length).toBe(4);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'createClass(...): `mixins` is now a static property and should ' +
-      'be defined inside "statics".'
-    );
-    expect(console.error.argsForCall[1][0]).toBe(
-      'createClass(...): `propTypes` is now a static property and should ' +
-      'be defined inside "statics".'
-    );
-    expect(console.error.argsForCall[2][0]).toBe(
-      'createClass(...): `contextTypes` is now a static property and ' +
-      'should be defined inside "statics".'
-    );
-    expect(console.error.argsForCall[3][0]).toBe(
-      'createClass(...): `childContextTypes` is now a static property and ' +
-      'should be defined inside "statics".'
-    );
-  });
-
-  it('should support statics', function() {
-    var Component = React.createClass({
-      statics: {
-        abc: 'def',
-        def: 0,
-        ghi: null,
-        jkl: 'mno',
-        pqr: function() {
-          return this;
-        },
-      },
-
-      render: function() {
-        return <span />;
-      },
-    });
-    var instance = <Component />;
-    instance = ReactTestUtils.renderIntoDocument(instance);
-    expect(instance.constructor.abc).toBe('def');
-    expect(Component.abc).toBe('def');
-    expect(instance.constructor.def).toBe(0);
-    expect(Component.def).toBe(0);
-    expect(instance.constructor.ghi).toBe(null);
-    expect(Component.ghi).toBe(null);
-    expect(instance.constructor.jkl).toBe('mno');
-    expect(Component.jkl).toBe('mno');
-    expect(instance.constructor.pqr()).toBe(Component);
-    expect(Component.pqr()).toBe(Component);
-  });
-
-  it('should work with object getInitialState() return values', function() {
-    var Component = React.createClass({
-      getInitialState: function() {
-        return {
-          occupation: 'clown',
-        };
-      },
-      render: function() {
-        return <span />;
-      },
-    });
-    var instance = <Component />;
-    instance = ReactTestUtils.renderIntoDocument(instance);
-    expect(instance.state.occupation).toEqual('clown');
-  });
-
-  it('renders based on context getInitialState', function() {
-    var Foo = React.createClass({
-      contextTypes: {
-        className: React.PropTypes.string,
-      },
-      getInitialState() {
-        return {className: this.context.className};
-      },
-      render() {
-        return <span className={this.state.className} />;
-      },
-    });
-
-    var Outer = React.createClass({
-      childContextTypes: {
-        className: React.PropTypes.string,
-      },
-      getChildContext() {
-        return {className: 'foo'};
-      },
-      render() {
-        return <Foo />;
-      },
-    });
-
-    var container = document.createElement('div');
-    ReactDOM.render(<Outer />, container);
-    expect(container.firstChild.className).toBe('foo');
-  });
-
-  it('should throw with non-object getInitialState() return values', function() {
-    [['an array'], 'a string', 1234].forEach(function(state) {
-      var Component = React.createClass({
-        getInitialState: function() {
-          return state;
-        },
-        render: function() {
-          return <span />;
-        },
-      });
-      var instance = <Component />;
-      expect(function() {
-        instance = ReactTestUtils.renderIntoDocument(instance);
-      }).toThrow(
-        'Component.getInitialState(): must return an object or null'
-      );
-    });
-  });
-
-  it('should work with a null getInitialState() return value', function() {
-    var Component = React.createClass({
-      getInitialState: function() {
-        return null;
-      },
-      render: function() {
-        return <span />;
-      },
-    });
-    expect(
-      () => ReactTestUtils.renderIntoDocument(<Component />)
-    ).not.toThrow();
-  });
-
-  it('should throw when using legacy factories', function() {
-    spyOn(console, 'error');
-    var Component = React.createClass({
-      render() {
-        return <div />;
-      },
-    });
-
-    expect(() => Component()).toThrow();
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: Something is calling a React component directly. Use a ' +
-      'factory or JSX instead. See: https://fb.me/react-legacyfactory'
-    );
-  });
-
-});
diff --git a/src/isomorphic/classic/class/__tests__/ReactClassMixin-test.js b/src/isomorphic/classic/class/__tests__/ReactClassMixin-test.js
deleted file mode 100644
index a65c68ff071b..000000000000
--- a/src/isomorphic/classic/class/__tests__/ReactClassMixin-test.js
+++ /dev/null
@@ -1,457 +0,0 @@
-/**
- * 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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-var React;
-var ReactTestUtils;
-
-var TestComponent;
-var TestComponentWithPropTypes;
-var TestComponentWithReverseSpec;
-var mixinPropValidator;
-var componentPropValidator;
-
-describe('ReactClass-mixin', function() {
-
-  beforeEach(function() {
-    React = require('React');
-    ReactTestUtils = require('ReactTestUtils');
-    mixinPropValidator = jest.genMockFn();
-    componentPropValidator = jest.genMockFn();
-
-    var MixinA = {
-      propTypes: {
-        propA: function() {},
-      },
-      componentDidMount: function() {
-        this.props.listener('MixinA didMount');
-      },
-    };
-
-    var MixinB = {
-      mixins: [MixinA],
-      propTypes: {
-        propB: function() {},
-      },
-      componentDidMount: function() {
-        this.props.listener('MixinB didMount');
-      },
-    };
-
-    var MixinBWithReverseSpec = {
-      componentDidMount: function() {
-        this.props.listener('MixinBWithReverseSpec didMount');
-      },
-      mixins: [MixinA],
-    };
-
-    var MixinC = {
-      statics: {
-        staticC: function() {},
-      },
-      componentDidMount: function() {
-        this.props.listener('MixinC didMount');
-      },
-    };
-
-    var MixinD = {
-      propTypes: {
-        value: mixinPropValidator,
-      },
-    };
-
-    TestComponent = React.createClass({
-      mixins: [MixinB, MixinC, MixinD],
-      statics: {
-        staticComponent: function() {},
-      },
-      propTypes: {
-        propComponent: function() {},
-      },
-      componentDidMount: function() {
-        this.props.listener('Component didMount');
-      },
-      render: function() {
-        return <div />;
-      },
-    });
-
-    TestComponentWithReverseSpec = React.createClass({
-      render: function() {
-        return <div />;
-      },
-      componentDidMount: function() {
-        this.props.listener('Component didMount');
-      },
-      mixins: [MixinBWithReverseSpec, MixinC, MixinD],
-    });
-
-    TestComponentWithPropTypes = React.createClass({
-      mixins: [MixinD],
-      propTypes: {
-        value: componentPropValidator,
-      },
-      render: function() {
-        return <div />;
-      },
-    });
-  });
-
-  it('should support merging propTypes and statics', function() {
-    var listener = jest.genMockFn();
-    var instance = <TestComponent listener={listener} />;
-    instance = ReactTestUtils.renderIntoDocument(instance);
-
-    var instancePropTypes = instance.constructor.propTypes;
-
-    expect('propA' in instancePropTypes).toBe(true);
-    expect('propB' in instancePropTypes).toBe(true);
-    expect('propComponent' in instancePropTypes).toBe(true);
-
-    expect('staticC' in TestComponent).toBe(true);
-    expect('staticComponent' in TestComponent).toBe(true);
-  });
-
-  it('should support chaining delegate functions', function() {
-    var listener = jest.genMockFn();
-    var instance = <TestComponent listener={listener} />;
-    instance = ReactTestUtils.renderIntoDocument(instance);
-
-    expect(listener.mock.calls).toEqual([
-      ['MixinA didMount'],
-      ['MixinB didMount'],
-      ['MixinC didMount'],
-      ['Component didMount'],
-    ]);
-  });
-
-  it('should chain functions regardless of spec property order', function() {
-    var listener = jest.genMockFn();
-    var instance = <TestComponentWithReverseSpec listener={listener} />;
-    instance = ReactTestUtils.renderIntoDocument(instance);
-
-    expect(listener.mock.calls).toEqual([
-      ['MixinA didMount'],
-      ['MixinBWithReverseSpec didMount'],
-      ['MixinC didMount'],
-      ['Component didMount'],
-    ]);
-  });
-
-  it('should validate prop types via mixins', function() {
-    expect(TestComponent.propTypes).toBeDefined();
-    expect(TestComponent.propTypes.value)
-      .toBe(mixinPropValidator);
-  });
-
-  it('should override mixin prop types with class prop types', function() {
-    // Sanity check...
-    expect(componentPropValidator).toNotBe(mixinPropValidator);
-    // Actually check...
-    expect(TestComponentWithPropTypes.propTypes)
-      .toBeDefined();
-    expect(TestComponentWithPropTypes.propTypes.value)
-      .toNotBe(mixinPropValidator);
-    expect(TestComponentWithPropTypes.propTypes.value)
-      .toBe(componentPropValidator);
-  });
-
-
-  it('should support mixins with getInitialState()', function() {
-    var Mixin = {
-      getInitialState: function() {
-        return {mixin: true};
-      },
-    };
-    var Component = React.createClass({
-      mixins: [Mixin],
-      getInitialState: function() {
-        return {component: true};
-      },
-      render: function() {
-        return <span />;
-      },
-    });
-    var instance = <Component />;
-    instance = ReactTestUtils.renderIntoDocument(instance);
-    expect(instance.state.component).toBe(true);
-    expect(instance.state.mixin).toBe(true);
-  });
-
-  it('should throw with conflicting getInitialState() methods', function() {
-    var Mixin = {
-      getInitialState: function() {
-        return {x: true};
-      },
-    };
-    var Component = React.createClass({
-      mixins: [Mixin],
-      getInitialState: function() {
-        return {x: true};
-      },
-      render: function() {
-        return <span />;
-      },
-    });
-    var instance = <Component />;
-    expect(function() {
-      instance = ReactTestUtils.renderIntoDocument(instance);
-    }).toThrow(
-      'mergeIntoWithNoDuplicateKeys(): Tried to merge two objects with the ' +
-      'same key: `x`. 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.'
-    );
-  });
-
-  it('should not mutate objects returned by getInitialState()', function() {
-    var Mixin = {
-      getInitialState: function() {
-        return Object.freeze({mixin: true});
-      },
-    };
-    var Component = React.createClass({
-      mixins: [Mixin],
-      getInitialState: function() {
-        return Object.freeze({component: true});
-      },
-      render: function() {
-        return <span />;
-      },
-    });
-    expect(() => {
-      ReactTestUtils.renderIntoDocument(<Component />);
-    }).not.toThrow();
-  });
-
-  it('should support statics in mixins', function() {
-    var Mixin = {
-      statics: {
-        foo: 'bar',
-      },
-    };
-    var Component = React.createClass({
-      mixins: [Mixin],
-
-      statics: {
-        abc: 'def',
-      },
-
-      render: function() {
-        return <span />;
-      },
-    });
-    var instance = <Component />;
-    instance = ReactTestUtils.renderIntoDocument(instance);
-    expect(instance.constructor.foo).toBe('bar');
-    expect(Component.foo).toBe('bar');
-    expect(instance.constructor.abc).toBe('def');
-    expect(Component.abc).toBe('def');
-  });
-
-  it("should throw if mixins override each others' statics", function() {
-    expect(function() {
-      var Mixin = {
-        statics: {
-          abc: 'foo',
-        },
-      };
-      React.createClass({
-        mixins: [Mixin],
-
-        statics: {
-          abc: 'bar',
-        },
-
-        render: function() {
-          return <span />;
-        },
-      });
-    }).toThrow(
-      'ReactClass: You are attempting to define `abc` on your component more ' +
-      'than once. This conflict may be due to a mixin.'
-    );
-  });
-
-  it('should throw if mixins override functions in statics', function() {
-    expect(function() {
-      var Mixin = {
-        statics: {
-          abc: function() {
-            console.log('foo');
-          },
-        },
-      };
-      React.createClass({
-        mixins: [Mixin],
-
-        statics: {
-          abc: function() {
-            console.log('bar');
-          },
-        },
-
-        render: function() {
-          return <span />;
-        },
-      });
-    }).toThrow(
-      'ReactClass: You are attempting to define `abc` on your component ' +
-      'more than once. This conflict may be due to a mixin.'
-    );
-  });
-
-  it('should throw if the mixin is a React component', function() {
-    expect(function() {
-      React.createClass({
-        mixins: [<div />],
-
-        render: function() {
-          return <span />;
-        },
-      });
-    }).toThrow(
-      'ReactClass: You\'re attempting to use a component as a mixin. ' +
-      'Instead, just use a regular object.'
-    );
-  });
-
-  it('should throw if the mixin is a React component class', function() {
-    expect(function() {
-      var Component = React.createClass({
-        render: function() {
-          return <span />;
-        },
-      });
-
-      React.createClass({
-        mixins: [Component],
-
-        render: function() {
-          return <span />;
-        },
-      });
-    }).toThrow(
-      'ReactClass: You\'re attempting to use a component class or function ' +
-      'as a mixin. Instead, just use a regular object.'
-    );
-  });
-
-  it('should have bound the mixin methods to the component', function() {
-    var mixin = {
-      mixinFunc: function() {
-        return this;
-      },
-    };
-
-    var Component = React.createClass({
-      mixins: [mixin],
-      componentDidMount: function() {
-        expect(this.mixinFunc()).toBe(this);
-      },
-      render: function() {
-        return <span />;
-      },
-    });
-    var instance = <Component />;
-    instance = ReactTestUtils.renderIntoDocument(instance);
-  });
-
-  it('should include the mixin keys in even if their values are falsy', function() {
-    var mixin = {
-      keyWithNullValue: null,
-      randomCounter: 0,
-    };
-
-    var Component = React.createClass({
-      mixins: [mixin],
-      componentDidMount: function() {
-        expect(this.randomCounter).toBe(0);
-        expect(this.keyWithNullValue).toBeNull();
-      },
-      render: function() {
-        return <span />;
-      },
-    });
-    var instance = <Component />;
-    instance = ReactTestUtils.renderIntoDocument(instance);
-  });
-
-  it('should work with a null getInitialState return value and a mixin', () => {
-    var Component;
-    var instance;
-
-    var Mixin = {
-      getInitialState: function() {
-        return {foo: 'bar'};
-      },
-    };
-    Component = React.createClass({
-      mixins: [Mixin],
-      getInitialState: function() {
-        return null;
-      },
-      render: function() {
-        return <span />;
-      },
-    });
-    expect(
-      () => ReactTestUtils.renderIntoDocument(<Component />)
-    ).not.toThrow();
-
-    instance = <Component />;
-    instance = ReactTestUtils.renderIntoDocument(instance);
-    expect(instance.state).toEqual({foo: 'bar'});
-
-    // Also the other way round should work
-    var Mixin2 = {
-      getInitialState: function() {
-        return null;
-      },
-    };
-    Component = React.createClass({
-      mixins: [Mixin2],
-      getInitialState: function() {
-        return {foo: 'bar'};
-      },
-      render: function() {
-        return <span />;
-      },
-    });
-    expect(
-      () => ReactTestUtils.renderIntoDocument(<Component />)
-    ).not.toThrow();
-
-    instance = <Component />;
-    instance = ReactTestUtils.renderIntoDocument(instance);
-    expect(instance.state).toEqual({foo: 'bar'});
-
-    // Multiple mixins should be fine too
-    Component = React.createClass({
-      mixins: [Mixin, Mixin2],
-      getInitialState: function() {
-        return {x: true};
-      },
-      render: function() {
-        return <span />;
-      },
-    });
-    expect(
-      () => ReactTestUtils.renderIntoDocument(<Component />)
-    ).not.toThrow();
-
-    instance = <Component />;
-    instance = ReactTestUtils.renderIntoDocument(instance);
-    expect(instance.state).toEqual({foo: 'bar', x: true});
-  });
-
-});
diff --git a/src/isomorphic/classic/class/__tests__/ReactCreateClass-test.js b/src/isomorphic/classic/class/__tests__/ReactCreateClass-test.js
new file mode 100644
index 000000000000..61f4fafa0dcf
--- /dev/null
+++ b/src/isomorphic/classic/class/__tests__/ReactCreateClass-test.js
@@ -0,0 +1,439 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var PropTypes;
+var React;
+var ReactDOM;
+var ReactTestUtils;
+var createReactClass;
+
+describe('ReactClass-spec', () => {
+  beforeEach(() => {
+    PropTypes = require('prop-types');
+    React = require('React');
+    ReactDOM = require('ReactDOM');
+    ReactTestUtils = require('ReactTestUtils');
+    var createReactClassFactory = require('create-react-class/factory');
+    createReactClass = createReactClassFactory(
+      React.Component,
+      React.isValidElement,
+      require('ReactNoopUpdateQueue'),
+    );
+  });
+
+  it('should throw when `render` is not specified', () => {
+    expect(function() {
+      createReactClass({});
+    }).toThrowError(
+      'createClass(...): Class specification must implement a `render` method.',
+    );
+  });
+
+  // TODO: Update babel-plugin-transform-react-display-name
+  xit('should copy `displayName` onto the Constructor', () => {
+    var TestComponent = createReactClass({
+      render: function() {
+        return <div />;
+      },
+    });
+
+    expect(TestComponent.displayName).toBe('TestComponent');
+  });
+
+  it('should copy prop types onto the Constructor', () => {
+    var propValidator = jest.fn();
+    var TestComponent = createReactClass({
+      propTypes: {
+        value: propValidator,
+      },
+      render: function() {
+        return <div />;
+      },
+    });
+
+    expect(TestComponent.propTypes).toBeDefined();
+    expect(TestComponent.propTypes.value).toBe(propValidator);
+  });
+
+  it('should warn on invalid prop types', () => {
+    spyOn(console, 'error');
+    createReactClass({
+      displayName: 'Component',
+      propTypes: {
+        prop: null,
+      },
+      render: function() {
+        return <span>{this.props.prop}</span>;
+      },
+    });
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: Component: prop type `prop` is invalid; ' +
+        'it must be a function, usually from React.PropTypes.',
+    );
+  });
+
+  it('should warn on invalid context types', () => {
+    spyOn(console, 'error');
+    createReactClass({
+      displayName: 'Component',
+      contextTypes: {
+        prop: null,
+      },
+      render: function() {
+        return <span>{this.props.prop}</span>;
+      },
+    });
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: Component: context type `prop` is invalid; ' +
+        'it must be a function, usually from React.PropTypes.',
+    );
+  });
+
+  it('should throw on invalid child context types', () => {
+    spyOn(console, 'error');
+    createReactClass({
+      displayName: 'Component',
+      childContextTypes: {
+        prop: null,
+      },
+      render: function() {
+        return <span>{this.props.prop}</span>;
+      },
+    });
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: Component: child context type `prop` is invalid; ' +
+        'it must be a function, usually from React.PropTypes.',
+    );
+  });
+
+  it('should warn when mispelling shouldComponentUpdate', () => {
+    spyOn(console, 'error');
+
+    createReactClass({
+      componentShouldUpdate: function() {
+        return false;
+      },
+      render: function() {
+        return <div />;
+      },
+    });
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: A component 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.',
+    );
+
+    createReactClass({
+      displayName: 'NamedComponent',
+      componentShouldUpdate: function() {
+        return false;
+      },
+      render: function() {
+        return <div />;
+      },
+    });
+    expect(console.error.calls.count()).toBe(2);
+    expect(console.error.calls.argsFor(1)[0]).toBe(
+      'Warning: NamedComponent 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.',
+    );
+  });
+
+  it('should warn when mispelling componentWillReceiveProps', () => {
+    spyOn(console, 'error');
+    createReactClass({
+      componentWillRecieveProps: function() {
+        return false;
+      },
+      render: function() {
+        return <div />;
+      },
+    });
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: A component has a method called componentWillRecieveProps(). Did you ' +
+        'mean componentWillReceiveProps()?',
+    );
+  });
+
+  it('should throw if a reserved property is in statics', () => {
+    expect(function() {
+      createReactClass({
+        statics: {
+          getDefaultProps: function() {
+            return {
+              foo: 0,
+            };
+          },
+        },
+
+        render: function() {
+          return <span />;
+        },
+      });
+    }).toThrowError(
+      'ReactClass: You are attempting to define a reserved property, ' +
+        '`getDefaultProps`, that shouldn\'t be on the "statics" key. Define ' +
+        'it as an instance property instead; it will still be accessible on ' +
+        'the constructor.',
+    );
+  });
+
+  // TODO: Consider actually moving these to statics or drop this unit test.
+
+  xit('should warn when using deprecated non-static spec keys', () => {
+    spyOn(console, 'error');
+    createReactClass({
+      mixins: [{}],
+      propTypes: {
+        foo: PropTypes.string,
+      },
+      contextTypes: {
+        foo: PropTypes.string,
+      },
+      childContextTypes: {
+        foo: PropTypes.string,
+      },
+      render: function() {
+        return <div />;
+      },
+    });
+    expect(console.error.calls.count()).toBe(4);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      'createClass(...): `mixins` is now a static property and should ' +
+        'be defined inside "statics".',
+    );
+    expect(console.error.calls.argsFor(1)[0]).toBe(
+      'createClass(...): `propTypes` is now a static property and should ' +
+        'be defined inside "statics".',
+    );
+    expect(console.error.calls.argsFor(2)[0]).toBe(
+      'createClass(...): `contextTypes` is now a static property and ' +
+        'should be defined inside "statics".',
+    );
+    expect(console.error.calls.argsFor(3)[0]).toBe(
+      'createClass(...): `childContextTypes` is now a static property and ' +
+        'should be defined inside "statics".',
+    );
+  });
+
+  it('should support statics', () => {
+    var Component = createReactClass({
+      statics: {
+        abc: 'def',
+        def: 0,
+        ghi: null,
+        jkl: 'mno',
+        pqr: function() {
+          return this;
+        },
+      },
+
+      render: function() {
+        return <span />;
+      },
+    });
+    var instance = <Component />;
+    instance = ReactTestUtils.renderIntoDocument(instance);
+    expect(instance.constructor.abc).toBe('def');
+    expect(Component.abc).toBe('def');
+    expect(instance.constructor.def).toBe(0);
+    expect(Component.def).toBe(0);
+    expect(instance.constructor.ghi).toBe(null);
+    expect(Component.ghi).toBe(null);
+    expect(instance.constructor.jkl).toBe('mno');
+    expect(Component.jkl).toBe('mno');
+    expect(instance.constructor.pqr()).toBe(Component);
+    expect(Component.pqr()).toBe(Component);
+  });
+
+  it('should work with object getInitialState() return values', () => {
+    var Component = createReactClass({
+      getInitialState: function() {
+        return {
+          occupation: 'clown',
+        };
+      },
+      render: function() {
+        return <span />;
+      },
+    });
+    var instance = <Component />;
+    instance = ReactTestUtils.renderIntoDocument(instance);
+    expect(instance.state.occupation).toEqual('clown');
+  });
+
+  it('renders based on context getInitialState', () => {
+    var Foo = createReactClass({
+      contextTypes: {
+        className: PropTypes.string,
+      },
+      getInitialState() {
+        return {className: this.context.className};
+      },
+      render() {
+        return <span className={this.state.className} />;
+      },
+    });
+
+    var Outer = createReactClass({
+      childContextTypes: {
+        className: PropTypes.string,
+      },
+      getChildContext() {
+        return {className: 'foo'};
+      },
+      render() {
+        return <Foo />;
+      },
+    });
+
+    var container = document.createElement('div');
+    ReactDOM.render(<Outer />, container);
+    expect(container.firstChild.className).toBe('foo');
+  });
+
+  it('should throw with non-object getInitialState() return values', () => {
+    [['an array'], 'a string', 1234].forEach(function(state) {
+      var Component = createReactClass({
+        getInitialState: function() {
+          return state;
+        },
+        render: function() {
+          return <span />;
+        },
+      });
+      var instance = <Component />;
+      expect(function() {
+        instance = ReactTestUtils.renderIntoDocument(instance);
+      }).toThrowError(
+        'Component.getInitialState(): must return an object or null',
+      );
+    });
+  });
+
+  it('should work with a null getInitialState() return value', () => {
+    var Component = createReactClass({
+      getInitialState: function() {
+        return null;
+      },
+      render: function() {
+        return <span />;
+      },
+    });
+    expect(() =>
+      ReactTestUtils.renderIntoDocument(<Component />),
+    ).not.toThrow();
+  });
+
+  it('should throw when using legacy factories', () => {
+    spyOn(console, 'error');
+    var Component = createReactClass({
+      render() {
+        return <div />;
+      },
+    });
+
+    expect(() => Component()).toThrow();
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: Something is calling a React component directly. Use a ' +
+        'factory or JSX instead. See: https://fb.me/react-legacyfactory',
+    );
+  });
+
+  it('replaceState and callback works', () => {
+    var ops = [];
+    var Component = createReactClass({
+      getInitialState() {
+        return {step: 0};
+      },
+      render() {
+        ops.push('Render: ' + this.state.step);
+        return <div />;
+      },
+    });
+
+    var instance = ReactTestUtils.renderIntoDocument(<Component />);
+    instance.replaceState({step: 1}, () => {
+      ops.push('Callback: ' + instance.state.step);
+    });
+    expect(ops).toEqual(['Render: 0', 'Render: 1', 'Callback: 1']);
+  });
+
+  it('isMounted works', () => {
+    spyOn(console, 'error');
+
+    var ops = [];
+    var instance;
+    var Component = createReactClass({
+      displayName: 'MyComponent',
+      log(name) {
+        ops.push(`${name}: ${this.isMounted()}`);
+      },
+      getInitialState() {
+        this.log('getInitialState');
+        return {};
+      },
+      componentWillMount() {
+        this.log('componentWillMount');
+      },
+      componentDidMount() {
+        this.log('componentDidMount');
+      },
+      componentWillUpdate() {
+        this.log('componentWillUpdate');
+      },
+      componentDidUpdate() {
+        this.log('componentDidUpdate');
+      },
+      componentWillUnmount() {
+        this.log('componentWillUnmount');
+      },
+      render() {
+        instance = this;
+        this.log('render');
+        return <div />;
+      },
+    });
+
+    var container = document.createElement('div');
+    ReactDOM.render(<Component />, container);
+    ReactDOM.render(<Component />, container);
+    ReactDOM.unmountComponentAtNode(container);
+    instance.log('after unmount');
+    expect(ops).toEqual([
+      'getInitialState: false',
+      'componentWillMount: false',
+      'render: false',
+      'componentDidMount: true',
+      'componentWillUpdate: true',
+      'render: true',
+      'componentDidUpdate: true',
+      'componentWillUnmount: false',
+      'after unmount: false',
+    ]);
+
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toEqual(
+      'Warning: MyComponent: isMounted is deprecated. Instead, make sure to ' +
+        'clean up subscriptions and pending requests in componentWillUnmount ' +
+        'to prevent memory leaks.',
+    );
+  });
+});
diff --git a/src/isomorphic/classic/class/__tests__/create-react-class-integration-test.js b/src/isomorphic/classic/class/__tests__/create-react-class-integration-test.js
new file mode 100644
index 000000000000..4c89c732acf1
--- /dev/null
+++ b/src/isomorphic/classic/class/__tests__/create-react-class-integration-test.js
@@ -0,0 +1,426 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var React;
+var ReactDOM;
+var ReactTestUtils;
+var createReactClass;
+
+describe('create-react-class-integration', () => {
+  beforeEach(() => {
+    React = require('React');
+    ReactDOM = require('ReactDOM');
+    ReactTestUtils = require('ReactTestUtils');
+    var createReactClassFactory = require('create-react-class/factory');
+    createReactClass = createReactClassFactory(
+      React.Component,
+      React.isValidElement,
+      require('ReactNoopUpdateQueue'),
+    );
+  });
+
+  it('should throw when `render` is not specified', () => {
+    expect(function() {
+      createReactClass({});
+    }).toThrowError(
+      'createClass(...): Class specification must implement a `render` method.',
+    );
+  });
+
+  it('should copy prop types onto the Constructor', () => {
+    var propValidator = jest.fn();
+    var TestComponent = createReactClass({
+      propTypes: {
+        value: propValidator,
+      },
+      render: function() {
+        return <div />;
+      },
+    });
+
+    expect(TestComponent.propTypes).toBeDefined();
+    expect(TestComponent.propTypes.value).toBe(propValidator);
+  });
+
+  it('should warn on invalid prop types', () => {
+    spyOn(console, 'error');
+    createReactClass({
+      displayName: 'Component',
+      propTypes: {
+        prop: null,
+      },
+      render: function() {
+        return <span>{this.props.prop}</span>;
+      },
+    });
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: Component: prop type `prop` is invalid; ' +
+        'it must be a function, usually from React.PropTypes.',
+    );
+  });
+
+  it('should warn on invalid context types', () => {
+    spyOn(console, 'error');
+    createReactClass({
+      displayName: 'Component',
+      contextTypes: {
+        prop: null,
+      },
+      render: function() {
+        return <span>{this.props.prop}</span>;
+      },
+    });
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: Component: context type `prop` is invalid; ' +
+        'it must be a function, usually from React.PropTypes.',
+    );
+  });
+
+  it('should throw on invalid child context types', () => {
+    spyOn(console, 'error');
+    createReactClass({
+      displayName: 'Component',
+      childContextTypes: {
+        prop: null,
+      },
+      render: function() {
+        return <span>{this.props.prop}</span>;
+      },
+    });
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: Component: child context type `prop` is invalid; ' +
+        'it must be a function, usually from React.PropTypes.',
+    );
+  });
+
+  it('should warn when mispelling shouldComponentUpdate', () => {
+    spyOn(console, 'error');
+
+    createReactClass({
+      componentShouldUpdate: function() {
+        return false;
+      },
+      render: function() {
+        return <div />;
+      },
+    });
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: A component 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.',
+    );
+
+    createReactClass({
+      displayName: 'NamedComponent',
+      componentShouldUpdate: function() {
+        return false;
+      },
+      render: function() {
+        return <div />;
+      },
+    });
+    expect(console.error.calls.count()).toBe(2);
+    expect(console.error.calls.argsFor(1)[0]).toBe(
+      'Warning: NamedComponent 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.',
+    );
+  });
+
+  it('should warn when mispelling componentWillReceiveProps', () => {
+    spyOn(console, 'error');
+    createReactClass({
+      componentWillRecieveProps: function() {
+        return false;
+      },
+      render: function() {
+        return <div />;
+      },
+    });
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: A component has a method called componentWillRecieveProps(). Did you ' +
+        'mean componentWillReceiveProps()?',
+    );
+  });
+
+  it('should throw if a reserved property is in statics', () => {
+    expect(function() {
+      createReactClass({
+        statics: {
+          getDefaultProps: function() {
+            return {
+              foo: 0,
+            };
+          },
+        },
+
+        render: function() {
+          return <span />;
+        },
+      });
+    }).toThrowError(
+      'ReactClass: You are attempting to define a reserved property, ' +
+        '`getDefaultProps`, that shouldn\'t be on the "statics" key. Define ' +
+        'it as an instance property instead; it will still be accessible on ' +
+        'the constructor.',
+    );
+  });
+
+  // TODO: Consider actually moving these to statics or drop this unit test.
+
+  xit('should warn when using deprecated non-static spec keys', () => {
+    spyOn(console, 'error');
+    createReactClass({
+      mixins: [{}],
+      propTypes: {
+        foo: React.PropTypes.string,
+      },
+      contextTypes: {
+        foo: React.PropTypes.string,
+      },
+      childContextTypes: {
+        foo: React.PropTypes.string,
+      },
+      render: function() {
+        return <div />;
+      },
+    });
+    expect(console.error.calls.count()).toBe(4);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      'createClass(...): `mixins` is now a static property and should ' +
+        'be defined inside "statics".',
+    );
+    expect(console.error.calls.argsFor(1)[0]).toBe(
+      'createClass(...): `propTypes` is now a static property and should ' +
+        'be defined inside "statics".',
+    );
+    expect(console.error.calls.argsFor(2)[0]).toBe(
+      'createClass(...): `contextTypes` is now a static property and ' +
+        'should be defined inside "statics".',
+    );
+    expect(console.error.calls.argsFor(3)[0]).toBe(
+      'createClass(...): `childContextTypes` is now a static property and ' +
+        'should be defined inside "statics".',
+    );
+  });
+
+  it('should support statics', () => {
+    var Component = createReactClass({
+      statics: {
+        abc: 'def',
+        def: 0,
+        ghi: null,
+        jkl: 'mno',
+        pqr: function() {
+          return this;
+        },
+      },
+
+      render: function() {
+        return <span />;
+      },
+    });
+    var instance = <Component />;
+    instance = ReactTestUtils.renderIntoDocument(instance);
+    expect(instance.constructor.abc).toBe('def');
+    expect(Component.abc).toBe('def');
+    expect(instance.constructor.def).toBe(0);
+    expect(Component.def).toBe(0);
+    expect(instance.constructor.ghi).toBe(null);
+    expect(Component.ghi).toBe(null);
+    expect(instance.constructor.jkl).toBe('mno');
+    expect(Component.jkl).toBe('mno');
+    expect(instance.constructor.pqr()).toBe(Component);
+    expect(Component.pqr()).toBe(Component);
+  });
+
+  it('should work with object getInitialState() return values', () => {
+    var Component = createReactClass({
+      getInitialState: function() {
+        return {
+          occupation: 'clown',
+        };
+      },
+      render: function() {
+        return <span />;
+      },
+    });
+    var instance = <Component />;
+    instance = ReactTestUtils.renderIntoDocument(instance);
+    expect(instance.state.occupation).toEqual('clown');
+  });
+
+  it('renders based on context getInitialState', () => {
+    var Foo = createReactClass({
+      contextTypes: {
+        className: React.PropTypes.string,
+      },
+      getInitialState() {
+        return {className: this.context.className};
+      },
+      render() {
+        return <span className={this.state.className} />;
+      },
+    });
+
+    var Outer = createReactClass({
+      childContextTypes: {
+        className: React.PropTypes.string,
+      },
+      getChildContext() {
+        return {className: 'foo'};
+      },
+      render() {
+        return <Foo />;
+      },
+    });
+
+    var container = document.createElement('div');
+    ReactDOM.render(<Outer />, container);
+    expect(container.firstChild.className).toBe('foo');
+  });
+
+  it('should throw with non-object getInitialState() return values', () => {
+    [['an array'], 'a string', 1234].forEach(function(state) {
+      var Component = createReactClass({
+        getInitialState: function() {
+          return state;
+        },
+        render: function() {
+          return <span />;
+        },
+      });
+      var instance = <Component />;
+      expect(function() {
+        instance = ReactTestUtils.renderIntoDocument(instance);
+      }).toThrowError(
+        'Component.getInitialState(): must return an object or null',
+      );
+    });
+  });
+
+  it('should work with a null getInitialState() return value', () => {
+    var Component = createReactClass({
+      getInitialState: function() {
+        return null;
+      },
+      render: function() {
+        return <span />;
+      },
+    });
+    expect(() =>
+      ReactTestUtils.renderIntoDocument(<Component />),
+    ).not.toThrow();
+  });
+
+  it('should throw when using legacy factories', () => {
+    spyOn(console, 'error');
+    var Component = createReactClass({
+      render() {
+        return <div />;
+      },
+    });
+
+    expect(() => Component()).toThrow();
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: Something is calling a React component directly. Use a ' +
+        'factory or JSX instead. See: https://fb.me/react-legacyfactory',
+    );
+  });
+
+  it('replaceState and callback works', () => {
+    var ops = [];
+    var Component = createReactClass({
+      getInitialState() {
+        return {step: 0};
+      },
+      render() {
+        ops.push('Render: ' + this.state.step);
+        return <div />;
+      },
+    });
+
+    var instance = ReactTestUtils.renderIntoDocument(<Component />);
+    instance.replaceState({step: 1}, () => {
+      ops.push('Callback: ' + instance.state.step);
+    });
+    expect(ops).toEqual(['Render: 0', 'Render: 1', 'Callback: 1']);
+  });
+
+  it('isMounted works', () => {
+    spyOn(console, 'error');
+
+    var ops = [];
+    var instance;
+    var Component = createReactClass({
+      displayName: 'MyComponent',
+      log(name) {
+        ops.push(`${name}: ${this.isMounted()}`);
+      },
+      getInitialState() {
+        this.log('getInitialState');
+        return {};
+      },
+      componentWillMount() {
+        this.log('componentWillMount');
+      },
+      componentDidMount() {
+        this.log('componentDidMount');
+      },
+      componentWillUpdate() {
+        this.log('componentWillUpdate');
+      },
+      componentDidUpdate() {
+        this.log('componentDidUpdate');
+      },
+      componentWillUnmount() {
+        this.log('componentWillUnmount');
+      },
+      render() {
+        instance = this;
+        this.log('render');
+        return <div />;
+      },
+    });
+
+    var container = document.createElement('div');
+    ReactDOM.render(<Component />, container);
+    ReactDOM.render(<Component />, container);
+    ReactDOM.unmountComponentAtNode(container);
+    instance.log('after unmount');
+    expect(ops).toEqual([
+      'getInitialState: false',
+      'componentWillMount: false',
+      'render: false',
+      'componentDidMount: true',
+      'componentWillUpdate: true',
+      'render: true',
+      'componentDidUpdate: true',
+      'componentWillUnmount: false',
+      'after unmount: false',
+    ]);
+
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toEqual(
+      'Warning: MyComponent: isMounted is deprecated. Instead, make sure to ' +
+        'clean up subscriptions and pending requests in componentWillUnmount ' +
+        'to prevent memory leaks.',
+    );
+  });
+});
diff --git a/src/isomorphic/classic/class/createClass.js b/src/isomorphic/classic/class/createClass.js
new file mode 100644
index 000000000000..3791e5392dc0
--- /dev/null
+++ b/src/isomorphic/classic/class/createClass.js
@@ -0,0 +1,19 @@
+/**
+ * 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 createClass
+ */
+
+'use strict';
+
+var {Component} = require('ReactBaseClasses');
+var {isValidElement} = require('ReactElement');
+var ReactNoopUpdateQueue = require('ReactNoopUpdateQueue');
+var factory = require('create-react-class/factory');
+
+module.exports = factory(Component, isValidElement, ReactNoopUpdateQueue);
diff --git a/src/isomorphic/classic/element/ReactCurrentOwner.js b/src/isomorphic/classic/element/ReactCurrentOwner.js
index e47505f41322..a095fe009740 100644
--- a/src/isomorphic/classic/element/ReactCurrentOwner.js
+++ b/src/isomorphic/classic/element/ReactCurrentOwner.js
@@ -7,10 +7,13 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule ReactCurrentOwner
+ * @flow
  */
 
 'use strict';
 
+import type {ReactInstance} from 'ReactInstanceType';
+
 /**
  * Keeps track of the current owner.
  *
@@ -18,13 +21,11 @@
  * currently being constructed.
  */
 var ReactCurrentOwner = {
-
   /**
    * @internal
    * @type {ReactComponent}
    */
-  current: null,
-
+  current: (null: null | ReactInstance),
 };
 
 module.exports = ReactCurrentOwner;
diff --git a/src/isomorphic/classic/element/ReactDOMFactories.js b/src/isomorphic/classic/element/ReactDOMFactories.js
deleted file mode 100644
index 422aaae77a01..000000000000
--- a/src/isomorphic/classic/element/ReactDOMFactories.js
+++ /dev/null
@@ -1,176 +0,0 @@
-/**
- * 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 ReactDOMFactories
- */
-
-'use strict';
-
-var ReactElement = require('ReactElement');
-var ReactElementValidator = require('ReactElementValidator');
-
-var mapObject = require('mapObject');
-
-/**
- * Create a factory that creates HTML tag elements.
- *
- * @param {string} tag Tag name (e.g. `div`).
- * @private
- */
-function createDOMFactory(tag) {
-  if (__DEV__) {
-    return ReactElementValidator.createFactory(tag);
-  }
-  return ReactElement.createFactory(tag);
-}
-
-/**
- * Creates a mapping from supported HTML tags to `ReactDOMComponent` classes.
- * This is also accessible via `React.DOM`.
- *
- * @public
- */
-var ReactDOMFactories = mapObject({
-  a: 'a',
-  abbr: 'abbr',
-  address: 'address',
-  area: 'area',
-  article: 'article',
-  aside: 'aside',
-  audio: 'audio',
-  b: 'b',
-  base: 'base',
-  bdi: 'bdi',
-  bdo: 'bdo',
-  big: 'big',
-  blockquote: 'blockquote',
-  body: 'body',
-  br: 'br',
-  button: 'button',
-  canvas: 'canvas',
-  caption: 'caption',
-  cite: 'cite',
-  code: 'code',
-  col: 'col',
-  colgroup: 'colgroup',
-  data: 'data',
-  datalist: 'datalist',
-  dd: 'dd',
-  del: 'del',
-  details: 'details',
-  dfn: 'dfn',
-  dialog: 'dialog',
-  div: 'div',
-  dl: 'dl',
-  dt: 'dt',
-  em: 'em',
-  embed: 'embed',
-  fieldset: 'fieldset',
-  figcaption: 'figcaption',
-  figure: 'figure',
-  footer: 'footer',
-  form: 'form',
-  h1: 'h1',
-  h2: 'h2',
-  h3: 'h3',
-  h4: 'h4',
-  h5: 'h5',
-  h6: 'h6',
-  head: 'head',
-  header: 'header',
-  hgroup: 'hgroup',
-  hr: 'hr',
-  html: 'html',
-  i: 'i',
-  iframe: 'iframe',
-  img: 'img',
-  input: 'input',
-  ins: 'ins',
-  kbd: 'kbd',
-  keygen: 'keygen',
-  label: 'label',
-  legend: 'legend',
-  li: 'li',
-  link: 'link',
-  main: 'main',
-  map: 'map',
-  mark: 'mark',
-  menu: 'menu',
-  menuitem: 'menuitem',
-  meta: 'meta',
-  meter: 'meter',
-  nav: 'nav',
-  noscript: 'noscript',
-  object: 'object',
-  ol: 'ol',
-  optgroup: 'optgroup',
-  option: 'option',
-  output: 'output',
-  p: 'p',
-  param: 'param',
-  picture: 'picture',
-  pre: 'pre',
-  progress: 'progress',
-  q: 'q',
-  rp: 'rp',
-  rt: 'rt',
-  ruby: 'ruby',
-  s: 's',
-  samp: 'samp',
-  script: 'script',
-  section: 'section',
-  select: 'select',
-  small: 'small',
-  source: 'source',
-  span: 'span',
-  strong: 'strong',
-  style: 'style',
-  sub: 'sub',
-  summary: 'summary',
-  sup: 'sup',
-  table: 'table',
-  tbody: 'tbody',
-  td: 'td',
-  textarea: 'textarea',
-  tfoot: 'tfoot',
-  th: 'th',
-  thead: 'thead',
-  time: 'time',
-  title: 'title',
-  tr: 'tr',
-  track: 'track',
-  u: 'u',
-  ul: 'ul',
-  'var': 'var',
-  video: 'video',
-  wbr: 'wbr',
-
-  // SVG
-  circle: 'circle',
-  clipPath: 'clipPath',
-  defs: 'defs',
-  ellipse: 'ellipse',
-  g: 'g',
-  image: 'image',
-  line: 'line',
-  linearGradient: 'linearGradient',
-  mask: 'mask',
-  path: 'path',
-  pattern: 'pattern',
-  polygon: 'polygon',
-  polyline: 'polyline',
-  radialGradient: 'radialGradient',
-  rect: 'rect',
-  stop: 'stop',
-  svg: 'svg',
-  text: 'text',
-  tspan: 'tspan',
-
-}, createDOMFactory);
-
-module.exports = ReactDOMFactories;
diff --git a/src/isomorphic/classic/element/ReactElement.js b/src/isomorphic/classic/element/ReactElement.js
index ee46a5f392db..cb95c2c5f112 100644
--- a/src/isomorphic/classic/element/ReactElement.js
+++ b/src/isomorphic/classic/element/ReactElement.js
@@ -15,12 +15,9 @@ var ReactCurrentOwner = require('ReactCurrentOwner');
 
 var warning = require('warning');
 var canDefineProperty = require('canDefineProperty');
+var hasOwnProperty = Object.prototype.hasOwnProperty;
 
-// 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;
+var REACT_ELEMENT_TYPE = require('ReactElementSymbol');
 
 var RESERVED_PROPS = {
   key: true,
@@ -31,6 +28,56 @@ var RESERVED_PROPS = {
 
 var specialPropKeyWarningShown, specialPropRefWarningShown;
 
+function hasValidRef(config) {
+  return config.ref !== undefined;
+}
+
+function hasValidKey(config) {
+  return config.key !== undefined;
+}
+
+function defineKeyPropWarningGetter(props, displayName) {
+  var warnAboutAccessingKey = function() {
+    if (!specialPropKeyWarningShown) {
+      specialPropKeyWarningShown = 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,
+      );
+    }
+  };
+  warnAboutAccessingKey.isReactWarning = true;
+  Object.defineProperty(props, 'key', {
+    get: warnAboutAccessingKey,
+    configurable: true,
+  });
+}
+
+function defineRefPropWarningGetter(props, displayName) {
+  var warnAboutAccessingRef = function() {
+    if (!specialPropRefWarningShown) {
+      specialPropRefWarningShown = 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,
+      );
+    }
+  };
+  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
@@ -66,54 +113,19 @@ var ReactElement = function(type, key, ref, self, source, owner, props) {
     _owner: owner,
   };
 
-  if (__DEV__) {
-    // 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) {
+  // type对应的就是jsx中的标签，可能是div这样的html元素，也可能是一个reactElement
+  // config 对应的是标签上的属性
+  // 对应孩子节点，可能会有多个
   var propName;
 
   // Reserved names are extracted
@@ -125,21 +137,25 @@ ReactElement.createElement = function(type, config, children) {
   var source = null;
 
   if (config != null) {
-    if (__DEV__) {
-      ref = !config.hasOwnProperty('ref') ||
-        Object.getOwnPropertyDescriptor(config, 'ref').get ? null : config.ref;
-      key = !config.hasOwnProperty('key') ||
-        Object.getOwnPropertyDescriptor(config, 'key').get ? null : '' + config.key;
-    } else {
-      ref = config.ref === undefined ? null : config.ref;
-      key = config.key === undefined ? null : '' + config.key;
+    //如果config存在ref
+    if (hasValidRef(config)) {
+      //设置ref值等于config中的ref
+      ref = config.ref;
+    }
+    //同理设置key
+    if (hasValidKey(config)) {
+      //转为字符串
+      key = '' + config.key;
     }
+    //初始化self和source
     self = config.__self === undefined ? null : config.__self;
     source = config.__source === undefined ? null : config.__source;
-    // Remaining properties are added to a new props object
+    //将config中的除了key ref __self __source放入props中
     for (propName in config) {
-      if (config.hasOwnProperty(propName) &&
-          !RESERVED_PROPS.hasOwnProperty(propName)) {
+      if (
+        hasOwnProperty.call(config, propName) &&
+        !RESERVED_PROPS.hasOwnProperty(propName)
+      ) {
         props[propName] = config[propName];
       }
     }
@@ -147,6 +163,7 @@ ReactElement.createElement = function(type, config, children) {
 
   // Children can be more than one argument, and those are transferred onto
   // the newly allocated props object.
+  //设置props的children属性，children可能是一个对象/数组
   var childrenLength = arguments.length - 2;
   if (childrenLength === 1) {
     props.children = children;
@@ -159,6 +176,8 @@ ReactElement.createElement = function(type, config, children) {
   }
 
   // Resolve default props
+  // 设置defaultPorps，
+  //type可能是普通标签或者ReactElement,当是ReactElement时，会用其中的defaultProps覆盖对应config的props
   if (type && type.defaultProps) {
     var defaultProps = type.defaultProps;
     for (propName in defaultProps) {
@@ -167,62 +186,21 @@ ReactElement.createElement = function(type, config, children) {
       }
     }
   }
-  if (__DEV__) {
-    // Create dummy `key` and `ref` property to `props` to warn users
-    // against its use
-    if (typeof props.$$typeof === 'undefined' ||
-        props.$$typeof !== REACT_ELEMENT_TYPE) {
-      if (!props.hasOwnProperty('key')) {
-        Object.defineProperty(props, 'key', {
-          get: function() {
-            if (!specialPropKeyWarningShown) {
-              specialPropKeyWarningShown = 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)',
-                typeof type === 'function' && 'displayName' in type ? type.displayName : 'Element'
-              );
-            }
-            return undefined;
-          },
-          configurable: true,
-        });
-      }
-      if (!props.hasOwnProperty('ref')) {
-        Object.defineProperty(props, 'ref', {
-          get: function() {
-            if (!specialPropRefWarningShown) {
-              specialPropRefWarningShown = 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)',
-                typeof type === 'function' && 'displayName' in type ? type.displayName : 'Element'
-              );
-            }
-            return undefined;
-          },
-          configurable: true,
-        });
-      }
-    }
-  }
   return ReactElement(
     type,
     key,
     ref,
     self,
     source,
-    ReactCurrentOwner.current,
-    props
+    ReactCurrentOwner.current, //null
+    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
@@ -242,12 +220,16 @@ ReactElement.cloneAndReplaceKey = function(oldElement, newKey) {
     oldElement._self,
     oldElement._source,
     oldElement._owner,
-    oldElement.props
+    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;
 
@@ -268,22 +250,27 @@ ReactElement.cloneElement = function(element, config, children) {
   var owner = element._owner;
 
   if (config != null) {
-    if (config.ref !== undefined) {
+    // 如果config中存在ref
+    if (hasValidRef(config)) {
       // Silently steal the ref from the parent.
+
       ref = config.ref;
       owner = ReactCurrentOwner.current;
     }
-    if (config.key !== undefined) {
+    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 (config.hasOwnProperty(propName) &&
-          !RESERVED_PROPS.hasOwnProperty(propName)) {
+      if (
+        hasOwnProperty.call(config, propName) &&
+        !RESERVED_PROPS.hasOwnProperty(propName)
+      ) {
         if (config[propName] === undefined && defaultProps !== undefined) {
           // Resolve default props
           props[propName] = defaultProps[propName];
@@ -307,18 +294,12 @@ ReactElement.cloneElement = function(element, config, children) {
     props.children = childArray;
   }
 
-  return ReactElement(
-    element.type,
-    key,
-    ref,
-    self,
-    source,
-    owner,
-    props
-  );
+  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
diff --git a/src/isomorphic/classic/element/ReactElementType.js b/src/isomorphic/classic/element/ReactElementType.js
new file mode 100644
index 000000000000..a0d8427b19e0
--- /dev/null
+++ b/src/isomorphic/classic/element/ReactElementType.js
@@ -0,0 +1,37 @@
+/**
+ * Copyright 2016-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.
+ *
+ * @flow
+ * @providesModule ReactElementType
+ */
+
+'use strict';
+
+import type {ReactInstance} from 'ReactInstanceType';
+
+export type Source = {
+  fileName: string,
+  lineNumber: number,
+};
+
+export type ReactElement = {
+  $$typeof: any,
+  type: any,
+  key: any,
+  ref: any,
+  props: any,
+  _owner: ReactInstance,
+
+  // __DEV__
+  _store: {
+    validated: boolean,
+  },
+  _self: ReactElement,
+  _shadowChildren: any,
+  _source: Source,
+};
diff --git a/src/isomorphic/classic/element/ReactElementValidator.js b/src/isomorphic/classic/element/ReactElementValidator.js
index 2051a212e3b9..17f0332f8d2e 100644
--- a/src/isomorphic/classic/element/ReactElementValidator.js
+++ b/src/isomorphic/classic/element/ReactElementValidator.js
@@ -18,15 +18,16 @@
 
 'use strict';
 
-var ReactElement = require('ReactElement');
-var ReactPropTypeLocations = require('ReactPropTypeLocations');
-var ReactPropTypeLocationNames = require('ReactPropTypeLocationNames');
 var ReactCurrentOwner = require('ReactCurrentOwner');
+var ReactComponentTreeHook = require('ReactComponentTreeHook');
+var ReactElement = require('ReactElement');
+
+var checkReactTypeSpec = require('checkReactTypeSpec');
 
 var canDefineProperty = require('canDefineProperty');
 var getIteratorFn = require('getIteratorFn');
-var invariant = require('invariant');
 var warning = require('warning');
+var lowPriorityWarning = require('lowPriorityWarning');
 
 function getDeclarationErrorAddendum() {
   if (ReactCurrentOwner.current) {
@@ -38,6 +39,20 @@ function getDeclarationErrorAddendum() {
   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
@@ -45,13 +60,26 @@ function getDeclarationErrorAddendum() {
  */
 var ownerHasKeyUseWarning = {};
 
-var loggedTypeFailures = {};
+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.
+ * 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.
@@ -63,67 +91,36 @@ function validateExplicitKey(element, parentType) {
   }
   element._store.validated = true;
 
-  var addenda = getAddendaForKeyUse('uniqueKey', element, parentType);
-  if (addenda === null) {
-    // we already showed the warning
-    return;
-  }
-  warning(
-    false,
-    'Each child in an array or iterator should have a unique "key" prop.' +
-    '%s%s%s',
-    addenda.parentOrOwner || '',
-    addenda.childOwner || '',
-    addenda.url || ''
-  );
-}
-
-/**
- * Shared warning and monitoring code for the key warnings.
- *
- * @internal
- * @param {string} messageType A key used for de-duping warnings.
- * @param {ReactElement} element Component that requires a key.
- * @param {*} parentType element's parent's type.
- * @returns {?object} A set of addenda to use in the warning message, or null
- * if the warning has already been shown before (and shouldn't be shown again).
- */
-function getAddendaForKeyUse(messageType, element, parentType) {
-  var addendum = getDeclarationErrorAddendum();
-  if (!addendum) {
-    var parentName = typeof parentType === 'string' ?
-      parentType : parentType.displayName || parentType.name;
-    if (parentName) {
-      addendum = ` Check the top-level render call using <${parentName}>.`;
-    }
-  }
+  var memoizer =
+    ownerHasKeyUseWarning.uniqueKey || (ownerHasKeyUseWarning.uniqueKey = {});
 
-  var memoizer = ownerHasKeyUseWarning[messageType] || (
-    ownerHasKeyUseWarning[messageType] = {}
-  );
-  if (memoizer[addendum]) {
-    return null;
+  var currentComponentErrorInfo = getCurrentComponentErrorInfo(parentType);
+  if (memoizer[currentComponentErrorInfo]) {
+    return;
   }
-  memoizer[addendum] = true;
-
-  var addenda = {
-    parentOrOwner: addendum,
-    url: ' See https://fb.me/react-warning-keys for more information.',
-    childOwner: null,
-  };
+  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.
-  if (element &&
-      element._owner &&
-      element._owner !== ReactCurrentOwner.current) {
+  var childOwner = '';
+  if (
+    element &&
+    element._owner &&
+    element._owner !== ReactCurrentOwner.current
+  ) {
     // Give the component that originally created this child.
-    addenda.childOwner =
-      ` It was passed a child from ${element._owner.getName()}.`;
+    childOwner = ` It was passed a child from ${element._owner.getName()}.`;
   }
 
-  return addenda;
+  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),
+  );
 }
 
 /**
@@ -168,61 +165,6 @@ function validateChildKeys(node, parentType) {
   }
 }
 
-/**
- * Assert that the props are valid
- *
- * @param {string} componentName Name of the component for error messages.
- * @param {object} propTypes Map of prop name to a ReactPropType
- * @param {object} props
- * @param {string} location e.g. "prop", "context", "child context"
- * @private
- */
-function checkPropTypes(componentName, propTypes, props, location) {
-  for (var propName in propTypes) {
-    if (propTypes.hasOwnProperty(propName)) {
-      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 propTypes[propName] === 'function',
-          '%s: %s type `%s` is invalid; it must be a function, usually from ' +
-          'React.PropTypes.',
-          componentName || 'React class',
-          ReactPropTypeLocationNames[location],
-          propName
-        );
-        error = propTypes[propName](props, propName, componentName, location);
-      } 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',
-        ReactPropTypeLocationNames[location],
-        propName,
-        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 addendum = getDeclarationErrorAddendum();
-        warning(false, 'Failed propType: %s%s', error.message, addendum);
-      }
-    }
-  }
-}
-
 /**
  * Given an element, validate that its props follow the propTypes definition,
  * provided by the type.
@@ -236,35 +178,69 @@ function validatePropTypes(element) {
   }
   var name = componentClass.displayName || componentClass.name;
   if (componentClass.propTypes) {
-    checkPropTypes(
-      name,
+    checkReactTypeSpec(
       componentClass.propTypes,
       element.props,
-      ReactPropTypeLocations.prop
+      'prop',
+      name,
+      element,
+      null,
     );
   }
   if (typeof componentClass.getDefaultProps === 'function') {
     warning(
       componentClass.getDefaultProps.isReactClassApproved,
       'getDefaultProps is only used on classic React.createClass ' +
-      'definitions. Use a static property named `defaultProps` instead.'
+        'definitions. Use a static property named `defaultProps` instead.',
     );
   }
 }
 
 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.
-    warning(
-      validType,
-      'React.createElement: type should not be null, undefined, boolean, or ' +
-        'number. It should be a string (for DOM elements) or a ReactClass ' +
-        '(for composite components).%s',
-      getDeclarationErrorAddendum()
-    );
+    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);
+        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,
+        );
+        ReactComponentTreeHook.popNonStandardWarningStack();
+      }
+    }
 
     var element = ReactElement.createElement.apply(this, arguments);
 
@@ -291,37 +267,29 @@ var ReactElementValidator = {
   },
 
   createFactory: function(type) {
-    var validatedFactory = ReactElementValidator.createElement.bind(
-      null,
-      type
-    );
+    var validatedFactory = ReactElementValidator.createElement.bind(null, type);
     // Legacy hook TODO: Warn if this is accessed
     validatedFactory.type = type;
 
     if (__DEV__) {
       if (canDefineProperty) {
-        Object.defineProperty(
-          validatedFactory,
-          'type',
-          {
-            enumerable: false,
-            get: function() {
-              warning(
-                false,
-                'Factory.type is deprecated. Access the class directly ' +
-                'before passing it to createFactory.'
-              );
-              Object.defineProperty(this, 'type', {
-                value: type,
-              });
-              return type;
-            },
-          }
-        );
+        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;
   },
 
@@ -333,7 +301,6 @@ var ReactElementValidator = {
     validatePropTypes(newElement);
     return newElement;
   },
-
 };
 
 module.exports = ReactElementValidator;
diff --git a/src/isomorphic/classic/element/__tests__/ReactElement-test.js b/src/isomorphic/classic/element/__tests__/ReactElement-test.js
index 402c9b95edde..de83b4e9120b 100644
--- a/src/isomorphic/classic/element/__tests__/ReactElement-test.js
+++ b/src/isomorphic/classic/element/__tests__/ReactElement-test.js
@@ -15,11 +15,11 @@ var React;
 var ReactDOM;
 var ReactTestUtils;
 
-describe('ReactElement', function() {
+describe('ReactElement', () => {
   var ComponentClass;
   var originalSymbol;
 
-  beforeEach(function() {
+  beforeEach(() => {
     jest.resetModuleRegistry();
 
     // Delete the native Symbol if we have one to ensure we test the
@@ -32,41 +32,41 @@ describe('ReactElement', function() {
     ReactTestUtils = require('ReactTestUtils');
     // NOTE: We're explicitly not using JSX here. This is intended to test
     // classic JS without JSX.
-    ComponentClass = React.createClass({
-      render: function() {
+    ComponentClass = class extends React.Component {
+      render() {
         return React.createElement('div');
-      },
-    });
+      }
+    };
   });
 
-  afterEach(function() {
+  afterEach(() => {
     global.Symbol = originalSymbol;
   });
 
-  it('uses the fallback value when in an environment without Symbol', function() {
+  it('uses the fallback value when in an environment without Symbol', () => {
     expect(<div />.$$typeof).toBe(0xeac7);
   });
 
-  it('returns a complete element according to spec', function() {
+  it('returns a complete element according to spec', () => {
     var element = React.createFactory(ComponentClass)();
     expect(element.type).toBe(ComponentClass);
     expect(element.key).toBe(null);
     expect(element.ref).toBe(null);
-    var expectation = {};
-    Object.freeze(expectation);
-    expect(element.props).toEqual(expectation);
+    expect(Object.isFrozen(element)).toBe(true);
+    expect(Object.isFrozen(element.props)).toBe(true);
+    expect(element.props).toEqual({});
   });
 
-  it('should warn when `key` is being accessed', function() {
+  it('should warn when `key` is being accessed on composite element', () => {
     spyOn(console, 'error');
     var container = document.createElement('div');
-    var Child = React.createClass({
-      render: function() {
+    class Child extends React.Component {
+      render() {
         return <div> {this.props.key} </div>;
-      },
-    });
-    var Parent = React.createClass({
-      render: function() {
+      }
+    }
+    class Parent extends React.Component {
+      render() {
         return (
           <div>
             <Child key="0" />
@@ -74,63 +74,77 @@ describe('ReactElement', function() {
             <Child key="2" />
           </div>
         );
-      },
-    });
-    expect(console.error.calls.length).toBe(0);
+      }
+    }
+    expect(console.error.calls.count()).toBe(0);
     ReactDOM.render(<Parent />, container);
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
       'Child: `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)'
+        '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)',
+    );
+  });
+
+  it('should warn when `key` is being accessed on a host element', () => {
+    spyOn(console, 'error');
+    var element = <div key="3" />;
+    expect(console.error.calls.count()).toBe(0);
+    void element.props.key;
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'div: `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)',
     );
   });
 
-  it('should warn when `ref` is being accessed', function() {
+  it('should warn when `ref` is being accessed', () => {
     spyOn(console, 'error');
     var container = document.createElement('div');
-    var Child = React.createClass({
-      render: function() {
+    class Child extends React.Component {
+      render() {
         return <div> {this.props.ref} </div>;
-      },
-    });
-    var Parent = React.createClass({
-      render: function() {
+      }
+    }
+    class Parent extends React.Component {
+      render() {
         return (
           <div>
             <Child ref="childElement" />
           </div>
         );
-      },
-    });
-    expect(console.error.calls.length).toBe(0);
+      }
+    }
+    expect(console.error.calls.count()).toBe(0);
     ReactDOM.render(<Parent />, container);
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
       'Child: `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)'
+        '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)',
     );
   });
 
-  it('allows a string to be passed as the type', function() {
+  it('allows a string to be passed as the type', () => {
     var element = React.createFactory('div')();
     expect(element.type).toBe('div');
     expect(element.key).toBe(null);
     expect(element.ref).toBe(null);
-    var expectation = {};
-    Object.freeze(expectation);
-    expect(element.props).toEqual(expectation);
+    expect(Object.isFrozen(element)).toBe(true);
+    expect(Object.isFrozen(element.props)).toBe(true);
+    expect(element.props).toEqual({});
   });
 
-  it('returns an immutable element', function() {
+  it('returns an immutable element', () => {
     var element = React.createFactory(ComponentClass)();
-    expect(() => element.type = 'div').toThrow();
+    expect(() => (element.type = 'div')).toThrow();
   });
 
-  it('does not reuse the original config object', function() {
+  it('does not reuse the original config object', () => {
     var config = {foo: 1};
     var element = React.createFactory(ComponentClass)(config);
     expect(element.props.foo).toBe(1);
@@ -138,7 +152,13 @@ describe('ReactElement', function() {
     expect(element.props.foo).toBe(1);
   });
 
-  it('extracts key and ref from the config', function() {
+  it('does not fail if config has no prototype', () => {
+    var config = Object.create(null, {foo: {value: 1, enumerable: true}});
+    var element = React.createFactory(ComponentClass)(config);
+    expect(element.props.foo).toBe(1);
+  });
+
+  it('extracts key and ref from the config', () => {
     var element = React.createFactory(ComponentClass)({
       key: '12',
       ref: '34',
@@ -147,12 +167,48 @@ describe('ReactElement', function() {
     expect(element.type).toBe(ComponentClass);
     expect(element.key).toBe('12');
     expect(element.ref).toBe('34');
-    var expectation = {foo:'56'};
-    Object.freeze(expectation);
-    expect(element.props).toEqual(expectation);
+    expect(Object.isFrozen(element)).toBe(true);
+    expect(Object.isFrozen(element.props)).toBe(true);
+    expect(element.props).toEqual({foo: '56'});
   });
 
-  it('coerces the key to a string', function() {
+  it('extracts null key and ref', () => {
+    var element = React.createFactory(ComponentClass)({
+      key: null,
+      ref: null,
+      foo: '12',
+    });
+    expect(element.type).toBe(ComponentClass);
+    expect(element.key).toBe('null');
+    expect(element.ref).toBe(null);
+    expect(Object.isFrozen(element)).toBe(true);
+    expect(Object.isFrozen(element.props)).toBe(true);
+    expect(element.props).toEqual({foo: '12'});
+  });
+
+  it('ignores undefined key and ref', () => {
+    var props = {
+      foo: '56',
+      key: undefined,
+      ref: undefined,
+    };
+    var element = React.createFactory(ComponentClass)(props);
+    expect(element.type).toBe(ComponentClass);
+    expect(element.key).toBe(null);
+    expect(element.ref).toBe(null);
+    expect(Object.isFrozen(element)).toBe(true);
+    expect(Object.isFrozen(element.props)).toBe(true);
+    expect(element.props).toEqual({foo: '56'});
+  });
+
+  it('ignores key and ref warning getters', () => {
+    var elementA = React.createElement('div');
+    var elementB = React.createElement('div', elementA.props);
+    expect(elementB.key).toBe(null);
+    expect(elementB.ref).toBe(null);
+  });
+
+  it('coerces the key to a string', () => {
     var element = React.createFactory(ComponentClass)({
       key: 12,
       foo: '56',
@@ -160,135 +216,117 @@ describe('ReactElement', function() {
     expect(element.type).toBe(ComponentClass);
     expect(element.key).toBe('12');
     expect(element.ref).toBe(null);
-    var expectation = {foo:'56'};
-    Object.freeze(expectation);
-    expect(element.props).toEqual(expectation);
+    expect(Object.isFrozen(element)).toBe(true);
+    expect(Object.isFrozen(element.props)).toBe(true);
+    expect(element.props).toEqual({foo: '56'});
   });
 
-  it('preserves the owner on the element', function() {
+  it('preserves the owner on the element', () => {
     var Component = React.createFactory(ComponentClass);
     var element;
 
-    var Wrapper = React.createClass({
-      render: function() {
+    class Wrapper extends React.Component {
+      render() {
         element = Component();
         return element;
-      },
-    });
+      }
+    }
 
     var instance = ReactTestUtils.renderIntoDocument(
-      React.createElement(Wrapper)
+      React.createElement(Wrapper),
     );
 
     expect(element._owner.getPublicInstance()).toBe(instance);
   });
 
-  it('merges an additional argument onto the children prop', function() {
+  it('merges an additional argument onto the children prop', () => {
     spyOn(console, 'error');
     var a = 1;
-    var element = React.createFactory(ComponentClass)({
-      children: 'text',
-    }, a);
+    var element = React.createFactory(ComponentClass)(
+      {
+        children: 'text',
+      },
+      a,
+    );
     expect(element.props.children).toBe(a);
-    expect(console.error.argsForCall.length).toBe(0);
+    expect(console.error.calls.count()).toBe(0);
   });
 
-  it('does not override children if no rest args are provided', function() {
+  it('does not override children if no rest args are provided', () => {
     spyOn(console, 'error');
     var element = React.createFactory(ComponentClass)({
       children: 'text',
     });
     expect(element.props.children).toBe('text');
-    expect(console.error.argsForCall.length).toBe(0);
+    expect(console.error.calls.count()).toBe(0);
   });
 
-  it('overrides children if null is provided as an argument', function() {
+  it('overrides children if null is provided as an argument', () => {
     spyOn(console, 'error');
-    var element = React.createFactory(ComponentClass)({
-      children: 'text',
-    }, null);
+    var element = React.createFactory(ComponentClass)(
+      {
+        children: 'text',
+      },
+      null,
+    );
     expect(element.props.children).toBe(null);
-    expect(console.error.argsForCall.length).toBe(0);
+    expect(console.error.calls.count()).toBe(0);
   });
 
-  it('merges rest arguments onto the children prop in an array', function() {
+  it('merges rest arguments onto the children prop in an array', () => {
     spyOn(console, 'error');
     var a = 1;
     var b = 2;
     var c = 3;
     var element = React.createFactory(ComponentClass)(null, a, b, c);
     expect(element.props.children).toEqual([1, 2, 3]);
-    expect(console.error.argsForCall.length).toBe(0);
+    expect(console.error.calls.count()).toBe(0);
   });
 
   // NOTE: We're explicitly not using JSX here. This is intended to test
   // classic JS without JSX.
-  it('allows static methods to be called using the type property', function() {
+  it('allows static methods to be called using the type property', () => {
     spyOn(console, 'error');
 
-    var StaticMethodComponentClass = React.createClass({
-      statics: {
-        someStaticMethod: function() {
-          return 'someReturnValue';
-        },
-      },
-      getInitialState: function() {
-        return {valueToReturn: 'hi'};
-      },
-      render: function() {
+    class StaticMethodComponentClass extends React.Component {
+      render() {
         return React.createElement('div');
-      },
-    });
+      }
+    }
+    StaticMethodComponentClass.someStaticMethod = () => 'someReturnValue';
 
     var element = React.createElement(StaticMethodComponentClass);
     expect(element.type.someStaticMethod()).toBe('someReturnValue');
-    expect(console.error.argsForCall.length).toBe(0);
+    expect(console.error.calls.count()).toBe(0);
   });
 
   // NOTE: We're explicitly not using JSX here. This is intended to test
   // classic JS without JSX.
-  it('identifies valid elements', function() {
-    var Component = React.createClass({
-      render: function() {
+  it('identifies valid elements', () => {
+    class Component extends React.Component {
+      render() {
         return React.createElement('div');
-      },
-    });
+      }
+    }
 
-    expect(React.isValidElement(React.createElement('div')))
-      .toEqual(true);
-    expect(React.isValidElement(React.createElement(Component)))
-      .toEqual(true);
+    expect(React.isValidElement(React.createElement('div'))).toEqual(true);
+    expect(React.isValidElement(React.createElement(Component))).toEqual(true);
 
     expect(React.isValidElement(null)).toEqual(false);
     expect(React.isValidElement(true)).toEqual(false);
     expect(React.isValidElement({})).toEqual(false);
     expect(React.isValidElement('string')).toEqual(false);
-    expect(React.isValidElement(React.DOM.div)).toEqual(false);
+    expect(React.isValidElement(React.createFactory('div'))).toEqual(false);
     expect(React.isValidElement(Component)).toEqual(false);
-    expect(React.isValidElement({ type: 'div', props: {} })).toEqual(false);
+    expect(React.isValidElement({type: 'div', props: {}})).toEqual(false);
 
     var jsonElement = JSON.stringify(React.createElement('div'));
     expect(React.isValidElement(JSON.parse(jsonElement))).toBe(true);
   });
 
-  it('allows the use of PropTypes validators in statics', function() {
-    // TODO: This test was added to cover a special case where we proxied
-    // methods. However, we don't do that any more so this test can probably
-    // be removed. Leaving it in classic as a safety precaution.
-    var Component = React.createClass({
-      render: () => null,
-      statics: {
-        specialType: React.PropTypes.shape({monkey: React.PropTypes.any}),
-      },
-    });
-
-    expect(typeof Component.specialType).toBe('function');
-    expect(typeof Component.specialType.isRequired).toBe('function');
-  });
-
   // NOTE: We're explicitly not using JSX here. This is intended to test
   // classic JS without JSX.
-  it('is indistinguishable from a plain object', function() {
+  it('is indistinguishable from a plain object', () => {
     var element = React.createElement('div', {className: 'foo'});
     var object = {};
     expect(element.constructor).toBe(object.constructor);
@@ -296,20 +334,18 @@ describe('ReactElement', function() {
 
   // NOTE: We're explicitly not using JSX here. This is intended to test
   // classic JS without JSX.
-  it('should use default prop value when removing a prop', function() {
-    var Component = React.createClass({
-      getDefaultProps: function() {
-        return {fruit: 'persimmon'};
-      },
-      render: function() {
+  it('should use default prop value when removing a prop', () => {
+    class Component extends React.Component {
+      render() {
         return React.createElement('span');
-      },
-    });
+      }
+    }
+    Component.defaultProps = {fruit: 'persimmon'};
 
     var container = document.createElement('div');
     var instance = ReactDOM.render(
       React.createElement(Component, {fruit: 'mango'}),
-      container
+      container,
     );
     expect(instance.props.fruit).toBe('mango');
 
@@ -319,53 +355,28 @@ describe('ReactElement', function() {
 
   // NOTE: We're explicitly not using JSX here. This is intended to test
   // classic JS without JSX.
-  it('should normalize props with default values', function() {
-    var Component = React.createClass({
-      getDefaultProps: function() {
-        return {prop: 'testKey'};
-      },
-      render: function() {
+  it('should normalize props with default values', () => {
+    class Component extends React.Component {
+      render() {
         return React.createElement('span', null, this.props.prop);
-      },
-    });
+      }
+    }
+    Component.defaultProps = {prop: 'testKey'};
 
     var instance = ReactTestUtils.renderIntoDocument(
-      React.createElement(Component)
+      React.createElement(Component),
     );
     expect(instance.props.prop).toBe('testKey');
 
     var inst2 = ReactTestUtils.renderIntoDocument(
-      React.createElement(Component, {prop: null})
+      React.createElement(Component, {prop: null}),
     );
     expect(inst2.props.prop).toBe(null);
   });
 
-  it('should normalize props with default values in cloning', function() {
-    var Component = React.createClass({
-      getDefaultProps: function() {
-        return {prop: 'testKey'};
-      },
-      render: function() {
-        return <span />;
-      },
-    });
-
-    var instance = React.createElement(Component);
-    var clonedInstance = React.cloneElement(instance, {prop: undefined});
-    expect(clonedInstance.props.prop).toBe('testKey');
-    var clonedInstance2 = React.cloneElement(instance, {prop: null});
-    expect(clonedInstance2.props.prop).toBe(null);
-
-    var instance2 = React.createElement(Component, {prop: 'newTestKey'});
-    var cloneInstance3 = React.cloneElement(instance2, {prop: undefined});
-    expect(cloneInstance3.props.prop).toBe('testKey');
-    var cloneInstance4 = React.cloneElement(instance2, {});
-    expect(cloneInstance4.props.prop).toBe('newTestKey');
-  });
-
-  it('throws when changing a prop (in dev) after element creation', function() {
-    var Outer = React.createClass({
-      render: function() {
+  it('throws when changing a prop (in dev) after element creation', () => {
+    class Outer extends React.Component {
+      render() {
         var el = <div className="moo" />;
 
         expect(function() {
@@ -374,17 +385,16 @@ describe('ReactElement', function() {
         expect(el.props.className).toBe('moo');
 
         return el;
-      },
-    });
+      }
+    }
     var outer = ReactTestUtils.renderIntoDocument(<Outer color="orange" />);
     expect(ReactDOM.findDOMNode(outer).className).toBe('moo');
   });
 
-  it('throws when adding a prop (in dev) after element creation', function() {
+  it('throws when adding a prop (in dev) after element creation', () => {
     var container = document.createElement('div');
-    var Outer = React.createClass({
-      getDefaultProps: () => ({sound: 'meow'}),
-      render: function() {
+    class Outer extends React.Component {
+      render() {
         var el = <div>{this.props.sound}</div>;
 
         expect(function() {
@@ -394,28 +404,29 @@ describe('ReactElement', function() {
         expect(el.props.className).toBe(undefined);
 
         return el;
-      },
-    });
+      }
+    }
+    Outer.defaultProps = {sound: 'meow'};
     var outer = ReactDOM.render(<Outer />, container);
     expect(ReactDOM.findDOMNode(outer).textContent).toBe('meow');
     expect(ReactDOM.findDOMNode(outer).className).toBe('');
   });
 
-  it('does not warn for NaN props', function() {
+  it('does not warn for NaN props', () => {
     spyOn(console, 'error');
-    var Test = React.createClass({
-      render: function() {
+    class Test extends React.Component {
+      render() {
         return <div />;
-      },
-    });
+      }
+    }
     var test = ReactTestUtils.renderIntoDocument(<Test value={+undefined} />);
     expect(test.props.value).toBeNaN();
-    expect(console.error.argsForCall.length).toBe(0);
+    expect(console.error.calls.count()).toBe(0);
   });
 
   // NOTE: We're explicitly not using JSX here. This is intended to test
   // classic JS without JSX.
-  it('identifies elements, but not JSON, if Symbols are supported', function() {
+  it('identifies elements, but not JSON, if Symbols are supported', () => {
     // Rudimentary polyfill
     // Once all jest engines support Symbols natively we can swap this to test
     // WITH native Symbols by default.
@@ -435,35 +446,32 @@ describe('ReactElement', function() {
 
     React = require('React');
 
-    var Component = React.createClass({
-      render: function() {
+    class Component extends React.Component {
+      render() {
         return React.createElement('div');
-      },
-    });
+      }
+    }
 
-    expect(React.isValidElement(React.createElement('div')))
-      .toEqual(true);
-    expect(React.isValidElement(React.createElement(Component)))
-      .toEqual(true);
+    expect(React.isValidElement(React.createElement('div'))).toEqual(true);
+    expect(React.isValidElement(React.createElement(Component))).toEqual(true);
 
     expect(React.isValidElement(null)).toEqual(false);
     expect(React.isValidElement(true)).toEqual(false);
     expect(React.isValidElement({})).toEqual(false);
     expect(React.isValidElement('string')).toEqual(false);
-    expect(React.isValidElement(React.DOM.div)).toEqual(false);
+    expect(React.isValidElement(React.createFactory('div'))).toEqual(false);
     expect(React.isValidElement(Component)).toEqual(false);
-    expect(React.isValidElement({ type: 'div', props: {} })).toEqual(false);
+    expect(React.isValidElement({type: 'div', props: {}})).toEqual(false);
 
     var jsonElement = JSON.stringify(React.createElement('div'));
     expect(React.isValidElement(JSON.parse(jsonElement))).toBe(false);
   });
-
 });
 
-describe('comparing jsx vs .createFactory() vs .createElement()', function() {
+describe('comparing jsx vs .createFactory() vs .createElement()', () => {
   var Child;
 
-  beforeEach(function() {
+  beforeEach(() => {
     jest.resetModuleRegistry();
     React = require('React');
     ReactDOM = require('ReactDOM');
@@ -471,86 +479,115 @@ describe('comparing jsx vs .createFactory() vs .createElement()', function() {
     Child = jest.genMockFromModule('ReactElementTestChild');
   });
 
-
-  describe('when using jsx only', function() {
+  describe('when using jsx only', () => {
     var Parent, instance;
-    beforeEach(function() {
-      Parent = React.createClass({
-        render: function() {
+    beforeEach(() => {
+      Parent = class extends React.Component {
+        render() {
           return (
             <div>
               <Child ref="child" foo="foo value">children value</Child>
             </div>
           );
-        },
-      });
-      instance = ReactTestUtils.renderIntoDocument(<Parent/>);
+        }
+      };
+      instance = ReactTestUtils.renderIntoDocument(<Parent />);
     });
 
-    it('should scry children but cannot', function() {
-      var children = ReactTestUtils.scryRenderedComponentsWithType(instance, Child);
+    it('should scry children but cannot', () => {
+      var children = ReactTestUtils.scryRenderedComponentsWithType(
+        instance,
+        Child,
+      );
       expect(children.length).toBe(1);
     });
 
-    it('does not maintain refs', function() {
+    it('does not maintain refs', () => {
       expect(instance.refs.child).not.toBeUndefined();
     });
 
-    it('can capture Child instantiation calls', function() {
-      expect(Child.mock.calls[0][0]).toEqual({ foo: 'foo value', children: 'children value' });
+    it('can capture Child instantiation calls', () => {
+      expect(Child.mock.calls[0][0]).toEqual({
+        foo: 'foo value',
+        children: 'children value',
+      });
     });
   });
 
-  describe('when using parent that uses .createFactory()', function() {
+  describe('when using parent that uses .createFactory()', () => {
     var factory, instance;
-    beforeEach(function() {
+    beforeEach(() => {
       var childFactory = React.createFactory(Child);
-      var Parent = React.createClass({
-        render: function() {
-          return React.DOM.div({}, childFactory({ ref: 'child', foo: 'foo value' }, 'children value'));
-        },
-      });
+      class Parent extends React.Component {
+        render() {
+          return React.createElement(
+            'div',
+            {},
+            childFactory({ref: 'child', foo: 'foo value'}, 'children value'),
+          );
+        }
+      }
       factory = React.createFactory(Parent);
       instance = ReactTestUtils.renderIntoDocument(factory());
     });
 
-    it('can properly scry children', function() {
-      var children = ReactTestUtils.scryRenderedComponentsWithType(instance, Child);
+    it('can properly scry children', () => {
+      var children = ReactTestUtils.scryRenderedComponentsWithType(
+        instance,
+        Child,
+      );
       expect(children.length).toBe(1);
     });
 
-    it('does not maintain refs', function() {
+    it('does not maintain refs', () => {
       expect(instance.refs.child).not.toBeUndefined();
     });
 
-    it('can capture Child instantiation calls', function() {
-      expect(Child.mock.calls[0][0]).toEqual({ foo: 'foo value', children: 'children value' });
+    it('can capture Child instantiation calls', () => {
+      expect(Child.mock.calls[0][0]).toEqual({
+        foo: 'foo value',
+        children: 'children value',
+      });
     });
   });
 
-  describe('when using parent that uses .createElement()', function() {
+  describe('when using parent that uses .createElement()', () => {
     var factory, instance;
-    beforeEach(function() {
-      var Parent = React.createClass({
-        render: function() {
-          return React.DOM.div({}, React.createElement(Child, { ref: 'child', foo: 'foo value' }, 'children value'));
-        },
-      });
+    beforeEach(() => {
+      class Parent extends React.Component {
+        render() {
+          return React.createElement(
+            'div',
+            {},
+            React.createElement(
+              Child,
+              {ref: 'child', foo: 'foo value'},
+              'children value',
+            ),
+          );
+        }
+      }
       factory = React.createFactory(Parent);
       instance = ReactTestUtils.renderIntoDocument(factory());
     });
 
-    it('should scry children but cannot', function() {
-      var children = ReactTestUtils.scryRenderedComponentsWithType(instance, Child);
+    it('should scry children but cannot', () => {
+      var children = ReactTestUtils.scryRenderedComponentsWithType(
+        instance,
+        Child,
+      );
       expect(children.length).toBe(1);
     });
 
-    it('does not maintain refs', function() {
+    it('does not maintain refs', () => {
       expect(instance.refs.child).not.toBeUndefined();
     });
 
-    it('can capture Child instantiation calls', function() {
-      expect(Child.mock.calls[0][0]).toEqual({ foo: 'foo value', children: 'children value' });
+    it('can capture Child instantiation calls', () => {
+      expect(Child.mock.calls[0][0]).toEqual({
+        foo: 'foo value',
+        children: 'children value',
+      });
     });
   });
 });
diff --git a/src/isomorphic/classic/element/__tests__/ReactElementClone-test.js b/src/isomorphic/classic/element/__tests__/ReactElementClone-test.js
index f4c5b4b761bd..a29bdff98174 100644
--- a/src/isomorphic/classic/element/__tests__/ReactElementClone-test.js
+++ b/src/isomorphic/classic/element/__tests__/ReactElementClone-test.js
@@ -11,256 +11,360 @@
 
 'use strict';
 
+var PropTypes;
 var React;
 var ReactDOM;
 var ReactTestUtils;
 
-describe('ReactElementClone', function() {
+describe('ReactElementClone', () => {
+  var ComponentClass;
 
-  beforeEach(function() {
+  beforeEach(() => {
     React = require('React');
     ReactDOM = require('ReactDOM');
     ReactTestUtils = require('ReactTestUtils');
+    PropTypes = require('prop-types');
+
+    // NOTE: We're explicitly not using JSX here. This is intended to test
+    // classic JS without JSX.
+    ComponentClass = class extends React.Component {
+      render() {
+        return React.createElement('div');
+      }
+    };
   });
 
-  it('should clone a DOM component with new props', function() {
-    var Grandparent = React.createClass({
-      render: function() {
+  it('should clone a DOM component with new props', () => {
+    class Grandparent extends React.Component {
+      render() {
         return <Parent child={<div className="child" />} />;
-      },
-    });
-    var Parent = React.createClass({
-      render: function() {
+      }
+    }
+    class Parent extends React.Component {
+      render() {
         return (
           <div className="parent">
-            {React.cloneElement(this.props.child, { className: 'xyz' })}
+            {React.cloneElement(this.props.child, {className: 'xyz'})}
           </div>
         );
-      },
-    });
+      }
+    }
     var component = ReactTestUtils.renderIntoDocument(<Grandparent />);
     expect(ReactDOM.findDOMNode(component).childNodes[0].className).toBe('xyz');
   });
 
-  it('should clone a composite component with new props', function() {
-    var Child = React.createClass({
-      render: function() {
+  it('should clone a composite component with new props', () => {
+    class Child extends React.Component {
+      render() {
         return <div className={this.props.className} />;
-      },
-    });
-    var Grandparent = React.createClass({
-      render: function() {
+      }
+    }
+    class Grandparent extends React.Component {
+      render() {
         return <Parent child={<Child className="child" />} />;
-      },
-    });
-    var Parent = React.createClass({
-      render: function() {
+      }
+    }
+    class Parent extends React.Component {
+      render() {
         return (
           <div className="parent">
-            {React.cloneElement(this.props.child, { className: 'xyz' })}
+            {React.cloneElement(this.props.child, {className: 'xyz'})}
           </div>
         );
-      },
-    });
+      }
+    }
     var component = ReactTestUtils.renderIntoDocument(<Grandparent />);
     expect(ReactDOM.findDOMNode(component).childNodes[0].className).toBe('xyz');
   });
 
-  it('should keep the original ref if it is not overridden', function() {
-    var Grandparent = React.createClass({
-      render: function() {
+  it('does not fail if config has no prototype', () => {
+    var config = Object.create(null, {foo: {value: 1, enumerable: true}});
+    React.cloneElement(<div />, config);
+  });
+
+  it('should keep the original ref if it is not overridden', () => {
+    class Grandparent extends React.Component {
+      render() {
         return <Parent child={<div ref="yolo" />} />;
-      },
-    });
+      }
+    }
 
-    var Parent = React.createClass({
-      render: function() {
+    class Parent extends React.Component {
+      render() {
         return (
           <div>
-            {React.cloneElement(this.props.child, { className: 'xyz' })}
+            {React.cloneElement(this.props.child, {className: 'xyz'})}
           </div>
         );
-      },
-    });
+      }
+    }
 
     var component = ReactTestUtils.renderIntoDocument(<Grandparent />);
     expect(component.refs.yolo.tagName).toBe('DIV');
   });
 
-  it('should transfer the key property', function() {
-    var Component = React.createClass({
-      render: function() {
+  it('should transfer the key property', () => {
+    class Component extends React.Component {
+      render() {
         return null;
-      },
-    });
+      }
+    }
     var clone = React.cloneElement(<Component />, {key: 'xyz'});
     expect(clone.key).toBe('xyz');
   });
 
-  it('should transfer children', function() {
-    var Component = React.createClass({
-      render: function() {
+  it('should transfer children', () => {
+    class Component extends React.Component {
+      render() {
         expect(this.props.children).toBe('xyz');
         return <div />;
-      },
-    });
+      }
+    }
 
     ReactTestUtils.renderIntoDocument(
-      React.cloneElement(<Component />, {children: 'xyz'})
+      React.cloneElement(<Component />, {children: 'xyz'}),
     );
   });
 
-  it('should shallow clone children', function() {
-    var Component = React.createClass({
-      render: function() {
+  it('should shallow clone children', () => {
+    class Component extends React.Component {
+      render() {
         expect(this.props.children).toBe('xyz');
         return <div />;
-      },
-    });
+      }
+    }
 
     ReactTestUtils.renderIntoDocument(
-      React.cloneElement(<Component>xyz</Component>, {})
+      React.cloneElement(<Component>xyz</Component>, {}),
     );
   });
 
-  it('should accept children as rest arguments', function() {
-    var Component = React.createClass({
-      render: function() {
+  it('should accept children as rest arguments', () => {
+    class Component extends React.Component {
+      render() {
         return null;
-      },
-    });
+      }
+    }
 
     var clone = React.cloneElement(
       <Component>xyz</Component>,
-      { children: <Component /> },
+      {children: <Component />},
       <div />,
-      <span />
+      <span />,
     );
 
-    expect(clone.props.children).toEqual([
-      <div />,
-      <span />,
-    ]);
+    expect(clone.props.children).toEqual([<div />, <span />]);
   });
 
-  it('should support keys and refs', function() {
-    var Parent = React.createClass({
-      render: function() {
-        var clone =
-          React.cloneElement(this.props.children, {key: 'xyz', ref: 'xyz'});
+  it('should override children if undefined is provided as an argument', () => {
+    var element = React.createElement(
+      ComponentClass,
+      {
+        children: 'text',
+      },
+      undefined,
+    );
+    expect(element.props.children).toBe(undefined);
+
+    var element2 = React.cloneElement(
+      React.createElement(ComponentClass, {
+        children: 'text',
+      }),
+      {},
+      undefined,
+    );
+    expect(element2.props.children).toBe(undefined);
+  });
+
+  it('should support keys and refs', () => {
+    class Parent extends React.Component {
+      render() {
+        var clone = React.cloneElement(this.props.children, {
+          key: 'xyz',
+          ref: 'xyz',
+        });
         expect(clone.key).toBe('xyz');
         expect(clone.ref).toBe('xyz');
         return <div>{clone}</div>;
-      },
-    });
+      }
+    }
 
-    var Grandparent = React.createClass({
-      render: function() {
+    class Grandparent extends React.Component {
+      render() {
         return <Parent ref="parent"><span key="abc" /></Parent>;
-      },
-    });
+      }
+    }
 
     var component = ReactTestUtils.renderIntoDocument(<Grandparent />);
     expect(component.refs.parent.refs.xyz.tagName).toBe('SPAN');
   });
 
-  it('should steal the ref if a new ref is specified', function() {
-    var Parent = React.createClass({
-      render: function() {
+  it('should steal the ref if a new ref is specified', () => {
+    class Parent extends React.Component {
+      render() {
         var clone = React.cloneElement(this.props.children, {ref: 'xyz'});
         return <div>{clone}</div>;
-      },
-    });
+      }
+    }
 
-    var Grandparent = React.createClass({
-      render: function() {
+    class Grandparent extends React.Component {
+      render() {
         return <Parent ref="parent"><span ref="child" /></Parent>;
-      },
-    });
+      }
+    }
 
     var component = ReactTestUtils.renderIntoDocument(<Grandparent />);
     expect(component.refs.child).toBeUndefined();
     expect(component.refs.parent.refs.xyz.tagName).toBe('SPAN');
   });
 
-  it('should overwrite props', function() {
-    var Component = React.createClass({
-      render: function() {
+  it('should overwrite props', () => {
+    class Component extends React.Component {
+      render() {
         expect(this.props.myprop).toBe('xyz');
         return <div />;
-      },
-    });
+      }
+    }
 
     ReactTestUtils.renderIntoDocument(
-      React.cloneElement(<Component myprop="abc" />, {myprop: 'xyz'})
+      React.cloneElement(<Component myprop="abc" />, {myprop: 'xyz'}),
     );
   });
 
-  it('warns for keys for arrays of elements in rest args', function() {
+  it('should normalize props with default values', () => {
+    class Component extends React.Component {
+      render() {
+        return <span />;
+      }
+    }
+    Component.defaultProps = {prop: 'testKey'};
+
+    var instance = React.createElement(Component);
+    var clonedInstance = React.cloneElement(instance, {prop: undefined});
+    expect(clonedInstance.props.prop).toBe('testKey');
+    var clonedInstance2 = React.cloneElement(instance, {prop: null});
+    expect(clonedInstance2.props.prop).toBe(null);
+
+    var instance2 = React.createElement(Component, {prop: 'newTestKey'});
+    var cloneInstance3 = React.cloneElement(instance2, {prop: undefined});
+    expect(cloneInstance3.props.prop).toBe('testKey');
+    var cloneInstance4 = React.cloneElement(instance2, {});
+    expect(cloneInstance4.props.prop).toBe('newTestKey');
+  });
+
+  it('warns for keys for arrays of elements in rest args', () => {
     spyOn(console, 'error');
 
     React.cloneElement(<div />, null, [<div />, <div />]);
 
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
-      'Each child in an array or iterator should have a unique "key" prop.'
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'Each child in an array or iterator should have a unique "key" prop.',
     );
   });
 
-  it('does not warns for arrays of elements with keys', function() {
+  it('does not warns for arrays of elements with keys', () => {
     spyOn(console, 'error');
 
     React.cloneElement(<div />, null, [<div key="#1" />, <div key="#2" />]);
 
-    expect(console.error.argsForCall.length).toBe(0);
+    expect(console.error.calls.count()).toBe(0);
   });
 
-  it('does not warn when the element is directly in rest args', function() {
+  it('does not warn when the element is directly in rest args', () => {
     spyOn(console, 'error');
 
     React.cloneElement(<div />, null, <div />, <div />);
 
-    expect(console.error.argsForCall.length).toBe(0);
+    expect(console.error.calls.count()).toBe(0);
   });
 
-  it('does not warn when the array contains a non-element', function() {
+  it('does not warn when the array contains a non-element', () => {
     spyOn(console, 'error');
 
     React.cloneElement(<div />, null, [{}, {}]);
 
-    expect(console.error.argsForCall.length).toBe(0);
+    expect(console.error.calls.count()).toBe(0);
   });
 
-  it('should check declared prop types after clone', function() {
+  it('should check declared prop types after clone', () => {
     spyOn(console, 'error');
-    var Component = React.createClass({
-      propTypes: {
-        color: React.PropTypes.string.isRequired,
-      },
-      render: function() {
+    class Component extends React.Component {
+      render() {
         return React.createElement('div', null, 'My color is ' + this.color);
-      },
-    });
-    var Parent = React.createClass({
-      render: function() {
+      }
+    }
+    Component.propTypes = {
+      color: PropTypes.string.isRequired,
+    };
+    class Parent extends React.Component {
+      render() {
         return React.cloneElement(this.props.child, {color: 123});
-      },
-    });
-    var GrandParent = React.createClass({
-      render: function() {
-        return React.createElement(
-          Parent,
-          { child: React.createElement(Component, {color: 'red'}) }
-        );
-      },
-    });
+      }
+    }
+    class GrandParent extends React.Component {
+      render() {
+        return React.createElement(Parent, {
+          child: React.createElement(Component, {color: 'red'}),
+        });
+      }
+    }
     ReactTestUtils.renderIntoDocument(React.createElement(GrandParent));
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: Failed propType: ' +
-      'Invalid prop `color` of type `number` supplied to `Component`, ' +
-      'expected `string`. Check the render method of `Parent`.'
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: Failed prop type: ' +
+        'Invalid prop `color` of type `number` supplied to `Component`, ' +
+        'expected `string`.\n' +
+        '    in Component (created by GrandParent)\n' +
+        '    in Parent (created by GrandParent)\n' +
+        '    in GrandParent',
     );
   });
 
+  it('should ignore key and ref warning getters', () => {
+    var elementA = React.createElement('div');
+    var elementB = React.cloneElement(elementA, elementA.props);
+    expect(elementB.key).toBe(null);
+    expect(elementB.ref).toBe(null);
+  });
+
+  it('should ignore undefined key and ref', () => {
+    var element = React.createFactory(ComponentClass)({
+      key: '12',
+      ref: '34',
+      foo: '56',
+    });
+    var props = {
+      key: undefined,
+      ref: undefined,
+      foo: 'ef',
+    };
+    var clone = React.cloneElement(element, props);
+    expect(clone.type).toBe(ComponentClass);
+    expect(clone.key).toBe('12');
+    expect(clone.ref).toBe('34');
+    expect(Object.isFrozen(element)).toBe(true);
+    expect(Object.isFrozen(element.props)).toBe(true);
+    expect(clone.props).toEqual({foo: 'ef'});
+  });
+
+  it('should extract null key and ref', () => {
+    var element = React.createFactory(ComponentClass)({
+      key: '12',
+      ref: '34',
+      foo: '56',
+    });
+    var props = {
+      key: null,
+      ref: null,
+      foo: 'ef',
+    };
+    var clone = React.cloneElement(element, props);
+    expect(clone.type).toBe(ComponentClass);
+    expect(clone.key).toBe('null');
+    expect(clone.ref).toBe(null);
+    expect(Object.isFrozen(element)).toBe(true);
+    expect(Object.isFrozen(element.props)).toBe(true);
+    expect(clone.props).toEqual({foo: 'ef'});
+  });
 });
diff --git a/src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js b/src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js
index 3cdcd48e5bb9..a772395aa6a2 100644
--- a/src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js
+++ b/src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js
@@ -14,135 +14,158 @@
 // NOTE: We're explicitly not using JSX in this file. This is intended to test
 // classic JS without JSX.
 
+var PropTypes;
 var React;
 var ReactDOM;
 var ReactTestUtils;
 
-describe('ReactElementValidator', function() {
+describe('ReactElementValidator', () => {
+  function normalizeCodeLocInfo(str) {
+    return str && str.replace(/at .+?:\d+/g, 'at **');
+  }
+
   var ComponentClass;
 
-  beforeEach(function() {
+  beforeEach(() => {
     jest.resetModuleRegistry();
 
     React = require('React');
     ReactDOM = require('ReactDOM');
     ReactTestUtils = require('ReactTestUtils');
-    ComponentClass = React.createClass({
-      render: function() {
+    PropTypes = require('prop-types');
+    ComponentClass = class extends React.Component {
+      render() {
         return React.createElement('div');
-      },
-    });
+      }
+    };
   });
 
-  it('warns for keys for arrays of elements in rest args', function() {
+  it('warns for keys for arrays of elements in rest args', () => {
     spyOn(console, 'error');
     var Component = React.createFactory(ComponentClass);
 
     Component(null, [Component(), Component()]);
 
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
-      'Each child in an array or iterator should have a unique "key" prop.'
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'Each child in an array or iterator should have a unique "key" prop.',
     );
   });
 
-  it('warns for keys for arrays of elements with owner info', function() {
+  it('warns for keys for arrays of elements with owner info', () => {
     spyOn(console, 'error');
     var Component = React.createFactory(ComponentClass);
 
-    var InnerClass = React.createClass({
-      displayName: 'InnerClass',
-      render: function() {
+    class InnerClass extends React.Component {
+      render() {
         return Component(null, this.props.childSet);
-      },
-    });
+      }
+    }
 
     var InnerComponent = React.createFactory(InnerClass);
 
-    var ComponentWrapper = React.createClass({
-      displayName: 'ComponentWrapper',
-      render: function() {
-        return InnerComponent({childSet: [Component(), Component()] });
-      },
-    });
+    class ComponentWrapper extends React.Component {
+      render() {
+        return InnerComponent({childSet: [Component(), Component()]});
+      }
+    }
 
-    ReactTestUtils.renderIntoDocument(
-      React.createElement(ComponentWrapper)
-    );
+    ReactTestUtils.renderIntoDocument(React.createElement(ComponentWrapper));
 
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
       'Each child in an array or iterator should have a unique "key" prop. ' +
-      'Check the render method of `InnerClass`. ' +
-      'It was passed a child from ComponentWrapper. '
+        'Check the render method of `InnerClass`. ' +
+        'It was passed a child from ComponentWrapper. ',
     );
   });
 
-  it('warns for keys for arrays with no owner or parent info', function() {
+  it('warns for keys for arrays with no owner or parent info', () => {
     spyOn(console, 'error');
 
-    var Anonymous = React.createClass({
-      displayName: undefined,
-      render: function() {
-        return <div />;
-      },
-    });
+    function Anonymous() {
+      return <div />;
+    }
+    Object.defineProperty(Anonymous, 'name', {value: undefined});
 
-    var divs = [
-      <div />,
-      <div />,
-    ];
+    var divs = [<div />, <div />];
     ReactTestUtils.renderIntoDocument(<Anonymous>{divs}</Anonymous>);
 
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
+    expect(console.error.calls.count()).toBe(1);
+    expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
       'Warning: Each child in an array or iterator should have a unique ' +
-      '"key" prop. See https://fb.me/react-warning-keys for more information.'
+        '"key" prop. See https://fb.me/react-warning-keys for more information.\n' +
+        '    in div (at **)',
     );
   });
 
-  it('warns for keys for arrays of elements with no owner info', function() {
+  it('warns for keys for arrays of elements with no owner info', () => {
     spyOn(console, 'error');
 
-    var divs = [
-      <div />,
-      <div />,
-    ];
+    var divs = [<div />, <div />];
     ReactTestUtils.renderIntoDocument(<div>{divs}</div>);
 
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
+    expect(console.error.calls.count()).toBe(1);
+    expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
       'Warning: Each child in an array or iterator should have a unique ' +
-      '"key" prop. Check the top-level render call using <div>. See ' +
-      'https://fb.me/react-warning-keys for more information.'
+        '"key" prop. Check the top-level render call using <div>. See ' +
+        'https://fb.me/react-warning-keys for more information.\n' +
+        '    in div (at **)',
     );
   });
 
-  it('does not warn for keys when passing children down', function() {
+  it('warns for keys with component stack info', () => {
     spyOn(console, 'error');
 
-    var Wrapper = React.createClass({
-      render: function() {
-        return (
-          <div>
-            {this.props.children}
-            <footer />
-          </div>
-        );
-      },
-    });
+    function Component() {
+      return <div>{[<div />, <div />]}</div>;
+    }
+
+    function Parent(props) {
+      return React.cloneElement(props.child);
+    }
+
+    function GrandParent() {
+      return <Parent child={<Component />} />;
+    }
+
+    ReactTestUtils.renderIntoDocument(<GrandParent />);
+
+    expect(console.error.calls.count()).toBe(1);
+    expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
+      'Warning: Each child in an array or iterator should have a unique ' +
+        '"key" prop. Check the render method of `Component`. See ' +
+        'https://fb.me/react-warning-keys for more information.\n' +
+        '    in div (at **)\n' +
+        '    in Component (at **)\n' +
+        '    in Parent (at **)\n' +
+        '    in GrandParent (at **)',
+    );
+  });
+
+  it('does not warn for keys when passing children down', () => {
+    spyOn(console, 'error');
+
+    function Wrapper(props) {
+      return (
+        <div>
+          {props.children}
+          <footer />
+        </div>
+      );
+    }
 
     ReactTestUtils.renderIntoDocument(
       <Wrapper>
         <span />
         <span />
-      </Wrapper>
+      </Wrapper>,
     );
 
-    expect(console.error.argsForCall.length).toBe(0);
+    expect(console.error.calls.count()).toBe(0);
   });
 
-  it('warns for keys for iterables of elements in rest args', function() {
+  it('warns for keys for iterables of elements in rest args', () => {
     spyOn(console, 'error');
     var Component = React.createFactory(ComponentClass);
 
@@ -160,22 +183,22 @@ describe('ReactElementValidator', function() {
 
     Component(null, iterable);
 
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
-      'Each child in an array or iterator should have a unique "key" prop.'
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'Each child in an array or iterator should have a unique "key" prop.',
     );
   });
 
-  it('does not warns for arrays of elements with keys', function() {
+  it('does not warns for arrays of elements with keys', () => {
     spyOn(console, 'error');
     var Component = React.createFactory(ComponentClass);
 
     Component(null, [Component({key: '#1'}), Component({key: '#2'})]);
 
-    expect(console.error.argsForCall.length).toBe(0);
+    expect(console.error.calls.count()).toBe(0);
   });
 
-  it('does not warns for iterable elements with keys', function() {
+  it('does not warns for iterable elements with keys', () => {
     spyOn(console, 'error');
     var Component = React.createFactory(ComponentClass);
 
@@ -196,25 +219,25 @@ describe('ReactElementValidator', function() {
 
     Component(null, iterable);
 
-    expect(console.error.argsForCall.length).toBe(0);
+    expect(console.error.calls.count()).toBe(0);
   });
 
-  it('does not warn when the element is directly in rest args', function() {
+  it('does not warn when the element is directly in rest args', () => {
     spyOn(console, 'error');
     var Component = React.createFactory(ComponentClass);
 
     Component(null, Component(), Component());
 
-    expect(console.error.argsForCall.length).toBe(0);
+    expect(console.error.calls.count()).toBe(0);
   });
 
-  it('does not warn when the array contains a non-element', function() {
+  it('does not warn when the array contains a non-element', () => {
     spyOn(console, 'error');
     var Component = React.createFactory(ComponentClass);
 
     Component(null, [{}, {}]);
 
-    expect(console.error.argsForCall.length).toBe(0);
+    expect(console.error.calls.count()).toBe(0);
   });
 
   // TODO: These warnings currently come from the composite component, but
@@ -225,229 +248,236 @@ describe('ReactElementValidator', function() {
     // component, we give a small hint as to which parent instantiated that
     // component as per warnings about key usage in ReactElementValidator.
     spyOn(console, 'error');
-    var MyComp = React.createClass({
-      propTypes: {
-        color: React.PropTypes.string,
-      },
-      render: function() {
-        return React.createElement('div', null, 'My color is ' + this.color);
-      },
-    });
-    var ParentComp = React.createClass({
-      render: function() {
-        return React.createElement(MyComp, {color: 123});
-      },
-    });
+    function MyComp(props) {
+      return React.createElement('div', null, 'My color is ' + props.color);
+    }
+    MyComp.propTypes = {
+      color: PropTypes.string,
+    };
+    function ParentComp() {
+      return React.createElement(MyComp, {color: 123});
+    }
     ReactTestUtils.renderIntoDocument(React.createElement(ParentComp));
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: Failed propType: ' +
-      'Invalid prop `color` of type `number` supplied to `MyComp`, ' +
-      'expected `string`. Check the render method of `ParentComp`.'
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: Failed prop type: ' +
+        'Invalid prop `color` of type `number` supplied to `MyComp`, ' +
+        'expected `string`.\n' +
+        '    in MyComp (created by ParentComp)\n' +
+        '    in ParentComp',
     );
   });
 
-  it('gives a helpful error when passing null, undefined, boolean, or number', function() {
+  it('gives a helpful error when passing invalid types', () => {
     spyOn(console, 'error');
     React.createElement(undefined);
     React.createElement(null);
     React.createElement(true);
     React.createElement(123);
-    expect(console.error.calls.length).toBe(4);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: React.createElement: type should not be null, undefined, ' +
-      'boolean, or number. It should be a string (for DOM elements) or a ' +
-      'ReactClass (for composite components).'
+    React.createElement({x: 17});
+    React.createElement({});
+    expect(console.error.calls.count()).toBe(6);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: React.createElement: type is invalid -- expected a string ' +
+        '(for built-in components) or a class/function (for composite ' +
+        'components) but got: undefined. You likely forgot to export your ' +
+        "component from the file it's defined in.",
+    );
+    expect(console.error.calls.argsFor(1)[0]).toBe(
+      'Warning: React.createElement: type is invalid -- expected a string ' +
+        '(for built-in components) or a class/function (for composite ' +
+        'components) but got: null.',
+    );
+    expect(console.error.calls.argsFor(2)[0]).toBe(
+      'Warning: React.createElement: type is invalid -- expected a string ' +
+        '(for built-in components) or a class/function (for composite ' +
+        'components) but got: boolean.',
     );
-    expect(console.error.argsForCall[1][0]).toBe(
-      'Warning: React.createElement: type should not be null, undefined, ' +
-      'boolean, or number. It should be a string (for DOM elements) or a ' +
-      'ReactClass (for composite components).'
+    expect(console.error.calls.argsFor(3)[0]).toBe(
+      'Warning: React.createElement: type is invalid -- expected a string ' +
+        '(for built-in components) or a class/function (for composite ' +
+        'components) but got: number.',
     );
-    expect(console.error.argsForCall[2][0]).toBe(
-      'Warning: React.createElement: type should not be null, undefined, ' +
-      'boolean, or number. It should be a string (for DOM elements) or a ' +
-      'ReactClass (for composite components).'
+    expect(console.error.calls.argsFor(4)[0]).toBe(
+      'Warning: React.createElement: type is invalid -- expected a string ' +
+        '(for built-in components) or a class/function (for composite ' +
+        'components) but got: object.',
     );
-    expect(console.error.argsForCall[3][0]).toBe(
-      'Warning: React.createElement: type should not be null, undefined, ' +
-      'boolean, or number. It should be a string (for DOM elements) or a ' +
-      'ReactClass (for composite components).'
+    expect(console.error.calls.argsFor(5)[0]).toBe(
+      'Warning: React.createElement: type is invalid -- expected a string ' +
+        '(for built-in components) or a class/function (for composite ' +
+        'components) but got: object. You likely forgot to export your ' +
+        "component from the file it's defined in.",
     );
     React.createElement('div');
-    expect(console.error.calls.length).toBe(4);
+    expect(console.error.calls.count()).toBe(6);
   });
 
-  it('includes the owner name when passing null, undefined, boolean, or number', function() {
+  it('includes the owner name when passing null, undefined, boolean, or number', () => {
     spyOn(console, 'error');
-    var ParentComp = React.createClass({
-      render: function() {
-        return React.createElement(null);
-      },
-    });
+    function ParentComp() {
+      return React.createElement(null);
+    }
     expect(function() {
       ReactTestUtils.renderIntoDocument(React.createElement(ParentComp));
-    }).toThrow(
+    }).toThrowError(
       'Element type is invalid: expected a string (for built-in components) ' +
-      'or a class/function (for composite components) but got: null. Check ' +
-      'the render method of `ParentComp`.'
+        'or a class/function (for composite components) but got: null. Check ' +
+        'the render method of `ParentComp`.',
     );
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: React.createElement: type should not be null, undefined, ' +
-      'boolean, or number. It should be a string (for DOM elements) or a ' +
-      'ReactClass (for composite components). Check the render method of ' +
-      '`ParentComp`.'
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: React.createElement: type is invalid -- expected a string ' +
+        '(for built-in components) or a class/function (for composite ' +
+        'components) but got: null. Check the render method of `ParentComp`.' +
+        '\n    in ParentComp',
     );
   });
 
-  it('should check default prop values', function() {
+  it('should check default prop values', () => {
     spyOn(console, 'error');
 
-    var Component = React.createClass({
-      propTypes: {prop: React.PropTypes.string.isRequired},
-      getDefaultProps: function() {
-        return {prop: null};
-      },
-      render: function() {
+    class Component extends React.Component {
+      render() {
         return React.createElement('span', null, this.props.prop);
-      },
-    });
+      }
+    }
+    Component.propTypes = {prop: PropTypes.string.isRequired};
+    Component.defaultProps = {prop: null};
 
     ReactTestUtils.renderIntoDocument(React.createElement(Component));
 
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: Failed propType: ' +
-      'Required prop `prop` was not specified in `Component`.'
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: Failed prop type: The prop `prop` is marked as required in ' +
+        '`Component`, but its value is `null`.\n' +
+        '    in Component',
     );
   });
 
-  it('should not check the default for explicit null', function() {
+  it('should not check the default for explicit null', () => {
     spyOn(console, 'error');
 
-    var Component = React.createClass({
-      propTypes: {prop: React.PropTypes.string.isRequired},
-      getDefaultProps: function() {
-        return {prop: 'text'};
-      },
-      render: function() {
+    class Component extends React.Component {
+      render() {
         return React.createElement('span', null, this.props.prop);
-      },
-    });
+      }
+    }
+    Component.propTypes = {prop: PropTypes.string.isRequired};
+    Component.defaultProps = {prop: 'text'};
 
     ReactTestUtils.renderIntoDocument(
-      React.createElement(Component, {prop:null})
+      React.createElement(Component, {prop: null}),
     );
 
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: Failed propType: ' +
-      'Required prop `prop` was not specified in `Component`.'
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: Failed prop type: The prop `prop` is marked as required in ' +
+        '`Component`, but its value is `null`.\n' +
+        '    in Component',
     );
   });
 
-  it('should check declared prop types', function() {
+  it('should check declared prop types', () => {
     spyOn(console, 'error');
 
-    var Component = React.createClass({
-      propTypes: {
-        prop: React.PropTypes.string.isRequired,
-      },
-      render: function() {
+    class Component extends React.Component {
+      render() {
         return React.createElement('span', null, this.props.prop);
-      },
-    });
+      }
+    }
+    Component.propTypes = {
+      prop: PropTypes.string.isRequired,
+    };
 
+    ReactTestUtils.renderIntoDocument(React.createElement(Component));
     ReactTestUtils.renderIntoDocument(
-      React.createElement(Component)
-    );
-    ReactTestUtils.renderIntoDocument(
-      React.createElement(Component, {prop: 42})
+      React.createElement(Component, {prop: 42}),
     );
 
-    expect(console.error.calls.length).toBe(2);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: Failed propType: ' +
-      'Required prop `prop` was not specified in `Component`.'
+    expect(console.error.calls.count()).toBe(2);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: Failed prop type: ' +
+        'The prop `prop` is marked as required in `Component`, but its value ' +
+        'is `undefined`.\n' +
+        '    in Component',
     );
 
-    expect(console.error.argsForCall[1][0]).toBe(
-      'Warning: Failed propType: ' +
-      'Invalid prop `prop` of type `number` supplied to ' +
-      '`Component`, expected `string`.'
+    expect(console.error.calls.argsFor(1)[0]).toBe(
+      'Warning: Failed prop type: ' +
+        'Invalid prop `prop` of type `number` supplied to ' +
+        '`Component`, expected `string`.\n' +
+        '    in Component',
     );
 
     ReactTestUtils.renderIntoDocument(
-      React.createElement(Component, {prop: 'string'})
+      React.createElement(Component, {prop: 'string'}),
     );
 
     // Should not error for strings
-    expect(console.error.calls.length).toBe(2);
+    expect(console.error.calls.count()).toBe(2);
   });
 
-  it('should warn if a PropType creator is used as a PropType', function() {
+  it('should warn if a PropType creator is used as a PropType', () => {
     spyOn(console, 'error');
 
-    var Component = React.createClass({
-      propTypes: {
-        myProp: React.PropTypes.shape,
-      },
-      render: function() {
+    class Component extends React.Component {
+      render() {
         return React.createElement('span', null, this.props.myProp.value);
-      },
-    });
+      }
+    }
+    Component.propTypes = {
+      myProp: PropTypes.shape,
+    };
 
     ReactTestUtils.renderIntoDocument(
-      React.createElement(Component, {myProp: {value: 'hi'}})
+      React.createElement(Component, {myProp: {value: 'hi'}}),
     );
 
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
       'Warning: Component: type specification of prop `myProp` is invalid; ' +
-      'the type checker function must return `null` or an `Error` but ' +
-      'returned a function. You may have forgotten to pass an argument to ' +
-      'the type checker creator (arrayOf, instanceOf, objectOf, oneOf, ' +
-      'oneOfType, and shape all require an argument).'
+        'the type checker function must return `null` or an `Error` but ' +
+        'returned a function. You may have forgotten to pass an argument to ' +
+        'the type checker creator (arrayOf, instanceOf, objectOf, oneOf, ' +
+        'oneOfType, and shape all require an argument).',
     );
   });
 
-  it('should warn when accessing .type on an element factory', function() {
-    spyOn(console, 'error');
-    var TestComponent = React.createClass({
-      render: function() {
-        return <div />;
-      },
-    });
+  it('should warn when accessing .type on an element factory', () => {
+    spyOn(console, 'warn');
+    function TestComponent() {
+      return <div />;
+    }
     var TestFactory = React.createFactory(TestComponent);
     expect(TestFactory.type).toBe(TestComponent);
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
+    expect(console.warn.calls.count()).toBe(1);
+    expect(console.warn.calls.argsFor(0)[0]).toBe(
       'Warning: Factory.type is deprecated. Access the class directly before ' +
-      'passing it to createFactory.'
+        'passing it to createFactory.',
     );
     // Warn once, not again
     expect(TestFactory.type).toBe(TestComponent);
-    expect(console.error.argsForCall.length).toBe(1);
+    expect(console.warn.calls.count()).toBe(1);
   });
 
-  it('does not warn when using DOM node as children', function() {
+  it('does not warn when using DOM node as children', () => {
     spyOn(console, 'error');
-    var DOMContainer = React.createClass({
-      render: function() {
+    class DOMContainer extends React.Component {
+      render() {
         return <div />;
-      },
-      componentDidMount: function() {
+      }
+      componentDidMount() {
         ReactDOM.findDOMNode(this).appendChild(this.props.children);
-      },
-    });
+      }
+    }
 
     var node = document.createElement('div');
     // This shouldn't cause a stack overflow or any other problems (#3883)
     ReactTestUtils.renderIntoDocument(<DOMContainer>{node}</DOMContainer>);
-    expect(console.error.argsForCall.length).toBe(0);
+    expect(console.error.calls.count()).toBe(0);
   });
 
-  it('should not enumerate enumerable numbers (#4776)', function() {
+  it('should not enumerate enumerable numbers (#4776)', () => {
     /*eslint-disable no-extend-native */
     Number.prototype['@@iterator'] = function() {
       throw new Error('number iterator called');
@@ -467,12 +497,12 @@ describe('ReactElementValidator', function() {
     }
   });
 
-  it('does not blow up with inlined children', function() {
+  it('does not blow up with inlined children', () => {
     // We don't suggest this since it silences all sorts of warnings, but we
     // shouldn't blow up either.
 
     var child = {
-      $$typeof: (<div />).$$typeof,
+      $$typeof: <div />.$$typeof,
       type: 'span',
       key: null,
       ref: null,
@@ -483,16 +513,67 @@ describe('ReactElementValidator', function() {
     void <div>{[child]}</div>;
   });
 
-  it('does not blow up on key warning with undefined type', function() {
+  it('does not blow up on key warning with undefined type', () => {
     spyOn(console, 'error');
     var Foo = undefined;
     void <Foo>{[<div />]}</Foo>;
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: React.createElement: type should not be null, undefined, ' +
-      'boolean, or number. It should be a string (for DOM elements) or a ' +
-      'ReactClass (for composite components).'
+    expect(console.error.calls.count()).toBe(1);
+    expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
+      'Warning: React.createElement: type is invalid -- expected a string ' +
+        '(for built-in components) or a class/function (for composite ' +
+        'components) but got: undefined. You likely forgot to export your ' +
+        "component from the file it's defined in. Check your code at **.",
     );
   });
 
+  it('provides stack via non-standard console.reactStack for invalid types', () => {
+    spyOn(console, 'error');
+
+    function Foo() {
+      var Bad = undefined;
+      return React.createElement(Bad);
+    }
+
+    function App() {
+      return React.createElement('div', null, React.createElement(Foo));
+    }
+
+    try {
+      console.reactStack = jest.fn();
+      console.reactStackEnd = jest.fn();
+
+      expect(() => {
+        ReactTestUtils.renderIntoDocument(React.createElement(App));
+      }).toThrow(
+        'Element type is invalid: expected a string (for built-in components) ' +
+          'or a class/function (for composite components) but got: undefined. ' +
+          "You likely forgot to export your component from the file it's " +
+          'defined in. Check the render method of `Foo`.',
+      );
+
+      expect(console.reactStack.mock.calls.length).toBe(1);
+      expect(console.reactStackEnd.mock.calls.length).toBe(1);
+
+      var stack = console.reactStack.mock.calls[0][0];
+      expect(Array.isArray(stack)).toBe(true);
+      expect(stack.map(frame => frame.name)).toEqual([
+        'Foo', // <Bad> is inside Foo
+        'App', // <Foo> is inside App
+        'App', // <div> is inside App
+        null, // <App> is outside a component
+      ]);
+      expect(
+        stack.map(frame => frame.fileName && frame.fileName.slice(-8)),
+      ).toEqual([null, null, null, null]);
+      expect(stack.map(frame => frame.lineNumber)).toEqual([
+        null,
+        null,
+        null,
+        null,
+      ]);
+    } finally {
+      delete console.reactStack;
+      delete console.reactStackEnd;
+    }
+  });
 });
diff --git a/src/isomorphic/classic/types/ReactPropTypeLocationNames.js b/src/isomorphic/classic/types/ReactPropTypeLocationNames.js
deleted file mode 100644
index 7ea35f0091e8..000000000000
--- a/src/isomorphic/classic/types/ReactPropTypeLocationNames.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/**
- * 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 ReactPropTypeLocationNames
- */
-
-'use strict';
-
-var ReactPropTypeLocationNames = {};
-
-if (__DEV__) {
-  ReactPropTypeLocationNames = {
-    prop: 'prop',
-    context: 'context',
-    childContext: 'child context',
-  };
-}
-
-module.exports = ReactPropTypeLocationNames;
diff --git a/src/isomorphic/classic/types/ReactPropTypeLocations.js b/src/isomorphic/classic/types/ReactPropTypeLocations.js
deleted file mode 100644
index 3ed5a649fdbc..000000000000
--- a/src/isomorphic/classic/types/ReactPropTypeLocations.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/**
- * 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 ReactPropTypeLocations
- */
-
-'use strict';
-
-var keyMirror = require('keyMirror');
-
-var ReactPropTypeLocations = keyMirror({
-  prop: null,
-  context: null,
-  childContext: null,
-});
-
-module.exports = ReactPropTypeLocations;
diff --git a/src/isomorphic/classic/types/ReactPropTypes.js b/src/isomorphic/classic/types/ReactPropTypes.js
index 99c036496aab..5c0ca7735103 100644
--- a/src/isomorphic/classic/types/ReactPropTypes.js
+++ b/src/isomorphic/classic/types/ReactPropTypes.js
@@ -11,436 +11,7 @@
 
 'use strict';
 
-var ReactElement = require('ReactElement');
-var ReactPropTypeLocationNames = require('ReactPropTypeLocationNames');
+var {isValidElement} = require('ReactElement');
+var factory = require('prop-types/factory');
 
-var emptyFunction = require('emptyFunction');
-var getIteratorFn = require('getIteratorFn');
-
-/**
- * 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>>';
-
-var ReactPropTypes = {
-  array: createPrimitiveTypeChecker('array'),
-  bool: createPrimitiveTypeChecker('boolean'),
-  func: createPrimitiveTypeChecker('function'),
-  number: createPrimitiveTypeChecker('number'),
-  object: createPrimitiveTypeChecker('object'),
-  string: createPrimitiveTypeChecker('string'),
-
-  any: createAnyTypeChecker(),
-  arrayOf: createArrayOfTypeChecker,
-  element: createElementTypeChecker(),
-  instanceOf: createInstanceTypeChecker,
-  node: createNodeChecker(),
-  objectOf: createObjectOfTypeChecker,
-  oneOf: createEnumTypeChecker,
-  oneOfType: createUnionTypeChecker,
-  shape: createShapeTypeChecker,
-};
-
-/**
- * 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*/
-
-function createChainableTypeChecker(validate) {
-  function checkType(
-    isRequired,
-    props,
-    propName,
-    componentName,
-    location,
-    propFullName
-  ) {
-    componentName = componentName || ANONYMOUS;
-    propFullName = propFullName || propName;
-    if (props[propName] == null) {
-      var locationName = ReactPropTypeLocationNames[location];
-      if (isRequired) {
-        return new Error(
-          `Required ${locationName} \`${propFullName}\` was not specified in ` +
-          `\`${componentName}\`.`
-        );
-      }
-      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) {
-    var propValue = props[propName];
-    var propType = getPropType(propValue);
-    if (propType !== expectedType) {
-      var locationName = ReactPropTypeLocationNames[location];
-      // `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 Error(
-        `Invalid ${locationName} \`${propFullName}\` of type ` +
-        `\`${preciseType}\` supplied to \`${componentName}\`, expected ` +
-        `\`${expectedType}\`.`
-      );
-    }
-    return null;
-  }
-  return createChainableTypeChecker(validate);
-}
-
-function createAnyTypeChecker() {
-  return createChainableTypeChecker(emptyFunction.thatReturns(null));
-}
-
-function createArrayOfTypeChecker(typeChecker) {
-  function validate(props, propName, componentName, location, propFullName) {
-    if (typeof typeChecker !== 'function') {
-      return new Error(
-        `Property \`${propFullName}\` of component \`${componentName}\` has invalid PropType notation inside arrayOf.`
-      );
-    }
-    var propValue = props[propName];
-    if (!Array.isArray(propValue)) {
-      var locationName = ReactPropTypeLocationNames[location];
-      var propType = getPropType(propValue);
-      return new Error(
-        `Invalid ${locationName} \`${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}]`
-      );
-      if (error instanceof Error) {
-        return error;
-      }
-    }
-    return null;
-  }
-  return createChainableTypeChecker(validate);
-}
-
-function createElementTypeChecker() {
-  function validate(props, propName, componentName, location, propFullName) {
-    if (!ReactElement.isValidElement(props[propName])) {
-      var locationName = ReactPropTypeLocationNames[location];
-      return new Error(
-        `Invalid ${locationName} \`${propFullName}\` 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 locationName = ReactPropTypeLocationNames[location];
-      var expectedClassName = expectedClass.name || ANONYMOUS;
-      var actualClassName = getClassName(props[propName]);
-      return new Error(
-        `Invalid ${locationName} \`${propFullName}\` of type ` +
-        `\`${actualClassName}\` supplied to \`${componentName}\`, expected ` +
-        `instance of \`${expectedClassName}\`.`
-      );
-    }
-    return null;
-  }
-  return createChainableTypeChecker(validate);
-}
-
-function createEnumTypeChecker(expectedValues) {
-  if (!Array.isArray(expectedValues)) {
-    return createChainableTypeChecker(function() {
-      return new Error(
-        `Invalid argument supplied to oneOf, expected an instance of array.`
-      );
-    });
-  }
-
-  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 locationName = ReactPropTypeLocationNames[location];
-    var valuesString = JSON.stringify(expectedValues);
-    return new Error(
-      `Invalid ${locationName} \`${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 Error(
-        `Property \`${propFullName}\` of component \`${componentName}\` has invalid PropType notation inside objectOf.`
-      );
-    }
-    var propValue = props[propName];
-    var propType = getPropType(propValue);
-    if (propType !== 'object') {
-      var locationName = ReactPropTypeLocationNames[location];
-      return new Error(
-        `Invalid ${locationName} \`${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}`
-        );
-        if (error instanceof Error) {
-          return error;
-        }
-      }
-    }
-    return null;
-  }
-  return createChainableTypeChecker(validate);
-}
-
-function createUnionTypeChecker(arrayOfTypeCheckers) {
-  if (!Array.isArray(arrayOfTypeCheckers)) {
-    return createChainableTypeChecker(function() {
-      return new Error(
-        `Invalid argument supplied to oneOfType, expected an instance of array.`
-      );
-    });
-  }
-
-  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) == null
-      ) {
-        return null;
-      }
-    }
-
-    var locationName = ReactPropTypeLocationNames[location];
-    return new Error(
-      `Invalid ${locationName} \`${propFullName}\` supplied to ` +
-      `\`${componentName}\`.`
-    );
-  }
-  return createChainableTypeChecker(validate);
-}
-
-function createNodeChecker() {
-  function validate(props, propName, componentName, location, propFullName) {
-    if (!isNode(props[propName])) {
-      var locationName = ReactPropTypeLocationNames[location];
-      return new Error(
-        `Invalid ${locationName} \`${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') {
-      var locationName = ReactPropTypeLocationNames[location];
-      return new Error(
-        `Invalid ${locationName} \`${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}`
-      );
-      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 || ReactElement.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;
-  }
-}
-
-// 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';
-  }
-  return propType;
-}
-
-// This handles more types than `getPropType`. Only used for error messages.
-// See `createPrimitiveTypeChecker`.
-function getPreciseType(propValue) {
-  var propType = getPropType(propValue);
-  if (propType === 'object') {
-    if (propValue instanceof Date) {
-      return 'date';
-    } else if (propValue instanceof RegExp) {
-      return 'regexp';
-    }
-  }
-  return propType;
-}
-
-// Returns class name of the object, if any.
-function getClassName(propValue) {
-  if (!propValue.constructor || !propValue.constructor.name) {
-    return ANONYMOUS;
-  }
-  return propValue.constructor.name;
-}
-
-module.exports = ReactPropTypes;
+module.exports = factory(isValidElement);
diff --git a/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js b/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js
index 9601e675b772..c12cc1c29fa7 100644
--- a/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js
+++ b/src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js
@@ -14,13 +14,11 @@
 var PropTypes;
 var React;
 var ReactFragment;
-var ReactPropTypeLocations;
 var ReactTestUtils;
+var ReactPropTypesSecret;
 
 var Component;
 var MyComponent;
-var requiredMessage =
-  'Required prop `testProp` was not specified in `testComponent`.';
 
 function typeCheckFail(declaration, value, message) {
   var props = {testProp: value};
@@ -28,76 +26,148 @@ function typeCheckFail(declaration, value, message) {
     props,
     'testProp',
     'testComponent',
-    ReactPropTypeLocations.prop
+    'prop',
+    null,
+    ReactPropTypesSecret,
   );
   expect(error instanceof Error).toBe(true);
   expect(error.message).toBe(message);
 }
 
+function typeCheckFailRequiredValues(declaration) {
+  var specifiedButIsNullMsg =
+    'The prop `testProp` is marked as required in ' +
+    '`testComponent`, but its value is `null`.';
+  var unspecifiedMsg =
+    'The prop `testProp` is marked as required in ' +
+    '`testComponent`, but its value is `undefined`.';
+  var props1 = {testProp: null};
+  var error1 = declaration(
+    props1,
+    'testProp',
+    'testComponent',
+    'prop',
+    null,
+    ReactPropTypesSecret,
+  );
+  expect(error1 instanceof Error).toBe(true);
+  expect(error1.message).toBe(specifiedButIsNullMsg);
+  var props2 = {testProp: undefined};
+  var error2 = declaration(
+    props2,
+    'testProp',
+    'testComponent',
+    'prop',
+    null,
+    ReactPropTypesSecret,
+  );
+  expect(error2 instanceof Error).toBe(true);
+  expect(error2.message).toBe(unspecifiedMsg);
+  var props3 = {};
+  var error3 = declaration(
+    props3,
+    'testProp',
+    'testComponent',
+    'prop',
+    null,
+    ReactPropTypesSecret,
+  );
+  expect(error3 instanceof Error).toBe(true);
+  expect(error3.message).toBe(unspecifiedMsg);
+}
+
 function typeCheckPass(declaration, value) {
   var props = {testProp: value};
   var error = declaration(
     props,
     'testProp',
     'testComponent',
-    ReactPropTypeLocations.prop
+    'prop',
+    null,
+    ReactPropTypesSecret,
   );
   expect(error).toBe(null);
 }
 
-describe('ReactPropTypes', function() {
-  beforeEach(function() {
-    PropTypes = require('ReactPropTypes');
-    React = require('React');
-    ReactFragment = require('ReactFragment');
-    ReactPropTypeLocations = require('ReactPropTypeLocations');
-    ReactTestUtils = require('ReactTestUtils');
+function resetWarningCache() {
+  jest.resetModules();
+  PropTypes = require('ReactPropTypes');
+  React = require('React');
+  ReactFragment = require('ReactFragment');
+  ReactTestUtils = require('ReactTestUtils');
+  ReactPropTypesSecret = require('ReactPropTypesSecret');
+}
+
+function expectWarningInDevelopment(declaration, value) {
+  resetWarningCache();
+  var props = {testProp: value};
+  var propName = 'testProp' + Math.random().toString();
+  var componentName = 'testComponent' + Math.random().toString();
+  for (var i = 0; i < 3; i++) {
+    declaration(props, propName, componentName, 'prop');
+  }
+  expect(console.error.calls.count()).toBe(1);
+  expect(console.error.calls.argsFor(0)[0]).toContain(
+    'You are manually calling a React.PropTypes validation ',
+  );
+  console.error.calls.reset();
+}
+
+describe('ReactPropTypes', () => {
+  beforeEach(() => {
+    resetWarningCache();
   });
 
-  describe('Primitive Types', function() {
-    it('should warn for invalid strings', function() {
+  describe('Primitive Types', () => {
+    it('should warn for invalid strings', () => {
       typeCheckFail(
         PropTypes.string,
         [],
         'Invalid prop `testProp` of type `array` supplied to ' +
-        '`testComponent`, expected `string`.'
+          '`testComponent`, expected `string`.',
       );
       typeCheckFail(
         PropTypes.string,
         false,
         'Invalid prop `testProp` of type `boolean` supplied to ' +
-        '`testComponent`, expected `string`.'
+          '`testComponent`, expected `string`.',
       );
       typeCheckFail(
         PropTypes.string,
         0,
         'Invalid prop `testProp` of type `number` supplied to ' +
-        '`testComponent`, expected `string`.'
+          '`testComponent`, expected `string`.',
       );
       typeCheckFail(
         PropTypes.string,
         {},
         'Invalid prop `testProp` of type `object` supplied to ' +
-        '`testComponent`, expected `string`.'
+          '`testComponent`, expected `string`.',
+      );
+      typeCheckFail(
+        PropTypes.string,
+        Symbol(),
+        'Invalid prop `testProp` of type `symbol` supplied to ' +
+          '`testComponent`, expected `string`.',
       );
     });
 
-    it('should fail date and regexp correctly', function() {
+    it('should fail date and regexp correctly', () => {
       typeCheckFail(
         PropTypes.string,
         new Date(),
         'Invalid prop `testProp` of type `date` supplied to ' +
-        '`testComponent`, expected `string`.'
+          '`testComponent`, expected `string`.',
       );
       typeCheckFail(
         PropTypes.string,
         /please/,
         'Invalid prop `testProp` of type `regexp` supplied to ' +
-        '`testComponent`, expected `string`.'
+          '`testComponent`, expected `string`.',
       );
     });
 
-    it('should not warn for valid values', function() {
+    it('should not warn for valid values', () => {
       typeCheckPass(PropTypes.array, []);
       typeCheckPass(PropTypes.bool, false);
       typeCheckPass(PropTypes.func, function() {});
@@ -106,75 +176,129 @@ describe('ReactPropTypes', function() {
       typeCheckPass(PropTypes.object, {});
       typeCheckPass(PropTypes.object, new Date());
       typeCheckPass(PropTypes.object, /please/);
+      typeCheckPass(PropTypes.symbol, Symbol());
     });
 
-    it('should be implicitly optional and not warn without values', function() {
+    it('should be implicitly optional and not warn without values', () => {
       typeCheckPass(PropTypes.string, null);
       typeCheckPass(PropTypes.string, undefined);
     });
 
-    it('should warn for missing required values', function() {
-      typeCheckFail(PropTypes.string.isRequired, null, requiredMessage);
-      typeCheckFail(PropTypes.string.isRequired, undefined, requiredMessage);
+    it('should warn for missing required values', () => {
+      typeCheckFailRequiredValues(PropTypes.string.isRequired);
+    });
+
+    it('should warn if called manually in development', () => {
+      spyOn(console, 'error');
+      expectWarningInDevelopment(PropTypes.array, /please/);
+      expectWarningInDevelopment(PropTypes.array, []);
+      expectWarningInDevelopment(PropTypes.array.isRequired, /please/);
+      expectWarningInDevelopment(PropTypes.array.isRequired, []);
+      expectWarningInDevelopment(PropTypes.array.isRequired, null);
+      expectWarningInDevelopment(PropTypes.array.isRequired, undefined);
+      expectWarningInDevelopment(PropTypes.bool, []);
+      expectWarningInDevelopment(PropTypes.bool, true);
+      expectWarningInDevelopment(PropTypes.bool.isRequired, []);
+      expectWarningInDevelopment(PropTypes.bool.isRequired, true);
+      expectWarningInDevelopment(PropTypes.bool.isRequired, null);
+      expectWarningInDevelopment(PropTypes.bool.isRequired, undefined);
+      expectWarningInDevelopment(PropTypes.func, false);
+      expectWarningInDevelopment(PropTypes.func, function() {});
+      expectWarningInDevelopment(PropTypes.func.isRequired, false);
+      expectWarningInDevelopment(PropTypes.func.isRequired, function() {});
+      expectWarningInDevelopment(PropTypes.func.isRequired, null);
+      expectWarningInDevelopment(PropTypes.func.isRequired, undefined);
+      expectWarningInDevelopment(PropTypes.number, function() {});
+      expectWarningInDevelopment(PropTypes.number, 42);
+      expectWarningInDevelopment(PropTypes.number.isRequired, function() {});
+      expectWarningInDevelopment(PropTypes.number.isRequired, 42);
+      expectWarningInDevelopment(PropTypes.number.isRequired, null);
+      expectWarningInDevelopment(PropTypes.number.isRequired, undefined);
+      expectWarningInDevelopment(PropTypes.string, 0);
+      expectWarningInDevelopment(PropTypes.string, 'foo');
+      expectWarningInDevelopment(PropTypes.string.isRequired, 0);
+      expectWarningInDevelopment(PropTypes.string.isRequired, 'foo');
+      expectWarningInDevelopment(PropTypes.string.isRequired, null);
+      expectWarningInDevelopment(PropTypes.string.isRequired, undefined);
+      expectWarningInDevelopment(PropTypes.symbol, 0);
+      expectWarningInDevelopment(PropTypes.symbol, Symbol('Foo'));
+      expectWarningInDevelopment(PropTypes.symbol.isRequired, 0);
+      expectWarningInDevelopment(PropTypes.symbol.isRequired, Symbol('Foo'));
+      expectWarningInDevelopment(PropTypes.symbol.isRequired, null);
+      expectWarningInDevelopment(PropTypes.symbol.isRequired, undefined);
+      expectWarningInDevelopment(PropTypes.object, '');
+      expectWarningInDevelopment(PropTypes.object, {foo: 'bar'});
+      expectWarningInDevelopment(PropTypes.object.isRequired, '');
+      expectWarningInDevelopment(PropTypes.object.isRequired, {foo: 'bar'});
+      expectWarningInDevelopment(PropTypes.object.isRequired, null);
+      expectWarningInDevelopment(PropTypes.object.isRequired, undefined);
     });
   });
 
-  describe('Any type', function() {
-    it('should should accept any value', function() {
+  describe('Any type', () => {
+    it('should should accept any value', () => {
       typeCheckPass(PropTypes.any, 0);
       typeCheckPass(PropTypes.any, 'str');
       typeCheckPass(PropTypes.any, []);
+      typeCheckPass(PropTypes.any, Symbol());
     });
 
-    it('should be implicitly optional and not warn without values', function() {
+    it('should be implicitly optional and not warn without values', () => {
       typeCheckPass(PropTypes.any, null);
       typeCheckPass(PropTypes.any, undefined);
     });
 
-    it('should warn for missing required values', function() {
-      typeCheckFail(PropTypes.any.isRequired, null, requiredMessage);
-      typeCheckFail(PropTypes.any.isRequired, undefined, requiredMessage);
+    it('should warn for missing required values', () => {
+      typeCheckFailRequiredValues(PropTypes.any.isRequired);
+    });
+
+    it('should warn if called manually in development', () => {
+      spyOn(console, 'error');
+      expectWarningInDevelopment(PropTypes.any, null);
+      expectWarningInDevelopment(PropTypes.any.isRequired, null);
+      expectWarningInDevelopment(PropTypes.any.isRequired, undefined);
     });
   });
 
-  describe('ArrayOf Type', function() {
-    it('should fail for invalid argument', function() {
+  describe('ArrayOf Type', () => {
+    it('should fail for invalid argument', () => {
       typeCheckFail(
-        PropTypes.arrayOf({ foo: PropTypes.string }),
-        { foo: 'bar' },
-        'Property `testProp` of component `testComponent` has invalid PropType notation inside arrayOf.'
+        PropTypes.arrayOf({foo: PropTypes.string}),
+        {foo: 'bar'},
+        'Property `testProp` of component `testComponent` has invalid PropType notation inside arrayOf.',
       );
     });
 
-    it('should support the arrayOf propTypes', function() {
+    it('should support the arrayOf propTypes', () => {
       typeCheckPass(PropTypes.arrayOf(PropTypes.number), [1, 2, 3]);
       typeCheckPass(PropTypes.arrayOf(PropTypes.string), ['a', 'b', 'c']);
       typeCheckPass(PropTypes.arrayOf(PropTypes.oneOf(['a', 'b'])), ['a', 'b']);
+      typeCheckPass(PropTypes.arrayOf(PropTypes.symbol), [Symbol(), Symbol()]);
     });
 
-    it('should support arrayOf with complex types', function() {
+    it('should support arrayOf with complex types', () => {
       typeCheckPass(
         PropTypes.arrayOf(PropTypes.shape({a: PropTypes.number.isRequired})),
-        [{a: 1}, {a: 2}]
+        [{a: 1}, {a: 2}],
       );
 
       function Thing() {}
-      typeCheckPass(
-        PropTypes.arrayOf(PropTypes.instanceOf(Thing)),
-        [new Thing(), new Thing()]
-      );
+      typeCheckPass(PropTypes.arrayOf(PropTypes.instanceOf(Thing)), [
+        new Thing(),
+        new Thing(),
+      ]);
     });
 
-    it('should warn with invalid items in the array', function() {
+    it('should warn with invalid items in the array', () => {
       typeCheckFail(
         PropTypes.arrayOf(PropTypes.number),
         [1, 2, 'b'],
         'Invalid prop `testProp[2]` of type `string` supplied to ' +
-        '`testComponent`, expected `number`.'
+          '`testComponent`, expected `number`.',
       );
     });
 
-    it('should warn with invalid complex types', function() {
+    it('should warn with invalid complex types', () => {
       function Thing() {}
       var name = Thing.name || '<<anonymous>>';
 
@@ -182,65 +306,84 @@ describe('ReactPropTypes', function() {
         PropTypes.arrayOf(PropTypes.instanceOf(Thing)),
         [new Thing(), 'xyz'],
         'Invalid prop `testProp[1]` of type `String` supplied to ' +
-        '`testComponent`, expected instance of `' + name + '`.'
+          '`testComponent`, expected instance of `' +
+          name +
+          '`.',
       );
     });
 
-    it('should warn when passed something other than an array', function() {
+    it('should warn when passed something other than an array', () => {
       typeCheckFail(
         PropTypes.arrayOf(PropTypes.number),
         {'0': 'maybe-array', length: 1},
         'Invalid prop `testProp` of type `object` supplied to ' +
-        '`testComponent`, expected an array.'
+          '`testComponent`, expected an array.',
       );
       typeCheckFail(
         PropTypes.arrayOf(PropTypes.number),
         123,
         'Invalid prop `testProp` of type `number` supplied to ' +
-        '`testComponent`, expected an array.'
+          '`testComponent`, expected an array.',
       );
       typeCheckFail(
         PropTypes.arrayOf(PropTypes.number),
         'string',
         'Invalid prop `testProp` of type `string` supplied to ' +
-        '`testComponent`, expected an array.'
+          '`testComponent`, expected an array.',
       );
     });
 
-    it('should not warn when passing an empty array', function() {
+    it('should not warn when passing an empty array', () => {
       typeCheckPass(PropTypes.arrayOf(PropTypes.number), []);
     });
 
-    it('should be implicitly optional and not warn without values', function() {
+    it('should be implicitly optional and not warn without values', () => {
       typeCheckPass(PropTypes.arrayOf(PropTypes.number), null);
       typeCheckPass(PropTypes.arrayOf(PropTypes.number), undefined);
     });
 
-    it('should warn for missing required values', function() {
-      typeCheckFail(
+    it('should warn for missing required values', () => {
+      typeCheckFailRequiredValues(
+        PropTypes.arrayOf(PropTypes.number).isRequired,
+      );
+    });
+
+    it('should warn if called manually in development', () => {
+      spyOn(console, 'error');
+      expectWarningInDevelopment(PropTypes.arrayOf({foo: PropTypes.string}), {
+        foo: 'bar',
+      });
+      expectWarningInDevelopment(PropTypes.arrayOf(PropTypes.number), [
+        1,
+        2,
+        'b',
+      ]);
+      expectWarningInDevelopment(PropTypes.arrayOf(PropTypes.number), {
+        '0': 'maybe-array',
+        length: 1,
+      });
+      expectWarningInDevelopment(
         PropTypes.arrayOf(PropTypes.number).isRequired,
         null,
-        requiredMessage
       );
-      typeCheckFail(
+      expectWarningInDevelopment(
         PropTypes.arrayOf(PropTypes.number).isRequired,
         undefined,
-        requiredMessage
       );
     });
   });
 
-  describe('Component Type', function() {
-    beforeEach(function() {
-      Component = React.createClass({
-        propTypes: {
+  describe('Component Type', () => {
+    beforeEach(() => {
+      Component = class extends React.Component {
+        static propTypes = {
           label: PropTypes.element.isRequired,
-        },
+        };
 
-        render: function() {
+        render() {
           return <div>{this.props.label}</div>;
-        },
-      });
+        }
+      };
     });
 
     it('should support components', () => {
@@ -248,45 +391,73 @@ describe('ReactPropTypes', function() {
     });
 
     it('should not support multiple components or scalar values', () => {
-      var message = 'Invalid prop `testProp` supplied to `testComponent`, ' +
-        'expected a single ReactElement.';
-      typeCheckFail(PropTypes.element, [<div />, <div />], message);
-      typeCheckFail(PropTypes.element, 123, message);
-      typeCheckFail(PropTypes.element, 'foo', message);
-      typeCheckFail(PropTypes.element, false, message);
+      typeCheckFail(
+        PropTypes.element,
+        [<div />, <div />],
+        'Invalid prop `testProp` of type `array` supplied to `testComponent`, ' +
+          'expected a single ReactElement.',
+      );
+      typeCheckFail(
+        PropTypes.element,
+        123,
+        'Invalid prop `testProp` of type `number` supplied to `testComponent`, ' +
+          'expected a single ReactElement.',
+      );
+      typeCheckFail(
+        PropTypes.element,
+        'foo',
+        'Invalid prop `testProp` of type `string` supplied to `testComponent`, ' +
+          'expected a single ReactElement.',
+      );
+      typeCheckFail(
+        PropTypes.element,
+        false,
+        'Invalid prop `testProp` of type `boolean` supplied to `testComponent`, ' +
+          'expected a single ReactElement.',
+      );
     });
 
     it('should be able to define a single child as label', () => {
       spyOn(console, 'error');
 
       var instance = <Component label={<div />} />;
-      instance = ReactTestUtils.renderIntoDocument(instance);
+      ReactTestUtils.renderIntoDocument(instance);
 
-      expect(console.error.argsForCall.length).toBe(0);
+      expect(console.error.calls.count()).toBe(0);
     });
 
     it('should warn when passing no label and isRequired is set', () => {
       spyOn(console, 'error');
 
       var instance = <Component />;
-      instance = ReactTestUtils.renderIntoDocument(instance);
+      ReactTestUtils.renderIntoDocument(instance);
 
-      expect(console.error.argsForCall.length).toBe(1);
+      expect(console.error.calls.count()).toBe(1);
     });
 
-    it('should be implicitly optional and not warn without values', function() {
+    it('should be implicitly optional and not warn without values', () => {
       typeCheckPass(PropTypes.element, null);
       typeCheckPass(PropTypes.element, undefined);
     });
 
-    it('should warn for missing required values', function() {
-      typeCheckFail(PropTypes.element.isRequired, null, requiredMessage);
-      typeCheckFail(PropTypes.element.isRequired, undefined, requiredMessage);
+    it('should warn for missing required values', () => {
+      typeCheckFailRequiredValues(PropTypes.element.isRequired);
+    });
+
+    it('should warn if called manually in development', () => {
+      spyOn(console, 'error');
+      expectWarningInDevelopment(PropTypes.element, [<div />, <div />]);
+      expectWarningInDevelopment(PropTypes.element, <div />);
+      expectWarningInDevelopment(PropTypes.element, 123);
+      expectWarningInDevelopment(PropTypes.element, 'foo');
+      expectWarningInDevelopment(PropTypes.element, false);
+      expectWarningInDevelopment(PropTypes.element.isRequired, null);
+      expectWarningInDevelopment(PropTypes.element.isRequired, undefined);
     });
   });
 
-  describe('Instance Types', function() {
-    it('should warn for invalid instances', function() {
+  describe('Instance Types', () => {
+    it('should warn for invalid instances', () => {
       function Person() {}
       function Cat() {}
       var personName = Person.name || '<<anonymous>>';
@@ -297,47 +468,61 @@ describe('ReactPropTypes', function() {
         PropTypes.instanceOf(Person),
         false,
         'Invalid prop `testProp` of type `Boolean` supplied to ' +
-        '`testComponent`, expected instance of `' + personName + '`.'
+          '`testComponent`, expected instance of `' +
+          personName +
+          '`.',
       );
       typeCheckFail(
         PropTypes.instanceOf(Person),
         {},
         'Invalid prop `testProp` of type `Object` supplied to ' +
-        '`testComponent`, expected instance of `' + personName + '`.'
+          '`testComponent`, expected instance of `' +
+          personName +
+          '`.',
       );
       typeCheckFail(
         PropTypes.instanceOf(Person),
         '',
         'Invalid prop `testProp` of type `String` supplied to ' +
-        '`testComponent`, expected instance of `' + personName + '`.'
+          '`testComponent`, expected instance of `' +
+          personName +
+          '`.',
       );
       typeCheckFail(
         PropTypes.instanceOf(Date),
         {},
         'Invalid prop `testProp` of type `Object` supplied to ' +
-        '`testComponent`, expected instance of `' + dateName + '`.'
+          '`testComponent`, expected instance of `' +
+          dateName +
+          '`.',
       );
       typeCheckFail(
         PropTypes.instanceOf(RegExp),
         {},
         'Invalid prop `testProp` of type `Object` supplied to ' +
-        '`testComponent`, expected instance of `' + regExpName + '`.'
+          '`testComponent`, expected instance of `' +
+          regExpName +
+          '`.',
       );
       typeCheckFail(
         PropTypes.instanceOf(Person),
         new Cat(),
         'Invalid prop `testProp` of type `Cat` supplied to ' +
-        '`testComponent`, expected instance of `' + personName + '`.'
+          '`testComponent`, expected instance of `' +
+          personName +
+          '`.',
       );
       typeCheckFail(
         PropTypes.instanceOf(Person),
         Object.create(null),
         'Invalid prop `testProp` of type `<<anonymous>>` supplied to ' +
-        '`testComponent`, expected instance of `' + personName + '`.'
+          '`testComponent`, expected instance of `' +
+          personName +
+          '`.',
       );
     });
 
-    it('should not warn for valid values', function() {
+    it('should not warn for valid values', () => {
       function Person() {}
       function Engineer() {}
       Engineer.prototype = new Person();
@@ -349,32 +534,39 @@ describe('ReactPropTypes', function() {
       typeCheckPass(PropTypes.instanceOf(RegExp), /please/);
     });
 
-    it('should be implicitly optional and not warn without values', function() {
+    it('should be implicitly optional and not warn without values', () => {
       typeCheckPass(PropTypes.instanceOf(String), null);
       typeCheckPass(PropTypes.instanceOf(String), undefined);
     });
 
-    it('should warn for missing required values', function() {
-      typeCheckFail(
-        PropTypes.instanceOf(String).isRequired, null, requiredMessage
-      );
-      typeCheckFail(
-        PropTypes.instanceOf(String).isRequired, undefined, requiredMessage
+    it('should warn for missing required values', () => {
+      typeCheckFailRequiredValues(PropTypes.instanceOf(String).isRequired);
+    });
+
+    it('should warn if called manually in development', () => {
+      spyOn(console, 'error');
+      expectWarningInDevelopment(PropTypes.instanceOf(Date), {});
+      expectWarningInDevelopment(PropTypes.instanceOf(Date), new Date());
+      expectWarningInDevelopment(PropTypes.instanceOf(Date).isRequired, {});
+      expectWarningInDevelopment(
+        PropTypes.instanceOf(Date).isRequired,
+        new Date(),
       );
     });
   });
 
-  describe('React Component Types', function() {
-    beforeEach(function() {
-      MyComponent = React.createClass({
-        render: function() {
+  describe('React Component Types', () => {
+    beforeEach(() => {
+      MyComponent = class extends React.Component {
+        render() {
           return <div />;
-        },
-      });
+        }
+      };
     });
 
-    it('should warn for invalid values', function() {
-      var failMessage = 'Invalid prop `testProp` supplied to ' +
+    it('should warn for invalid values', () => {
+      var failMessage =
+        'Invalid prop `testProp` supplied to ' +
         '`testComponent`, expected a ReactNode.';
       typeCheckFail(PropTypes.node, true, failMessage);
       typeCheckFail(PropTypes.node, function() {}, failMessage);
@@ -382,7 +574,7 @@ describe('ReactPropTypes', function() {
       typeCheckFail(PropTypes.node, {key: <div />}, failMessage);
     });
 
-    it('should not warn for valid values', function() {
+    it('should not warn for valid values', () => {
       spyOn(console, 'error');
       typeCheckPass(PropTypes.node, <div />);
       typeCheckPass(PropTypes.node, false);
@@ -400,22 +592,25 @@ describe('ReactPropTypes', function() {
 
       // Object of renderable things
       var frag = ReactFragment.create;
-      typeCheckPass(PropTypes.node, frag({
-        k0: 123,
-        k1: 'Some string',
-        k2: <div />,
-        k3: frag({
-          k30: <MyComponent />,
-          k31: frag({k310: <a />}),
-          k32: 'Another string',
+      typeCheckPass(
+        PropTypes.node,
+        frag({
+          k0: 123,
+          k1: 'Some string',
+          k2: <div />,
+          k3: frag({
+            k30: <MyComponent />,
+            k31: frag({k310: <a />}),
+            k32: 'Another string',
+          }),
+          k4: null,
+          k5: undefined,
         }),
-        k4: null,
-        k5: undefined,
-      }));
-      expect(console.error.calls).toEqual([]);
+      );
+      expect(console.error.calls.count()).toBe(0);
     });
 
-    it('should not warn for iterables', function() {
+    it('should not warn for iterables', () => {
       var iterable = {
         '@@iterator': function() {
           var i = 0;
@@ -431,14 +626,17 @@ describe('ReactPropTypes', function() {
       typeCheckPass(PropTypes.node, iterable);
     });
 
-    it('should not warn for entry iterables', function() {
+    it('should not warn for entry iterables', () => {
       var iterable = {
         '@@iterator': function() {
           var i = 0;
           return {
             next: function() {
               var done = ++i > 2;
-              return {value: done ? undefined : ['#' + i, <MyComponent />], done: done};
+              return {
+                value: done ? undefined : ['#' + i, <MyComponent />],
+                done: done,
+              };
             },
           };
         },
@@ -448,73 +646,79 @@ describe('ReactPropTypes', function() {
       typeCheckPass(PropTypes.node, iterable);
     });
 
-    it('should not warn for null/undefined if not required', function() {
+    it('should not warn for null/undefined if not required', () => {
       typeCheckPass(PropTypes.node, null);
       typeCheckPass(PropTypes.node, undefined);
     });
 
-    it('should warn for missing required values', function() {
-      typeCheckFail(
-        PropTypes.node.isRequired,
-        null,
-        'Required prop `testProp` was not specified in `testComponent`.'
-      );
-      typeCheckFail(
-        PropTypes.node.isRequired,
-        undefined,
-        'Required prop `testProp` was not specified in `testComponent`.'
-      );
+    it('should warn for missing required values', () => {
+      typeCheckFailRequiredValues(PropTypes.node.isRequired);
     });
 
-    it('should accept empty array for required props', function() {
+    it('should accept empty array for required props', () => {
       typeCheckPass(PropTypes.node.isRequired, []);
     });
+
+    it('should warn if called manually in development', () => {
+      spyOn(console, 'error');
+      expectWarningInDevelopment(PropTypes.node, 'node');
+      expectWarningInDevelopment(PropTypes.node, {});
+      expectWarningInDevelopment(PropTypes.node.isRequired, 'node');
+      expectWarningInDevelopment(PropTypes.node.isRequired, undefined);
+      expectWarningInDevelopment(PropTypes.node.isRequired, undefined);
+    });
   });
 
-  describe('ObjectOf Type', function() {
-    it('should fail for invalid argument', function() {
+  describe('ObjectOf Type', () => {
+    it('should fail for invalid argument', () => {
       typeCheckFail(
-        PropTypes.objectOf({ foo: PropTypes.string }),
-        { foo: 'bar' },
-        'Property `testProp` of component `testComponent` has invalid PropType notation inside objectOf.'
+        PropTypes.objectOf({foo: PropTypes.string}),
+        {foo: 'bar'},
+        'Property `testProp` of component `testComponent` has invalid PropType notation inside objectOf.',
       );
     });
 
-    it('should support the objectOf propTypes', function() {
+    it('should support the objectOf propTypes', () => {
       typeCheckPass(PropTypes.objectOf(PropTypes.number), {a: 1, b: 2, c: 3});
-      typeCheckPass(
-        PropTypes.objectOf(PropTypes.string),
-        {a: 'a', b: 'b', c: 'c'}
-      );
-      typeCheckPass(
-        PropTypes.objectOf(PropTypes.oneOf(['a', 'b'])),
-        {a: 'a', b: 'b'}
-      );
+      typeCheckPass(PropTypes.objectOf(PropTypes.string), {
+        a: 'a',
+        b: 'b',
+        c: 'c',
+      });
+      typeCheckPass(PropTypes.objectOf(PropTypes.oneOf(['a', 'b'])), {
+        a: 'a',
+        b: 'b',
+      });
+      typeCheckPass(PropTypes.objectOf(PropTypes.symbol), {
+        a: Symbol(),
+        b: Symbol(),
+        c: Symbol(),
+      });
     });
 
-    it('should support objectOf with complex types', function() {
+    it('should support objectOf with complex types', () => {
       typeCheckPass(
         PropTypes.objectOf(PropTypes.shape({a: PropTypes.number.isRequired})),
-        {a: {a: 1}, b: {a: 2}}
+        {a: {a: 1}, b: {a: 2}},
       );
 
       function Thing() {}
-      typeCheckPass(
-        PropTypes.objectOf(PropTypes.instanceOf(Thing)),
-        {a: new Thing(), b: new Thing()}
-      );
+      typeCheckPass(PropTypes.objectOf(PropTypes.instanceOf(Thing)), {
+        a: new Thing(),
+        b: new Thing(),
+      });
     });
 
-    it('should warn with invalid items in the object', function() {
+    it('should warn with invalid items in the object', () => {
       typeCheckFail(
         PropTypes.objectOf(PropTypes.number),
         {a: 1, b: 2, c: 'b'},
         'Invalid prop `testProp.c` of type `string` supplied to `testComponent`, ' +
-        'expected `number`.'
+          'expected `number`.',
       );
     });
 
-    it('should warn with invalid complex types', function() {
+    it('should warn with invalid complex types', () => {
       function Thing() {}
       var name = Thing.name || '<<anonymous>>';
 
@@ -522,129 +726,156 @@ describe('ReactPropTypes', function() {
         PropTypes.objectOf(PropTypes.instanceOf(Thing)),
         {a: new Thing(), b: 'xyz'},
         'Invalid prop `testProp.b` of type `String` supplied to ' +
-        '`testComponent`, expected instance of `' + name + '`.'
+          '`testComponent`, expected instance of `' +
+          name +
+          '`.',
       );
     });
 
-    it('should warn when passed something other than an object', function() {
+    it('should warn when passed something other than an object', () => {
       typeCheckFail(
         PropTypes.objectOf(PropTypes.number),
         [1, 2],
         'Invalid prop `testProp` of type `array` supplied to ' +
-        '`testComponent`, expected an object.'
+          '`testComponent`, expected an object.',
       );
       typeCheckFail(
         PropTypes.objectOf(PropTypes.number),
         123,
         'Invalid prop `testProp` of type `number` supplied to ' +
-        '`testComponent`, expected an object.'
+          '`testComponent`, expected an object.',
       );
       typeCheckFail(
         PropTypes.objectOf(PropTypes.number),
         'string',
         'Invalid prop `testProp` of type `string` supplied to ' +
-        '`testComponent`, expected an object.'
+          '`testComponent`, expected an object.',
+      );
+      typeCheckFail(
+        PropTypes.objectOf(PropTypes.symbol),
+        Symbol(),
+        'Invalid prop `testProp` of type `symbol` supplied to ' +
+          '`testComponent`, expected an object.',
       );
     });
 
-    it('should not warn when passing an empty object', function() {
+    it('should not warn when passing an empty object', () => {
       typeCheckPass(PropTypes.objectOf(PropTypes.number), {});
     });
 
-    it('should be implicitly optional and not warn without values', function() {
+    it('should be implicitly optional and not warn without values', () => {
       typeCheckPass(PropTypes.objectOf(PropTypes.number), null);
       typeCheckPass(PropTypes.objectOf(PropTypes.number), undefined);
     });
 
-    it('should warn for missing required values', function() {
-      typeCheckFail(
+    it('should warn for missing required values', () => {
+      typeCheckFailRequiredValues(
         PropTypes.objectOf(PropTypes.number).isRequired,
-        null,
-        requiredMessage
       );
-      typeCheckFail(
-        PropTypes.objectOf(PropTypes.number).isRequired,
+    });
+
+    it('should warn if called manually in development', () => {
+      spyOn(console, 'error');
+      expectWarningInDevelopment(PropTypes.objectOf({foo: PropTypes.string}), {
+        foo: 'bar',
+      });
+      expectWarningInDevelopment(PropTypes.objectOf(PropTypes.number), {
+        a: 1,
+        b: 2,
+        c: 'b',
+      });
+      expectWarningInDevelopment(PropTypes.objectOf(PropTypes.number), [1, 2]);
+      expectWarningInDevelopment(PropTypes.objectOf(PropTypes.number), null);
+      expectWarningInDevelopment(
+        PropTypes.objectOf(PropTypes.number),
         undefined,
-        requiredMessage
       );
     });
   });
 
-  describe('OneOf Types', function() {
-    it('should fail for invalid argument', function() {
-      typeCheckFail(
-        PropTypes.oneOf('red', 'blue'),
-        'red',
-        'Invalid argument supplied to oneOf, expected an instance of array.'
+  describe('OneOf Types', () => {
+    it('should warn but not error for invalid argument', () => {
+      spyOn(console, 'error');
+
+      PropTypes.oneOf('red', 'blue');
+
+      expect(console.error).toHaveBeenCalled();
+      expect(console.error.calls.argsFor(0)[0]).toContain(
+        'Invalid argument supplied to oneOf, expected an instance of array.',
       );
+
+      typeCheckPass(PropTypes.oneOf('red', 'blue'), 'red');
     });
 
-    it('should warn for invalid values', function() {
+    it('should warn for invalid values', () => {
       typeCheckFail(
         PropTypes.oneOf(['red', 'blue']),
         true,
         'Invalid prop `testProp` of value `true` supplied to ' +
-        '`testComponent`, expected one of ["red","blue"].'
+          '`testComponent`, expected one of ["red","blue"].',
       );
       typeCheckFail(
         PropTypes.oneOf(['red', 'blue']),
         [],
         'Invalid prop `testProp` of value `` supplied to `testComponent`, ' +
-        'expected one of ["red","blue"].'
+          'expected one of ["red","blue"].',
       );
       typeCheckFail(
         PropTypes.oneOf(['red', 'blue']),
         '',
         'Invalid prop `testProp` of value `` supplied to `testComponent`, ' +
-        'expected one of ["red","blue"].'
+          'expected one of ["red","blue"].',
       );
       typeCheckFail(
         PropTypes.oneOf([0, 'false']),
         false,
         'Invalid prop `testProp` of value `false` supplied to ' +
-        '`testComponent`, expected one of [0,"false"].'
+          '`testComponent`, expected one of [0,"false"].',
       );
     });
 
-    it('should not warn for valid values', function() {
+    it('should not warn for valid values', () => {
       typeCheckPass(PropTypes.oneOf(['red', 'blue']), 'red');
       typeCheckPass(PropTypes.oneOf(['red', 'blue']), 'blue');
       typeCheckPass(PropTypes.oneOf(['red', 'blue', NaN]), NaN);
     });
 
-    it('should be implicitly optional and not warn without values', function() {
+    it('should be implicitly optional and not warn without values', () => {
       typeCheckPass(PropTypes.oneOf(['red', 'blue']), null);
       typeCheckPass(PropTypes.oneOf(['red', 'blue']), undefined);
     });
 
-    it('should warn for missing required values', function() {
-      typeCheckFail(
-        PropTypes.oneOf(['red', 'blue']).isRequired,
-        null,
-        requiredMessage
-      );
-      typeCheckFail(
-        PropTypes.oneOf(['red', 'blue']).isRequired,
-        undefined,
-        requiredMessage
-      );
+    it('should warn for missing required values', () => {
+      typeCheckFailRequiredValues(PropTypes.oneOf(['red', 'blue']).isRequired);
+    });
+
+    it('should warn if called manually in development', () => {
+      spyOn(console, 'error');
+      expectWarningInDevelopment(PropTypes.oneOf(['red', 'blue']), true);
+      expectWarningInDevelopment(PropTypes.oneOf(['red', 'blue']), null);
+      expectWarningInDevelopment(PropTypes.oneOf(['red', 'blue']), undefined);
     });
   });
 
-  describe('Union Types', function() {
-    it('should fail for invalid argument', function() {
-      typeCheckFail(
-        PropTypes.oneOfType(PropTypes.string, PropTypes.number),
-        'red',
-        'Invalid argument supplied to oneOfType, expected an instance of array.'
+  describe('Union Types', () => {
+    it('should warn but not error for invalid argument', () => {
+      spyOn(console, 'error');
+
+      PropTypes.oneOfType(PropTypes.string, PropTypes.number);
+
+      expect(console.error).toHaveBeenCalled();
+      expect(console.error.calls.argsFor(0)[0]).toContain(
+        'Invalid argument supplied to oneOfType, expected an instance of array.',
       );
+
+      typeCheckPass(PropTypes.oneOf(PropTypes.string, PropTypes.number), []);
     });
 
-    it('should warn if none of the types are valid', function() {
+    it('should warn if none of the types are valid', () => {
       typeCheckFail(
         PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
         [],
-        'Invalid prop `testProp` supplied to `testComponent`.'
+        'Invalid prop `testProp` supplied to `testComponent`.',
       );
 
       var checker = PropTypes.oneOfType([
@@ -654,15 +885,12 @@ describe('ReactPropTypes', function() {
       typeCheckFail(
         checker,
         {c: 1},
-        'Invalid prop `testProp` supplied to `testComponent`.'
+        'Invalid prop `testProp` supplied to `testComponent`.',
       );
     });
 
-    it('should not warn if one of the types are valid', function() {
-      var checker = PropTypes.oneOfType([
-        PropTypes.string,
-        PropTypes.number,
-      ]);
+    it('should not warn if one of the types are valid', () => {
+      var checker = PropTypes.oneOfType([PropTypes.string, PropTypes.number]);
       typeCheckPass(checker, null);
       typeCheckPass(checker, 'foo');
       typeCheckPass(checker, 123);
@@ -675,199 +903,254 @@ describe('ReactPropTypes', function() {
       typeCheckPass(checker, {b: 1});
     });
 
-    it('should be implicitly optional and not warn without values', function() {
+    it('should be implicitly optional and not warn without values', () => {
       typeCheckPass(
-        PropTypes.oneOfType([PropTypes.string, PropTypes.number]), null
+        PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+        null,
       );
       typeCheckPass(
-        PropTypes.oneOfType([PropTypes.string, PropTypes.number]), undefined
+        PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+        undefined,
       );
     });
 
-    it('should warn for missing required values', function() {
-      typeCheckFail(
+    it('should warn for missing required values', () => {
+      typeCheckFailRequiredValues(
         PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
+      );
+    });
+
+    it('should warn if called manually in development', () => {
+      spyOn(console, 'error');
+      expectWarningInDevelopment(
+        PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+        [],
+      );
+      expectWarningInDevelopment(
+        PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
         null,
-        requiredMessage
       );
-      typeCheckFail(
-        PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
+      expectWarningInDevelopment(
+        PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
         undefined,
-        requiredMessage
       );
     });
   });
 
-  describe('Shape Types', function() {
-    it('should warn for non objects', function() {
+  describe('Shape Types', () => {
+    it('should warn for non objects', () => {
       typeCheckFail(
         PropTypes.shape({}),
         'some string',
         'Invalid prop `testProp` of type `string` supplied to ' +
-        '`testComponent`, expected `object`.'
+          '`testComponent`, expected `object`.',
       );
       typeCheckFail(
         PropTypes.shape({}),
         ['array'],
         'Invalid prop `testProp` of type `array` supplied to ' +
-        '`testComponent`, expected `object`.'
+          '`testComponent`, expected `object`.',
       );
     });
 
-    it('should not warn for empty values', function() {
+    it('should not warn for empty values', () => {
       typeCheckPass(PropTypes.shape({}), undefined);
       typeCheckPass(PropTypes.shape({}), null);
       typeCheckPass(PropTypes.shape({}), {});
     });
 
-    it('should not warn for an empty object', function() {
+    it('should not warn for an empty object', () => {
       typeCheckPass(PropTypes.shape({}).isRequired, {});
     });
 
-    it('should not warn for non specified types', function() {
+    it('should not warn for non specified types', () => {
       typeCheckPass(PropTypes.shape({}), {key: 1});
     });
 
-    it('should not warn for valid types', function() {
+    it('should not warn for valid types', () => {
       typeCheckPass(PropTypes.shape({key: PropTypes.number}), {key: 1});
     });
 
-    it('should warn for required valid types', function() {
+    it('should warn for required valid types', () => {
       typeCheckFail(
         PropTypes.shape({key: PropTypes.number.isRequired}),
         {},
-        'Required prop `testProp.key` was not specified in `testComponent`.'
+        'The prop `testProp.key` is marked as required in `testComponent`, ' +
+          'but its value is `undefined`.',
       );
     });
 
-    it('should warn for the first required type', function() {
+    it('should warn for the first required type', () => {
       typeCheckFail(
         PropTypes.shape({
           key: PropTypes.number.isRequired,
           secondKey: PropTypes.number.isRequired,
         }),
         {},
-        'Required prop `testProp.key` was not specified in `testComponent`.'
+        'The prop `testProp.key` is marked as required in `testComponent`, ' +
+          'but its value is `undefined`.',
       );
     });
 
-    it('should warn for invalid key types', function() {
-      typeCheckFail(PropTypes.shape({key: PropTypes.number}),
+    it('should warn for invalid key types', () => {
+      typeCheckFail(
+        PropTypes.shape({key: PropTypes.number}),
         {key: 'abc'},
         'Invalid prop `testProp.key` of type `string` supplied to `testComponent`, ' +
-        'expected `number`.'
+          'expected `number`.',
       );
     });
 
-    it('should be implicitly optional and not warn without values', function() {
+    it('should be implicitly optional and not warn without values', () => {
       typeCheckPass(
-        PropTypes.shape(PropTypes.shape({key: PropTypes.number})), null
+        PropTypes.shape(PropTypes.shape({key: PropTypes.number})),
+        null,
       );
       typeCheckPass(
-        PropTypes.shape(PropTypes.shape({key: PropTypes.number})), undefined
+        PropTypes.shape(PropTypes.shape({key: PropTypes.number})),
+        undefined,
       );
     });
 
-    it('should warn for missing required values', function() {
-      typeCheckFail(
+    it('should warn for missing required values', () => {
+      typeCheckFailRequiredValues(
+        PropTypes.shape({key: PropTypes.number}).isRequired,
+      );
+    });
+
+    it('should warn if called manually in development', () => {
+      spyOn(console, 'error');
+      expectWarningInDevelopment(PropTypes.shape({}), 'some string');
+      expectWarningInDevelopment(PropTypes.shape({foo: PropTypes.number}), {
+        foo: 42,
+      });
+      expectWarningInDevelopment(
         PropTypes.shape({key: PropTypes.number}).isRequired,
         null,
-        requiredMessage
       );
-      typeCheckFail(
+      expectWarningInDevelopment(
         PropTypes.shape({key: PropTypes.number}).isRequired,
         undefined,
-        requiredMessage
       );
+      expectWarningInDevelopment(PropTypes.element, <div />);
+    });
+  });
+
+  describe('Symbol Type', () => {
+    it('should warn for non-symbol', () => {
+      typeCheckFail(
+        PropTypes.symbol,
+        'hello',
+        'Invalid prop `testProp` of type `string` supplied to ' +
+          '`testComponent`, expected `symbol`.',
+      );
+      typeCheckFail(
+        PropTypes.symbol,
+        function() {},
+        'Invalid prop `testProp` of type `function` supplied to ' +
+          '`testComponent`, expected `symbol`.',
+      );
+      typeCheckFail(
+        PropTypes.symbol,
+        {
+          '@@toStringTag': 'Katana',
+        },
+        'Invalid prop `testProp` of type `object` supplied to ' +
+          '`testComponent`, expected `symbol`.',
+      );
+    });
+
+    it('should not warn for a polyfilled Symbol', () => {
+      var CoreSymbol = require('core-js/library/es6/symbol');
+      typeCheckPass(PropTypes.symbol, CoreSymbol('core-js'));
     });
   });
 
-  describe('Custom validator', function() {
-    beforeEach(function() {
+  describe('Custom validator', () => {
+    beforeEach(() => {
       jest.resetModuleRegistry();
     });
 
-    it('should have been called with the right params', function() {
+    it('should have been called with the right params', () => {
       var spy = jasmine.createSpy();
-      Component = React.createClass({
-        propTypes: {num: spy},
+      Component = class extends React.Component {
+        static propTypes = {num: spy};
 
-        render: function() {
+        render() {
           return <div />;
-        },
-      });
+        }
+      };
 
       var instance = <Component num={5} />;
-      instance = ReactTestUtils.renderIntoDocument(instance);
+      ReactTestUtils.renderIntoDocument(instance);
 
-      expect(spy.argsForCall.length).toBe(2); // temp double validation
-      expect(spy.argsForCall[0][1]).toBe('num');
-      expect(spy.argsForCall[0][2]).toBe('Component');
+      expect(spy.calls.count()).toBe(1);
+      expect(spy.calls.argsFor(0)[1]).toBe('num');
     });
 
-    it('should have been called even if the prop is not present', function() {
+    it('should have been called even if the prop is not present', () => {
       var spy = jasmine.createSpy();
-      Component = React.createClass({
-        propTypes: {num: spy},
+      Component = class extends React.Component {
+        static propTypes = {num: spy};
 
-        render: function() {
+        render() {
           return <div />;
-        },
-      });
+        }
+      };
 
       var instance = <Component bla={5} />;
-      instance = ReactTestUtils.renderIntoDocument(instance);
+      ReactTestUtils.renderIntoDocument(instance);
 
-      expect(spy.argsForCall.length).toBe(2); // temp double validation
+      expect(spy.calls.count()).toBe(1);
+      expect(spy.calls.argsFor(0)[1]).toBe('num');
     });
 
-    it('should have received the validator\'s return value', function() {
+    it("should have received the validator's return value", () => {
       spyOn(console, 'error');
-
-      var spy = jasmine.createSpy().andCallFake(
-        function(props, propName, componentName) {
+      var spy = jasmine
+        .createSpy()
+        .and.callFake(function(props, propName, componentName) {
           if (props[propName] !== 5) {
             return new Error('num must be 5!');
           }
-        }
-      );
-      Component = React.createClass({
-        propTypes: {num: spy},
+        });
+      Component = class extends React.Component {
+        static propTypes = {num: spy};
 
-        render: function() {
+        render() {
           return <div />;
-        },
-      });
+        }
+      };
 
       var instance = <Component num={6} />;
-      instance = ReactTestUtils.renderIntoDocument(instance);
-      expect(console.error.argsForCall.length).toBe(1);
-      expect(console.error.argsForCall[0][0]).toBe(
-        'Warning: Failed propType: num must be 5!'
+      ReactTestUtils.renderIntoDocument(instance);
+      expect(console.error.calls.count()).toBe(1);
+      expect(
+        console.error.calls.argsFor(0)[0].replace(/\(at .+?:\d+\)/g, '(at **)'),
+      ).toBe(
+        'Warning: Failed prop type: num must be 5!\n' +
+          '    in Component (at **)',
       );
     });
 
-    it('should not warn if the validator returned null',
-      function() {
-        spyOn(console, 'error');
-
-        var spy = jasmine.createSpy().andCallFake(
-          function(props, propName, componentName) {
-            return null;
-          }
-        );
-        Component = React.createClass({
-          propTypes: {num: spy},
-
-          render: function() {
-            return <div />;
-          },
+    it('should not warn if the validator returned null', () => {
+      spyOn(console, 'error');
+      var spy = jasmine
+        .createSpy()
+        .and.callFake(function(props, propName, componentName) {
+          return null;
         });
+      Component = class extends React.Component {
+        static propTypes = {num: spy};
 
-        var instance = <Component num={5} />;
-        instance = ReactTestUtils.renderIntoDocument(instance);
-        expect(console.error.argsForCall.length).toBe(0);
-      }
-    );
+        render() {
+          return <div />;
+        }
+      };
+
+      var instance = <Component num={5} />;
+      ReactTestUtils.renderIntoDocument(instance);
+      expect(console.error.calls.count()).toBe(0);
+    });
   });
 });
diff --git a/src/isomorphic/deprecated/OrderedMap.js b/src/isomorphic/deprecated/OrderedMap.js
deleted file mode 100644
index 4336cdc38449..000000000000
--- a/src/isomorphic/deprecated/OrderedMap.js
+++ /dev/null
@@ -1,505 +0,0 @@
-/**
- * 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 OrderedMap
- */
-
-'use strict';
-
-var invariant = require('invariant');
-
-var PREFIX = 'key:';
-
-/**
- * Utility to extract a backing object from an initialization `Array`, allowing
- * the caller to assist in resolving the unique ID for each entry via the
- * `keyExtractor` callback. The `keyExtractor` must extract non-empty strings or
- * numbers.
- * @param {Array<Object!>} arr Array of items.
- * @param {function} keyExtractor Extracts a unique key from each item.
- * @return {Object} Map from unique key to originating value that the key was
- * extracted from.
- * @throws Exception if the initialization array has duplicate extracted keys.
- */
-function extractObjectFromArray(arr, keyExtractor) {
-  var normalizedObj = {};
-  for (var i = 0; i < arr.length; i++) {
-    var item = arr[i];
-    var key = keyExtractor(item);
-    assertValidPublicKey(key);
-    var normalizedKey = PREFIX + key;
-    invariant(
-      !(normalizedKey in normalizedObj),
-      'OrderedMap: IDs returned by the key extraction function must be unique.'
-    );
-    normalizedObj[normalizedKey] = item;
-  }
-  return normalizedObj;
-}
-
-/**
- * Utility class for mappings with ordering. This class is to be used in an
- * immutable manner. A `OrderedMap` is very much like the native JavaScript
- * object, where keys map to values via the `get()` function. Also, like the
- * native JavaScript object, there is an ordering associated with the mapping.
- * This class is helpful because it eliminates many of the pitfalls that come
- * with the native JavaScript ordered mappings. Specifically, there are
- * inconsistencies with numeric keys in some JavaScript implementations
- * (enumeration ordering). This class protects against those pitfalls and
- * provides functional utilities for dealing with these `OrderedMap`s.
- *
- * - TODO:
- * - orderedMergeExclusive: Merges mutually exclusive `OrderedMap`s.
- * - mapReverse().
- *
- * @class {OrderedMap}
- * @constructor {OrderedMap}
- * @param {Object} normalizedObj Object that is known to be a defensive copy of
- * caller supplied data. We require a defensive copy to guard against callers
- * mutating.  It is also assumed that the keys of `normalizedObj` have been
- * normalized and do not contain any numeric-appearing strings.
- * @param {number} computedLength The precomputed length of `_normalizedObj`
- * keys.
- * @private
- */
-function OrderedMapImpl(normalizedObj, computedLength) {
-  this._normalizedObj = normalizedObj;
-  this._computedPositions = null;
-  this.length = computedLength;
-}
-
-/**
- * Validates a "public" key - that is, one that the public facing API supplies.
- * The key is then normalized for internal storage. In order to be considered
- * valid, all keys must be non-empty, defined, non-null strings or numbers.
- *
- * @param {string?} key Validates that the key is suitable for use in a
- * `OrderedMap`.
- * @throws Error if key is not appropriate for use in `OrderedMap`.
- */
-function assertValidPublicKey(key) {
-  invariant(
-    key !== '' && (typeof key === 'string' || typeof key === 'number'),
-    'OrderedMap: Key must be non-empty, non-null string or number.'
-  );
-}
-
-/**
- * Validates that arguments to range operations are within the correct limits.
- *
- * @param {number} start Start of range.
- * @param {number} length Length of range.
- * @param {number} actualLen Actual length of range that should not be
- * exceeded.
- * @throws Error if range arguments are out of bounds.
- */
-function assertValidRangeIndices(start, length, actualLen) {
-  invariant(
-    typeof start === 'number' &&
-    typeof length === 'number' &&
-    length >= 0 &&
-    start >= 0 &&
-    start + length <= actualLen,
-    'OrderedMap: `mapRange` and `forEachRange` expect non-negative start and ' +
-    'length arguments within the bounds of the instance.'
-  );
-}
-
-/**
- * Merges two "normalized" objects (objects who's key have been normalized) into
- * a `OrderedMap`.
- *
- * @param {Object} a Object of key value pairs.
- * @param {Object} b Object of key value pairs.
- * @return {OrderedMap} new `OrderedMap` that results in merging `a` and `b`.
- */
-function _fromNormalizedObjects(a, b) {
-  // Second optional, both must be plain JavaScript objects.
-  invariant(
-    a && a.constructor === Object && (!b || b.constructor === Object),
-    'OrderedMap: Corrupted instance of OrderedMap detected.'
-  );
-
-  var newSet = {};
-  var length = 0;
-  var key;
-  for (key in a) {
-    if (a.hasOwnProperty(key)) {
-      newSet[key] = a[key];
-      length++;
-    }
-  }
-
-  for (key in b) {
-    if (b.hasOwnProperty(key)) {
-      // Increment length if not already added via first object (a)
-      if (!(key in newSet)) {
-        length++;
-      }
-      newSet[key] = b[key];
-    }
-  }
-  return new OrderedMapImpl(newSet, length);
-}
-
-/**
- * Methods for `OrderedMap` instances.
- *
- * @lends OrderedMap.prototype
- * TODO: Make this data structure lazy, unify with LazyArray.
- * TODO: Unify this with ImmutableObject - it is to be used immutably.
- * TODO: If so, consider providing `fromObject` API.
- * TODO: Create faster implementation of merging/mapping from original Array,
- * without having to first create an object - simply for the sake of merging.
- */
-var OrderedMapMethods = {
-
-  /**
-   * Returns whether or not a given key is present in the map.
-   *
-   * @param {string} key Valid string key to lookup membership for.
-   * @return {boolean} Whether or not `key` is a member of the map.
-   * @throws Error if provided known invalid key.
-   */
-  has: function(key) {
-    assertValidPublicKey(key);
-    var normalizedKey = PREFIX + key;
-    return normalizedKey in this._normalizedObj;
-  },
-
-  /**
-   * Returns the object for a given key, or `undefined` if not present. To
-   * distinguish an undefined entry vs not being in the set, use `has()`.
-   *
-   * @param {string} key String key to lookup the value for.
-   * @return {Object?} Object at key `key`, or undefined if not in map.
-   * @throws Error if provided known invalid key.
-   */
-  get: function(key) {
-    assertValidPublicKey(key);
-    var normalizedKey = PREFIX + key;
-    return this.has(key) ? this._normalizedObj[normalizedKey] : undefined;
-  },
-
-  /**
-   * Merges, appending new keys to the end of the ordering. Keys in `orderedMap`
-   * that are redundant with `this`, maintain the same ordering index that they
-   * had in `this`.  This is how standard JavaScript object merging would work.
-   * If you wish to prepend a `OrderedMap` to the beginning of another
-   * `OrderedMap` then simply reverse the order of operation. This is the analog
-   * to `merge(x, y)`.
-   *
-   * @param {OrderedMap} orderedMap OrderedMap to merge onto the end.
-   * @return {OrderedMap} New OrderedMap that represents the result of the
-   * merge.
-   */
-  merge: function(orderedMap) {
-    invariant(
-      orderedMap instanceof OrderedMapImpl,
-      'OrderedMap.merge(...): Expected an OrderedMap instance.'
-    );
-    return _fromNormalizedObjects(
-      this._normalizedObj,
-      orderedMap._normalizedObj
-    );
-  },
-
-  /**
-   * Functional map API. Returns a new `OrderedMap`.
-   *
-   * @param {Function} cb Callback to invoke for each item.
-   * @param {Object?=} context Context to invoke callback from.
-   * @return {OrderedMap} OrderedMap that results from mapping.
-   */
-  map: function(cb, context) {
-    return this.mapRange(cb, 0, this.length, context);
-  },
-
-  /**
-   * The callback `cb` is invoked with the arguments (item, key,
-   * indexInOriginal).
-   *
-   * @param {Function} cb Determines result for each item.
-   * @param {number} start Start index of map range.
-   * @param {end} length End index of map range.
-   * @param {*!?} context Context of callback invocation.
-   * @return {OrderedMap} OrderedMap resulting from mapping the range.
-   */
-  mapRange: function(cb, start, length, context) {
-    var thisSet = this._normalizedObj;
-    var newSet = {};
-    var i = 0;
-    assertValidRangeIndices(start, length, this.length);
-    var end = start + length - 1;
-    for (var key in thisSet) {
-      if (thisSet.hasOwnProperty(key)) {
-        if (i >= start) {
-          if (i > end) {
-            break;
-          }
-          var item = thisSet[key];
-          newSet[key] = cb.call(context, item, key.substr(PREFIX.length), i);
-        }
-        i++;
-      }
-    }
-    return new OrderedMapImpl(newSet, length);
-  },
-
-  /**
-   * Function filter API. Returns new `OrderedMap`.
-   *
-   * @param {Function} cb Callback to invoke for each item.
-   * @param {Object?=} context Context to invoke callback from.
-   * @return {OrderedMap} OrderedMap that results from filtering.
-   */
-  filter: function(cb, context) {
-    return this.filterRange(cb, 0, this.length, context);
-  },
-
-  /**
-   * The callback `cb` is invoked with the arguments (item, key,
-   * indexInOriginal).
-   *
-   * @param {Function} cb Returns true if item should be in result.
-   * @param {number} start Start index of filter range.
-   * @param {number} length End index of map range.
-   * @param {*!?} context Context of callback invocation.
-   * @return {OrderedMap} OrderedMap resulting from filtering the range.
-   */
-  filterRange: function(cb, start, length, context) {
-    var newSet = {};
-    var newSetLength = 0;
-    this.forEachRange(function(item, key, originalIndex) {
-      if (cb.call(context, item, key, originalIndex)) {
-        var normalizedKey = PREFIX + key;
-        newSet[normalizedKey] = item;
-        newSetLength++;
-      }
-    }, start, length);
-    return new OrderedMapImpl(newSet, newSetLength);
-  },
-
-  forEach: function(cb, context) {
-    this.forEachRange(cb, 0, this.length, context);
-  },
-
-  forEachRange: function(cb, start, length, context) {
-    assertValidRangeIndices(start, length, this.length);
-    var thisSet = this._normalizedObj;
-    var i = 0;
-    var end = start + length - 1;
-    for (var key in thisSet) {
-      if (thisSet.hasOwnProperty(key)) {
-        if (i >= start) {
-          if (i > end) {
-            break;
-          }
-          var item = thisSet[key];
-          cb.call(context, item, key.substr(PREFIX.length), i);
-        }
-        i++;
-      }
-    }
-  },
-
-  /**
-   * Even though `mapRange`/`forEachKeyRange` allow zero length mappings, we'll
-   * impose an additional restriction here that the length of mapping be greater
-   * than zero - the only reason is that there are many ways to express length
-   * zero in terms of two keys and that is confusing.
-   */
-  mapKeyRange: function(cb, startKey, endKey, context) {
-    var startIndex = this.indexOfKey(startKey);
-    var endIndex = this.indexOfKey(endKey);
-    invariant(
-      startIndex !== undefined && endIndex !== undefined,
-      'mapKeyRange must be given keys that are present.'
-    );
-    invariant(
-      endIndex >= startIndex,
-      'OrderedMap.mapKeyRange(...): `endKey` must not come before `startIndex`.'
-    );
-    return this.mapRange(cb, startIndex, (endIndex - startIndex) + 1, context);
-  },
-
-  forEachKeyRange: function(cb, startKey, endKey, context) {
-    var startIndex = this.indexOfKey(startKey);
-    var endIndex = this.indexOfKey(endKey);
-    invariant(
-      startIndex !== undefined && endIndex !== undefined,
-      'forEachKeyRange must be given keys that are present.'
-    );
-    invariant(
-      endIndex >= startIndex,
-      'OrderedMap.forEachKeyRange(...): `endKey` must not come before ' +
-      '`startIndex`.'
-    );
-    this.forEachRange(cb, startIndex, (endIndex - startIndex) + 1, context);
-  },
-
-  /**
-   * @param {number} pos Index to search for key at.
-   * @return {string|undefined} Either the key at index `pos` or undefined if
-   * not in map.
-   */
-  keyAtIndex: function(pos) {
-    var computedPositions = this._getOrComputePositions();
-    var keyAtPos = computedPositions.keyByIndex[pos];
-    return keyAtPos ? keyAtPos.substr(PREFIX.length) : undefined;
-  },
-
-  /**
-   * @param {string} key String key from which to find the next key.
-   * @return {string|undefined} Either the next key, or undefined if there is no
-   * next key.
-   * @throws Error if `key` is not in this `OrderedMap`.
-   */
-  keyAfter: function(key) {
-    return this.nthKeyAfter(key, 1);
-  },
-
-  /**
-   * @param {string} key String key from which to find the preceding key.
-   * @return {string|undefined} Either the preceding key, or undefined if there
-   * is no preceding.key.
-   * @throws Error if `key` is not in this `OrderedMap`.
-   */
-  keyBefore: function(key) {
-    return this.nthKeyBefore(key, 1);
-  },
-
-  /**
-   * @param {string} key String key from which to find a following key.
-   * @param {number} n Distance to scan forward after `key`.
-   * @return {string|undefined} Either the nth key after `key`, or undefined if
-   * there is no next key.
-   * @throws Error if `key` is not in this `OrderedMap`.
-   */
-  nthKeyAfter: function(key, n) {
-    var curIndex = this.indexOfKey(key);
-    invariant(
-      curIndex !== undefined,
-      'OrderedMap.nthKeyAfter: The key `%s` does not exist in this instance.',
-      key
-    );
-    return this.keyAtIndex(curIndex + n);
-  },
-
-  /**
-   * @param {string} key String key from which to find a preceding key.
-   * @param {number} n Distance to scan backwards before `key`.
-   * @return {string|undefined} Either the nth key before `key`, or undefined if
-   * there is no previous key.
-   * @throws Error if `key` is not in this `OrderedMap`.
-   */
-  nthKeyBefore: function(key, n) {
-    return this.nthKeyAfter(key, -n);
-  },
-
-  /**
-   * @param {string} key Key to find the index of.
-   * @return {number|undefined} Index of the provided key, or `undefined` if the
-   * key is not found.
-   */
-  indexOfKey: function(key) {
-    assertValidPublicKey(key);
-    var normalizedKey = PREFIX + key;
-    var computedPositions = this._getOrComputePositions();
-    var computedPosition = computedPositions.indexByKey[normalizedKey];
-    // Just writing it this way to make it clear this is intentional.
-    return computedPosition === undefined ? undefined : computedPosition;
-  },
-
-  /**
-   * @return {Array} An ordered array of this object's values.
-   */
-  toArray: function() {
-    var result = [];
-    var thisSet = this._normalizedObj;
-    for (var key in thisSet) {
-      if (thisSet.hasOwnProperty(key)) {
-        result.push(thisSet[key]);
-      }
-    }
-    return result;
-  },
-
-  /**
-   * Finds the key at a given position, or indicates via `undefined` that that
-   * position does not exist in the `OrderedMap`. It is appropriate to return
-   * undefined, indicating that the key doesn't exist in the `OrderedMap`
-   * because `undefined` is not ever a valid `OrderedMap` key.
-   *
-   * @private
-   * @return {string?} Name of the item at position `pos`, or `undefined` if
-   * there is no item at that position.
-   */
-  _getOrComputePositions: function() {
-    // TODO: Entertain computing this at construction time in some less
-    // performance critical paths.
-    var computedPositions = this._computedPositions;
-    if (!computedPositions) {
-      this._computePositions();
-    }
-    return this._computedPositions;
-  },
-
-  /**
-   * Precomputes the index/key mapping for future lookup. Since `OrderedMap`s
-   * are immutable, there is only ever a need to perform this once.
-   * @private
-   */
-  _computePositions: function() {
-    this._computedPositions = {
-      keyByIndex: {},
-      indexByKey: {},
-    };
-    var keyByIndex = this._computedPositions.keyByIndex;
-    var indexByKey = this._computedPositions.indexByKey;
-    var index = 0;
-    var thisSet = this._normalizedObj;
-    for (var key in thisSet) {
-      if (thisSet.hasOwnProperty(key)) {
-        keyByIndex[index] = key;
-        indexByKey[key] = index;
-        index++;
-      }
-    }
-  },
-};
-
-Object.assign(OrderedMapImpl.prototype, OrderedMapMethods);
-
-var OrderedMap = {
-  from: function(orderedMap) {
-    invariant(
-      orderedMap instanceof OrderedMapImpl,
-      'OrderedMap.from(...): Expected an OrderedMap instance.'
-    );
-    return _fromNormalizedObjects(orderedMap._normalizedObj, null);
-  },
-
-  fromArray: function(arr, keyExtractor) {
-    invariant(
-      Array.isArray(arr),
-      'OrderedMap.fromArray(...): First argument must be an array.'
-    );
-    invariant(
-      typeof keyExtractor === 'function',
-      'OrderedMap.fromArray(...): Second argument must be a function used ' +
-      'to determine the unique key for each entry.'
-    );
-    return new OrderedMapImpl(
-      extractObjectFromArray(arr, keyExtractor),
-      arr.length
-    );
-  },
-};
-
-module.exports = OrderedMap;
diff --git a/src/isomorphic/deprecated/ReactPropTransferer.js b/src/isomorphic/deprecated/ReactPropTransferer.js
deleted file mode 100644
index da009cafe0ac..000000000000
--- a/src/isomorphic/deprecated/ReactPropTransferer.js
+++ /dev/null
@@ -1,107 +0,0 @@
-/**
- * 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 ReactPropTransferer
- */
-
-'use strict';
-
-var emptyFunction = require('emptyFunction');
-var joinClasses = require('joinClasses');
-
-/**
- * Creates a transfer strategy that will merge prop values using the supplied
- * `mergeStrategy`. If a prop was previously unset, this just sets it.
- *
- * @param {function} mergeStrategy
- * @return {function}
- */
-function createTransferStrategy(mergeStrategy) {
-  return function(props, key, value) {
-    if (!props.hasOwnProperty(key)) {
-      props[key] = value;
-    } else {
-      props[key] = mergeStrategy(props[key], value);
-    }
-  };
-}
-
-var transferStrategyMerge = createTransferStrategy(function(a, b) {
-  // `merge` overrides the first object's (`props[key]` above) keys using the
-  // second object's (`value`) keys. An object's style's existing `propA` would
-  // get overridden. Flip the order here.
-  return Object.assign({}, b, a);
-});
-
-/**
- * Transfer strategies dictate how props are transferred by `transferPropsTo`.
- * NOTE: if you add any more exceptions to this list you should be sure to
- * update `cloneWithProps()` accordingly.
- */
-var TransferStrategies = {
-  /**
-   * Never transfer `children`.
-   */
-  children: emptyFunction,
-  /**
-   * Transfer the `className` prop by merging them.
-   */
-  className: createTransferStrategy(joinClasses),
-  /**
-   * Transfer the `style` prop (which is an object) by merging them.
-   */
-  style: transferStrategyMerge,
-};
-
-/**
- * Mutates the first argument by transferring the properties from the second
- * argument.
- *
- * @param {object} props
- * @param {object} newProps
- * @return {object}
- */
-function transferInto(props, newProps) {
-  for (var thisKey in newProps) {
-    if (!newProps.hasOwnProperty(thisKey)) {
-      continue;
-    }
-
-    var transferStrategy = TransferStrategies[thisKey];
-
-    if (transferStrategy && TransferStrategies.hasOwnProperty(thisKey)) {
-      transferStrategy(props, thisKey, newProps[thisKey]);
-    } else if (!props.hasOwnProperty(thisKey)) {
-      props[thisKey] = newProps[thisKey];
-    }
-  }
-  return props;
-}
-
-/**
- * ReactPropTransferer are capable of transferring props to another component
- * using a `transferPropsTo` method.
- *
- * @class ReactPropTransferer
- */
-var ReactPropTransferer = {
-
-  /**
-   * Merge two props objects using TransferStrategies.
-   *
-   * @param {object} oldProps original props (they take precedence)
-   * @param {object} newProps new props to merge in
-   * @return {object} a new object containing both sets of props merged.
-   */
-  mergeProps: function(oldProps, newProps) {
-    return transferInto(Object.assign({}, oldProps), newProps);
-  },
-
-};
-
-module.exports = ReactPropTransferer;
diff --git a/src/isomorphic/devtools/ReactInvalidSetStateWarningDevTool.js b/src/isomorphic/devtools/ReactInvalidSetStateWarningDevTool.js
deleted file mode 100644
index 74275187cb32..000000000000
--- a/src/isomorphic/devtools/ReactInvalidSetStateWarningDevTool.js
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * Copyright 2016-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 ReactInvalidSetStateWarningDevTool
- */
-
-'use strict';
-
-var warning = require('warning');
-
-if (__DEV__) {
-  var processingChildContext = false;
-
-  var warnInvalidSetState = function() {
-    warning(
-      !processingChildContext,
-      'setState(...): Cannot call setState() inside getChildContext()'
-    );
-  };
-}
-
-var ReactInvalidSetStateWarningDevTool = {
-  onBeginProcessingChildContext() {
-    processingChildContext = true;
-  },
-  onEndProcessingChildContext() {
-    processingChildContext = false;
-  },
-  onSetState() {
-    warnInvalidSetState();
-  },
-};
-
-module.exports = ReactInvalidSetStateWarningDevTool;
diff --git a/src/isomorphic/getNextDebugID.js b/src/isomorphic/getNextDebugID.js
new file mode 100644
index 000000000000..6e7ecb43b84a
--- /dev/null
+++ b/src/isomorphic/getNextDebugID.js
@@ -0,0 +1,21 @@
+/**
+ * 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 getNextDebugID
+ * @flow
+ */
+
+'use strict';
+
+var nextDebugID = 1;
+
+function getNextDebugID(): number {
+  return nextDebugID++;
+}
+
+module.exports = getNextDebugID;
diff --git a/src/isomorphic/hooks/ReactComponentTreeDevtool.js b/src/isomorphic/hooks/ReactComponentTreeDevtool.js
new file mode 100644
index 000000000000..8e9898e3c1e5
--- /dev/null
+++ b/src/isomorphic/hooks/ReactComponentTreeDevtool.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright 2016-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 ReactComponentTreeDevtool
+ */
+'use strict';
+
+// TODO remove this proxy when RN/www gets updated
+module.exports = require('ReactComponentTreeHook');
diff --git a/src/isomorphic/hooks/ReactComponentTreeHook.js b/src/isomorphic/hooks/ReactComponentTreeHook.js
new file mode 100644
index 000000000000..6ff41657ab09
--- /dev/null
+++ b/src/isomorphic/hooks/ReactComponentTreeHook.js
@@ -0,0 +1,458 @@
+/**
+ * Copyright 2016-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.
+ *
+ * @flow
+ * @providesModule ReactComponentTreeHook
+ */
+
+'use strict';
+
+var ReactCurrentOwner = require('ReactCurrentOwner');
+
+var invariant = require('invariant');
+var warning = require('warning');
+
+import type {ReactElement, Source} from 'ReactElementType';
+import type {DebugID} from 'ReactInstanceType';
+
+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: DebugID): string {
+    return '.' + id;
+  };
+  var getIDFromKey = function(key: string): DebugID {
+    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: Array<DebugID> = [];
+
+function purgeDeep(id) {
+  var item = getItem(id);
+  if (item) {
+    var {childIDs} = item;
+    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: ?ReactElement): string {
+  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: DebugID): string {
+  var name = ReactComponentTreeHook.getDisplayName(id);
+  var element = ReactComponentTreeHook.getElement(id);
+  var ownerID = ReactComponentTreeHook.getOwnerID(id);
+  var ownerName;
+  if (ownerID) {
+    ownerName = ReactComponentTreeHook.getDisplayName(ownerID);
+  }
+  warning(
+    element,
+    'ReactComponentTreeHook: Missing React element for debugID %s when ' +
+      'building stack',
+    id,
+  );
+  return describeComponentFrame(name, element && element._source, ownerName);
+}
+
+var ReactComponentTreeHook = {
+  onSetChildren(id: DebugID, nextChildIDs: Array<DebugID>): void {
+    var item = getItem(id);
+    invariant(item, 'Item must have been set');
+    item.childIDs = nextChildIDs;
+
+    for (var i = 0; i < nextChildIDs.length; i++) {
+      var nextChildID = nextChildIDs[i];
+      var nextChild = getItem(nextChildID);
+      invariant(
+        nextChild,
+        'Expected hook events to fire for the child ' +
+          'before its parent includes it in onSetChildren().',
+      );
+      invariant(
+        nextChild.childIDs != null ||
+          typeof nextChild.element !== 'object' ||
+          nextChild.element == null,
+        'Expected onSetChildren() to fire for a container child ' +
+          'before its parent includes it in onSetChildren().',
+      );
+      invariant(
+        nextChild.isMounted,
+        'Expected onMountComponent() to fire for the child ' +
+          'before its parent includes it in onSetChildren().',
+      );
+      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.
+      }
+      invariant(
+        nextChild.parentID === id,
+        'Expected onBeforeMountComponent() parent and onSetChildren() to ' +
+          'be consistent (%s has parents %s and %s).',
+        nextChildID,
+        nextChild.parentID,
+        id,
+      );
+    }
+  },
+
+  onBeforeMountComponent(
+    id: DebugID,
+    element: ReactElement,
+    parentID: DebugID,
+  ): void {
+    var item = {
+      element,
+      parentID,
+      text: null,
+      childIDs: [],
+      isMounted: false,
+      updateCount: 0,
+    };
+    setItem(id, item);
+  },
+
+  onBeforeUpdateComponent(id: DebugID, element: ReactElement): void {
+    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(id: DebugID): void {
+    var item = getItem(id);
+    invariant(item, 'Item must have been set');
+    item.isMounted = true;
+    var isRoot = item.parentID === 0;
+    if (isRoot) {
+      addRoot(id);
+    }
+  },
+
+  onUpdateComponent(id: DebugID): void {
+    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(id: DebugID): void {
+    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(): void {
+    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(id: DebugID): boolean {
+    var item = getItem(id);
+    return item ? item.isMounted : false;
+  },
+
+  getCurrentStackAddendum(topElement: ?ReactElement): string {
+    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(id: ?DebugID): string {
+    var info = '';
+    while (id) {
+      info += describeID(id);
+      id = ReactComponentTreeHook.getParentID(id);
+    }
+    return info;
+  },
+
+  getChildIDs(id: DebugID): Array<DebugID> {
+    var item = getItem(id);
+    return item ? item.childIDs : [];
+  },
+
+  getDisplayName(id: DebugID): ?string {
+    var element = ReactComponentTreeHook.getElement(id);
+    if (!element) {
+      return null;
+    }
+    return getDisplayName(element);
+  },
+
+  getElement(id: DebugID): ?ReactElement {
+    var item = getItem(id);
+    return item ? item.element : null;
+  },
+
+  getOwnerID(id: DebugID): ?DebugID {
+    var element = ReactComponentTreeHook.getElement(id);
+    if (!element || !element._owner) {
+      return null;
+    }
+    return element._owner._debugID;
+  },
+
+  getParentID(id: DebugID): ?DebugID {
+    var item = getItem(id);
+    return item ? item.parentID : null;
+  },
+
+  getSource(id: DebugID): ?Source {
+    var item = getItem(id);
+    var element = item ? item.element : null;
+    var source = element != null ? element._source : null;
+    return source;
+  },
+
+  getText(id: DebugID): ?string {
+    var element = ReactComponentTreeHook.getElement(id);
+    if (typeof element === 'string') {
+      return element;
+    } else if (typeof element === 'number') {
+      return '' + element;
+    } else {
+      return null;
+    }
+  },
+
+  getUpdateCount(id: DebugID): number {
+    var item = getItem(id);
+    return item ? item.updateCount : 0;
+  },
+
+  getRootIDs,
+  getRegisteredIDs: getItemIDs,
+
+  pushNonStandardWarningStack(
+    isCreatingElement: boolean,
+    currentSource: ?Source,
+  ) {
+    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() {
+    if (typeof console.reactStackEnd !== 'function') {
+      return;
+    }
+    console.reactStackEnd();
+  },
+};
+
+module.exports = ReactComponentTreeHook;
diff --git a/src/isomorphic/modern/class/PropTypes.d.ts b/src/isomorphic/modern/class/PropTypes.d.ts
new file mode 100644
index 000000000000..a8802e66fe85
--- /dev/null
+++ b/src/isomorphic/modern/class/PropTypes.d.ts
@@ -0,0 +1,19 @@
+/*!
+ * Copyright 2015-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.
+ */
+
+/**
+ * TypeScript Definition File for React.
+ *
+ * Full type definitions are not yet officially supported. These are mostly
+ * just helpers for the unit test.
+ */
+
+declare module 'prop-types' {
+  export var string : any;
+}
diff --git a/src/isomorphic/modern/class/ReactBaseClasses.js b/src/isomorphic/modern/class/ReactBaseClasses.js
new file mode 100644
index 000000000000..ed8d31e9bc33
--- /dev/null
+++ b/src/isomorphic/modern/class/ReactBaseClasses.js
@@ -0,0 +1,159 @@
+/**
+ * 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 ReactBaseClasses
+ */
+
+'use strict';
+
+var ReactNoopUpdateQueue = require('ReactNoopUpdateQueue');
+
+var canDefineProperty = require('canDefineProperty');
+var emptyObject = require('emptyObject');
+var invariant = require('invariant');
+var lowPriorityWarning = require('lowPriorityWarning');
+
+/**
+ * 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) {
+  invariant(
+    typeof partialState === 'object' ||
+      typeof partialState === 'function' ||
+      partialState == null,
+    'setState(...): takes an object of state variables to update or a ' +
+      'function which returns an object of state variables.',
+  );
+  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 (__DEV__) {
+  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.
+Object.assign(ReactPureComponent.prototype, ReactComponent.prototype);
+ReactPureComponent.prototype.isPureReactComponent = true;
+
+module.exports = {
+  Component: ReactComponent,
+  PureComponent: ReactPureComponent,
+};
diff --git a/src/isomorphic/modern/class/ReactComponent.js b/src/isomorphic/modern/class/ReactComponent.js
deleted file mode 100644
index a775abd67dda..000000000000
--- a/src/isomorphic/modern/class/ReactComponent.js
+++ /dev/null
@@ -1,144 +0,0 @@
-/**
- * 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 ReactComponent
- */
-
-'use strict';
-
-var ReactNoopUpdateQueue = require('ReactNoopUpdateQueue');
-var ReactInstrumentation = require('ReactInstrumentation');
-
-var canDefineProperty = require('canDefineProperty');
-var emptyObject = require('emptyObject');
-var invariant = require('invariant');
-var warning = require('warning');
-
-/**
- * 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) {
-  invariant(
-    typeof partialState === 'object' ||
-    typeof partialState === 'function' ||
-    partialState == null,
-    'setState(...): takes an object of state variables to update or a ' +
-    'function which returns an object of state variables.'
-  );
-  if (__DEV__) {
-    ReactInstrumentation.debugTool.onSetState();
-    warning(
-      partialState != null,
-      'setState(...): You passed an undefined or null state object; ' +
-      'instead, use forceUpdate().'
-    );
-  }
-  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 (__DEV__) {
-  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() {
-          warning(
-            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]);
-    }
-  }
-}
-
-module.exports = ReactComponent;
diff --git a/src/isomorphic/modern/class/ReactNoopUpdateQueue.js b/src/isomorphic/modern/class/ReactNoopUpdateQueue.js
index 2f0be661c9b5..c9e03b723e54 100644
--- a/src/isomorphic/modern/class/ReactNoopUpdateQueue.js
+++ b/src/isomorphic/modern/class/ReactNoopUpdateQueue.js
@@ -13,16 +13,18 @@
 
 var warning = require('warning');
 
-function warnTDZ(publicInstance, callerName) {
+function warnNoop(publicInstance, callerName) {
   if (__DEV__) {
+    var constructor = publicInstance.constructor;
     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.',
+        '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,
-      publicInstance.constructor && publicInstance.constructor.displayName || ''
+      (constructor && (constructor.displayName || constructor.name)) ||
+        'ReactClass',
     );
   }
 }
@@ -31,7 +33,6 @@ function warnTDZ(publicInstance, callerName) {
  * 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.
@@ -51,7 +52,7 @@ var ReactNoopUpdateQueue = {
    * @param {?function} callback Called after state is updated.
    * @internal
    */
-  enqueueCallback: function(publicInstance, callback) { },
+  enqueueCallback: function(publicInstance, callback) {},
 
   /**
    * Forces an update. This should only be invoked when it is known with
@@ -67,7 +68,7 @@ var ReactNoopUpdateQueue = {
    * @internal
    */
   enqueueForceUpdate: function(publicInstance) {
-    warnTDZ(publicInstance, 'forceUpdate');
+    warnNoop(publicInstance, 'forceUpdate');
   },
 
   /**
@@ -82,7 +83,7 @@ var ReactNoopUpdateQueue = {
    * @internal
    */
   enqueueReplaceState: function(publicInstance, completeState) {
-    warnTDZ(publicInstance, 'replaceState');
+    warnNoop(publicInstance, 'replaceState');
   },
 
   /**
@@ -96,7 +97,7 @@ var ReactNoopUpdateQueue = {
    * @internal
    */
   enqueueSetState: function(publicInstance, partialState) {
-    warnTDZ(publicInstance, 'setState');
+    warnNoop(publicInstance, 'setState');
   },
 };
 
diff --git a/src/isomorphic/modern/class/__tests__/ReactClassEquivalence-test.js b/src/isomorphic/modern/class/__tests__/ReactClassEquivalence-test.js
index 36cf5c75ce6b..bfa6c3b21405 100644
--- a/src/isomorphic/modern/class/__tests__/ReactClassEquivalence-test.js
+++ b/src/isomorphic/modern/class/__tests__/ReactClassEquivalence-test.js
@@ -11,24 +11,64 @@
 
 'use strict';
 
-var MetaMatchers = require('MetaMatchers');
+var spawnSync = require('child_process').spawnSync;
+var path = require('path');
 
-describe('ReactClassEquivalence', function() {
+describe('ReactClassEquivalence', () => {
+  it('tests the same thing for es6 classes and CoffeeScript', () => {
+    var result1 = runJest('ReactCoffeeScriptClass-test.coffee');
+    var result2 = runJest('ReactES6Class-test.js');
+    compareResults(result1, result2);
+  });
 
-  beforeEach(function() {
-    this.addMatchers(MetaMatchers);
+  it('tests the same thing for es6 classes and TypeScript', () => {
+    var result1 = runJest('ReactTypeScriptClass-test.ts');
+    var result2 = runJest('ReactES6Class-test.js');
+    compareResults(result1, result2);
   });
+});
 
-  var es6 = () => require('./ReactES6Class-test.js');
-  var coffee = () => require('./ReactCoffeeScriptClass-test.coffee');
-  var ts = () => require('./ReactTypeScriptClass-test.ts');
+function runJest(testFile) {
+  var cwd = process.cwd();
+  var jestBin = path.resolve('node_modules', '.bin', 'jest');
+  var setupFile = path.resolve(
+    'scripts',
+    'jest',
+    'setupSpecEquivalenceReporter.js',
+  );
+  var result = spawnSync(
+    'node',
+    [jestBin, testFile, '--setupTestFrameworkScriptFile', setupFile],
+    {cwd},
+  );
 
-  it('tests the same thing for es6 classes and CoffeeScript', function() {
-    expect(coffee).toEqualSpecsIn(es6);
-  });
+  if (result.error) {
+    throw result.error;
+  }
 
-  it('tests the same thing for es6 classes and TypeScript', function() {
-    expect(ts).toEqualSpecsIn(es6);
-  });
+  if (result.status !== 0) {
+    throw new Error(
+      'jest process exited with: ' +
+        result.status +
+        '\n' +
+        'stdout: ' +
+        result.stdout.toString() +
+        'stderr: ' +
+        result.stderr.toString(),
+    );
+  }
 
-});
+  return result.stdout.toString();
+}
+
+function compareResults(a, b) {
+  var regexp = /EQUIVALENCE.*$/gm;
+  var aSpecs = (a.match(regexp) || []).sort().join('\n');
+  var bSpecs = (b.match(regexp) || []).sort().join('\n');
+
+  if (aSpecs.length === 0 && bSpecs.length === 0) {
+    throw new Error('No spec results found in the output');
+  }
+
+  expect(aSpecs).toEqual(bSpecs);
+}
diff --git a/src/isomorphic/modern/class/__tests__/ReactCoffeeScriptClass-test.coffee b/src/isomorphic/modern/class/__tests__/ReactCoffeeScriptClass-test.coffee
index e7b1f574c579..23661be18e54 100644
--- a/src/isomorphic/modern/class/__tests__/ReactCoffeeScriptClass-test.coffee
+++ b/src/isomorphic/modern/class/__tests__/ReactCoffeeScriptClass-test.coffee
@@ -7,6 +7,7 @@ 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.
 ###
 
+PropTypes = null
 React = null
 ReactDOM = null
 
@@ -21,6 +22,7 @@ describe 'ReactCoffeeScriptClass', ->
   beforeEach ->
     React = require 'React'
     ReactDOM = require 'ReactDOM'
+    PropTypes = require 'prop-types'
     container = document.createElement 'div'
     attachedListener = null
     renderedName = null
@@ -51,8 +53,9 @@ describe 'ReactCoffeeScriptClass', ->
     expect(->
       ReactDOM.render React.createElement(Foo), container
     ).toThrow()
-    expect(console.error.calls.length).toBe(1)
-    expect(console.error.argsForCall[0][0]).toContain('No `render` method found on the returned component instance')
+    expect(console.error.calls.count()).toBe(1)
+    expect(console.error.calls.argsFor(0)[0]).toContain('No `render` method found on the returned component instance')
+    undefined
 
   it 'renders a simple stateless component with prop', ->
     class Foo extends React.Component
@@ -62,6 +65,7 @@ describe 'ReactCoffeeScriptClass', ->
 
     test React.createElement(Foo, bar: 'foo'), 'DIV', 'foo'
     test React.createElement(Foo, bar: 'bar'), 'DIV', 'bar'
+    undefined
 
   it 'renders based on state using initial values in this.props', ->
     class Foo extends React.Component
@@ -74,6 +78,7 @@ describe 'ReactCoffeeScriptClass', ->
           className: @state.bar
 
     test React.createElement(Foo, initialValue: 'foo'), 'SPAN', 'foo'
+    undefined
 
   it 'renders based on state using props in the constructor', ->
     class Foo extends React.Component
@@ -94,12 +99,13 @@ describe 'ReactCoffeeScriptClass', ->
     instance = test React.createElement(Foo, initialValue: 'foo'), 'DIV', 'foo'
     instance.changeState()
     test React.createElement(Foo), 'SPAN', 'bar'
+    undefined
 
   it 'renders based on context in the constructor', ->
     class Foo extends React.Component
       @contextTypes:
-        tag: React.PropTypes.string
-        className: React.PropTypes.string
+        tag: PropTypes.string
+        className: PropTypes.string
 
       constructor: (props, context) ->
         super props, context
@@ -114,8 +120,8 @@ describe 'ReactCoffeeScriptClass', ->
 
     class Outer extends React.Component
       @childContextTypes:
-        tag: React.PropTypes.string
-        className: React.PropTypes.string
+        tag: PropTypes.string
+        className: PropTypes.string
 
       getChildContext: ->
         tag: 'span'
@@ -125,6 +131,7 @@ describe 'ReactCoffeeScriptClass', ->
         React.createElement Foo
 
     test React.createElement(Outer), 'SPAN', 'foo'
+    undefined
 
   it 'renders only once when setting state in componentWillMount', ->
     renderCount = 0
@@ -141,6 +148,7 @@ describe 'ReactCoffeeScriptClass', ->
 
     test React.createElement(Foo, initialValue: 'foo'), 'SPAN', 'bar'
     expect(renderCount).toBe 1
+    undefined
 
   it 'should throw with non-object in the initial state property', ->
     [['an array'], 'a string', 1234].forEach (state) ->
@@ -153,9 +161,10 @@ describe 'ReactCoffeeScriptClass', ->
 
       expect(->
         test React.createElement(Foo), 'span', ''
-      ).toThrow(
+      ).toThrowError(
         'Foo.state: must be set to an object or null'
       )
+    undefined
 
   it 'should render with null in the initial state property', ->
     class Foo extends React.Component
@@ -166,6 +175,7 @@ describe 'ReactCoffeeScriptClass', ->
         span()
 
     test React.createElement(Foo), 'SPAN', ''
+    undefined
 
   it 'setState through an event handler', ->
     class Foo extends React.Component
@@ -183,6 +193,7 @@ describe 'ReactCoffeeScriptClass', ->
     test React.createElement(Foo, initialValue: 'foo'), 'DIV', 'foo'
     attachedListener()
     expect(renderedName).toBe 'bar'
+    undefined
 
   it 'should not implicitly bind event handlers', ->
     class Foo extends React.Component
@@ -199,6 +210,7 @@ describe 'ReactCoffeeScriptClass', ->
 
     test React.createElement(Foo, initialValue: 'foo'), 'DIV', 'foo'
     expect(attachedListener).toThrow()
+    undefined
 
   it 'renders using forceUpdate even when there is no state', ->
     class Foo extends React.Component
@@ -217,6 +229,7 @@ describe 'ReactCoffeeScriptClass', ->
     test React.createElement(Foo, initialValue: 'foo'), 'DIV', 'foo'
     attachedListener()
     expect(renderedName).toBe 'bar'
+    undefined
 
   it 'will call all the normal life cycle methods', ->
     lifeCycles = []
@@ -266,6 +279,7 @@ describe 'ReactCoffeeScriptClass', ->
     lifeCycles = [] # reset
     ReactDOM.unmountComponentAtNode container
     expect(lifeCycles).toEqual ['will-unmount']
+    undefined
 
   it 'warns when classic properties are defined on the instance,
       but does not invoke them.', ->
@@ -292,19 +306,39 @@ describe 'ReactCoffeeScriptClass', ->
     test React.createElement(Foo), 'SPAN', 'foo'
     expect(getInitialStateWasCalled).toBe false
     expect(getDefaultPropsWasCalled).toBe false
-    expect(console.error.calls.length).toBe 4
-    expect(console.error.argsForCall[0][0]).toContain(
+    expect(console.error.calls.count()).toBe 4
+    expect(console.error.calls.argsFor(0)[0]).toContain(
       'getInitialState was defined on Foo, a plain JavaScript class.'
     )
-    expect(console.error.argsForCall[1][0]).toContain(
+    expect(console.error.calls.argsFor(1)[0]).toContain(
       'getDefaultProps was defined on Foo, a plain JavaScript class.'
     )
-    expect(console.error.argsForCall[2][0]).toContain(
+    expect(console.error.calls.argsFor(2)[0]).toContain(
       'propTypes was defined as an instance property on Foo.'
     )
-    expect(console.error.argsForCall[3][0]).toContain(
+    expect(console.error.calls.argsFor(3)[0]).toContain(
       'contextTypes was defined as an instance property on Foo.'
     )
+    undefined
+
+  it 'does not warn about getInitialState() on class components
+      if state is also defined.', ->
+    spyOn console, 'error'
+    class Foo extends React.Component
+      constructor: (props) ->
+        super props
+        @state = bar: @props.initialValue
+
+      getInitialState: ->
+        {}
+
+      render: ->
+        span
+          className: 'foo'
+
+    test React.createElement(Foo), 'SPAN', 'foo'
+    expect(console.error.calls.count()).toBe 0
+    undefined
 
   it 'should warn when misspelling shouldComponentUpdate', ->
     spyOn console, 'error'
@@ -317,12 +351,13 @@ describe 'ReactCoffeeScriptClass', ->
           className: 'foo'
 
     test React.createElement(NamedComponent), 'SPAN', 'foo'
-    expect(console.error.calls.length).toBe 1
-    expect(console.error.argsForCall[0][0]).toBe(
+    expect(console.error.calls.count()).toBe 1
+    expect(console.error.calls.argsFor(0)[0]).toBe(
       'Warning: NamedComponent 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.'
     )
+    undefined
 
   it 'should warn when misspelling componentWillReceiveProps', ->
     spyOn console, 'error'
@@ -335,44 +370,45 @@ describe 'ReactCoffeeScriptClass', ->
           className: 'foo'
 
     test React.createElement(NamedComponent), 'SPAN', 'foo'
-    expect(console.error.calls.length).toBe 1
-    expect(console.error.argsForCall[0][0]).toBe(
+    expect(console.error.calls.count()).toBe 1
+    expect(console.error.calls.argsFor(0)[0]).toBe(
       'Warning: NamedComponent has a method called componentWillRecieveProps().
        Did you mean componentWillReceiveProps()?'
     )
+    undefined
 
   it 'should throw AND warn when trying to access classic APIs', ->
-    spyOn console, 'error'
+    spyOn console, 'warn'
     instance =
       test Inner(name: 'foo'), 'DIV', 'foo'
     expect(-> instance.replaceState {}).toThrow()
     expect(-> instance.isMounted()).toThrow()
-    expect(-> instance.setProps name: 'bar').toThrow()
-    expect(-> instance.replaceProps name: 'bar').toThrow()
-    expect(console.error.calls.length).toBe 2
-    expect(console.error.argsForCall[0][0]).toContain(
+    expect(console.warn.calls.count()).toBe 2
+    expect(console.warn.calls.argsFor(0)[0]).toContain(
       'replaceState(...) is deprecated in plain JavaScript React classes'
     )
-    expect(console.error.argsForCall[1][0]).toContain(
+    expect(console.warn.calls.argsFor(1)[0]).toContain(
       'isMounted(...) is deprecated in plain JavaScript React classes'
     )
+    undefined
 
   it 'supports this.context passed via getChildContext', ->
     class Bar extends React.Component
       @contextTypes:
-        bar: React.PropTypes.string
+        bar: PropTypes.string
       render: ->
         div className: @context.bar
 
     class Foo extends React.Component
       @childContextTypes:
-        bar: React.PropTypes.string
+        bar: PropTypes.string
       getChildContext: ->
         bar: 'bar-through-context'
       render: ->
         React.createElement Bar
 
     test React.createElement(Foo), 'DIV', 'bar-through-context'
+    undefined
 
   it 'supports classic refs', ->
     class Foo extends React.Component
@@ -383,8 +419,10 @@ describe 'ReactCoffeeScriptClass', ->
 
     instance = test(React.createElement(Foo), 'DIV', 'foo')
     expect(instance.refs.inner.getName()).toBe 'foo'
+    undefined
 
   it 'supports drilling through to the DOM using findDOMNode', ->
     instance = test Inner(name: 'foo'), 'DIV', 'foo'
     node = ReactDOM.findDOMNode(instance)
     expect(node).toBe container.firstChild
+    undefined
diff --git a/src/isomorphic/modern/class/__tests__/ReactES6Class-test.js b/src/isomorphic/modern/class/__tests__/ReactES6Class-test.js
index 17a2414c53d2..ee63a7af70ab 100644
--- a/src/isomorphic/modern/class/__tests__/ReactES6Class-test.js
+++ b/src/isomorphic/modern/class/__tests__/ReactES6Class-test.js
@@ -11,11 +11,11 @@
 
 'use strict';
 
+var PropTypes;
 var React;
 var ReactDOM;
 
-describe('ReactES6Class', function() {
-
+describe('ReactES6Class', () => {
   var container;
   var freeze = function(expectation) {
     Object.freeze(expectation);
@@ -25,9 +25,10 @@ describe('ReactES6Class', function() {
   var attachedListener = null;
   var renderedName = null;
 
-  beforeEach(function() {
+  beforeEach(() => {
     React = require('React');
     ReactDOM = require('ReactDOM');
+    PropTypes = require('prop-types');
     container = document.createElement('div');
     attachedListener = null;
     renderedName = null;
@@ -51,24 +52,24 @@ describe('ReactES6Class', function() {
     return instance;
   }
 
-  it('preserves the name of the class for use in error messages', function() {
-    class Foo extends React.Component { }
+  it('preserves the name of the class for use in error messages', () => {
+    class Foo extends React.Component {}
     expect(Foo.name).toBe('Foo');
   });
 
-  it('throws if no render function is defined', function() {
+  it('throws if no render function is defined', () => {
     spyOn(console, 'error');
-    class Foo extends React.Component { }
+    class Foo extends React.Component {}
     expect(() => ReactDOM.render(<Foo />, container)).toThrow();
 
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
       'Warning: Foo(...): No `render` method found on the returned component ' +
-      'instance: you may have forgotten to define `render`.'
+        'instance: you may have forgotten to define `render`.',
     );
   });
 
-  it('renders a simple stateless component with prop', function() {
+  it('renders a simple stateless component with prop', () => {
     class Foo extends React.Component {
       render() {
         return <Inner name={this.props.bar} />;
@@ -78,7 +79,7 @@ describe('ReactES6Class', function() {
     test(<Foo bar="bar" />, 'DIV', 'bar');
   });
 
-  it('renders based on state using initial values in this.props', function() {
+  it('renders based on state using initial values in this.props', () => {
     class Foo extends React.Component {
       constructor(props) {
         super(props);
@@ -91,7 +92,7 @@ describe('ReactES6Class', function() {
     test(<Foo initialValue="foo" />, 'SPAN', 'foo');
   });
 
-  it('renders based on state using props in the constructor', function() {
+  it('renders based on state using props in the constructor', () => {
     class Foo extends React.Component {
       constructor(props) {
         super(props);
@@ -112,7 +113,7 @@ describe('ReactES6Class', function() {
     test(<Foo />, 'SPAN', 'bar');
   });
 
-  it('renders based on context in the constructor', function() {
+  it('renders based on context in the constructor', () => {
     class Foo extends React.Component {
       constructor(props, context) {
         super(props, context);
@@ -124,8 +125,8 @@ describe('ReactES6Class', function() {
       }
     }
     Foo.contextTypes = {
-      tag: React.PropTypes.string,
-      className: React.PropTypes.string,
+      tag: PropTypes.string,
+      className: PropTypes.string,
     };
 
     class Outer extends React.Component {
@@ -137,13 +138,13 @@ describe('ReactES6Class', function() {
       }
     }
     Outer.childContextTypes = {
-      tag: React.PropTypes.string,
-      className: React.PropTypes.string,
+      tag: PropTypes.string,
+      className: PropTypes.string,
     };
     test(<Outer />, 'SPAN', 'foo');
   });
 
-  it('renders only once when setting state in componentWillMount', function() {
+  it('renders only once when setting state in componentWillMount', () => {
     var renderCount = 0;
     class Foo extends React.Component {
       constructor(props) {
@@ -162,7 +163,7 @@ describe('ReactES6Class', function() {
     expect(renderCount).toBe(1);
   });
 
-  it('should throw with non-object in the initial state property', function() {
+  it('should throw with non-object in the initial state property', () => {
     [['an array'], 'a string', 1234].forEach(function(state) {
       class Foo extends React.Component {
         constructor() {
@@ -173,13 +174,13 @@ describe('ReactES6Class', function() {
           return <span />;
         }
       }
-      expect(() => test(<Foo />, 'span', '')).toThrow(
-        'Foo.state: must be set to an object or null'
+      expect(() => test(<Foo />, 'span', '')).toThrowError(
+        'Foo.state: must be set to an object or null',
       );
     });
   });
 
-  it('should render with null in the initial state property', function() {
+  it('should render with null in the initial state property', () => {
     class Foo extends React.Component {
       constructor() {
         super();
@@ -192,7 +193,7 @@ describe('ReactES6Class', function() {
     test(<Foo />, 'SPAN', '');
   });
 
-  it('setState through an event handler', function() {
+  it('setState through an event handler', () => {
     class Foo extends React.Component {
       constructor(props) {
         super(props);
@@ -203,10 +204,7 @@ describe('ReactES6Class', function() {
       }
       render() {
         return (
-          <Inner
-            name={this.state.bar}
-            onClick={this.handleClick.bind(this)}
-          />
+          <Inner name={this.state.bar} onClick={this.handleClick.bind(this)} />
         );
       }
     }
@@ -215,7 +213,7 @@ describe('ReactES6Class', function() {
     expect(renderedName).toBe('bar');
   });
 
-  it('should not implicitly bind event handlers', function() {
+  it('should not implicitly bind event handlers', () => {
     class Foo extends React.Component {
       constructor(props) {
         super(props);
@@ -225,19 +223,14 @@ describe('ReactES6Class', function() {
         this.setState({bar: 'bar'});
       }
       render() {
-        return (
-          <Inner
-            name={this.state.bar}
-            onClick={this.handleClick}
-          />
-        );
+        return <Inner name={this.state.bar} onClick={this.handleClick} />;
       }
     }
     test(<Foo initialValue="foo" />, 'DIV', 'foo');
     expect(attachedListener).toThrow();
   });
 
-  it('renders using forceUpdate even when there is no state', function() {
+  it('renders using forceUpdate even when there is no state', () => {
     class Foo extends React.Component {
       constructor(props) {
         super(props);
@@ -261,7 +254,7 @@ describe('ReactES6Class', function() {
     expect(renderedName).toBe('bar');
   });
 
-  it('will call all the normal life cycle methods', function() {
+  it('will call all the normal life cycle methods', () => {
     var lifeCycles = [];
     class Foo extends React.Component {
       constructor() {
@@ -295,26 +288,28 @@ describe('ReactES6Class', function() {
       }
     }
     test(<Foo value="foo" />, 'SPAN', 'foo');
-    expect(lifeCycles).toEqual([
-      'will-mount',
-      'did-mount',
-    ]);
+    expect(lifeCycles).toEqual(['will-mount', 'did-mount']);
     lifeCycles = []; // reset
     test(<Foo value="bar" />, 'SPAN', 'bar');
     expect(lifeCycles).toEqual([
-      'receive-props', freeze({value: 'bar'}),
-      'should-update', freeze({value: 'bar'}), {},
-      'will-update', freeze({value: 'bar'}), {},
-      'did-update', freeze({value: 'foo'}), {},
+      'receive-props',
+      freeze({value: 'bar'}),
+      'should-update',
+      freeze({value: 'bar'}),
+      {},
+      'will-update',
+      freeze({value: 'bar'}),
+      {},
+      'did-update',
+      freeze({value: 'foo'}),
+      {},
     ]);
     lifeCycles = []; // reset
     ReactDOM.unmountComponentAtNode(container);
-    expect(lifeCycles).toEqual([
-      'will-unmount',
-    ]);
+    expect(lifeCycles).toEqual(['will-unmount']);
   });
 
-  it('warns when classic properties are defined on the instance, but does not invoke them.', function() {
+  it('warns when classic properties are defined on the instance, but does not invoke them.', () => {
     spyOn(console, 'error');
     var getDefaultPropsWasCalled = false;
     var getInitialStateWasCalled = false;
@@ -339,22 +334,37 @@ describe('ReactES6Class', function() {
     test(<Foo />, 'SPAN', 'foo');
     expect(getInitialStateWasCalled).toBe(false);
     expect(getDefaultPropsWasCalled).toBe(false);
-    expect(console.error.calls.length).toBe(4);
-    expect(console.error.argsForCall[0][0]).toContain(
-      'getInitialState was defined on Foo, a plain JavaScript class.'
+    expect(console.error.calls.count()).toBe(4);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'getInitialState was defined on Foo, a plain JavaScript class.',
     );
-    expect(console.error.argsForCall[1][0]).toContain(
-      'getDefaultProps was defined on Foo, a plain JavaScript class.'
+    expect(console.error.calls.argsFor(1)[0]).toContain(
+      'getDefaultProps was defined on Foo, a plain JavaScript class.',
     );
-    expect(console.error.argsForCall[2][0]).toContain(
-      'propTypes was defined as an instance property on Foo.'
+    expect(console.error.calls.argsFor(2)[0]).toContain(
+      'propTypes was defined as an instance property on Foo.',
     );
-    expect(console.error.argsForCall[3][0]).toContain(
-      'contextTypes was defined as an instance property on Foo.'
+    expect(console.error.calls.argsFor(3)[0]).toContain(
+      'contextTypes was defined as an instance property on Foo.',
     );
   });
 
-  it('should warn when misspelling shouldComponentUpdate', function() {
+  it('does not warn about getInitialState() on class components if state is also defined.', () => {
+    spyOn(console, 'error');
+    class Foo extends React.Component {
+      state = this.getInitialState();
+      getInitialState() {
+        return {};
+      }
+      render() {
+        return <span className="foo" />;
+      }
+    }
+    test(<Foo />, 'SPAN', 'foo');
+    expect(console.error.calls.count()).toBe(0);
+  });
+
+  it('should warn when misspelling shouldComponentUpdate', () => {
     spyOn(console, 'error');
 
     class NamedComponent extends React.Component {
@@ -367,16 +377,16 @@ describe('ReactES6Class', function() {
     }
     test(<NamedComponent />, 'SPAN', 'foo');
 
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
       'Warning: ' +
-      'NamedComponent 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.'
+        'NamedComponent 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.',
     );
   });
 
-  it('should warn when misspelling componentWillReceiveProps', function() {
+  it('should warn when misspelling componentWillReceiveProps', () => {
     spyOn(console, 'error');
 
     class NamedComponent extends React.Component {
@@ -389,37 +399,35 @@ describe('ReactES6Class', function() {
     }
     test(<NamedComponent />, 'SPAN', 'foo');
 
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
       'Warning: ' +
-      'NamedComponent has a method called componentWillRecieveProps(). Did ' +
-      'you mean componentWillReceiveProps()?'
+        'NamedComponent has a method called componentWillRecieveProps(). Did ' +
+        'you mean componentWillReceiveProps()?',
     );
   });
 
-  it('should throw AND warn when trying to access classic APIs', function() {
-    spyOn(console, 'error');
+  it('should throw AND warn when trying to access classic APIs', () => {
+    spyOn(console, 'warn');
     var instance = test(<Inner name="foo" />, 'DIV', 'foo');
     expect(() => instance.replaceState({})).toThrow();
     expect(() => instance.isMounted()).toThrow();
-    expect(() => instance.setProps({name: 'bar'})).toThrow();
-    expect(() => instance.replaceProps({name: 'bar'})).toThrow();
-    expect(console.error.calls.length).toBe(2);
-    expect(console.error.argsForCall[0][0]).toContain(
-      'replaceState(...) is deprecated in plain JavaScript React classes'
+    expect(console.warn.calls.count()).toBe(2);
+    expect(console.warn.calls.argsFor(0)[0]).toContain(
+      'replaceState(...) is deprecated in plain JavaScript React classes',
     );
-    expect(console.error.argsForCall[1][0]).toContain(
-      'isMounted(...) is deprecated in plain JavaScript React classes'
+    expect(console.warn.calls.argsFor(1)[0]).toContain(
+      'isMounted(...) is deprecated in plain JavaScript React classes',
     );
   });
 
-  it('supports this.context passed via getChildContext', function() {
+  it('supports this.context passed via getChildContext', () => {
     class Bar extends React.Component {
       render() {
         return <div className={this.context.bar} />;
       }
     }
-    Bar.contextTypes = {bar: React.PropTypes.string};
+    Bar.contextTypes = {bar: PropTypes.string};
     class Foo extends React.Component {
       getChildContext() {
         return {bar: 'bar-through-context'};
@@ -428,11 +436,11 @@ describe('ReactES6Class', function() {
         return <Bar />;
       }
     }
-    Foo.childContextTypes = {bar: React.PropTypes.string};
+    Foo.childContextTypes = {bar: PropTypes.string};
     test(<Foo />, 'DIV', 'bar-through-context');
   });
 
-  it('supports classic refs', function() {
+  it('supports classic refs', () => {
     class Foo extends React.Component {
       render() {
         return <Inner name="foo" ref="inner" />;
@@ -442,10 +450,9 @@ describe('ReactES6Class', function() {
     expect(instance.refs.inner.getName()).toBe('foo');
   });
 
-  it('supports drilling through to the DOM using findDOMNode', function() {
+  it('supports drilling through to the DOM using findDOMNode', () => {
     var instance = test(<Inner name="foo" />, 'DIV', 'foo');
     var node = ReactDOM.findDOMNode(instance);
     expect(node).toBe(container.firstChild);
   });
-
 });
diff --git a/src/isomorphic/modern/class/__tests__/ReactPureComponent-test.js b/src/isomorphic/modern/class/__tests__/ReactPureComponent-test.js
new file mode 100644
index 000000000000..0cf7f751a7b7
--- /dev/null
+++ b/src/isomorphic/modern/class/__tests__/ReactPureComponent-test.js
@@ -0,0 +1,96 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var React;
+var ReactDOM;
+
+describe('ReactPureComponent', () => {
+  beforeEach(() => {
+    React = require('React');
+    ReactDOM = require('ReactDOM');
+  });
+
+  it('should render', () => {
+    var renders = 0;
+    class Component extends React.PureComponent {
+      constructor() {
+        super();
+        this.state = {type: 'mushrooms'};
+      }
+      render() {
+        renders++;
+        return <div>{this.props.text[0]}</div>;
+      }
+    }
+
+    var container = document.createElement('div');
+    var text;
+    var component;
+
+    text = ['porcini'];
+    component = ReactDOM.render(<Component text={text} />, container);
+    expect(container.textContent).toBe('porcini');
+    expect(renders).toBe(1);
+
+    text = ['morel'];
+    component = ReactDOM.render(<Component text={text} />, container);
+    expect(container.textContent).toBe('morel');
+    expect(renders).toBe(2);
+
+    text[0] = 'portobello';
+    component = ReactDOM.render(<Component text={text} />, container);
+    expect(container.textContent).toBe('morel');
+    expect(renders).toBe(2);
+
+    // Setting state without changing it doesn't cause a rerender.
+    component.setState({type: 'mushrooms'});
+    expect(container.textContent).toBe('morel');
+    expect(renders).toBe(2);
+
+    // But changing state does.
+    component.setState({type: 'portobello mushrooms'});
+    expect(container.textContent).toBe('portobello');
+    expect(renders).toBe(3);
+  });
+
+  it('can override shouldComponentUpdate', () => {
+    var renders = 0;
+    class Component extends React.PureComponent {
+      render() {
+        renders++;
+        return <div />;
+      }
+      shouldComponentUpdate() {
+        return true;
+      }
+    }
+    var container = document.createElement('div');
+    ReactDOM.render(<Component />, container);
+    ReactDOM.render(<Component />, container);
+    expect(renders).toBe(2);
+  });
+
+  it('extends React.Component', () => {
+    var renders = 0;
+    class Component extends React.PureComponent {
+      render() {
+        expect(this instanceof React.Component).toBe(true);
+        expect(this instanceof React.PureComponent).toBe(true);
+        renders++;
+        return <div />;
+      }
+    }
+    ReactDOM.render(<Component />, document.createElement('div'));
+    expect(renders).toBe(1);
+  });
+});
diff --git a/src/isomorphic/modern/class/__tests__/ReactTypeScriptClass-test.ts b/src/isomorphic/modern/class/__tests__/ReactTypeScriptClass-test.ts
index 0078265bcb25..d7de7469d343 100644
--- a/src/isomorphic/modern/class/__tests__/ReactTypeScriptClass-test.ts
+++ b/src/isomorphic/modern/class/__tests__/ReactTypeScriptClass-test.ts
@@ -1,3 +1,7 @@
+/// <reference path="../PropTypes.d.ts" />
+/// <reference path="../React.d.ts" />
+/// <reference path="../ReactDOM.d.ts" />
+
 /*!
  * Copyright 2015-present, Facebook, Inc.
  * All rights reserved.
@@ -9,6 +13,7 @@
 
 import React = require('React');
 import ReactDOM = require('ReactDOM');
+import PropTypes = require('prop-types');
 
 // Before Each
 
@@ -82,8 +87,8 @@ class StateBasedOnProps extends React.Component {
 // it renders based on context in the constructor
 class StateBasedOnContext extends React.Component {
   static contextTypes = {
-    tag: React.PropTypes.string,
-    className: React.PropTypes.string
+    tag: PropTypes.string,
+    className: PropTypes.string
   };
   state = {
     tag: this.context.tag,
@@ -97,8 +102,8 @@ class StateBasedOnContext extends React.Component {
 
 class ProvideChildContextTypes extends React.Component {
   static childContextTypes = {
-    tag: React.PropTypes.string,
-    className: React.PropTypes.string
+    tag: PropTypes.string,
+    className: PropTypes.string
   };
   getChildContext() {
     return { tag: 'span', className: 'foo' };
@@ -275,13 +280,13 @@ class MisspelledComponent2 extends React.Component {
 
 // it supports this.context passed via getChildContext
 class ReadContext extends React.Component {
-  static contextTypes = { bar: React.PropTypes.string };
+  static contextTypes = { bar: PropTypes.string };
   render() {
     return React.createElement('div', { className: this.context.bar });
   }
 }
 class ProvideContext extends React.Component {
-  static childContextTypes = { bar: React.PropTypes.string };
+  static childContextTypes = { bar: PropTypes.string };
   getChildContext() {
     return { bar: 'bar-through-context' };
   }
@@ -316,8 +321,8 @@ describe('ReactTypeScriptClass', function() {
 
     expect(() => ReactDOM.render(React.createElement(Empty), container)).toThrow();
 
-    expect((<any>console.error).argsForCall.length).toBe(1);
-    expect((<any>console.error).argsForCall[0][0]).toBe(
+    expect((<any>console.error).calls.count()).toBe(1);
+    expect((<any>console.error).calls.argsFor(0)[0]).toBe(
       'Warning: Empty(...): No `render` method found on the returned ' +
       'component instance: you may have forgotten to define `render`.'
     );
@@ -358,15 +363,15 @@ describe('ReactTypeScriptClass', function() {
 
   it('should throw with non-object in the initial state property', function() {
     expect(() => test(React.createElement(ArrayState), 'span', ''))
-    .toThrow(
+    .toThrowError(
       'ArrayState.state: must be set to an object or null'
     );
     expect(() => test(React.createElement(StringState), 'span', ''))
-    .toThrow(
+    .toThrowError(
       'StringState.state: must be set to an object or null'
     );
     expect(() => test(React.createElement(NumberState), 'span', ''))
-    .toThrow(
+    .toThrowError(
       'NumberState.state: must be set to an object or null'
     );
   });
@@ -434,30 +439,48 @@ describe('ReactTypeScriptClass', function() {
     test(React.createElement(ClassicProperties), 'SPAN', 'foo');
     expect(getInitialStateWasCalled).toBe(false);
     expect(getDefaultPropsWasCalled).toBe(false);
-    expect((<any>console.error).argsForCall.length).toBe(4);
-    expect((<any>console.error).argsForCall[0][0]).toContain(
+    expect((<any>console.error).calls.count()).toBe(4);
+    expect((<any>console.error).calls.argsFor(0)[0]).toContain(
       'getInitialState was defined on ClassicProperties, ' +
       'a plain JavaScript class.'
     );
-    expect((<any>console.error).argsForCall[1][0]).toContain(
+    expect((<any>console.error).calls.argsFor(1)[0]).toContain(
       'getDefaultProps was defined on ClassicProperties, ' +
       'a plain JavaScript class.'
     );
-    expect((<any>console.error).argsForCall[2][0]).toContain(
+    expect((<any>console.error).calls.argsFor(2)[0]).toContain(
       'propTypes was defined as an instance property on ClassicProperties.'
     );
-    expect((<any>console.error).argsForCall[3][0]).toContain(
+    expect((<any>console.error).calls.argsFor(3)[0]).toContain(
       'contextTypes was defined as an instance property on ClassicProperties.'
     );
   });
 
+  it('does not warn about getInitialState() on class components ' +
+     'if state is also defined.', () => {
+    spyOn(console, 'error');
+
+    class Example extends React.Component {
+      state = {};
+      getInitialState() {
+        return {};
+      }
+      render() {
+        return React.createElement('span', {className: 'foo'});
+      }
+    }
+
+    test(React.createElement(Example), 'SPAN', 'foo');
+    expect((<any>console.error).calls.count()).toBe(0);
+  });
+
   it('should warn when misspelling shouldComponentUpdate', function() {
     spyOn(console, 'error');
 
     test(React.createElement(MisspelledComponent1), 'SPAN', 'foo');
 
-    expect((<any>console.error).argsForCall.length).toBe(1);
-    expect((<any>console.error).argsForCall[0][0]).toBe(
+    expect((<any>console.error).calls.count()).toBe(1);
+    expect((<any>console.error).calls.argsFor(0)[0]).toBe(
       'Warning: ' +
       'MisspelledComponent1 has a method called componentShouldUpdate(). Did ' +
       'you mean shouldComponentUpdate()? The name is phrased as a question ' +
@@ -470,8 +493,8 @@ describe('ReactTypeScriptClass', function() {
 
     test(React.createElement(MisspelledComponent2), 'SPAN', 'foo');
 
-    expect((<any>console.error).argsForCall.length).toBe(1);
-    expect((<any>console.error).argsForCall[0][0]).toBe(
+    expect((<any>console.error).calls.count()).toBe(1);
+    expect((<any>console.error).calls.argsFor(0)[0]).toBe(
       'Warning: ' +
       'MisspelledComponent2 has a method called componentWillRecieveProps(). ' +
       'Did you mean componentWillReceiveProps()?'
@@ -479,20 +502,18 @@ describe('ReactTypeScriptClass', function() {
   });
 
   it('should throw AND warn when trying to access classic APIs', function() {
-    spyOn(console, 'error');
+    spyOn(console, 'warn');
     var instance = test(
       React.createElement(Inner, {name: 'foo'}),
       'DIV','foo'
     );
     expect(() => instance.replaceState({})).toThrow();
     expect(() => instance.isMounted()).toThrow();
-    expect(() => instance.setProps({ name: 'bar' })).toThrow();
-    expect(() => instance.replaceProps({ name: 'bar' })).toThrow();
-    expect((<any>console.error).argsForCall.length).toBe(2);
-    expect((<any>console.error).argsForCall[0][0]).toContain(
+    expect((<any>console.warn).calls.count()).toBe(2);
+    expect((<any>console.warn).calls.argsFor(0)[0]).toContain(
       'replaceState(...) is deprecated in plain JavaScript React classes'
     );
-    expect((<any>console.error).argsForCall[1][0]).toContain(
+    expect((<any>console.warn).calls.argsFor(1)[0]).toContain(
       'isMounted(...) is deprecated in plain JavaScript React classes'
     );
   });
diff --git a/src/isomorphic/modern/element/__tests__/ReactJSXElement-test.js b/src/isomorphic/modern/element/__tests__/ReactJSXElement-test.js
index 95126ca11191..fc494b436ca6 100644
--- a/src/isomorphic/modern/element/__tests__/ReactJSXElement-test.js
+++ b/src/isomorphic/modern/element/__tests__/ReactJSXElement-test.js
@@ -15,10 +15,10 @@ var React;
 var ReactDOM;
 var ReactTestUtils;
 
-describe('ReactJSXElement', function() {
+describe('ReactJSXElement', () => {
   var Component;
 
-  beforeEach(function() {
+  beforeEach(() => {
     jest.resetModuleRegistry();
 
     React = require('React');
@@ -31,7 +31,7 @@ describe('ReactJSXElement', function() {
     };
   });
 
-  it('returns a complete element according to spec', function() {
+  it('returns a complete element according to spec', () => {
     var element = <Component />;
     expect(element.type).toBe(Component);
     expect(element.key).toBe(null);
@@ -41,7 +41,7 @@ describe('ReactJSXElement', function() {
     expect(element.props).toEqual(expectation);
   });
 
-  it('allows a lower-case to be passed as the string type', function() {
+  it('allows a lower-case to be passed as the string type', () => {
     var element = <div />;
     expect(element.type).toBe('div');
     expect(element.key).toBe(null);
@@ -51,7 +51,7 @@ describe('ReactJSXElement', function() {
     expect(element.props).toEqual(expectation);
   });
 
-  it('allows a string to be passed as the type', function() {
+  it('allows a string to be passed as the type', () => {
     var TagName = 'div';
     var element = <TagName />;
     expect(element.type).toBe('div');
@@ -62,12 +62,12 @@ describe('ReactJSXElement', function() {
     expect(element.props).toEqual(expectation);
   });
 
-  it('returns an immutable element', function() {
+  it('returns an immutable element', () => {
     var element = <Component />;
-    expect(() => element.type = 'div').toThrow();
+    expect(() => (element.type = 'div')).toThrow();
   });
 
-  it('does not reuse the object that is spread into props', function() {
+  it('does not reuse the object that is spread into props', () => {
     var config = {foo: 1};
     var element = <Component {...config} />;
     expect(element.props.foo).toBe(1);
@@ -75,59 +75,71 @@ describe('ReactJSXElement', function() {
     expect(element.props.foo).toBe(1);
   });
 
-  it('extracts key and ref from the rest of the props', function() {
+  it('extracts key and ref from the rest of the props', () => {
     var element = <Component key="12" ref="34" foo="56" />;
     expect(element.type).toBe(Component);
     expect(element.key).toBe('12');
     expect(element.ref).toBe('34');
-    var expectation = {foo:'56'};
+    var expectation = {foo: '56'};
     Object.freeze(expectation);
     expect(element.props).toEqual(expectation);
   });
 
-  it('coerces the key to a string', function() {
+  it('coerces the key to a string', () => {
     var element = <Component key={12} foo="56" />;
     expect(element.type).toBe(Component);
     expect(element.key).toBe('12');
     expect(element.ref).toBe(null);
-    var expectation = {foo:'56'};
+    var expectation = {foo: '56'};
     Object.freeze(expectation);
     expect(element.props).toEqual(expectation);
   });
 
-  it('merges JSX children onto the children prop', function() {
+  it('merges JSX children onto the children prop', () => {
     spyOn(console, 'error');
     var a = 1;
     var element = <Component children="text">{a}</Component>;
     expect(element.props.children).toBe(a);
-    expect(console.error.argsForCall.length).toBe(0);
+    expect(console.error.calls.count()).toBe(0);
   });
 
-  it('does not override children if no JSX children are provided', function() {
+  it('does not override children if no JSX children are provided', () => {
     spyOn(console, 'error');
     var element = <Component children="text" />;
     expect(element.props.children).toBe('text');
-    expect(console.error.argsForCall.length).toBe(0);
+    expect(console.error.calls.count()).toBe(0);
   });
 
-  it('overrides children if null is provided as a JSX child', function() {
+  it('overrides children if null is provided as a JSX child', () => {
     spyOn(console, 'error');
     var element = <Component children="text">{null}</Component>;
     expect(element.props.children).toBe(null);
-    expect(console.error.argsForCall.length).toBe(0);
+    expect(console.error.calls.count()).toBe(0);
   });
 
-  it('merges JSX children onto the children prop in an array', function() {
+  it('overrides children if undefined is provided as an argument', () => {
+    var element = <Component children="text">{undefined}</Component>;
+    expect(element.props.children).toBe(undefined);
+
+    var element2 = React.cloneElement(
+      <Component children="text" />,
+      {},
+      undefined,
+    );
+    expect(element2.props.children).toBe(undefined);
+  });
+
+  it('merges JSX children onto the children prop in an array', () => {
     spyOn(console, 'error');
     var a = 1;
     var b = 2;
     var c = 3;
     var element = <Component>{a}{b}{c}</Component>;
     expect(element.props.children).toEqual([1, 2, 3]);
-    expect(console.error.argsForCall.length).toBe(0);
+    expect(console.error.calls.count()).toBe(0);
   });
 
-  it('allows static methods to be called using the type property', function() {
+  it('allows static methods to be called using the type property', () => {
     spyOn(console, 'error');
 
     class StaticMethodComponent {
@@ -135,16 +147,16 @@ describe('ReactJSXElement', function() {
         return 'someReturnValue';
       }
       render() {
-        return <div></div>;
+        return <div />;
       }
     }
 
     var element = <StaticMethodComponent />;
     expect(element.type.someStaticMethod()).toBe('someReturnValue');
-    expect(console.error.argsForCall.length).toBe(0);
+    expect(console.error.calls.count()).toBe(0);
   });
 
-  it('identifies valid elements', function() {
+  it('identifies valid elements', () => {
     expect(React.isValidElement(<div />)).toEqual(true);
     expect(React.isValidElement(<Component />)).toEqual(true);
 
@@ -153,30 +165,27 @@ describe('ReactJSXElement', function() {
     expect(React.isValidElement({})).toEqual(false);
     expect(React.isValidElement('string')).toEqual(false);
     expect(React.isValidElement(Component)).toEqual(false);
-    expect(React.isValidElement({ type: 'div', props: {} })).toEqual(false);
+    expect(React.isValidElement({type: 'div', props: {}})).toEqual(false);
   });
 
-  it('is indistinguishable from a plain object', function() {
+  it('is indistinguishable from a plain object', () => {
     var element = <div className="foo" />;
     var object = {};
     expect(element.constructor).toBe(object.constructor);
   });
 
-  it('should use default prop value when removing a prop', function() {
+  it('should use default prop value when removing a prop', () => {
     Component.defaultProps = {fruit: 'persimmon'};
 
     var container = document.createElement('div');
-    var instance = ReactDOM.render(
-      <Component fruit="mango" />,
-      container
-    );
+    var instance = ReactDOM.render(<Component fruit="mango" />, container);
     expect(instance.props.fruit).toBe('mango');
 
     ReactDOM.render(<Component />, container);
     expect(instance.props.fruit).toBe('persimmon');
   });
 
-  it('should normalize props with default values', function() {
+  it('should normalize props with default values', () => {
     class NormalizingComponent extends React.Component {
       render() {
         return <span>{this.props.prop}</span>;
@@ -187,9 +196,9 @@ describe('ReactJSXElement', function() {
     var instance = ReactTestUtils.renderIntoDocument(<NormalizingComponent />);
     expect(instance.props.prop).toBe('testKey');
 
-    var inst2 =
-      ReactTestUtils.renderIntoDocument(<NormalizingComponent prop={null} />);
+    var inst2 = ReactTestUtils.renderIntoDocument(
+      <NormalizingComponent prop={null} />,
+    );
     expect(inst2.props.prop).toBe(null);
   });
-
 });
diff --git a/src/isomorphic/modern/element/__tests__/ReactJSXElementValidator-test.js b/src/isomorphic/modern/element/__tests__/ReactJSXElementValidator-test.js
index 1e2890e9f0fd..0502161aad8e 100644
--- a/src/isomorphic/modern/element/__tests__/ReactJSXElementValidator-test.js
+++ b/src/isomorphic/modern/element/__tests__/ReactJSXElementValidator-test.js
@@ -14,18 +14,26 @@
 // TODO: All these warnings should become static errors using Flow instead
 // of dynamic errors when using JSX with Flow.
 
+var PropTypes;
 var React;
+var ReactDOM;
 var ReactTestUtils;
 
-describe('ReactJSXElementValidator', function() {
+describe('ReactJSXElementValidator', () => {
+  function normalizeCodeLocInfo(str) {
+    return str && str.replace(/at .+?:\d+/g, 'at **');
+  }
+
   var Component;
   var RequiredPropComponent;
 
-  beforeEach(function() {
+  beforeEach(() => {
     jest.resetModuleRegistry();
 
     React = require('React');
+    ReactDOM = require('ReactDOM');
     ReactTestUtils = require('ReactTestUtils');
+    PropTypes = require('prop-types');
 
     Component = class extends React.Component {
       render() {
@@ -39,21 +47,21 @@ describe('ReactJSXElementValidator', function() {
       }
     };
     RequiredPropComponent.displayName = 'RequiredPropComponent';
-    RequiredPropComponent.propTypes = {prop: React.PropTypes.string.isRequired};
+    RequiredPropComponent.propTypes = {prop: PropTypes.string.isRequired};
   });
 
-  it('warns for keys for arrays of elements in children position', function() {
+  it('warns for keys for arrays of elements in children position', () => {
     spyOn(console, 'error');
 
     void <Component>{[<Component />, <Component />]}</Component>;
 
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
-      'Each child in an array or iterator should have a unique "key" prop.'
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'Each child in an array or iterator should have a unique "key" prop.',
     );
   });
 
-  it('warns for keys for arrays of elements with owner info', function() {
+  it('warns for keys for arrays of elements with owner info', () => {
     spyOn(console, 'error');
 
     class InnerComponent extends React.Component {
@@ -64,25 +72,21 @@ describe('ReactJSXElementValidator', function() {
 
     class ComponentWrapper extends React.Component {
       render() {
-        return (
-          <InnerComponent
-            childSet={[<Component />, <Component />]}
-          />
-        );
+        return <InnerComponent childSet={[<Component />, <Component />]} />;
       }
     }
 
     ReactTestUtils.renderIntoDocument(<ComponentWrapper />);
 
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
       'Each child in an array or iterator should have a unique "key" prop. ' +
-      'Check the render method of `InnerComponent`. ' +
-      'It was passed a child from ComponentWrapper. '
+        'Check the render method of `InnerComponent`. ' +
+        'It was passed a child from ComponentWrapper. ',
     );
   });
 
-  it('warns for keys for iterables of elements in rest args', function() {
+  it('warns for keys for iterables of elements in rest args', () => {
     spyOn(console, 'error');
 
     var iterable = {
@@ -99,21 +103,23 @@ describe('ReactJSXElementValidator', function() {
 
     void <Component>{iterable}</Component>;
 
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
-      'Each child in an array or iterator should have a unique "key" prop.'
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'Each child in an array or iterator should have a unique "key" prop.',
     );
   });
 
-  it('does not warns for arrays of elements with keys', function() {
+  it('does not warns for arrays of elements with keys', () => {
     spyOn(console, 'error');
 
-    void <Component>{[<Component key="#1" />, <Component key="#2" />]}</Component>;
+    void (
+      <Component>{[<Component key="#1" />, <Component key="#2" />]}</Component>
+    );
 
-    expect(console.error.argsForCall.length).toBe(0);
+    expect(console.error.calls.count()).toBe(0);
   });
 
-  it('does not warns for iterable elements with keys', function() {
+  it('does not warns for iterable elements with keys', () => {
     spyOn(console, 'error');
 
     var iterable = {
@@ -133,10 +139,10 @@ describe('ReactJSXElementValidator', function() {
 
     void <Component>{iterable}</Component>;
 
-    expect(console.error.argsForCall.length).toBe(0);
+    expect(console.error.calls.count()).toBe(0);
   });
 
-  it('does not warn for numeric keys in entry iterable as a child', function() {
+  it('does not warn for numeric keys in entry iterable as a child', () => {
     spyOn(console, 'error');
 
     var iterable = {
@@ -154,23 +160,23 @@ describe('ReactJSXElementValidator', function() {
 
     void <Component>{iterable}</Component>;
 
-    expect(console.error.argsForCall.length).toBe(0);
+    expect(console.error.calls.count()).toBe(0);
   });
 
-  it('does not warn when the element is directly as children', function() {
+  it('does not warn when the element is directly as children', () => {
     spyOn(console, 'error');
 
     void <Component><Component /><Component /></Component>;
 
-    expect(console.error.argsForCall.length).toBe(0);
+    expect(console.error.calls.count()).toBe(0);
   });
 
-  it('does not warn when the child array contains non-elements', function() {
+  it('does not warn when the child array contains non-elements', () => {
     spyOn(console, 'error');
 
     void <Component>{[{}, {}]}</Component>;
 
-    expect(console.error.argsForCall.length).toBe(0);
+    expect(console.error.calls.count()).toBe(0);
   });
 
   // TODO: These warnings currently come from the composite component, but
@@ -187,7 +193,7 @@ describe('ReactJSXElementValidator', function() {
       }
     }
     MyComp.propTypes = {
-      color: React.PropTypes.string,
+      color: PropTypes.string,
     };
     class ParentComp extends React.Component {
       render() {
@@ -195,10 +201,49 @@ describe('ReactJSXElementValidator', function() {
       }
     }
     ReactTestUtils.renderIntoDocument(<ParentComp />);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: Failed propType: ' +
-      'Invalid prop `color` of type `number` supplied to `MyComp`, ' +
-      'expected `string`. Check the render method of `ParentComp`.'
+    expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
+      'Warning: Failed prop type: ' +
+        'Invalid prop `color` of type `number` supplied to `MyComp`, ' +
+        'expected `string`.\n' +
+        '    in MyComp (at **)\n' +
+        '    in ParentComp (at **)',
+    );
+  });
+
+  it('should update component stack after receiving next element', () => {
+    spyOn(console, 'error');
+    function MyComp() {
+      return null;
+    }
+    MyComp.propTypes = {
+      color: PropTypes.string,
+    };
+    function MiddleComp(props) {
+      return <MyComp color={props.color} />;
+    }
+    function ParentComp(props) {
+      if (props.warn) {
+        // This element has a source thanks to JSX.
+        return <MiddleComp color={42} />;
+      }
+      // This element has no source.
+      return React.createElement(MiddleComp, {color: 'blue'});
+    }
+
+    var container = document.createElement('div');
+    ReactDOM.render(<ParentComp warn={false} />, container);
+    ReactDOM.render(<ParentComp warn={true} />, container);
+
+    expect(console.error.calls.count()).toBe(1);
+    // The warning should have the full stack with line numbers.
+    // If it doesn't, it means we're using information from the old element.
+    expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
+      'Warning: Failed prop type: ' +
+        'Invalid prop `color` of type `number` supplied to `MyComp`, ' +
+        'expected `string`.\n' +
+        '    in MyComp (at **)\n' +
+        '    in MiddleComp (at **)\n' +
+        '    in ParentComp (at **)',
     );
   });
 
@@ -213,78 +258,92 @@ describe('ReactJSXElementValidator', function() {
     void <Null />;
     void <True />;
     void <Num />;
-    expect(console.error.calls.length).toBe(4);
-    expect(console.error.argsForCall[0][0]).toContain(
-      'type should not be null, undefined, boolean, or number. It should be ' +
-      'a string (for DOM elements) or a ReactClass (for composite components).'
+    expect(console.error.calls.count()).toBe(4);
+    expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
+      'Warning: React.createElement: type is invalid -- expected a string ' +
+        '(for built-in components) or a class/function (for composite ' +
+        'components) but got: undefined. You likely forgot to export your ' +
+        "component from the file it's defined in. " +
+        'Check your code at **.',
     );
-    expect(console.error.argsForCall[1][0]).toContain(
-      'type should not be null, undefined, boolean, or number. It should be ' +
-      'a string (for DOM elements) or a ReactClass (for composite components).'
+    expect(normalizeCodeLocInfo(console.error.calls.argsFor(1)[0])).toBe(
+      'Warning: React.createElement: type is invalid -- expected a string ' +
+        '(for built-in components) or a class/function (for composite ' +
+        'components) but got: null. ' +
+        'Check your code at **.',
     );
-    expect(console.error.argsForCall[2][0]).toContain(
-      'type should not be null, undefined, boolean, or number. It should be ' +
-      'a string (for DOM elements) or a ReactClass (for composite components).'
+    expect(normalizeCodeLocInfo(console.error.calls.argsFor(2)[0])).toBe(
+      'Warning: React.createElement: type is invalid -- expected a string ' +
+        '(for built-in components) or a class/function (for composite ' +
+        'components) but got: boolean. ' +
+        'Check your code at **.',
     );
-    expect(console.error.argsForCall[3][0]).toContain(
-      'type should not be null, undefined, boolean, or number. It should be ' +
-      'a string (for DOM elements) or a ReactClass (for composite components).'
+    expect(normalizeCodeLocInfo(console.error.calls.argsFor(3)[0])).toBe(
+      'Warning: React.createElement: type is invalid -- expected a string ' +
+        '(for built-in components) or a class/function (for composite ' +
+        'components) but got: number. ' +
+        'Check your code at **.',
     );
     void <Div />;
-    expect(console.error.calls.length).toBe(4);
+    expect(console.error.calls.count()).toBe(4);
   });
 
-  it('should check default prop values', function() {
+  it('should check default prop values', () => {
     spyOn(console, 'error');
 
     RequiredPropComponent.defaultProps = {prop: null};
 
     ReactTestUtils.renderIntoDocument(<RequiredPropComponent />);
 
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: Failed propType: ' +
-      'Required prop `prop` was not specified in `RequiredPropComponent`.'
+    expect(console.error.calls.count()).toBe(1);
+    expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
+      'Warning: Failed prop type: The prop `prop` is marked as required in ' +
+        '`RequiredPropComponent`, but its value is `null`.\n' +
+        '    in RequiredPropComponent (at **)',
     );
   });
 
-  it('should not check the default for explicit null', function() {
+  it('should not check the default for explicit null', () => {
     spyOn(console, 'error');
 
     ReactTestUtils.renderIntoDocument(<RequiredPropComponent prop={null} />);
 
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: Failed propType: ' +
-      'Required prop `prop` was not specified in `RequiredPropComponent`.'
+    expect(console.error.calls.count()).toBe(1);
+    expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
+      'Warning: Failed prop type: The prop `prop` is marked as required in ' +
+        '`RequiredPropComponent`, but its value is `null`.\n' +
+        '    in RequiredPropComponent (at **)',
     );
   });
 
-  it('should check declared prop types', function() {
+  it('should check declared prop types', () => {
     spyOn(console, 'error');
 
     ReactTestUtils.renderIntoDocument(<RequiredPropComponent />);
     ReactTestUtils.renderIntoDocument(<RequiredPropComponent prop={42} />);
 
-    expect(console.error.calls.length).toBe(2);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: Failed propType: ' +
-      'Required prop `prop` was not specified in `RequiredPropComponent`.'
+    expect(console.error.calls.count()).toBe(2);
+    expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
+      'Warning: Failed prop type: ' +
+        'The prop `prop` is marked as required in `RequiredPropComponent`, but ' +
+        'its value is `undefined`.\n' +
+        '    in RequiredPropComponent (at **)',
     );
 
-    expect(console.error.argsForCall[1][0]).toBe(
-      'Warning: Failed propType: ' +
-      'Invalid prop `prop` of type `number` supplied to ' +
-      '`RequiredPropComponent`, expected `string`.'
+    expect(normalizeCodeLocInfo(console.error.calls.argsFor(1)[0])).toBe(
+      'Warning: Failed prop type: ' +
+        'Invalid prop `prop` of type `number` supplied to ' +
+        '`RequiredPropComponent`, expected `string`.\n' +
+        '    in RequiredPropComponent (at **)',
     );
 
     ReactTestUtils.renderIntoDocument(<RequiredPropComponent prop="string" />);
 
     // Should not error for strings
-    expect(console.error.calls.length).toBe(2);
+    expect(console.error.calls.count()).toBe(2);
   });
 
-  it('should warn on invalid prop types', function() {
+  it('should warn on invalid prop types', () => {
     // Since there is no prevalidation step for ES6 classes, there is no hook
     // for us to issue a warning earlier than element creation when the error
     // actually occurs. Since this step is skipped in production, we should just
@@ -299,14 +358,14 @@ describe('ReactJSXElementValidator', function() {
       prop: null,
     };
     ReactTestUtils.renderIntoDocument(<NullPropTypeComponent />);
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
       'NullPropTypeComponent: prop type `prop` is invalid; it must be a ' +
-      'function, usually from React.PropTypes.'
+        'function, usually from React.PropTypes.',
     );
   });
 
-  it('should warn on invalid context types', function() {
+  it('should warn on invalid context types', () => {
     spyOn(console, 'error');
     class NullContextTypeComponent extends React.Component {
       render() {
@@ -317,14 +376,14 @@ describe('ReactJSXElementValidator', function() {
       prop: null,
     };
     ReactTestUtils.renderIntoDocument(<NullContextTypeComponent />);
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
       'NullContextTypeComponent: context type `prop` is invalid; it must ' +
-      'be a function, usually from React.PropTypes.'
+        'be a function, usually from React.PropTypes.',
     );
   });
 
-  it('should warn if getDefaultProps is specificed on the class', function() {
+  it('should warn if getDefaultProps is specificed on the class', () => {
     spyOn(console, 'error');
     class GetDefaultPropsComponent extends React.Component {
       render() {
@@ -335,11 +394,61 @@ describe('ReactJSXElementValidator', function() {
       prop: 'foo',
     });
     ReactTestUtils.renderIntoDocument(<GetDefaultPropsComponent />);
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
       'getDefaultProps is only used on classic React.createClass definitions.' +
-      ' Use a static property named `defaultProps` instead.'
+        ' Use a static property named `defaultProps` instead.',
     );
   });
 
+  it('provides stack via non-standard console.reactStack for invalid types', () => {
+    spyOn(console, 'error');
+
+    function Foo() {
+      var Bad = undefined;
+      return <Bad />;
+    }
+
+    function App() {
+      return <div><Foo /></div>;
+    }
+
+    try {
+      console.reactStack = jest.fn();
+      console.reactStackEnd = jest.fn();
+
+      expect(() => {
+        ReactTestUtils.renderIntoDocument(<App />);
+      }).toThrow(
+        'Element type is invalid: expected a string (for built-in components) ' +
+          'or a class/function (for composite components) but got: undefined. ' +
+          "You likely forgot to export your component from the file it's " +
+          'defined in. Check the render method of `Foo`.',
+      );
+
+      expect(console.reactStack.mock.calls.length).toBe(1);
+      expect(console.reactStackEnd.mock.calls.length).toBe(1);
+
+      var stack = console.reactStack.mock.calls[0][0];
+      expect(Array.isArray(stack)).toBe(true);
+      expect(stack.map(frame => frame.name)).toEqual([
+        'Foo', // <Bad> is inside Foo
+        'App', // <Foo> is inside App
+        'App', // <div> is inside App
+        null, // <App> is outside a component
+      ]);
+      expect(
+        stack.map(frame => frame.fileName && frame.fileName.slice(-8)),
+      ).toEqual(['-test.js', '-test.js', '-test.js', '-test.js']);
+      expect(stack.map(frame => typeof frame.lineNumber)).toEqual([
+        'number',
+        'number',
+        'number',
+        'number',
+      ]);
+    } finally {
+      delete console.reactStack;
+      delete console.reactStackEnd;
+    }
+  });
 });
diff --git a/src/isomorphic/modern/types/__tests__/ReactFlowPropTypes-test.js b/src/isomorphic/modern/types/__tests__/ReactFlowPropTypes-test.js
deleted file mode 100644
index 986b918780ec..000000000000
--- a/src/isomorphic/modern/types/__tests__/ReactFlowPropTypes-test.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/**
- * Copyright 2014-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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-describe('ReactFlowPropTypes', function() {
-
-  // TODO: Test Flow integration and ensure that prop types works.
-
-});
diff --git a/src/isomorphic/modern/types/__tests__/ReactTypeScriptPropTypes-test.js b/src/isomorphic/modern/types/__tests__/ReactTypeScriptPropTypes-test.js
deleted file mode 100644
index 82a72b42849e..000000000000
--- a/src/isomorphic/modern/types/__tests__/ReactTypeScriptPropTypes-test.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/**
- * Copyright 2014-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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-describe('ReactTypeScriptPropTypes', function() {
-
-  // TODO: Test TypeScript integration and ensure that prop types works.
-
-});
diff --git a/src/node_modules/react/lib/getNextDebugID.js b/src/node_modules/react/lib/getNextDebugID.js
new file mode 100644
index 000000000000..e7e3d8ca6a01
--- /dev/null
+++ b/src/node_modules/react/lib/getNextDebugID.js
@@ -0,0 +1,9 @@
+/**
+ *  * Copyright 2016-present Facebook. All Rights Reserved.
+ *   *
+ *    * @flow
+ *     */
+
+'use strict';
+
+module.exports = require('getNextDebugID');
diff --git a/src/package.json b/src/package.json
index 8338c878d119..9d50d45d1be7 100644
--- a/src/package.json
+++ b/src/package.json
@@ -1,5 +1,5 @@
 {
   "name": "react-haste",
-  "version": "15.0.0-rc.2",
+  "version": "15.0.1",
   "license": "BSD-3-Clause"
 }
diff --git a/src/renderers/art/ReactART.js b/src/renderers/art/ReactART.js
new file mode 100644
index 000000000000..7550e330d29e
--- /dev/null
+++ b/src/renderers/art/ReactART.js
@@ -0,0 +1,630 @@
+/**
+ * Copyright (c) 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 ReactART
+ */
+
+'use strict';
+
+require('art/modes/current').setCurrent(
+  require('art/modes/fast-noSideEffects'), // Flip this to DOM mode for debugging
+);
+
+const Transform = require('art/core/transform');
+const Mode = require('art/modes/current');
+
+const React = require('React');
+const ReactDOM = require('ReactDOM');
+const ReactInstanceMap = require('ReactInstanceMap');
+const ReactMultiChild = require('ReactMultiChild');
+const ReactUpdates = require('ReactUpdates');
+
+const createReactClass = require('createClass');
+const emptyObject = require('emptyObject');
+const invariant = require('invariant');
+
+const assign = require('object-assign');
+const pooledTransform = new Transform();
+
+// Utilities
+
+function childrenAsString(children) {
+  if (!children) {
+    return '';
+  }
+  if (typeof children === 'string') {
+    return children;
+  }
+  if (children.length) {
+    return children.join('\n');
+  }
+  return '';
+}
+
+function createComponent(name) {
+  const ReactARTComponent = function(element) {
+    this.node = null;
+    this.subscriptions = null;
+    this.listeners = null;
+    this._mountImage = null;
+    this._renderedChildren = null;
+    this.construct(element);
+  };
+  ReactARTComponent.displayName = name;
+  for (let i = 1, l = arguments.length; i < l; i++) {
+    assign(ReactARTComponent.prototype, arguments[i]);
+  }
+
+  return ReactARTComponent;
+}
+
+/**
+ * Insert `node` into `parentNode` after `referenceNode`.
+ */
+function injectAfter(parentNode, referenceNode, node) {
+  let beforeNode;
+  if (
+    node.parentNode === parentNode &&
+    node.previousSibling === referenceNode
+  ) {
+    return;
+  }
+  if (referenceNode == null) {
+    // node is supposed to be first.
+    beforeNode = parentNode.firstChild;
+  } else {
+    // node is supposed to be after referenceNode.
+    beforeNode = referenceNode.nextSibling;
+  }
+  if (beforeNode && beforeNode.previousSibling !== node) {
+    // Cases where `node === beforeNode` should get filtered out by earlier
+    // checks and the behavior isn't well-defined.
+    invariant(
+      node !== beforeNode,
+      'ReactART: Can not insert node before itself',
+    );
+    node.injectBefore(beforeNode);
+  } else if (node.parentNode !== parentNode) {
+    node.inject(parentNode);
+  }
+}
+
+// ContainerMixin for components that can hold ART nodes
+
+const ContainerMixin = assign({}, ReactMultiChild.Mixin, {
+  /**
+   * Moves a child component to the supplied index.
+   *
+   * @param {ReactComponent} child Component to move.
+   * @param {number} toIndex Destination index of the element.
+   * @protected
+   */
+  moveChild: function(child, afterNode, toIndex, lastIndex) {
+    const childNode = child._mountImage;
+    injectAfter(this.node, afterNode, childNode);
+  },
+
+  /**
+   * Creates a child component.
+   *
+   * @param {ReactComponent} child Component to create.
+   * @param {object} childNode ART node to insert.
+   * @protected
+   */
+  createChild: function(child, afterNode, childNode) {
+    child._mountImage = childNode;
+    injectAfter(this.node, afterNode, childNode);
+  },
+
+  /**
+   * Removes a child component.
+   *
+   * @param {ReactComponent} child Child to remove.
+   * @protected
+   */
+  removeChild: function(child) {
+    child._mountImage.eject();
+    child._mountImage = null;
+  },
+
+  updateChildrenAtRoot: function(nextChildren, transaction) {
+    this.updateChildren(nextChildren, transaction, emptyObject);
+  },
+
+  mountAndInjectChildrenAtRoot: function(children, transaction) {
+    this.mountAndInjectChildren(children, transaction, emptyObject);
+  },
+
+  /**
+   * Override to bypass batch updating because it is not necessary.
+   *
+   * @param {?object} nextChildren.
+   * @param {ReactReconcileTransaction} transaction
+   * @internal
+   * @override {ReactMultiChild.Mixin.updateChildren}
+   */
+  updateChildren: function(nextChildren, transaction, context) {
+    this._updateChildren(nextChildren, transaction, context);
+  },
+
+  // Shorthands
+
+  mountAndInjectChildren: function(children, transaction, context) {
+    const mountedImages = this.mountChildren(children, transaction, context);
+    // Each mount image corresponds to one of the flattened children
+    let i = 0;
+    for (let key in this._renderedChildren) {
+      if (this._renderedChildren.hasOwnProperty(key)) {
+        const child = this._renderedChildren[key];
+        child._mountImage = mountedImages[i];
+        mountedImages[i].inject(this.node);
+        i++;
+      }
+    }
+  },
+});
+
+// Surface is a React DOM Component, not an ART component. It serves as the
+// entry point into the ART reconciler.
+
+const Surface = createReactClass({
+  displayName: 'Surface',
+
+  mixins: [ContainerMixin],
+
+  componentDidMount: function() {
+    const domNode = ReactDOM.findDOMNode(this);
+
+    this.node = Mode.Surface(+this.props.width, +this.props.height, domNode);
+
+    const transaction = ReactUpdates.ReactReconcileTransaction.getPooled();
+    transaction.perform(
+      this.mountAndInjectChildren,
+      this,
+      this.props.children,
+      transaction,
+      ReactInstanceMap.get(this)._context,
+    );
+    ReactUpdates.ReactReconcileTransaction.release(transaction);
+  },
+
+  componentDidUpdate: function(oldProps) {
+    const node = this.node;
+    if (
+      this.props.width != oldProps.width ||
+      this.props.height != oldProps.height
+    ) {
+      node.resize(+this.props.width, +this.props.height);
+    }
+
+    const transaction = ReactUpdates.ReactReconcileTransaction.getPooled();
+    transaction.perform(
+      this.updateChildren,
+      this,
+      this.props.children,
+      transaction,
+      ReactInstanceMap.get(this)._context,
+    );
+    ReactUpdates.ReactReconcileTransaction.release(transaction);
+
+    if (node.render) {
+      node.render();
+    }
+  },
+
+  componentWillUnmount: function() {
+    this.unmountChildren();
+  },
+
+  render: function() {
+    // This is going to be a placeholder because we don't know what it will
+    // actually resolve to because ART may render canvas, vml or svg tags here.
+    // We only allow a subset of properties since others might conflict with
+    // ART's properties.
+    const props = this.props;
+
+    // TODO: ART's Canvas Mode overrides surface title and cursor
+    const Tag = Mode.Surface.tagName;
+    return (
+      <Tag
+        className={props.className}
+        draggable={props.draggable}
+        role={props.role}
+        style={props.style}
+        title={props.title}
+      />
+    );
+  },
+});
+
+// Various nodes that can go into a surface
+
+const EventTypes = {
+  onMouseMove: 'mousemove',
+  onMouseOver: 'mouseover',
+  onMouseOut: 'mouseout',
+  onMouseUp: 'mouseup',
+  onMouseDown: 'mousedown',
+  onClick: 'click',
+};
+
+const NodeMixin = {
+  construct: function(element) {
+    this._currentElement = element;
+  },
+
+  getNativeNode: function() {
+    return this.node;
+  },
+
+  getPublicInstance: function() {
+    return this.node;
+  },
+
+  putEventListener: function(type, listener) {
+    const subscriptions = this.subscriptions || (this.subscriptions = {});
+    const listeners = this.listeners || (this.listeners = {});
+    listeners[type] = listener;
+    if (listener) {
+      if (!subscriptions[type]) {
+        subscriptions[type] = this.node.subscribe(type, listener, this);
+      }
+    } else {
+      if (subscriptions[type]) {
+        subscriptions[type]();
+        delete subscriptions[type];
+      }
+    }
+  },
+
+  handleEvent: function(event) {
+    const listener = this.listeners[event.type];
+    if (!listener) {
+      return;
+    }
+    if (typeof listener === 'function') {
+      listener.call(this, event);
+    } else if (listener.handleEvent) {
+      listener.handleEvent(event);
+    }
+  },
+
+  destroyEventListeners: function() {
+    const subscriptions = this.subscriptions;
+    if (subscriptions) {
+      for (let type in subscriptions) {
+        subscriptions[type]();
+      }
+    }
+    this.subscriptions = null;
+    this.listeners = null;
+  },
+
+  applyNodeProps: function(oldProps, props) {
+    const node = this.node;
+
+    const scaleX = props.scaleX != null
+      ? props.scaleX
+      : props.scale != null ? props.scale : 1;
+    const scaleY = props.scaleY != null
+      ? props.scaleY
+      : props.scale != null ? props.scale : 1;
+
+    pooledTransform
+      .transformTo(1, 0, 0, 1, 0, 0)
+      .move(props.x || 0, props.y || 0)
+      .rotate(props.rotation || 0, props.originX, props.originY)
+      .scale(scaleX, scaleY, props.originX, props.originY);
+
+    if (props.transform != null) {
+      pooledTransform.transform(props.transform);
+    }
+
+    if (
+      node.xx !== pooledTransform.xx ||
+      node.yx !== pooledTransform.yx ||
+      node.xy !== pooledTransform.xy ||
+      node.yy !== pooledTransform.yy ||
+      node.x !== pooledTransform.x ||
+      node.y !== pooledTransform.y
+    ) {
+      node.transformTo(pooledTransform);
+    }
+
+    if (props.cursor !== oldProps.cursor || props.title !== oldProps.title) {
+      node.indicate(props.cursor, props.title);
+    }
+
+    if (node.blend && props.opacity !== oldProps.opacity) {
+      node.blend(props.opacity == null ? 1 : props.opacity);
+    }
+
+    if (props.visible !== oldProps.visible) {
+      if (props.visible == null || props.visible) {
+        node.show();
+      } else {
+        node.hide();
+      }
+    }
+
+    for (let type in EventTypes) {
+      this.putEventListener(EventTypes[type], props[type]);
+    }
+  },
+
+  mountComponentIntoNode: function(rootID, container) {
+    throw new Error(
+      'You cannot render an ART component standalone. ' +
+        'You need to wrap it in a Surface.',
+    );
+  },
+};
+
+// Group
+
+const Group = createComponent('Group', NodeMixin, ContainerMixin, {
+  mountComponent: function(
+    transaction,
+    nativeParent,
+    nativeContainerInfo,
+    context,
+  ) {
+    this.node = Mode.Group();
+    const props = this._currentElement.props;
+    this.applyGroupProps(emptyObject, props);
+    this.mountAndInjectChildren(props.children, transaction, context);
+    return this.node;
+  },
+
+  receiveComponent: function(nextComponent, transaction, context) {
+    const props = nextComponent.props;
+    const oldProps = this._currentElement.props;
+    this.applyGroupProps(oldProps, props);
+    this.updateChildren(props.children, transaction, context);
+    this._currentElement = nextComponent;
+  },
+
+  applyGroupProps: function(oldProps, props) {
+    this.node.width = props.width;
+    this.node.height = props.height;
+    this.applyNodeProps(oldProps, props);
+  },
+
+  unmountComponent: function() {
+    this.destroyEventListeners();
+    this.unmountChildren();
+  },
+});
+
+// ClippingRectangle
+const ClippingRectangle = createComponent(
+  'ClippingRectangle',
+  NodeMixin,
+  ContainerMixin,
+  {
+    mountComponent: function(
+      transaction,
+      nativeParent,
+      nativeContainerInfo,
+      context,
+    ) {
+      this.node = Mode.ClippingRectangle();
+      const props = this._currentElement.props;
+      this.applyClippingProps(emptyObject, props);
+      this.mountAndInjectChildren(props.children, transaction, context);
+      return this.node;
+    },
+
+    receiveComponent: function(nextComponent, transaction, context) {
+      const props = nextComponent.props;
+      const oldProps = this._currentElement.props;
+      this.applyClippingProps(oldProps, props);
+      this.updateChildren(props.children, transaction, context);
+      this._currentElement = nextComponent;
+    },
+
+    applyClippingProps: function(oldProps, props) {
+      this.node.width = props.width;
+      this.node.height = props.height;
+      this.node.x = props.x;
+      this.node.y = props.y;
+      this.applyNodeProps(oldProps, props);
+    },
+
+    unmountComponent: function() {
+      this.destroyEventListeners();
+      this.unmountChildren();
+    },
+  },
+);
+
+// Renderables
+
+const RenderableMixin = assign({}, NodeMixin, {
+  applyRenderableProps: function(oldProps, props) {
+    if (oldProps.fill !== props.fill) {
+      if (props.fill && props.fill.applyFill) {
+        props.fill.applyFill(this.node);
+      } else {
+        this.node.fill(props.fill);
+      }
+    }
+    if (
+      oldProps.stroke !== props.stroke ||
+      oldProps.strokeWidth !== props.strokeWidth ||
+      oldProps.strokeCap !== props.strokeCap ||
+      oldProps.strokeJoin !== props.strokeJoin ||
+      // TODO: Consider a deep check of stokeDash.
+      // This may benefit the VML version in IE.
+      oldProps.strokeDash !== props.strokeDash
+    ) {
+      this.node.stroke(
+        props.stroke,
+        props.strokeWidth,
+        props.strokeCap,
+        props.strokeJoin,
+        props.strokeDash,
+      );
+    }
+    this.applyNodeProps(oldProps, props);
+  },
+
+  unmountComponent: function() {
+    this.destroyEventListeners();
+  },
+});
+
+// Shape
+
+const Shape = createComponent('Shape', RenderableMixin, {
+  construct: function(element) {
+    this._currentElement = element;
+    this._oldDelta = null;
+    this._oldPath = null;
+  },
+
+  mountComponent: function(
+    transaction,
+    nativeParent,
+    nativeContainerInfo,
+    context,
+  ) {
+    this.node = Mode.Shape();
+    const props = this._currentElement.props;
+    this.applyShapeProps(emptyObject, props);
+    return this.node;
+  },
+
+  receiveComponent: function(nextComponent, transaction, context) {
+    const props = nextComponent.props;
+    const oldProps = this._currentElement.props;
+    this.applyShapeProps(oldProps, props);
+    this._currentElement = nextComponent;
+  },
+
+  applyShapeProps: function(oldProps, props) {
+    const oldDelta = this._oldDelta;
+    const oldPath = this._oldPath;
+    const path = props.d || childrenAsString(props.children);
+
+    if (
+      path.delta !== oldDelta ||
+      path !== oldPath ||
+      oldProps.width !== props.width ||
+      oldProps.height !== props.height
+    ) {
+      this.node.draw(path, props.width, props.height);
+
+      this._oldPath = path;
+      this._oldDelta = path.delta;
+    }
+
+    this.applyRenderableProps(oldProps, props);
+  },
+});
+
+// Text
+
+const Text = createComponent('Text', RenderableMixin, {
+  construct: function(element) {
+    this._currentElement = element;
+    this._oldString = null;
+  },
+
+  mountComponent: function(
+    transaction,
+    nativeParent,
+    nativeContainerInfo,
+    context,
+  ) {
+    const props = this._currentElement.props;
+    const newString = childrenAsString(props.children);
+    this.node = Mode.Text(newString, props.font, props.alignment, props.path);
+    this._oldString = newString;
+    this.applyRenderableProps(emptyObject, props);
+    return this.node;
+  },
+
+  isSameFont: function(oldFont, newFont) {
+    if (oldFont === newFont) {
+      return true;
+    }
+    if (typeof newFont === 'string' || typeof oldFont === 'string') {
+      return false;
+    }
+    return (
+      newFont.fontSize === oldFont.fontSize &&
+      newFont.fontStyle === oldFont.fontStyle &&
+      newFont.fontVariant === oldFont.fontVariant &&
+      newFont.fontWeight === oldFont.fontWeight &&
+      newFont.fontFamily === oldFont.fontFamily
+    );
+  },
+
+  receiveComponent: function(nextComponent, transaction, context) {
+    const props = nextComponent.props;
+    const oldProps = this._currentElement.props;
+
+    const oldString = this._oldString;
+    const newString = childrenAsString(props.children);
+
+    if (
+      oldString !== newString ||
+      !this.isSameFont(oldProps.font, props.font) ||
+      oldProps.alignment !== props.alignment ||
+      oldProps.path !== props.path
+    ) {
+      this.node.draw(newString, props.font, props.alignment, props.path);
+      this._oldString = newString;
+    }
+
+    this.applyRenderableProps(oldProps, props);
+    this._currentElement = nextComponent;
+  },
+});
+
+// Declarative fill type objects - API design not finalized
+
+const slice = Array.prototype.slice;
+
+function LinearGradient(stops, x1, y1, x2, y2) {
+  this.args = slice.call(arguments);
+}
+
+LinearGradient.prototype.applyFill = function(node) {
+  node.fillLinear.apply(node, this.args);
+};
+
+function RadialGradient(stops, fx, fy, rx, ry, cx, cy) {
+  this.args = slice.call(arguments);
+}
+
+RadialGradient.prototype.applyFill = function(node) {
+  node.fillRadial.apply(node, this.args);
+};
+
+function Pattern(url, width, height, left, top) {
+  this.args = slice.call(arguments);
+}
+
+Pattern.prototype.applyFill = function(node) {
+  node.fillImage.apply(node, this.args);
+};
+
+module.exports = {
+  ClippingRectangle,
+  Group,
+  LinearGradient,
+  Path: Mode.Path,
+  Pattern,
+  RadialGradient,
+  Shape,
+  Surface,
+  Text,
+  Transform,
+};
diff --git a/src/renderers/art/__tests__/ReactART-test.js b/src/renderers/art/__tests__/ReactART-test.js
new file mode 100644
index 000000000000..7d9ce37ffefc
--- /dev/null
+++ b/src/renderers/art/__tests__/ReactART-test.js
@@ -0,0 +1,301 @@
+/**
+ * Copyright (c) 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.
+ *
+ * @emails react-core
+ */
+
+/*jslint evil: true */
+
+'use strict';
+
+var React = require('React');
+var ReactDOM = require('ReactDOM');
+var ReactTestUtils = require('ReactTestUtils');
+
+var Group;
+var Shape;
+var Surface;
+var TestComponent;
+
+var Missing = {};
+
+var ReactART = require('ReactART');
+var ARTSVGMode = require('art/modes/svg');
+var ARTCurrentMode = require('art/modes/current');
+
+function testDOMNodeStructure(domNode, expectedStructure) {
+  expect(domNode).toBeDefined();
+  expect(domNode.nodeName).toBe(expectedStructure.nodeName);
+  for (var prop in expectedStructure) {
+    if (!expectedStructure.hasOwnProperty(prop)) continue;
+    if (prop != 'nodeName' && prop != 'children') {
+      if (expectedStructure[prop] === Missing) {
+        expect(domNode.hasAttribute(prop)).toBe(false);
+      } else {
+        expect(domNode.getAttribute(prop)).toBe(expectedStructure[prop]);
+      }
+    }
+  }
+  if (expectedStructure.children) {
+    expectedStructure.children.forEach(function(subTree, index) {
+      testDOMNodeStructure(domNode.childNodes[index], subTree);
+    });
+  }
+}
+
+describe('ReactART', () => {
+  beforeEach(() => {
+    ARTCurrentMode.setCurrent(ARTSVGMode);
+
+    Group = ReactART.Group;
+    Shape = ReactART.Shape;
+    Surface = ReactART.Surface;
+
+    TestComponent = class extends React.Component {
+      render() {
+        var a = (
+          <Shape
+            d="M0,0l50,0l0,50l-50,0z"
+            fill={new ReactART.LinearGradient(['black', 'white'])}
+            key="a"
+            width={50}
+            height={50}
+            x={50}
+            y={50}
+            opacity={0.1}
+          />
+        );
+
+        var b = (
+          <Shape
+            fill="#3C5A99"
+            key="b"
+            scale={0.5}
+            x={50}
+            y={50}
+            title="This is an F"
+            cursor="pointer">
+            M64.564,38.583H54l0.008-5.834c0-3.035,0.293-4.666,4.657-4.666
+            h5.833V16.429h-9.33c-11.213,0-15.159,5.654-15.159,15.16v6.994
+            h-6.99v11.652h6.99v33.815H54V50.235h9.331L64.564,38.583z
+          </Shape>
+        );
+
+        var c = <Group key="c" />;
+
+        return (
+          <Surface width={150} height={200}>
+            <Group ref="group">
+              {this.props.flipped ? [b, a, c] : [a, b, c]}
+            </Group>
+          </Surface>
+        );
+      }
+    };
+  });
+
+  it('should have the correct lifecycle state', () => {
+    var instance = <TestComponent />;
+    instance = ReactTestUtils.renderIntoDocument(instance);
+    var group = instance.refs.group;
+    // Duck type test for an ART group
+    expect(typeof group.indicate).toBe('function');
+  });
+
+  it('should render a reasonable SVG structure in SVG mode', () => {
+    var instance = <TestComponent />;
+    instance = ReactTestUtils.renderIntoDocument(instance);
+
+    var expectedStructure = {
+      nodeName: 'svg',
+      width: '150',
+      height: '200',
+      children: [
+        {nodeName: 'defs'},
+        {
+          nodeName: 'g',
+          children: [
+            {
+              nodeName: 'defs',
+              children: [{nodeName: 'linearGradient'}],
+            },
+            {nodeName: 'path'},
+            {nodeName: 'path'},
+            {nodeName: 'g'},
+          ],
+        },
+      ],
+    };
+
+    var realNode = ReactDOM.findDOMNode(instance);
+    testDOMNodeStructure(realNode, expectedStructure);
+  });
+
+  it('should be able to reorder components', () => {
+    var container = document.createElement('div');
+    var instance = ReactDOM.render(
+      <TestComponent flipped={false} />,
+      container,
+    );
+
+    var expectedStructure = {
+      nodeName: 'svg',
+      children: [
+        {nodeName: 'defs'},
+        {
+          nodeName: 'g',
+          children: [
+            {nodeName: 'defs'},
+            {nodeName: 'path', opacity: '0.1'},
+            {nodeName: 'path', opacity: Missing},
+            {nodeName: 'g'},
+          ],
+        },
+      ],
+    };
+
+    var realNode = ReactDOM.findDOMNode(instance);
+    testDOMNodeStructure(realNode, expectedStructure);
+
+    ReactDOM.render(<TestComponent flipped={true} />, container);
+
+    var expectedNewStructure = {
+      nodeName: 'svg',
+      children: [
+        {nodeName: 'defs'},
+        {
+          nodeName: 'g',
+          children: [
+            {nodeName: 'defs'},
+            {nodeName: 'path', opacity: Missing},
+            {nodeName: 'path', opacity: '0.1'},
+            {nodeName: 'g'},
+          ],
+        },
+      ],
+    };
+
+    testDOMNodeStructure(realNode, expectedNewStructure);
+  });
+
+  it('should be able to reorder many components', () => {
+    var container = document.createElement('div');
+
+    class Component extends React.Component {
+      render() {
+        var chars = this.props.chars.split('');
+        return (
+          <Surface>
+            {chars.map(text => <Shape key={text} title={text} />)}
+          </Surface>
+        );
+      }
+    }
+
+    // Mini multi-child stress test: lots of reorders, some adds, some removes.
+    var before = 'abcdefghijklmnopqrst';
+    var after = 'mxhpgwfralkeoivcstzy';
+
+    var instance = ReactDOM.render(<Component chars={before} />, container);
+    var realNode = ReactDOM.findDOMNode(instance);
+    expect(realNode.textContent).toBe(before);
+
+    instance = ReactDOM.render(<Component chars={after} />, container);
+    expect(realNode.textContent).toBe(after);
+
+    ReactDOM.unmountComponentAtNode(container);
+  });
+
+  it('renders composite with lifecycle inside group', () => {
+    var mounted = false;
+
+    class CustomShape extends React.Component {
+      render() {
+        return <Shape />;
+      }
+
+      componentDidMount() {
+        mounted = true;
+      }
+    }
+
+    ReactTestUtils.renderIntoDocument(
+      <Surface>
+        <Group>
+          <CustomShape />
+        </Group>
+      </Surface>,
+    );
+    expect(mounted).toBe(true);
+  });
+
+  it('resolves refs before componentDidMount', () => {
+    class CustomShape extends React.Component {
+      render() {
+        return <Shape />;
+      }
+    }
+
+    var ref = null;
+
+    class Outer extends React.Component {
+      componentDidMount() {
+        ref = this.refs.test;
+      }
+
+      render() {
+        return (
+          <Surface>
+            <Group>
+              <CustomShape ref="test" />
+            </Group>
+          </Surface>
+        );
+      }
+    }
+
+    ReactTestUtils.renderIntoDocument(<Outer />);
+    expect(ref.constructor).toBe(CustomShape);
+  });
+
+  it('resolves refs before componentDidUpdate', () => {
+    class CustomShape extends React.Component {
+      render() {
+        return <Shape />;
+      }
+    }
+
+    var ref = {};
+
+    class Outer extends React.Component {
+      componentDidMount() {
+        ref = this.refs.test;
+      }
+
+      componentDidUpdate() {
+        ref = this.refs.test;
+      }
+
+      render() {
+        return (
+          <Surface>
+            <Group>
+              {this.props.mountCustomShape && <CustomShape ref="test" />}
+            </Group>
+          </Surface>
+        );
+      }
+    }
+
+    var container = document.createElement('div');
+    ReactDOM.render(<Outer />, container);
+    expect(ref).not.toBeDefined();
+    ReactDOM.render(<Outer mountCustomShape={true} />, container);
+    expect(ref.constructor).toBe(CustomShape);
+  });
+});
diff --git a/src/renderers/dom/ReactDOM.js b/src/renderers/dom/ReactDOM.js
index 75644b1209d8..4a56deda0f0b 100644
--- a/src/renderers/dom/ReactDOM.js
+++ b/src/renderers/dom/ReactDOM.js
@@ -16,23 +16,20 @@
 var ReactDOMComponentTree = require('ReactDOMComponentTree');
 var ReactDefaultInjection = require('ReactDefaultInjection');
 var ReactMount = require('ReactMount');
-var ReactPerf = require('ReactPerf');
 var ReactReconciler = require('ReactReconciler');
 var ReactUpdates = require('ReactUpdates');
 var ReactVersion = require('ReactVersion');
 
 var findDOMNode = require('findDOMNode');
-var getNativeComponentFromComposite = require('getNativeComponentFromComposite');
+var getHostComponentFromComposite = require('getHostComponentFromComposite');
 var renderSubtreeIntoContainer = require('renderSubtreeIntoContainer');
 var warning = require('warning');
 
 ReactDefaultInjection.inject();
 
-var render = ReactPerf.measure('React', 'render', ReactMount.render);
-
-var React = {
+var ReactDOM = {
   findDOMNode: findDOMNode,
-  render: render,
+  render: ReactMount.render,
   unmountComponentAtNode: ReactMount.unmountComponentAtNode,
   version: ReactVersion,
 
@@ -46,7 +43,8 @@ var React = {
 // 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') {
+  typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.inject === 'function'
+) {
   __REACT_DEVTOOLS_GLOBAL_HOOK__.inject({
     ComponentTree: {
       getClosestInstanceFromNode:
@@ -54,7 +52,7 @@ if (
       getNodeFromInstance: function(inst) {
         // inst is an internal instance (but could be a composite)
         if (inst._renderedComponent) {
-          inst = getNativeComponentFromComposite(inst);
+          inst = getHostComponentFromComposite(inst);
         }
         if (inst) {
           return ReactDOMComponentTree.getNodeFromInstance(inst);
@@ -68,74 +66,6 @@ if (
   });
 }
 
-if (__DEV__) {
-  var ExecutionEnvironment = require('ExecutionEnvironment');
-  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() {};
-    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.'
-    );
-
-    // 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;
 
-    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" />'
-    );
-
-    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.split,
-      String.prototype.trim,
-    ];
-
-    for (var i = 0; i < expectedFeatures.length; i++) {
-      if (!expectedFeatures[i]) {
-        warning(
-          false,
-          'One or more ES5 shims expected by React are not available: ' +
-          'https://fb.me/react-warning-polyfills'
-        );
-        break;
-      }
-    }
-  }
-}
 
-module.exports = React;
+module.exports = ReactDOM;
diff --git a/src/renderers/dom/__mocks__/ReactDOM.js b/src/renderers/dom/__mocks__/ReactDOM.js
new file mode 100644
index 000000000000..c5965c9ec91b
--- /dev/null
+++ b/src/renderers/dom/__mocks__/ReactDOM.js
@@ -0,0 +1,18 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+'use strict';
+
+var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
+
+var useFiber = ReactDOMFeatureFlags.useFiber;
+
+module.exports = useFiber
+  ? require('ReactDOMFiber')
+  : require.requireActual('ReactDOM');
diff --git a/src/renderers/dom/__tests__/ReactDOMProduction-test.js b/src/renderers/dom/__tests__/ReactDOMProduction-test.js
index dd5a96a98859..f2b4a7fc1251 100644
--- a/src/renderers/dom/__tests__/ReactDOMProduction-test.js
+++ b/src/renderers/dom/__tests__/ReactDOMProduction-test.js
@@ -8,16 +8,15 @@
  *
  * @emails react-core
  */
-
 'use strict';
 
-describe('ReactDOMProduction', function() {
+describe('ReactDOMProduction', () => {
   var oldProcess;
 
   var React;
   var ReactDOM;
 
-  beforeEach(function() {
+  beforeEach(() => {
     __DEV__ = false;
     oldProcess = process;
     global.process = {env: {NODE_ENV: 'production'}};
@@ -27,34 +26,34 @@ describe('ReactDOMProduction', function() {
     ReactDOM = require('ReactDOM');
   });
 
-  afterEach(function() {
+  afterEach(() => {
     __DEV__ = true;
     global.process = oldProcess;
   });
 
-  it('should use prod fbjs', function() {
+  it('should use prod fbjs', () => {
     var warning = require('warning');
 
     spyOn(console, 'error');
     warning(false, 'Do cows go moo?');
-    expect(console.error.argsForCall.length).toBe(0);
+    expect(console.error.calls.count()).toBe(0);
   });
 
-  it('should use prod React', function() {
+  it('should use prod React', () => {
     spyOn(console, 'error');
 
     // no key warning
     void <div>{[<span />]}</div>;
 
-    expect(console.error.argsForCall.length).toBe(0);
+    expect(console.error.calls.count()).toBe(0);
   });
 
-  it('should handle a simple flow', function() {
-    var Component = React.createClass({
-      render: function() {
+  it('should handle a simple flow', () => {
+    class Component extends React.Component {
+      render() {
         return <span>{this.props.children}</span>;
-      },
-    });
+      }
+    }
 
     var container = document.createElement('div');
     var inst = ReactDOM.render(
@@ -63,7 +62,7 @@ describe('ReactDOMProduction', function() {
         <Component key={2}>B</Component>
         <Component key={3}>C</Component>
       </div>,
-      container
+      container,
     );
 
     expect(container.firstChild).toBe(inst);
@@ -76,7 +75,7 @@ describe('ReactDOMProduction', function() {
         <Component key={1}>A</Component>
         <Component key={3}>C</Component>
       </div>,
-      container
+      container,
     );
 
     expect(inst.className).toBe('red');
@@ -87,4 +86,96 @@ describe('ReactDOMProduction', function() {
     expect(container.childNodes.length).toBe(0);
   });
 
+  it('should call lifecycle methods', () => {
+    var log = [];
+    class Component extends React.Component {
+      state = {y: 1};
+      shouldComponentUpdate(nextProps, nextState) {
+        log.push(['shouldComponentUpdate', nextProps, nextState]);
+        return nextProps.x !== this.props.x || nextState.y !== this.state.y;
+      }
+      componentWillMount() {
+        log.push(['componentWillMount']);
+      }
+      componentDidMount() {
+        log.push(['componentDidMount']);
+      }
+      componentWillReceiveProps(nextProps) {
+        log.push(['componentWillReceiveProps', nextProps]);
+      }
+      componentWillUpdate(nextProps, nextState) {
+        log.push(['componentWillUpdate', nextProps, nextState]);
+      }
+      componentDidUpdate(prevProps, prevState) {
+        log.push(['componentDidUpdate', prevProps, prevState]);
+      }
+      componentWillUnmount() {
+        log.push(['componentWillUnmount']);
+      }
+      render() {
+        log.push(['render']);
+        return null;
+      }
+    }
+
+    var container = document.createElement('div');
+    var inst = ReactDOM.render(<Component x={1} />, container);
+    expect(log).toEqual([
+      ['componentWillMount'],
+      ['render'],
+      ['componentDidMount'],
+    ]);
+    log = [];
+
+    inst.setState({y: 2});
+    expect(log).toEqual([
+      ['shouldComponentUpdate', {x: 1}, {y: 2}],
+      ['componentWillUpdate', {x: 1}, {y: 2}],
+      ['render'],
+      ['componentDidUpdate', {x: 1}, {y: 1}],
+    ]);
+    log = [];
+
+    inst.setState({y: 2});
+    expect(log).toEqual([['shouldComponentUpdate', {x: 1}, {y: 2}]]);
+    log = [];
+
+    ReactDOM.render(<Component x={2} />, container);
+    expect(log).toEqual([
+      ['componentWillReceiveProps', {x: 2}],
+      ['shouldComponentUpdate', {x: 2}, {y: 2}],
+      ['componentWillUpdate', {x: 2}, {y: 2}],
+      ['render'],
+      ['componentDidUpdate', {x: 1}, {y: 2}],
+    ]);
+    log = [];
+
+    ReactDOM.render(<Component x={2} />, container);
+    expect(log).toEqual([
+      ['componentWillReceiveProps', {x: 2}],
+      ['shouldComponentUpdate', {x: 2}, {y: 2}],
+    ]);
+    log = [];
+
+    ReactDOM.unmountComponentAtNode(container);
+    expect(log).toEqual([['componentWillUnmount']]);
+  });
+
+  it('should throw with an error code in production', () => {
+    expect(function() {
+      class Component extends React.Component {
+        render() {
+          return ['this is wrong'];
+        }
+      }
+
+      var container = document.createElement('div');
+      ReactDOM.render(<Component />, container);
+    }).toThrowError(
+      'Minified React error #109; visit ' +
+        'http://facebook.github.io/react/docs/error-decoder.html?invariant=109&args[]=Component' +
+        ' for the full message or use the non-minified dev environment' +
+        ' for full errors and additional helpful warnings.',
+    );
+  });
 });
diff --git a/src/renderers/dom/client/ReactBrowserEventEmitter.js b/src/renderers/dom/client/ReactBrowserEventEmitter.js
index dd7334f48463..e51837c11280 100644
--- a/src/renderers/dom/client/ReactBrowserEventEmitter.js
+++ b/src/renderers/dom/client/ReactBrowserEventEmitter.js
@@ -11,7 +11,6 @@
 
 'use strict';
 
-var EventConstants = require('EventConstants');
 var EventPluginRegistry = require('EventPluginRegistry');
 var ReactEventEmitterMixin = require('ReactEventEmitterMixin');
 var ViewportMetrics = require('ViewportMetrics');
@@ -85,8 +84,10 @@ var reactTopListenersCounter = 0;
 var topEventMapping = {
   topAbort: 'abort',
   topAnimationEnd: getVendorPrefixedEventName('animationend') || 'animationend',
-  topAnimationIteration: getVendorPrefixedEventName('animationiteration') || 'animationiteration',
-  topAnimationStart: getVendorPrefixedEventName('animationstart') || 'animationstart',
+  topAnimationIteration:
+    getVendorPrefixedEventName('animationiteration') || 'animationiteration',
+  topAnimationStart:
+    getVendorPrefixedEventName('animationstart') || 'animationstart',
   topBlur: 'blur',
   topCanPlay: 'canplay',
   topCanPlayThrough: 'canplaythrough',
@@ -143,7 +144,8 @@ var topEventMapping = {
   topTouchEnd: 'touchend',
   topTouchMove: 'touchmove',
   topTouchStart: 'touchstart',
-  topTransitionEnd: getVendorPrefixedEventName('transitionend') || 'transitionend',
+  topTransitionEnd:
+    getVendorPrefixedEventName('transitionend') || 'transitionend',
   topVolumeChange: 'volumechange',
   topWaiting: 'waiting',
   topWheel: 'wheel',
@@ -175,7 +177,6 @@ function getListeningForDocument(mountAt) {
  * @internal
  */
 var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
-
   /**
    * Injectable event backend
    */
@@ -187,7 +188,7 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
      */
     injectReactEventListener: function(ReactEventListener) {
       ReactEventListener.setHandleTopLevel(
-        ReactBrowserEventEmitter.handleTopLevel
+        ReactBrowserEventEmitter.handleTopLevel,
       );
       ReactBrowserEventEmitter.ReactEventListener = ReactEventListener;
     },
@@ -241,87 +242,82 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
     var dependencies =
       EventPluginRegistry.registrationNameDependencies[registrationName];
 
-    var topLevelTypes = EventConstants.topLevelTypes;
     for (var i = 0; i < dependencies.length; i++) {
       var dependency = dependencies[i];
-      if (!(
-            isListening.hasOwnProperty(dependency) &&
-            isListening[dependency]
-          )) {
-        if (dependency === topLevelTypes.topWheel) {
+      if (
+        !(isListening.hasOwnProperty(dependency) && isListening[dependency])
+      ) {
+        if (dependency === 'topWheel') {
           if (isEventSupported('wheel')) {
             ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
-              topLevelTypes.topWheel,
+              'topWheel',
               'wheel',
-              mountAt
+              mountAt,
             );
           } else if (isEventSupported('mousewheel')) {
             ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
-              topLevelTypes.topWheel,
+              'topWheel',
               'mousewheel',
-              mountAt
+              mountAt,
             );
           } else {
             // Firefox needs to capture a different mouse scroll event.
             // @see http://www.quirksmode.org/dom/events/tests/scroll.html
             ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
-              topLevelTypes.topWheel,
+              'topWheel',
               'DOMMouseScroll',
-              mountAt
+              mountAt,
             );
           }
-        } else if (dependency === topLevelTypes.topScroll) {
-
+        } else if (dependency === 'topScroll') {
           if (isEventSupported('scroll', true)) {
             ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
-              topLevelTypes.topScroll,
+              'topScroll',
               'scroll',
-              mountAt
+              mountAt,
             );
           } else {
             ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
-              topLevelTypes.topScroll,
+              'topScroll',
               'scroll',
-              ReactBrowserEventEmitter.ReactEventListener.WINDOW_HANDLE
+              ReactBrowserEventEmitter.ReactEventListener.WINDOW_HANDLE,
             );
           }
-        } else if (dependency === topLevelTypes.topFocus ||
-            dependency === topLevelTypes.topBlur) {
-
+        } else if (dependency === 'topFocus' || dependency === 'topBlur') {
           if (isEventSupported('focus', true)) {
             ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
-              topLevelTypes.topFocus,
+              'topFocus',
               'focus',
-              mountAt
+              mountAt,
             );
             ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
-              topLevelTypes.topBlur,
+              'topBlur',
               'blur',
-              mountAt
+              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(
-              topLevelTypes.topFocus,
+              'topFocus',
               'focusin',
-              mountAt
+              mountAt,
             );
             ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
-              topLevelTypes.topBlur,
+              'topBlur',
               'focusout',
-              mountAt
+              mountAt,
             );
           }
 
           // to make sure blur and focus event listeners are only attached once
-          isListening[topLevelTypes.topBlur] = true;
-          isListening[topLevelTypes.topFocus] = true;
+          isListening.topBlur = true;
+          isListening.topFocus = true;
         } else if (topEventMapping.hasOwnProperty(dependency)) {
           ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
             dependency,
             topEventMapping[dependency],
-            mountAt
+            mountAt,
           );
         }
 
@@ -334,7 +330,7 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
     return ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
       topLevelType,
       handlerBaseName,
-      handle
+      handle,
     );
   },
 
@@ -342,10 +338,23 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
     return ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
       topLevelType,
       handlerBaseName,
-      handle
+      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.
@@ -359,8 +368,7 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
    */
   ensureScrollValueMonitoring: function() {
     if (hasEventPageXY === undefined) {
-      hasEventPageXY =
-        document.createEvent && 'pageX' in document.createEvent('MouseEvent');
+      hasEventPageXY = ReactBrowserEventEmitter.supportsEventPageXY();
     }
     if (!hasEventPageXY && !isMonitoringScrollValue) {
       var refresh = ViewportMetrics.refreshScrollValues;
@@ -368,7 +376,6 @@ var ReactBrowserEventEmitter = Object.assign({}, ReactEventEmitterMixin, {
       isMonitoringScrollValue = true;
     }
   },
-
 });
 
 module.exports = ReactBrowserEventEmitter;
diff --git a/src/renderers/dom/client/ReactDOMComponentTree.js b/src/renderers/dom/client/ReactDOMComponentTree.js
index ec95b26c6322..88e2b4bf15d5 100644
--- a/src/renderers/dom/client/ReactDOMComponentTree.js
+++ b/src/renderers/dom/client/ReactDOMComponentTree.js
@@ -23,13 +23,25 @@ var internalInstanceKey =
   '__reactInternalInstance$' + Math.random().toString(36).slice(2);
 
 /**
- * Drill down (through composites and empty components) until we get a native or
- * native text component.
+ * 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 getRenderedNativeOrTextFromComponent(component) {
+function getRenderedHostOrTextFromComponent(component) {
   var rendered;
   while ((rendered = component._renderedComponent)) {
     component = rendered;
@@ -38,25 +50,25 @@ function getRenderedNativeOrTextFromComponent(component) {
 }
 
 /**
- * Populate `_nativeNode` on the rendered native/text component with the given
+ * 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 nativeInst = getRenderedNativeOrTextFromComponent(inst);
-  nativeInst._nativeNode = node;
-  node[internalInstanceKey] = nativeInst;
+  var hostInst = getRenderedHostOrTextFromComponent(inst);
+  hostInst._hostNode = node;
+  node[internalInstanceKey] = hostInst;
 }
 
 function uncacheNode(inst) {
-  var node = inst._nativeNode;
+  var node = inst._hostNode;
   if (node) {
     delete node[internalInstanceKey];
-    inst._nativeNode = null;
+    inst._hostNode = null;
   }
 }
 
 /**
- * Populate `_nativeNode` on each child of `inst`, assuming that the children
+ * 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
@@ -80,19 +92,14 @@ function precacheChildNodes(inst, node) {
       continue;
     }
     var childInst = children[name];
-    var childID = getRenderedNativeOrTextFromComponent(childInst)._domID;
-    if (childID == null) {
+    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 ((childNode.nodeType === 1 &&
-           childNode.getAttribute(ATTR_NAME) === String(childID)) ||
-          (childNode.nodeType === 8 &&
-           childNode.nodeValue === ' react-text: ' + childID + ' ') ||
-          (childNode.nodeType === 8 &&
-           childNode.nodeValue === ' react-empty: ' + childID + ' ')) {
+      if (shouldPrecacheNode(childNode, childID)) {
         precacheNode(childInst, childNode);
         continue outer;
       }
@@ -143,7 +150,7 @@ function getClosestInstanceFromNode(node) {
  */
 function getInstanceFromNode(node) {
   var inst = getClosestInstanceFromNode(node);
-  if (inst != null && inst._nativeNode === node) {
+  if (inst != null && inst._hostNode === node) {
     return inst;
   } else {
     return null;
@@ -158,32 +165,32 @@ function getNodeFromInstance(inst) {
   // Without this first invariant, passing a non-DOM-component triggers the next
   // invariant for a missing parent, which is super confusing.
   invariant(
-    inst._nativeNode !== undefined,
-    'getNodeFromInstance: Invalid argument.'
+    inst._hostNode !== undefined,
+    'getNodeFromInstance: Invalid argument.',
   );
 
-  if (inst._nativeNode) {
-    return inst._nativeNode;
+  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._nativeNode) {
+  while (!inst._hostNode) {
     parents.push(inst);
     invariant(
-      inst._nativeParent,
-      'React DOM tree root should always have a node reference.'
+      inst._hostParent,
+      'React DOM tree root should always have a node reference.',
     );
-    inst = inst._nativeParent;
+    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._nativeNode);
+    precacheChildNodes(inst, inst._hostNode);
   }
 
-  return inst._nativeNode;
+  return inst._hostNode;
 }
 
 var ReactDOMComponentTree = {
diff --git a/src/renderers/dom/client/ReactDOMIDOperations.js b/src/renderers/dom/client/ReactDOMIDOperations.js
index cb03d3f06adf..e24335341d81 100644
--- a/src/renderers/dom/client/ReactDOMIDOperations.js
+++ b/src/renderers/dom/client/ReactDOMIDOperations.js
@@ -13,13 +13,11 @@
 
 var DOMChildrenOperations = require('DOMChildrenOperations');
 var ReactDOMComponentTree = require('ReactDOMComponentTree');
-var ReactPerf = require('ReactPerf');
 
 /**
  * Operations used to process updates to DOM nodes.
  */
 var ReactDOMIDOperations = {
-
   /**
    * Updates a component's children by processing a series of updates.
    *
@@ -32,8 +30,4 @@ var ReactDOMIDOperations = {
   },
 };
 
-ReactPerf.measureMethods(ReactDOMIDOperations, 'ReactDOMIDOperations', {
-  dangerouslyProcessChildrenUpdates: 'dangerouslyProcessChildrenUpdates',
-});
-
 module.exports = ReactDOMIDOperations;
diff --git a/src/renderers/dom/client/ReactDOMSelection.js b/src/renderers/dom/client/ReactDOMSelection.js
index aff9e894bba1..307d5c340a27 100644
--- a/src/renderers/dom/client/ReactDOMSelection.js
+++ b/src/renderers/dom/client/ReactDOMSelection.js
@@ -99,7 +99,7 @@ function getModernOffsets(node) {
     selection.anchorNode,
     selection.anchorOffset,
     selection.focusNode,
-    selection.focusOffset
+    selection.focusOffset,
   );
 
   var rangeLength = isSelectionCollapsed ? 0 : currentRange.toString().length;
@@ -112,7 +112,7 @@ function getModernOffsets(node) {
     tempRange.startContainer,
     tempRange.startOffset,
     tempRange.endContainer,
-    tempRange.endOffset
+    tempRange.endOffset,
   );
 
   var start = isTempRangeCollapsed ? 0 : tempRange.toString().length;
@@ -176,8 +176,7 @@ function setModernOffsets(node, offsets) {
   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);
+  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.
@@ -205,11 +204,10 @@ function setModernOffsets(node, offsets) {
   }
 }
 
-var useIEOffsets = (
+var useIEOffsets =
   ExecutionEnvironment.canUseDOM &&
   'selection' in document &&
-  !('getSelection' in window)
-);
+  !('getSelection' in window);
 
 var ReactDOMSelection = {
   /**
diff --git a/src/renderers/dom/client/ReactDOMTreeTraversal.js b/src/renderers/dom/client/ReactDOMTreeTraversal.js
index c4767736bb56..4d809cfdbe0c 100644
--- a/src/renderers/dom/client/ReactDOMTreeTraversal.js
+++ b/src/renderers/dom/client/ReactDOMTreeTraversal.js
@@ -18,27 +18,27 @@ var invariant = require('invariant');
  * different trees.
  */
 function getLowestCommonAncestor(instA, instB) {
-  invariant('_nativeNode' in instA, 'getNodeFromInstance: Invalid argument.');
-  invariant('_nativeNode' in instB, 'getNodeFromInstance: Invalid argument.');
+  invariant('_hostNode' in instA, 'getNodeFromInstance: Invalid argument.');
+  invariant('_hostNode' in instB, 'getNodeFromInstance: Invalid argument.');
 
   var depthA = 0;
-  for (var tempA = instA; tempA; tempA = tempA._nativeParent) {
+  for (var tempA = instA; tempA; tempA = tempA._hostParent) {
     depthA++;
   }
   var depthB = 0;
-  for (var tempB = instB; tempB; tempB = tempB._nativeParent) {
+  for (var tempB = instB; tempB; tempB = tempB._hostParent) {
     depthB++;
   }
 
   // If A is deeper, crawl up.
   while (depthA - depthB > 0) {
-    instA = instA._nativeParent;
+    instA = instA._hostParent;
     depthA--;
   }
 
   // If B is deeper, crawl up.
   while (depthB - depthA > 0) {
-    instB = instB._nativeParent;
+    instB = instB._hostParent;
     depthB--;
   }
 
@@ -48,8 +48,8 @@ function getLowestCommonAncestor(instA, instB) {
     if (instA === instB) {
       return instA;
     }
-    instA = instA._nativeParent;
-    instB = instB._nativeParent;
+    instA = instA._hostParent;
+    instB = instB._hostParent;
   }
   return null;
 }
@@ -58,14 +58,14 @@ function getLowestCommonAncestor(instA, instB) {
  * Return if A is an ancestor of B.
  */
 function isAncestor(instA, instB) {
-  invariant('_nativeNode' in instA, 'isAncestor: Invalid argument.');
-  invariant('_nativeNode' in instB, 'isAncestor: Invalid argument.');
+  invariant('_hostNode' in instA, 'isAncestor: Invalid argument.');
+  invariant('_hostNode' in instB, 'isAncestor: Invalid argument.');
 
   while (instB) {
     if (instB === instA) {
       return true;
     }
-    instB = instB._nativeParent;
+    instB = instB._hostParent;
   }
   return false;
 }
@@ -74,9 +74,9 @@ function isAncestor(instA, instB) {
  * Return the parent instance of the passed-in instance.
  */
 function getParentInstance(inst) {
-  invariant('_nativeNode' in inst, 'getParentInstance: Invalid argument.');
+  invariant('_hostNode' in inst, 'getParentInstance: Invalid argument.');
 
-  return inst._nativeParent;
+  return inst._hostParent;
 }
 
 /**
@@ -86,14 +86,14 @@ function traverseTwoPhase(inst, fn, arg) {
   var path = [];
   while (inst) {
     path.push(inst);
-    inst = inst._nativeParent;
+    inst = inst._hostParent;
   }
   var i;
-  for (i = path.length; i-- > 0;) {
-    fn(path[i], false, arg);
+  for (i = path.length; i-- > 0; ) {
+    fn(path[i], 'captured', arg);
   }
   for (i = 0; i < path.length; i++) {
-    fn(path[i], true, arg);
+    fn(path[i], 'bubbled', arg);
   }
 }
 
@@ -109,19 +109,19 @@ function traverseEnterLeave(from, to, fn, argFrom, argTo) {
   var pathFrom = [];
   while (from && from !== common) {
     pathFrom.push(from);
-    from = from._nativeParent;
+    from = from._hostParent;
   }
   var pathTo = [];
   while (to && to !== common) {
     pathTo.push(to);
-    to = to._nativeParent;
+    to = to._hostParent;
   }
   var i;
   for (i = 0; i < pathFrom.length; i++) {
-    fn(pathFrom[i], true, argFrom);
+    fn(pathFrom[i], 'bubbled', argFrom);
   }
-  for (i = pathTo.length; i-- > 0;) {
-    fn(pathTo[i], false, argTo);
+  for (i = pathTo.length; i-- > 0; ) {
+    fn(pathTo[i], 'captured', argTo);
   }
 }
 
diff --git a/src/renderers/dom/client/ReactEventListener.js b/src/renderers/dom/client/ReactEventListener.js
index bbdbbcf29115..a885cb9b9cb1 100644
--- a/src/renderers/dom/client/ReactEventListener.js
+++ b/src/renderers/dom/client/ReactEventListener.js
@@ -29,8 +29,8 @@ 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._nativeParent) {
-    inst = inst._nativeParent;
+  while (inst._hostParent) {
+    inst = inst._hostParent;
   }
   var rootNode = ReactDOMComponentTree.getNodeFromInstance(inst);
   var container = rootNode.parentNode;
@@ -52,13 +52,13 @@ Object.assign(TopLevelCallbackBookKeeping.prototype, {
 });
 PooledClass.addPoolingTo(
   TopLevelCallbackBookKeeping,
-  PooledClass.twoArgumentPooler
+  PooledClass.twoArgumentPooler,
 );
 
 function handleTopLevelImpl(bookKeeping) {
   var nativeEventTarget = getEventTarget(bookKeeping.nativeEvent);
   var targetInst = ReactDOMComponentTree.getClosestInstanceFromNode(
-    nativeEventTarget
+    nativeEventTarget,
   );
 
   // Loop through the hierarchy, in case there's any nested components.
@@ -77,7 +77,7 @@ function handleTopLevelImpl(bookKeeping) {
       bookKeeping.topLevelType,
       targetInst,
       bookKeeping.nativeEvent,
-      getEventTarget(bookKeeping.nativeEvent)
+      getEventTarget(bookKeeping.nativeEvent),
     );
   }
 }
@@ -105,26 +105,24 @@ var ReactEventListener = {
     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} handle Element on which to attach listener.
+   * @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, handle) {
-    var element = handle;
+  trapBubbledEvent: function(topLevelType, handlerBaseName, element) {
     if (!element) {
       return null;
     }
     return EventListener.listen(
       element,
       handlerBaseName,
-      ReactEventListener.dispatchEvent.bind(null, topLevelType)
+      ReactEventListener.dispatchEvent.bind(null, topLevelType),
     );
   },
 
@@ -133,20 +131,19 @@ var ReactEventListener = {
    *
    * @param {string} topLevelType Record from `EventConstants`.
    * @param {string} handlerBaseName Event name (e.g. "click").
-   * @param {object} handle Element on which to attach listener.
+   * @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, handle) {
-    var element = handle;
+  trapCapturedEvent: function(topLevelType, handlerBaseName, element) {
     if (!element) {
       return null;
     }
     return EventListener.capture(
       element,
       handlerBaseName,
-      ReactEventListener.dispatchEvent.bind(null, topLevelType)
+      ReactEventListener.dispatchEvent.bind(null, topLevelType),
     );
   },
 
@@ -162,7 +159,7 @@ var ReactEventListener = {
 
     var bookKeeping = TopLevelCallbackBookKeeping.getPooled(
       topLevelType,
-      nativeEvent
+      nativeEvent,
     );
     try {
       // Event queue being processed in the same cycle allows
diff --git a/src/renderers/dom/client/ReactInputSelection.js b/src/renderers/dom/client/ReactInputSelection.js
index 46e6931a6db7..ee9d33ddce30 100644
--- a/src/renderers/dom/client/ReactInputSelection.js
+++ b/src/renderers/dom/client/ReactInputSelection.js
@@ -28,13 +28,13 @@ function isInDocument(node) {
  * 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'
+    return (
+      nodeName &&
+      ((nodeName === 'input' && elem.type === 'text') ||
+        nodeName === 'textarea' ||
+        elem.contentEditable === 'true')
     );
   },
 
@@ -42,10 +42,9 @@ var ReactInputSelection = {
     var focusedElem = getActiveElement();
     return {
       focusedElem: focusedElem,
-      selectionRange:
-          ReactInputSelection.hasSelectionCapabilities(focusedElem) ?
-          ReactInputSelection.getSelection(focusedElem) :
-          null,
+      selectionRange: ReactInputSelection.hasSelectionCapabilities(focusedElem)
+        ? ReactInputSelection.getSelection(focusedElem)
+        : null,
     };
   },
 
@@ -58,13 +57,9 @@ var ReactInputSelection = {
     var curFocusedElem = getActiveElement();
     var priorFocusedElem = priorSelectionInformation.focusedElem;
     var priorSelectionRange = priorSelectionInformation.selectionRange;
-    if (curFocusedElem !== priorFocusedElem &&
-        isInDocument(priorFocusedElem)) {
+    if (curFocusedElem !== priorFocusedElem && isInDocument(priorFocusedElem)) {
       if (ReactInputSelection.hasSelectionCapabilities(priorFocusedElem)) {
-        ReactInputSelection.setSelection(
-          priorFocusedElem,
-          priorSelectionRange
-        );
+        ReactInputSelection.setSelection(priorFocusedElem, priorSelectionRange);
       }
       focusNode(priorFocusedElem);
     }
@@ -85,8 +80,10 @@ var ReactInputSelection = {
         start: input.selectionStart,
         end: input.selectionEnd,
       };
-    } else if (document.selection &&
-        (input.nodeName && input.nodeName.toLowerCase() === 'input')) {
+    } 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
@@ -121,8 +118,10 @@ var ReactInputSelection = {
     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')) {
+    } else if (
+      document.selection &&
+      (input.nodeName && input.nodeName.toLowerCase() === 'input')
+    ) {
       var range = input.createTextRange();
       range.collapse(true);
       range.moveStart('character', start);
diff --git a/src/renderers/dom/client/ReactMount.js b/src/renderers/dom/client/ReactMount.js
index 7f6f8cac6ff5..18eb806f447c 100644
--- a/src/renderers/dom/client/ReactMount.js
+++ b/src/renderers/dom/client/ReactMount.js
@@ -13,16 +13,16 @@
 
 var DOMLazyTree = require('DOMLazyTree');
 var DOMProperty = require('DOMProperty');
+var React = require('React');
 var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
 var ReactCurrentOwner = require('ReactCurrentOwner');
 var ReactDOMComponentTree = require('ReactDOMComponentTree');
 var ReactDOMContainerInfo = require('ReactDOMContainerInfo');
 var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
-var ReactElement = require('ReactElement');
 var ReactFeatureFlags = require('ReactFeatureFlags');
+var ReactInstanceMap = require('ReactInstanceMap');
 var ReactInstrumentation = require('ReactInstrumentation');
 var ReactMarkupChecksum = require('ReactMarkupChecksum');
-var ReactPerf = require('ReactPerf');
 var ReactReconciler = require('ReactReconciler');
 var ReactUpdateQueue = require('ReactUpdateQueue');
 var ReactUpdates = require('ReactUpdates');
@@ -80,7 +80,7 @@ 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) || '';
+  return (node.getAttribute && node.getAttribute(ATTR_NAME)) || '';
 }
 
 /**
@@ -96,16 +96,15 @@ function mountComponentIntoNode(
   container,
   transaction,
   shouldReuseMarkup,
-  context
+  context,
 ) {
   var markerName;
   if (ReactFeatureFlags.logTopLevelRenders) {
-    var wrappedElement = wrapperInstance._currentElement.props;
+    var wrappedElement = wrapperInstance._currentElement.props.child;
     var type = wrappedElement.type;
-    markerName = 'React mount: ' + (
-      typeof type === 'string' ? type :
-      type.displayName || type.name
-    );
+    markerName =
+      'React mount: ' +
+      (typeof type === 'string' ? type : type.displayName || type.name);
     console.time(markerName);
   }
 
@@ -114,7 +113,8 @@ function mountComponentIntoNode(
     transaction,
     null,
     ReactDOMContainerInfo(wrapperInstance, container),
-    context
+    context,
+    0 /* parentDebugID */,
   );
 
   if (markerName) {
@@ -127,7 +127,7 @@ function mountComponentIntoNode(
     container,
     wrapperInstance,
     shouldReuseMarkup,
-    transaction
+    transaction,
   );
 }
 
@@ -142,11 +142,11 @@ function batchedMountComponentIntoNode(
   componentInstance,
   container,
   shouldReuseMarkup,
-  context
+  context,
 ) {
   var transaction = ReactUpdates.ReactReconcileTransaction.getPooled(
     /* useCreateElement */
-    !shouldReuseMarkup && ReactDOMFeatureFlags.useCreateElement
+    !shouldReuseMarkup && ReactDOMFeatureFlags.useCreateElement,
   );
   transaction.perform(
     mountComponentIntoNode,
@@ -155,7 +155,7 @@ function batchedMountComponentIntoNode(
     container,
     transaction,
     shouldReuseMarkup,
-    context
+    context,
   );
   ReactUpdates.ReactReconcileTransaction.release(transaction);
 }
@@ -196,23 +196,69 @@ function hasNonRootReactChild(container) {
   var rootEl = getReactRootElementInContainer(container);
   if (rootEl) {
     var inst = ReactDOMComponentTree.getInstanceFromNode(rootEl);
-    return !!(inst && inst._nativeParent);
+    return !!(inst && inst._hostParent);
   }
 }
 
-function getNativeRootInstanceInContainer(container) {
+/**
+ * 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);
-  var prevNativeInstance =
-    rootEl && ReactDOMComponentTree.getInstanceFromNode(rootEl);
+  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 (
-    prevNativeInstance && !prevNativeInstance._nativeParent ?
-    prevNativeInstance : null
+    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 = getNativeRootInstanceInContainer(container);
-  return root ? root._nativeContainerInfo._topLevelWrapper : null;
+  var root = getHostRootInstanceInContainer(container);
+  return root ? root._hostContainerInfo._topLevelWrapper : null;
 }
 
 /**
@@ -225,13 +271,10 @@ var TopLevelWrapper = function() {
   this.rootID = topLevelRootCounter++;
 };
 TopLevelWrapper.prototype.isReactComponent = {};
-if (__DEV__) {
-  TopLevelWrapper.displayName = 'TopLevelWrapper';
-}
 TopLevelWrapper.prototype.render = function() {
-  // this.props is actually a ReactElement
-  return this.props;
+  return this.props.child;
 };
+TopLevelWrapper.isReactTopLevelWrapper = true;
 
 /**
  * Mounting is the process of initializing a React component by creating its
@@ -252,7 +295,6 @@ TopLevelWrapper.prototype.render = function() {
  * Inside of `container`, the first element rendered is the "reactRoot".
  */
 var ReactMount = {
-
   TopLevelWrapper: TopLevelWrapper,
 
   /**
@@ -280,12 +322,18 @@ var ReactMount = {
    * @param {?function} callback function triggered on completion
    */
   _updateRootComponent: function(
-      prevComponent,
-      nextElement,
-      container,
-      callback) {
+    prevComponent,
+    nextElement,
+    nextContext,
+    container,
+    callback,
+  ) {
     ReactMount.scrollMonitor(container, function() {
-      ReactUpdateQueue.enqueueElementInternal(prevComponent, nextElement);
+      ReactUpdateQueue.enqueueElementInternal(
+        prevComponent,
+        nextElement,
+        nextContext,
+      );
       if (callback) {
         ReactUpdateQueue.enqueueCallbackInternal(prevComponent, callback);
       }
@@ -295,7 +343,7 @@ var ReactMount = {
   },
 
   /**
-   * Render a new component into the DOM. Hooked by devtools!
+   * Render a new component into the DOM. Hooked by hooks!
    *
    * @param {ReactElement} nextElement element to render
    * @param {DOMElement} container container to render into
@@ -306,32 +354,13 @@ var ReactMount = {
     nextElement,
     container,
     shouldReuseMarkup,
-    context
+    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.
-    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'
-    );
-
-    invariant(
-      container && (
-        container.nodeType === ELEMENT_NODE_TYPE ||
-        container.nodeType === DOC_NODE_TYPE ||
-        container.nodeType === DOCUMENT_FRAGMENT_NODE_TYPE
-      ),
-      '_registerComponent(...): Target container is not a DOM element.'
-    );
-
     ReactBrowserEventEmitter.ensureScrollValueMonitoring();
-    var componentInstance = instantiateReactComponent(nextElement);
+    var componentInstance = instantiateReactComponent(nextElement, false);
 
     // The initial render is synchronous but any updates that happen during
     // rendering, in componentWillMount or componentDidMount, will be batched
@@ -342,16 +371,12 @@ var ReactMount = {
       componentInstance,
       container,
       shouldReuseMarkup,
-      context
+      context,
     );
 
     var wrapperID = componentInstance._instance.rootID;
     instancesByReactRootID[wrapperID] = componentInstance;
 
-    if (__DEV__) {
-      ReactInstrumentation.debugTool.onMountRootComponent(componentInstance);
-    }
-
     return componentInstance;
   },
 
@@ -368,74 +393,59 @@ var ReactMount = {
    * @param {?function} callback function triggered on completion
    * @return {ReactComponent} Component instance rendered in `container`.
    */
-  renderSubtreeIntoContainer: function(parentComponent, nextElement, container, callback) {
-    invariant(
-      parentComponent != null && parentComponent._reactInternalInstance != null,
-      'parentComponent must be a valid React Component'
-    );
+  renderSubtreeIntoContainer: function(
+    parentComponent,
+    nextElement,
+    container,
+    callback,
+  ) {
     return ReactMount._renderSubtreeIntoContainer(
       parentComponent,
       nextElement,
       container,
-      callback
+      callback,
     );
   },
 
-  _renderSubtreeIntoContainer: function(parentComponent, nextElement, container, callback) {
+  _renderSubtreeIntoContainer: function(
+    parentComponent,
+    nextElement,
+    container,
+    callback,
+  ) {
     ReactUpdateQueue.validateCallback(callback, 'ReactDOM.render');
-    invariant(
-      ReactElement.isValidElement(nextElement),
-      '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.' :
-          ''
-      )
-    );
 
-    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.'
-    );
 
-    var nextWrappedElement = ReactElement(
-      TopLevelWrapper,
-      null,
-      null,
-      null,
-      null,
-      null,
-      nextElement
-    );
+    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;
+      var prevElement = prevWrappedElement.props.child;
       if (shouldUpdateReactComponent(prevElement, nextElement)) {
         var publicInst = prevComponent._renderedComponent.getPublicInstance();
-        var updatedCallback = callback && function() {
-          callback.call(publicInst);
-        };
+        var updatedCallback =
+          callback &&
+          function() {
+            callback.call(publicInst);
+          };
         ReactMount._updateRootComponent(
           prevComponent,
           nextWrappedElement,
+          nextContext,
           container,
-          updatedCallback
+          updatedCallback,
         );
         return publicInst;
       } else {
@@ -448,31 +458,6 @@ var ReactMount = {
       reactRootElement && !!internalGetID(reactRootElement);
     var containerHasNonRootReactChild = hasNonRootReactChild(container);
 
-    if (__DEV__) {
-      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.'
-      );
-
-      if (!containerHasReactMarkup || reactRootElement.nextSibling) {
-        var rootElementSibling = reactRootElement;
-        while (rootElementSibling) {
-          if (internalGetID(rootElementSibling)) {
-            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.'
-            );
-            break;
-          }
-          rootElementSibling = rootElementSibling.nextSibling;
-        }
-      }
-    }
 
     var shouldReuseMarkup =
       containerHasReactMarkup &&
@@ -482,11 +467,7 @@ var ReactMount = {
       nextWrappedElement,
       container,
       shouldReuseMarkup,
-      parentComponent != null ?
-        parentComponent._reactInternalInstance._processChildContext(
-          parentComponent._reactInternalInstance._context
-        ) :
-        emptyObject
+      nextContext,
     )._renderedComponent.getPublicInstance();
     if (callback) {
       callback.call(component);
@@ -494,9 +475,9 @@ var ReactMount = {
     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
@@ -508,11 +489,17 @@ var ReactMount = {
    * @return {ReactComponent} Component instance rendered in `container`.
    */
   render: function(nextElement, container, callback) {
-    return ReactMount._renderSubtreeIntoContainer(null, 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
@@ -526,21 +513,13 @@ var ReactMount = {
     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'
+        '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',
     );
 
-    invariant(
-      container && (
-        container.nodeType === ELEMENT_NODE_TYPE ||
-        container.nodeType === DOC_NODE_TYPE ||
-        container.nodeType === DOCUMENT_FRAGMENT_NODE_TYPE
-      ),
-      'unmountComponentAtNode(...): Target container is not a DOM element.'
-    );
 
     var prevComponent = getTopLevelWrapperInContainer(container);
     if (!prevComponent) {
@@ -552,20 +531,6 @@ var ReactMount = {
       var isContainerReactRoot =
         container.nodeType === 1 && container.hasAttribute(ROOT_ATTR_NAME);
 
-      if (__DEV__) {
-        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.'
-          )
-        );
-      }
 
       return false;
     }
@@ -574,7 +539,7 @@ var ReactMount = {
       unmountComponentFromNode,
       prevComponent,
       container,
-      false
+      false,
     );
     return true;
   },
@@ -584,16 +549,8 @@ var ReactMount = {
     container,
     instance,
     shouldReuseMarkup,
-    transaction
+    transaction,
   ) {
-    invariant(
-      container && (
-        container.nodeType === ELEMENT_NODE_TYPE ||
-        container.nodeType === DOC_NODE_TYPE ||
-        container.nodeType === DOCUMENT_FRAGMENT_NODE_TYPE
-      ),
-      'mountComponentIntoNode(...): Target container is not valid.'
-    );
 
     if (shouldReuseMarkup) {
       var rootElement = getReactRootElementInContainer(container);
@@ -602,79 +559,29 @@ var ReactMount = {
         return;
       } else {
         var checksum = rootElement.getAttribute(
-          ReactMarkupChecksum.CHECKSUM_ATTR_NAME
+          ReactMarkupChecksum.CHECKSUM_ATTR_NAME,
         );
         rootElement.removeAttribute(ReactMarkupChecksum.CHECKSUM_ATTR_NAME);
 
         var rootMarkup = rootElement.outerHTML;
         rootElement.setAttribute(
           ReactMarkupChecksum.CHECKSUM_ATTR_NAME,
-          checksum
+          checksum,
         );
 
         var normalizedMarkup = markup;
-        if (__DEV__) {
-          // 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) ' +
+        var difference =
+          ' (client) ' +
           normalizedMarkup.substring(diffIndex - 20, diffIndex + 20) +
-          '\n (server) ' + rootMarkup.substring(diffIndex - 20, diffIndex + 20);
-
-        invariant(
-          container.nodeType !== DOC_NODE_TYPE,
-          '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
-        );
+          '\n (server) ' +
+          rootMarkup.substring(diffIndex - 20, diffIndex + 20);
+
 
-        if (__DEV__) {
-          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
-          );
-        }
       }
     }
 
-    invariant(
-      container.nodeType !== DOC_NODE_TYPE,
-      '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.'
-    );
-
     if (transaction.useCreateElement) {
       while (container.lastChild) {
         container.removeChild(container.lastChild);
@@ -684,12 +591,8 @@ var ReactMount = {
       setInnerHTML(container, markup);
       ReactDOMComponentTree.precacheNode(instance, container.firstChild);
     }
+
   },
 };
 
-ReactPerf.measureMethods(ReactMount, 'ReactMount', {
-  _renderNewRootComponent: '_renderNewRootComponent',
-  _mountImageIntoNode: '_mountImageIntoNode',
-});
-
 module.exports = ReactMount;
diff --git a/src/renderers/dom/client/ReactReconcileTransaction.js b/src/renderers/dom/client/ReactReconcileTransaction.js
index fedd883bf1cb..4b3950bbf991 100644
--- a/src/renderers/dom/client/ReactReconcileTransaction.js
+++ b/src/renderers/dom/client/ReactReconcileTransaction.js
@@ -15,8 +15,9 @@ var CallbackQueue = require('CallbackQueue');
 var PooledClass = require('PooledClass');
 var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
 var ReactInputSelection = require('ReactInputSelection');
+var ReactInstrumentation = require('ReactInstrumentation');
 var Transaction = require('Transaction');
-
+var ReactUpdateQueue = require('ReactUpdateQueue');
 
 /**
  * Ensures that, when possible, the selection range (currently selected text
@@ -90,6 +91,13 @@ var TRANSACTION_WRAPPERS = [
   ON_DOM_READY_QUEUEING,
 ];
 
+if (__DEV__) {
+  TRANSACTION_WRAPPERS.push({
+    initialize: ReactInstrumentation.debugTool.onBeginFlush,
+    close: ReactInstrumentation.debugTool.onEndFlush,
+  });
+}
+
 /**
  * Currently:
  * - The order that these are listed in the transaction is critical:
@@ -104,13 +112,13 @@ var TRANSACTION_WRAPPERS = [
  *
  * @class ReactReconcileTransaction
  */
-function ReactReconcileTransaction(useCreateElement) {
+function ReactReconcileTransaction(useCreateElement: boolean) {
   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
-  // `ReactTextComponent` checks it in `mountComponent`.`
+  // `ReactDOMTextComponent` checks it in `mountComponent`.`
   this.renderToStaticMarkup = false;
   this.reactMountReady = CallbackQueue.getPooled(null);
   this.useCreateElement = useCreateElement;
@@ -135,6 +143,13 @@ var Mixin = {
     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.
@@ -158,8 +173,7 @@ var Mixin = {
   },
 };
 
-
-Object.assign(ReactReconcileTransaction.prototype, Transaction.Mixin, Mixin);
+Object.assign(ReactReconcileTransaction.prototype, Transaction, Mixin);
 
 PooledClass.addPoolingTo(ReactReconcileTransaction);
 
diff --git a/src/renderers/dom/client/__tests__/ReactBrowserEventEmitter-test.js b/src/renderers/dom/client/__tests__/ReactBrowserEventEmitter-test.js
index 5dbf91c2cd85..fb0f0619bc11 100644
--- a/src/renderers/dom/client/__tests__/ReactBrowserEventEmitter-test.js
+++ b/src/renderers/dom/client/__tests__/ReactBrowserEventEmitter-test.js
@@ -11,8 +11,6 @@
 
 'use strict';
 
-var keyOf = require('keyOf');
-
 var EventListener;
 var EventPluginHub;
 var EventPluginRegistry;
@@ -35,11 +33,11 @@ var recordIDAndReturnFalse = function(id, event) {
   recordID(id);
   return false;
 };
-var LISTENER = jest.genMockFn();
-var ON_CLICK_KEY = keyOf({onClick: null});
-var ON_TOUCH_TAP_KEY = keyOf({onTouchTap: null});
-var ON_CHANGE_KEY = keyOf({onChange: null});
-var ON_MOUSE_ENTER_KEY = keyOf({onMouseEnter: null});
+var LISTENER = jest.fn();
+var ON_CLICK_KEY = 'onClick';
+var ON_TOUCH_TAP_KEY = 'onTouchTap';
+var ON_CHANGE_KEY = 'onChange';
+var ON_MOUSE_ENTER_KEY = 'onMouseEnter';
 
 var GRANDPARENT;
 var PARENT;
@@ -56,9 +54,8 @@ function getInternal(node) {
   return ReactDOMComponentTree.getInstanceFromNode(node);
 }
 
-
-describe('ReactBrowserEventEmitter', function() {
-  beforeEach(function() {
+describe('ReactBrowserEventEmitter', () => {
+  beforeEach(() => {
     jest.resetModuleRegistry();
     LISTENER.mockClear();
     EventListener = require('EventListener');
@@ -71,11 +68,11 @@ describe('ReactBrowserEventEmitter', function() {
     TapEventPlugin = require('TapEventPlugin');
 
     ReactTestUtils.renderIntoDocument(
-      <div ref={(c) => GRANDPARENT = c}>
-        <div ref={(c) => PARENT = c}>
-          <div ref={(c) => CHILD = c} />
+      <div ref={c => (GRANDPARENT = c)}>
+        <div ref={c => (PARENT = c)}>
+          <div ref={c => (CHILD = c)} />
         </div>
-      </div>
+      </div>,
     );
 
     idCallOrder = [];
@@ -85,59 +82,56 @@ describe('ReactBrowserEventEmitter', function() {
     });
   });
 
-  it('should store a listener correctly', function() {
+  it('should store a listener correctly', () => {
     registerSimpleTestHandler();
     var listener = EventPluginHub.getListener(getInternal(CHILD), ON_CLICK_KEY);
     expect(listener).toBe(LISTENER);
   });
 
-  it('should retrieve a listener correctly', function() {
+  it('should retrieve a listener correctly', () => {
     registerSimpleTestHandler();
     var listener = EventPluginHub.getListener(getInternal(CHILD), ON_CLICK_KEY);
     expect(listener).toEqual(LISTENER);
   });
 
-  it('should clear all handlers when asked to', function() {
+  it('should clear all handlers when asked to', () => {
     registerSimpleTestHandler();
     EventPluginHub.deleteAllListeners(getInternal(CHILD));
     var listener = EventPluginHub.getListener(getInternal(CHILD), ON_CLICK_KEY);
     expect(listener).toBe(undefined);
   });
 
-  it('should invoke a simple handler registered on a node', function() {
+  it('should invoke a simple handler registered on a node', () => {
     registerSimpleTestHandler();
     ReactTestUtils.Simulate.click(CHILD);
     expect(LISTENER.mock.calls.length).toBe(1);
   });
 
-  it(
-    'should not invoke handlers if ReactBrowserEventEmitter is disabled',
-    function() {
-      registerSimpleTestHandler();
-      ReactBrowserEventEmitter.setEnabled(false);
-      ReactTestUtils.SimulateNative.click(CHILD);
-      expect(LISTENER.mock.calls.length).toBe(0);
-      ReactBrowserEventEmitter.setEnabled(true);
-      ReactTestUtils.SimulateNative.click(CHILD);
-      expect(LISTENER.mock.calls.length).toBe(1);
-    }
-  );
+  it('should not invoke handlers if ReactBrowserEventEmitter is disabled', () => {
+    registerSimpleTestHandler();
+    ReactBrowserEventEmitter.setEnabled(false);
+    ReactTestUtils.SimulateNative.click(CHILD);
+    expect(LISTENER.mock.calls.length).toBe(0);
+    ReactBrowserEventEmitter.setEnabled(true);
+    ReactTestUtils.SimulateNative.click(CHILD);
+    expect(LISTENER.mock.calls.length).toBe(1);
+  });
 
-  it('should bubble simply', function() {
+  it('should bubble simply', () => {
     EventPluginHub.putListener(
       getInternal(CHILD),
       ON_CLICK_KEY,
-      recordID.bind(null, getInternal(CHILD))
+      recordID.bind(null, getInternal(CHILD)),
     );
     EventPluginHub.putListener(
       getInternal(PARENT),
       ON_CLICK_KEY,
-      recordID.bind(null, getInternal(PARENT))
+      recordID.bind(null, getInternal(PARENT)),
     );
     EventPluginHub.putListener(
       getInternal(GRANDPARENT),
       ON_CLICK_KEY,
-      recordID.bind(null, getInternal(GRANDPARENT))
+      recordID.bind(null, getInternal(GRANDPARENT)),
     );
     ReactTestUtils.Simulate.click(CHILD);
     expect(idCallOrder.length).toBe(3);
@@ -146,24 +140,20 @@ describe('ReactBrowserEventEmitter', function() {
     expect(idCallOrder[2]).toBe(getInternal(GRANDPARENT));
   });
 
-  it('should continue bubbling if an error is thrown', function() {
+  it('should continue bubbling if an error is thrown', () => {
     EventPluginHub.putListener(
       getInternal(CHILD),
       ON_CLICK_KEY,
-      recordID.bind(null, getInternal(CHILD))
-    );
-    EventPluginHub.putListener(
-      getInternal(PARENT),
-      ON_CLICK_KEY,
-      function() {
-        recordID(getInternal(PARENT));
-        throw new Error('Handler interrupted');
-      }
+      recordID.bind(null, getInternal(CHILD)),
     );
+    EventPluginHub.putListener(getInternal(PARENT), ON_CLICK_KEY, function() {
+      recordID(getInternal(PARENT));
+      throw new Error('Handler interrupted');
+    });
     EventPluginHub.putListener(
       getInternal(GRANDPARENT),
       ON_CLICK_KEY,
-      recordID.bind(null, getInternal(GRANDPARENT))
+      recordID.bind(null, getInternal(GRANDPARENT)),
     );
     expect(function() {
       ReactTestUtils.Simulate.click(CHILD);
@@ -174,31 +164,25 @@ describe('ReactBrowserEventEmitter', function() {
     expect(idCallOrder[2]).toBe(getInternal(GRANDPARENT));
   });
 
-  it('should set currentTarget', function() {
-    EventPluginHub.putListener(
-      getInternal(CHILD),
-      ON_CLICK_KEY,
-      function(event) {
-        recordID(getInternal(CHILD));
-        expect(event.currentTarget).toBe(CHILD);
-      }
-    );
-    EventPluginHub.putListener(
-      getInternal(PARENT),
-      ON_CLICK_KEY,
-      function(event) {
-        recordID(getInternal(PARENT));
-        expect(event.currentTarget).toBe(PARENT);
-      }
-    );
-    EventPluginHub.putListener(
-      getInternal(GRANDPARENT),
-      ON_CLICK_KEY,
-      function(event) {
-        recordID(getInternal(GRANDPARENT));
-        expect(event.currentTarget).toBe(GRANDPARENT);
-      }
-    );
+  it('should set currentTarget', () => {
+    EventPluginHub.putListener(getInternal(CHILD), ON_CLICK_KEY, function(
+      event,
+    ) {
+      recordID(getInternal(CHILD));
+      expect(event.currentTarget).toBe(CHILD);
+    });
+    EventPluginHub.putListener(getInternal(PARENT), ON_CLICK_KEY, function(
+      event,
+    ) {
+      recordID(getInternal(PARENT));
+      expect(event.currentTarget).toBe(PARENT);
+    });
+    EventPluginHub.putListener(getInternal(GRANDPARENT), ON_CLICK_KEY, function(
+      event,
+    ) {
+      recordID(getInternal(GRANDPARENT));
+      expect(event.currentTarget).toBe(GRANDPARENT);
+    });
     ReactTestUtils.Simulate.click(CHILD);
     expect(idCallOrder.length).toBe(3);
     expect(idCallOrder[0]).toBe(getInternal(CHILD));
@@ -206,21 +190,21 @@ describe('ReactBrowserEventEmitter', function() {
     expect(idCallOrder[2]).toBe(getInternal(GRANDPARENT));
   });
 
-  it('should support stopPropagation()', function() {
+  it('should support stopPropagation()', () => {
     EventPluginHub.putListener(
       getInternal(CHILD),
       ON_CLICK_KEY,
-      recordID.bind(null, getInternal(CHILD))
+      recordID.bind(null, getInternal(CHILD)),
     );
     EventPluginHub.putListener(
       getInternal(PARENT),
       ON_CLICK_KEY,
-      recordIDAndStopPropagation.bind(null, getInternal(PARENT))
+      recordIDAndStopPropagation.bind(null, getInternal(PARENT)),
     );
     EventPluginHub.putListener(
       getInternal(GRANDPARENT),
       ON_CLICK_KEY,
-      recordID.bind(null, getInternal(GRANDPARENT))
+      recordID.bind(null, getInternal(GRANDPARENT)),
     );
     ReactTestUtils.Simulate.click(CHILD);
     expect(idCallOrder.length).toBe(2);
@@ -228,42 +212,42 @@ describe('ReactBrowserEventEmitter', function() {
     expect(idCallOrder[1]).toBe(getInternal(PARENT));
   });
 
-  it('should stop after first dispatch if stopPropagation', function() {
+  it('should stop after first dispatch if stopPropagation', () => {
     EventPluginHub.putListener(
       getInternal(CHILD),
       ON_CLICK_KEY,
-      recordIDAndStopPropagation.bind(null, getInternal(CHILD))
+      recordIDAndStopPropagation.bind(null, getInternal(CHILD)),
     );
     EventPluginHub.putListener(
       getInternal(PARENT),
       ON_CLICK_KEY,
-      recordID.bind(null, getInternal(PARENT))
+      recordID.bind(null, getInternal(PARENT)),
     );
     EventPluginHub.putListener(
       getInternal(GRANDPARENT),
       ON_CLICK_KEY,
-      recordID.bind(null, getInternal(GRANDPARENT))
+      recordID.bind(null, getInternal(GRANDPARENT)),
     );
     ReactTestUtils.Simulate.click(CHILD);
     expect(idCallOrder.length).toBe(1);
     expect(idCallOrder[0]).toBe(getInternal(CHILD));
   });
 
-  it('should not stopPropagation if false is returned', function() {
+  it('should not stopPropagation if false is returned', () => {
     EventPluginHub.putListener(
       getInternal(CHILD),
       ON_CLICK_KEY,
-      recordIDAndReturnFalse.bind(null, getInternal(CHILD))
+      recordIDAndReturnFalse.bind(null, getInternal(CHILD)),
     );
     EventPluginHub.putListener(
       getInternal(PARENT),
       ON_CLICK_KEY,
-      recordID.bind(null, getInternal(PARENT))
+      recordID.bind(null, getInternal(PARENT)),
     );
     EventPluginHub.putListener(
       getInternal(GRANDPARENT),
       ON_CLICK_KEY,
-      recordID.bind(null, getInternal(GRANDPARENT))
+      recordID.bind(null, getInternal(GRANDPARENT)),
     );
     spyOn(console, 'error');
     ReactTestUtils.Simulate.click(CHILD);
@@ -271,7 +255,7 @@ describe('ReactBrowserEventEmitter', function() {
     expect(idCallOrder[0]).toBe(getInternal(CHILD));
     expect(idCallOrder[1]).toBe(getInternal(PARENT));
     expect(idCallOrder[2]).toBe(getInternal(GRANDPARENT));
-    expect(console.error.calls.length).toEqual(0);
+    expect(console.error.calls.count()).toEqual(0);
   });
 
   /**
@@ -283,131 +267,131 @@ describe('ReactBrowserEventEmitter', function() {
    * these new listeners.
    */
 
-  it('should invoke handlers that were removed while bubbling', function() {
-    var handleParentClick = jest.genMockFn();
+  it('should invoke handlers that were removed while bubbling', () => {
+    var handleParentClick = jest.fn();
     var handleChildClick = function(event) {
       EventPluginHub.deleteAllListeners(getInternal(PARENT));
     };
     EventPluginHub.putListener(
       getInternal(CHILD),
       ON_CLICK_KEY,
-      handleChildClick
+      handleChildClick,
     );
     EventPluginHub.putListener(
       getInternal(PARENT),
       ON_CLICK_KEY,
-      handleParentClick
+      handleParentClick,
     );
     ReactTestUtils.Simulate.click(CHILD);
     expect(handleParentClick.mock.calls.length).toBe(1);
   });
 
-  it('should not invoke newly inserted handlers while bubbling', function() {
-    var handleParentClick = jest.genMockFn();
+  it('should not invoke newly inserted handlers while bubbling', () => {
+    var handleParentClick = jest.fn();
     var handleChildClick = function(event) {
       EventPluginHub.putListener(
         getInternal(PARENT),
         ON_CLICK_KEY,
-        handleParentClick
+        handleParentClick,
       );
     };
     EventPluginHub.putListener(
       getInternal(CHILD),
       ON_CLICK_KEY,
-      handleChildClick
+      handleChildClick,
     );
     ReactTestUtils.Simulate.click(CHILD);
     expect(handleParentClick.mock.calls.length).toBe(0);
   });
 
-  it('should have mouse enter simulated by test utils', function() {
+  it('should have mouse enter simulated by test utils', () => {
     EventPluginHub.putListener(
       getInternal(CHILD),
       ON_MOUSE_ENTER_KEY,
-      recordID.bind(null, getInternal(CHILD))
+      recordID.bind(null, getInternal(CHILD)),
     );
     ReactTestUtils.Simulate.mouseEnter(CHILD);
     expect(idCallOrder.length).toBe(1);
     expect(idCallOrder[0]).toBe(getInternal(CHILD));
   });
 
-  it('should infer onTouchTap from a touchStart/End', function() {
+  it('should infer onTouchTap from a touchStart/End', () => {
     EventPluginHub.putListener(
       getInternal(CHILD),
       ON_TOUCH_TAP_KEY,
-      recordID.bind(null, getInternal(CHILD))
+      recordID.bind(null, getInternal(CHILD)),
     );
     ReactTestUtils.SimulateNative.touchStart(
       CHILD,
-      ReactTestUtils.nativeTouchData(0, 0)
+      ReactTestUtils.nativeTouchData(0, 0),
     );
     ReactTestUtils.SimulateNative.touchEnd(
       CHILD,
-      ReactTestUtils.nativeTouchData(0, 0)
+      ReactTestUtils.nativeTouchData(0, 0),
     );
     expect(idCallOrder.length).toBe(1);
     expect(idCallOrder[0]).toBe(getInternal(CHILD));
   });
 
-  it('should infer onTouchTap from when dragging below threshold', function() {
+  it('should infer onTouchTap from when dragging below threshold', () => {
     EventPluginHub.putListener(
       getInternal(CHILD),
       ON_TOUCH_TAP_KEY,
-      recordID.bind(null, getInternal(CHILD))
+      recordID.bind(null, getInternal(CHILD)),
     );
     ReactTestUtils.SimulateNative.touchStart(
       CHILD,
-      ReactTestUtils.nativeTouchData(0, 0)
+      ReactTestUtils.nativeTouchData(0, 0),
     );
     ReactTestUtils.SimulateNative.touchEnd(
       CHILD,
-      ReactTestUtils.nativeTouchData(0, tapMoveThreshold - 1)
+      ReactTestUtils.nativeTouchData(0, tapMoveThreshold - 1),
     );
     expect(idCallOrder.length).toBe(1);
     expect(idCallOrder[0]).toBe(getInternal(CHILD));
   });
 
-  it('should not onTouchTap from when dragging beyond threshold', function() {
+  it('should not onTouchTap from when dragging beyond threshold', () => {
     EventPluginHub.putListener(
       getInternal(CHILD),
       ON_TOUCH_TAP_KEY,
-      recordID.bind(null, getInternal(CHILD))
+      recordID.bind(null, getInternal(CHILD)),
     );
     ReactTestUtils.SimulateNative.touchStart(
       CHILD,
-      ReactTestUtils.nativeTouchData(0, 0)
+      ReactTestUtils.nativeTouchData(0, 0),
     );
     ReactTestUtils.SimulateNative.touchEnd(
       CHILD,
-      ReactTestUtils.nativeTouchData(0, tapMoveThreshold + 1)
+      ReactTestUtils.nativeTouchData(0, tapMoveThreshold + 1),
     );
     expect(idCallOrder.length).toBe(0);
   });
 
-  it('should listen to events only once', function() {
+  it('should listen to events only once', () => {
     spyOn(EventListener, 'listen');
     ReactBrowserEventEmitter.listenTo(ON_CLICK_KEY, document);
     ReactBrowserEventEmitter.listenTo(ON_CLICK_KEY, document);
-    expect(EventListener.listen.calls.length).toBe(1);
+    expect(EventListener.listen.calls.count()).toBe(1);
   });
 
-  it('should work with event plugins without dependencies', function() {
+  it('should work with event plugins without dependencies', () => {
     spyOn(EventListener, 'listen');
 
     ReactBrowserEventEmitter.listenTo(ON_CLICK_KEY, document);
 
-    expect(EventListener.listen.argsForCall[0][1]).toBe('click');
+    expect(EventListener.listen.calls.argsFor(0)[1]).toBe('click');
   });
 
-  it('should work with event plugins with dependencies', function() {
+  it('should work with event plugins with dependencies', () => {
     spyOn(EventListener, 'listen');
     spyOn(EventListener, 'capture');
 
     ReactBrowserEventEmitter.listenTo(ON_CHANGE_KEY, document);
 
     var setEventListeners = [];
-    var listenCalls = EventListener.listen.argsForCall;
-    var captureCalls = EventListener.capture.argsForCall;
+    var listenCalls = EventListener.listen.calls.allArgs();
+    var captureCalls = EventListener.capture.calls.allArgs();
     for (var i = 0; i < listenCalls.length; i++) {
       setEventListeners.push(listenCalls[i][1]);
     }
@@ -424,29 +408,29 @@ describe('ReactBrowserEventEmitter', function() {
     }
   });
 
-  it('should bubble onTouchTap', function() {
+  it('should bubble onTouchTap', () => {
     EventPluginHub.putListener(
       getInternal(CHILD),
       ON_TOUCH_TAP_KEY,
-      recordID.bind(null, getInternal(CHILD))
+      recordID.bind(null, getInternal(CHILD)),
     );
     EventPluginHub.putListener(
       getInternal(PARENT),
       ON_TOUCH_TAP_KEY,
-      recordID.bind(null, getInternal(PARENT))
+      recordID.bind(null, getInternal(PARENT)),
     );
     EventPluginHub.putListener(
       getInternal(GRANDPARENT),
       ON_TOUCH_TAP_KEY,
-      recordID.bind(null, getInternal(GRANDPARENT))
+      recordID.bind(null, getInternal(GRANDPARENT)),
     );
     ReactTestUtils.SimulateNative.touchStart(
       CHILD,
-      ReactTestUtils.nativeTouchData(0, 0)
+      ReactTestUtils.nativeTouchData(0, 0),
     );
     ReactTestUtils.SimulateNative.touchEnd(
       CHILD,
-      ReactTestUtils.nativeTouchData(0, 0)
+      ReactTestUtils.nativeTouchData(0, 0),
     );
     expect(idCallOrder.length).toBe(3);
     expect(idCallOrder[0]).toBe(getInternal(CHILD));
@@ -454,4 +438,19 @@ describe('ReactBrowserEventEmitter', function() {
     expect(idCallOrder[2]).toBe(getInternal(GRANDPARENT));
   });
 
+  it('should not crash ensureScrollValueMonitoring when createEvent returns null', () => {
+    var originalCreateEvent = document.createEvent;
+    document.createEvent = function() {
+      return null;
+    };
+    spyOn(document, 'createEvent');
+
+    try {
+      var hasEventPageXY = ReactBrowserEventEmitter.supportsEventPageXY();
+      expect(document.createEvent.calls.count()).toBe(1);
+      expect(hasEventPageXY).toBe(false);
+    } finally {
+      document.createEvent = originalCreateEvent;
+    }
+  });
 });
diff --git a/src/renderers/dom/client/__tests__/ReactDOM-test.js b/src/renderers/dom/client/__tests__/ReactDOM-test.js
index 9c3cef57f90d..b55e913ffba9 100644
--- a/src/renderers/dom/client/__tests__/ReactDOM-test.js
+++ b/src/renderers/dom/client/__tests__/ReactDOM-test.js
@@ -16,7 +16,7 @@ var ReactDOM = require('ReactDOM');
 var ReactTestUtils = require('ReactTestUtils');
 var div = React.createFactory('div');
 
-describe('ReactDOM', function() {
+describe('ReactDOM', () => {
   // TODO: uncomment this test once we can run in phantom, which
   // supports real submit events.
   /*
@@ -46,23 +46,21 @@ describe('ReactDOM', function() {
   });
   */
 
-  it('allows a DOM element to be used with a string', function() {
+  it('allows a DOM element to be used with a string', () => {
     var element = React.createElement('div', {className: 'foo'});
     var instance = ReactTestUtils.renderIntoDocument(element);
     expect(ReactDOM.findDOMNode(instance).tagName).toBe('DIV');
   });
 
-  it('should allow children to be passed as an argument', function() {
-    var argDiv = ReactTestUtils.renderIntoDocument(
-      div(null, 'child')
-    );
+  it('should allow children to be passed as an argument', () => {
+    var argDiv = ReactTestUtils.renderIntoDocument(div(null, 'child'));
     var argNode = ReactDOM.findDOMNode(argDiv);
     expect(argNode.innerHTML).toBe('child');
   });
 
-  it('should overwrite props.children with children argument', function() {
+  it('should overwrite props.children with children argument', () => {
     var conflictDiv = ReactTestUtils.renderIntoDocument(
-      div({children: 'fakechild'}, 'child')
+      div({children: 'fakechild'}, 'child'),
     );
     var conflictNode = ReactDOM.findDOMNode(conflictDiv);
     expect(conflictNode.innerHTML).toBe('child');
@@ -72,109 +70,109 @@ describe('ReactDOM', function() {
    * We need to make sure that updates occur to the actual node that's in the
    * DOM, instead of a stale cache.
    */
-  it('should purge the DOM cache when removing nodes', function() {
+  it('should purge the DOM cache when removing nodes', () => {
     var myDiv = ReactTestUtils.renderIntoDocument(
       <div>
         <div key="theDog" className="dog" />,
         <div key="theBird" className="bird" />
-      </div>
+      </div>,
     );
     // Warm the cache with theDog
     myDiv = ReactTestUtils.renderIntoDocument(
       <div>
         <div key="theDog" className="dogbeforedelete" />,
         <div key="theBird" className="bird" />,
-      </div>
+      </div>,
     );
     // Remove theDog - this should purge the cache
     myDiv = ReactTestUtils.renderIntoDocument(
       <div>
         <div key="theBird" className="bird" />,
-      </div>
+      </div>,
     );
     // Now, put theDog back. It's now a different DOM node.
     myDiv = ReactTestUtils.renderIntoDocument(
       <div>
         <div key="theDog" className="dog" />,
         <div key="theBird" className="bird" />,
-      </div>
+      </div>,
     );
     // Change the className of theDog. It will use the same element
     myDiv = ReactTestUtils.renderIntoDocument(
       <div>
         <div key="theDog" className="bigdog" />,
         <div key="theBird" className="bird" />,
-      </div>
+      </div>,
     );
     var root = ReactDOM.findDOMNode(myDiv);
     var dog = root.childNodes[0];
     expect(dog.className).toBe('bigdog');
   });
 
-  it('allow React.DOM factories to be called without warnings', function() {
-    spyOn(console, 'error');
+  it('throws warning when  React.DOM factories are called', () => {
+    spyOn(console, 'warn');
     var element = React.DOM.div();
     expect(element.type).toBe('div');
-    expect(console.error.argsForCall.length).toBe(0);
+    expect(console.warn.calls.count()).toBe(1);
   });
 
-  it('throws in render() if the mount callback is not a function', function() {
+  it('throws in render() if the mount callback is not a function', () => {
     function Foo() {
       this.a = 1;
       this.b = 2;
     }
-    var A = React.createClass({
-      getInitialState: function() {
-        return {};
-      },
-      render: function() {
+
+    class A extends React.Component {
+      state = {};
+
+      render() {
         return <div />;
-      },
-    });
+      }
+    }
 
     var myDiv = document.createElement('div');
-    expect(() => ReactDOM.render(<A />, myDiv, 'no')).toThrow(
+    expect(() => ReactDOM.render(<A />, myDiv, 'no')).toThrowError(
       'ReactDOM.render(...): Expected the last optional `callback` argument ' +
-      'to be a function. Instead received: string.'
+        'to be a function. Instead received: string.',
     );
-    expect(() => ReactDOM.render(<A />, myDiv, {})).toThrow(
+    expect(() => ReactDOM.render(<A />, myDiv, {})).toThrowError(
       'ReactDOM.render(...): Expected the last optional `callback` argument ' +
-      'to be a function. Instead received: Object.'
+        'to be a function. Instead received: Object.',
     );
-    expect(() => ReactDOM.render(<A />, myDiv, new Foo())).toThrow(
+    expect(() => ReactDOM.render(<A />, myDiv, new Foo())).toThrowError(
       'ReactDOM.render(...): Expected the last optional `callback` argument ' +
-      'to be a function. Instead received: Foo (keys: a, b).'
+        'to be a function. Instead received: Foo (keys: a, b).',
     );
   });
 
-  it('throws in render() if the update callback is not a function', function() {
+  it('throws in render() if the update callback is not a function', () => {
     function Foo() {
       this.a = 1;
       this.b = 2;
     }
-    var A = React.createClass({
-      getInitialState: function() {
-        return {};
-      },
-      render: function() {
+
+    class A extends React.Component {
+      state = {};
+
+      render() {
         return <div />;
-      },
-    });
+      }
+    }
 
     var myDiv = document.createElement('div');
     ReactDOM.render(<A />, myDiv);
 
-    expect(() => ReactDOM.render(<A />, myDiv, 'no')).toThrow(
+    expect(() => ReactDOM.render(<A />, myDiv, 'no')).toThrowError(
       'ReactDOM.render(...): Expected the last optional `callback` argument ' +
-      'to be a function. Instead received: string.'
+        'to be a function. Instead received: string.',
     );
-    expect(() => ReactDOM.render(<A />, myDiv, {})).toThrow(
+    expect(() => ReactDOM.render(<A />, myDiv, {})).toThrowError(
       'ReactDOM.render(...): Expected the last optional `callback` argument ' +
-      'to be a function. Instead received: Object.'
+        'to be a function. Instead received: Object.',
     );
-    expect(() => ReactDOM.render(<A />, myDiv, new Foo())).toThrow(
+    expect(() => ReactDOM.render(<A />, myDiv, new Foo())).toThrowError(
       'ReactDOM.render(...): Expected the last optional `callback` argument ' +
-      'to be a function. Instead received: Foo (keys: a, b).'
+        'to be a function. Instead received: Foo (keys: a, b).',
     );
   });
 });
diff --git a/src/renderers/dom/client/__tests__/ReactDOMComponentTree-test.js b/src/renderers/dom/client/__tests__/ReactDOMComponentTree-test.js
index 89ec35d58e75..f6ce6f4286ff 100644
--- a/src/renderers/dom/client/__tests__/ReactDOMComponentTree-test.js
+++ b/src/renderers/dom/client/__tests__/ReactDOMComponentTree-test.js
@@ -11,7 +11,7 @@
 
 'use strict';
 
-describe('ReactDOMComponentTree', function() {
+describe('ReactDOMComponentTree', () => {
   var React;
   var ReactDOM;
   var ReactDOMComponentTree;
@@ -24,19 +24,19 @@ describe('ReactDOMComponentTree', function() {
     return ReactDOM.render(elt, container);
   }
 
-  beforeEach(function() {
+  beforeEach(() => {
     React = require('React');
     ReactDOM = require('ReactDOM');
     ReactDOMComponentTree = require('ReactDOMComponentTree');
     ReactDOMServer = require('ReactDOMServer');
   });
 
-  it('finds nodes for instances', function() {
+  it('finds nodes for instances', () => {
     // This is a little hard to test directly. But refs rely on it -- so we
     // check that we can find a ref at arbitrary points in the tree, even if
     // other nodes don't have a ref.
-    var Component = React.createClass({
-      render: function() {
+    class Component extends React.Component {
+      render() {
         var toRef = this.props.toRef;
         return (
           <div ref={toRef === 'div' ? 'target' : null}>
@@ -47,8 +47,8 @@ describe('ReactDOMComponentTree', function() {
             goodbye.
           </div>
         );
-      },
-    });
+      }
+    }
 
     function renderAndGetRef(toRef) {
       var inst = renderMarkupIntoDocument(<Component toRef={toRef} />);
@@ -61,9 +61,9 @@ describe('ReactDOMComponentTree', function() {
     expect(renderAndGetRef('input')).toBe('INPUT');
   });
 
-  it('finds instances for nodes', function() {
-    var Component = React.createClass({
-      render: function() {
+  it('finds instances for nodes', () => {
+    class Component extends React.Component {
+      render() {
         return (
           <div>
             <h1>hello</h1>
@@ -74,8 +74,8 @@ describe('ReactDOMComponentTree', function() {
             <main dangerouslySetInnerHTML={{__html: '<b><img></b>'}} />
           </div>
         );
-      },
-    });
+      }
+    }
 
     function renderAndQuery(sel) {
       var root = renderMarkupIntoDocument(<section><Component /></section>);
@@ -88,7 +88,7 @@ describe('ReactDOMComponentTree', function() {
 
     function renderAndGetClosest(sel) {
       return ReactDOMComponentTree.getClosestInstanceFromNode(
-        renderAndQuery(sel)
+        renderAndQuery(sel),
       );
     }
 
@@ -101,11 +101,12 @@ describe('ReactDOMComponentTree', function() {
 
     // This one's a text component!
     var root = renderAndQuery(null);
-    var inst = ReactDOMComponentTree.getInstanceFromNode(root.children[0].childNodes[2]);
+    var inst = ReactDOMComponentTree.getInstanceFromNode(
+      root.children[0].childNodes[2],
+    );
     expect(inst._stringText).toBe('goodbye.');
 
     expect(renderAndGetClosest('b')._currentElement.type).toBe('main');
     expect(renderAndGetClosest('img')._currentElement.type).toBe('main');
   });
-
 });
diff --git a/src/renderers/dom/client/__tests__/ReactDOMIDOperations-test.js b/src/renderers/dom/client/__tests__/ReactDOMIDOperations-test.js
index bdeb485e244b..1187c9bf5f2b 100644
--- a/src/renderers/dom/client/__tests__/ReactDOMIDOperations-test.js
+++ b/src/renderers/dom/client/__tests__/ReactDOMIDOperations-test.js
@@ -11,23 +11,27 @@
 
 'use strict';
 
-describe('ReactDOMIDOperations', function() {
+describe('ReactDOMIDOperations', () => {
+  var ReactDOMComponentTree = require('ReactDOMComponentTree');
   var ReactDOMIDOperations = require('ReactDOMIDOperations');
-  var ReactMultiChildUpdateTypes = require('ReactMultiChildUpdateTypes');
 
-  it('should update innerHTML and preserve whitespace', function() {
+  it('should update innerHTML and preserve whitespace', () => {
     var stubNode = document.createElement('div');
-    var html = '\n  \t  <span>  \n  testContent  \t  </span>  \n  \t';
+    var stubInstance = {_debugID: 1};
+    ReactDOMComponentTree.precacheNode(stubInstance, stubNode);
 
+    var html = '\n  \t  <span>  \n  testContent  \t  </span>  \n  \t';
     ReactDOMIDOperations.dangerouslyProcessChildrenUpdates(
-      {_nativeNode: stubNode},
-      [{
-        type: ReactMultiChildUpdateTypes.SET_MARKUP,
-        content: html,
-        fromIndex: null,
-        toIndex: null,
-      }],
-      []
+      stubInstance,
+      [
+        {
+          type: 'SET_MARKUP',
+          content: html,
+          fromIndex: null,
+          toIndex: null,
+        },
+      ],
+      [],
     );
 
     expect(stubNode.innerHTML).toBe(html);
diff --git a/src/renderers/dom/client/__tests__/ReactDOMSVG-test.js b/src/renderers/dom/client/__tests__/ReactDOMSVG-test.js
index 84fb2711f42a..d7904b003004 100644
--- a/src/renderers/dom/client/__tests__/ReactDOMSVG-test.js
+++ b/src/renderers/dom/client/__tests__/ReactDOMSVG-test.js
@@ -14,20 +14,18 @@
 var React;
 var ReactDOMServer;
 
-describe('ReactDOMSVG', function() {
-
-  beforeEach(function() {
+describe('ReactDOMSVG', () => {
+  beforeEach(() => {
     React = require('React');
     ReactDOMServer = require('ReactDOMServer');
   });
 
-  it('creates initial namespaced markup', function() {
+  it('creates initial namespaced markup', () => {
     var markup = ReactDOMServer.renderToString(
       <svg>
         <image xlinkHref="http://i.imgur.com/w7GCRPb.png" />
-      </svg>
+      </svg>,
     );
     expect(markup).toContain('xlink:href="http://i.imgur.com/w7GCRPb.png"');
   });
-
 });
diff --git a/src/renderers/dom/client/__tests__/ReactDOMTreeTraversal-test.js b/src/renderers/dom/client/__tests__/ReactDOMTreeTraversal-test.js
index 888e17d1596c..ed40c811213e 100644
--- a/src/renderers/dom/client/__tests__/ReactDOMTreeTraversal-test.js
+++ b/src/renderers/dom/client/__tests__/ReactDOMTreeTraversal-test.js
@@ -21,19 +21,19 @@ var ReactTestUtils = require('ReactTestUtils');
 var ARG = {arg: true};
 var ARG2 = {arg2: true};
 
-var ChildComponent = React.createClass({
-  render: function() {
+class ChildComponent extends React.Component {
+  render() {
     return (
       <div ref="DIV">
         <div ref="DIV_1" />
         <div ref="DIV_2" />
       </div>
     );
-  },
-});
+  }
+}
 
-var ParentComponent = React.createClass({
-  render: function() {
+class ParentComponent extends React.Component {
+  render() {
     return (
       <div ref="P">
         <div ref="P_P1">
@@ -43,21 +43,21 @@ var ParentComponent = React.createClass({
         <div ref="P_OneOff" />
       </div>
     );
-  },
-});
+  }
+}
 
 function renderParentIntoDocument() {
   return ReactTestUtils.renderIntoDocument(<ParentComponent />);
 }
 
-describe('ReactDOMTreeTraversal', function() {
+describe('ReactDOMTreeTraversal', () => {
   var ReactDOMTreeTraversal;
 
   var aggregatedArgs;
-  function argAggregator(inst, isUp, arg) {
+  function argAggregator(inst, phase, arg) {
     aggregatedArgs.push({
       node: ReactDOMComponentTree.getNodeFromInstance(inst),
-      isUp: isUp,
+      phase: phase,
       arg: arg,
     });
   }
@@ -66,162 +66,195 @@ describe('ReactDOMTreeTraversal', function() {
     return ReactDOMComponentTree.getInstanceFromNode(node);
   }
 
-  beforeEach(function() {
+  beforeEach(() => {
     ReactDOMTreeTraversal = require('ReactDOMTreeTraversal');
     aggregatedArgs = [];
   });
 
-  describe('traverseTwoPhase', function() {
-    it('should not traverse when traversing outside DOM', function() {
+  describe('traverseTwoPhase', () => {
+    it('should not traverse when traversing outside DOM', () => {
       var expectedAggregation = [];
       ReactDOMTreeTraversal.traverseTwoPhase(null, argAggregator, ARG);
       expect(aggregatedArgs).toEqual(expectedAggregation);
     });
 
-    it('should traverse two phase across component boundary', function() {
+    it('should traverse two phase across component boundary', () => {
       var parent = renderParentIntoDocument();
       var target = getInst(parent.refs.P_P1_C1.refs.DIV_1);
       var expectedAggregation = [
-        {node: parent.refs.P, isUp: false, arg: ARG},
-        {node: parent.refs.P_P1, isUp: false, arg: ARG},
-        {node: parent.refs.P_P1_C1.refs.DIV, isUp: false, arg: ARG},
-        {node: parent.refs.P_P1_C1.refs.DIV_1, isUp: false, arg: ARG},
+        {node: parent.refs.P, phase: 'captured', arg: ARG},
+        {node: parent.refs.P_P1, phase: 'captured', arg: ARG},
+        {node: parent.refs.P_P1_C1.refs.DIV, phase: 'captured', arg: ARG},
+        {node: parent.refs.P_P1_C1.refs.DIV_1, phase: 'captured', arg: ARG},
 
-        {node: parent.refs.P_P1_C1.refs.DIV_1, isUp: true, arg: ARG},
-        {node: parent.refs.P_P1_C1.refs.DIV, isUp: true, arg: ARG},
-        {node: parent.refs.P_P1, isUp: true, arg: ARG},
-        {node: parent.refs.P, isUp: true, arg: ARG},
+        {node: parent.refs.P_P1_C1.refs.DIV_1, phase: 'bubbled', arg: ARG},
+        {node: parent.refs.P_P1_C1.refs.DIV, phase: 'bubbled', arg: ARG},
+        {node: parent.refs.P_P1, phase: 'bubbled', arg: ARG},
+        {node: parent.refs.P, phase: 'bubbled', arg: ARG},
       ];
       ReactDOMTreeTraversal.traverseTwoPhase(target, argAggregator, ARG);
       expect(aggregatedArgs).toEqual(expectedAggregation);
     });
 
-    it('should traverse two phase at shallowest node', function() {
+    it('should traverse two phase at shallowest node', () => {
       var parent = renderParentIntoDocument();
       var target = getInst(parent.refs.P);
       var expectedAggregation = [
-        {node: parent.refs.P, isUp: false, arg: ARG},
-        {node: parent.refs.P, isUp: true, arg: ARG},
+        {node: parent.refs.P, phase: 'captured', arg: ARG},
+        {node: parent.refs.P, phase: 'bubbled', arg: ARG},
       ];
       ReactDOMTreeTraversal.traverseTwoPhase(target, argAggregator, ARG);
       expect(aggregatedArgs).toEqual(expectedAggregation);
     });
   });
 
-  describe('traverseEnterLeave', function() {
-    it('should not traverse when enter/leaving outside DOM', function() {
+  describe('traverseEnterLeave', () => {
+    it('should not traverse when enter/leaving outside DOM', () => {
       var target = null;
       var expectedAggregation = [];
       ReactDOMTreeTraversal.traverseEnterLeave(
-        target, target, argAggregator, ARG, ARG2
+        target,
+        target,
+        argAggregator,
+        ARG,
+        ARG2,
       );
       expect(aggregatedArgs).toEqual(expectedAggregation);
     });
 
-    it('should not traverse if enter/leave the same node', function() {
+    it('should not traverse if enter/leave the same node', () => {
       var parent = renderParentIntoDocument();
       var leave = getInst(parent.refs.P_P1_C1.refs.DIV_1);
       var enter = getInst(parent.refs.P_P1_C1.refs.DIV_1);
       var expectedAggregation = [];
       ReactDOMTreeTraversal.traverseEnterLeave(
-        leave, enter, argAggregator, ARG, ARG2
+        leave,
+        enter,
+        argAggregator,
+        ARG,
+        ARG2,
       );
       expect(aggregatedArgs).toEqual(expectedAggregation);
     });
 
-    it('should traverse enter/leave to sibling - avoids parent', function() {
+    it('should traverse enter/leave to sibling - avoids parent', () => {
       var parent = renderParentIntoDocument();
       var leave = getInst(parent.refs.P_P1_C1.refs.DIV_1);
       var enter = getInst(parent.refs.P_P1_C1.refs.DIV_2);
       var expectedAggregation = [
-        {node: parent.refs.P_P1_C1.refs.DIV_1, isUp: true, arg: ARG},
+        {node: parent.refs.P_P1_C1.refs.DIV_1, phase: 'bubbled', arg: ARG},
         // enter/leave shouldn't fire anything on the parent
-        {node: parent.refs.P_P1_C1.refs.DIV_2, isUp: false, arg: ARG2},
+        {node: parent.refs.P_P1_C1.refs.DIV_2, phase: 'captured', arg: ARG2},
       ];
       ReactDOMTreeTraversal.traverseEnterLeave(
-        leave, enter, argAggregator, ARG, ARG2
+        leave,
+        enter,
+        argAggregator,
+        ARG,
+        ARG2,
       );
       expect(aggregatedArgs).toEqual(expectedAggregation);
     });
 
-    it('should traverse enter/leave to parent - avoids parent', function() {
+    it('should traverse enter/leave to parent - avoids parent', () => {
       var parent = renderParentIntoDocument();
       var leave = getInst(parent.refs.P_P1_C1.refs.DIV_1);
       var enter = getInst(parent.refs.P_P1_C1.refs.DIV);
       var expectedAggregation = [
-        {node: parent.refs.P_P1_C1.refs.DIV_1, isUp: true, arg: ARG},
+        {node: parent.refs.P_P1_C1.refs.DIV_1, phase: 'bubbled', arg: ARG},
       ];
       ReactDOMTreeTraversal.traverseEnterLeave(
-        leave, enter, argAggregator, ARG, ARG2
+        leave,
+        enter,
+        argAggregator,
+        ARG,
+        ARG2,
       );
       expect(aggregatedArgs).toEqual(expectedAggregation);
     });
 
-    it('should enter from the window', function() {
+    it('should enter from the window', () => {
       var parent = renderParentIntoDocument();
       var leave = null; // From the window or outside of the React sandbox.
       var enter = getInst(parent.refs.P_P1_C1.refs.DIV);
       var expectedAggregation = [
-        {node: parent.refs.P, isUp: false, arg: ARG2},
-        {node: parent.refs.P_P1, isUp: false, arg: ARG2},
-        {node: parent.refs.P_P1_C1.refs.DIV, isUp: false, arg: ARG2},
+        {node: parent.refs.P, phase: 'captured', arg: ARG2},
+        {node: parent.refs.P_P1, phase: 'captured', arg: ARG2},
+        {node: parent.refs.P_P1_C1.refs.DIV, phase: 'captured', arg: ARG2},
       ];
       ReactDOMTreeTraversal.traverseEnterLeave(
-        leave, enter, argAggregator, ARG, ARG2
+        leave,
+        enter,
+        argAggregator,
+        ARG,
+        ARG2,
       );
       expect(aggregatedArgs).toEqual(expectedAggregation);
     });
 
-    it('should enter from the window to the shallowest', function() {
+    it('should enter from the window to the shallowest', () => {
       var parent = renderParentIntoDocument();
       var leave = null; // From the window or outside of the React sandbox.
       var enter = getInst(parent.refs.P);
       var expectedAggregation = [
-        {node: parent.refs.P, isUp: false, arg: ARG2},
+        {node: parent.refs.P, phase: 'captured', arg: ARG2},
       ];
       ReactDOMTreeTraversal.traverseEnterLeave(
-        leave, enter, argAggregator, ARG, ARG2
+        leave,
+        enter,
+        argAggregator,
+        ARG,
+        ARG2,
       );
       expect(aggregatedArgs).toEqual(expectedAggregation);
     });
 
-    it('should leave to the window', function() {
+    it('should leave to the window', () => {
       var parent = renderParentIntoDocument();
       var enter = null; // From the window or outside of the React sandbox.
       var leave = getInst(parent.refs.P_P1_C1.refs.DIV);
       var expectedAggregation = [
-        {node: parent.refs.P_P1_C1.refs.DIV, isUp: true, arg: ARG},
-        {node: parent.refs.P_P1, isUp: true, arg: ARG},
-        {node: parent.refs.P, isUp: true, arg: ARG},
+        {node: parent.refs.P_P1_C1.refs.DIV, phase: 'bubbled', arg: ARG},
+        {node: parent.refs.P_P1, phase: 'bubbled', arg: ARG},
+        {node: parent.refs.P, phase: 'bubbled', arg: ARG},
       ];
       ReactDOMTreeTraversal.traverseEnterLeave(
-        leave, enter, argAggregator, ARG, ARG2
+        leave,
+        enter,
+        argAggregator,
+        ARG,
+        ARG2,
       );
       expect(aggregatedArgs).toEqual(expectedAggregation);
     });
 
-    it('should leave to the window from the shallowest', function() {
+    it('should leave to the window from the shallowest', () => {
       var parent = renderParentIntoDocument();
       var enter = null; // From the window or outside of the React sandbox.
       var leave = getInst(parent.refs.P_P1_C1.refs.DIV);
       var expectedAggregation = [
-        {node: parent.refs.P_P1_C1.refs.DIV, isUp: true, arg: ARG},
-        {node: parent.refs.P_P1, isUp: true, arg: ARG},
-        {node: parent.refs.P, isUp: true, arg: ARG},
+        {node: parent.refs.P_P1_C1.refs.DIV, phase: 'bubbled', arg: ARG},
+        {node: parent.refs.P_P1, phase: 'bubbled', arg: ARG},
+        {node: parent.refs.P, phase: 'bubbled', arg: ARG},
       ];
       ReactDOMTreeTraversal.traverseEnterLeave(
-        leave, enter, argAggregator, ARG, ARG2
+        leave,
+        enter,
+        argAggregator,
+        ARG,
+        ARG2,
       );
       expect(aggregatedArgs).toEqual(expectedAggregation);
     });
   });
 
-  describe('getFirstCommonAncestor', function() {
-    it('should determine the first common ancestor correctly', function() {
+  describe('getFirstCommonAncestor', () => {
+    it('should determine the first common ancestor correctly', () => {
       var parent = renderParentIntoDocument();
       var ancestors = [
         // Common ancestor with self is self.
-        {one: parent.refs.P_P1_C1.refs.DIV_1,
+        {
+          one: parent.refs.P_P1_C1.refs.DIV_1,
           two: parent.refs.P_P1_C1.refs.DIV_1,
           com: parent.refs.P_P1_C1.refs.DIV_1,
         },
@@ -263,11 +296,10 @@ describe('ReactDOMTreeTraversal', function() {
         var plan = ancestors[i];
         var firstCommon = ReactDOMTreeTraversal.getLowestCommonAncestor(
           getInst(plan.one),
-          getInst(plan.two)
+          getInst(plan.two),
         );
         expect(firstCommon).toBe(getInst(plan.com));
       }
     });
   });
-
 });
diff --git a/src/renderers/dom/client/__tests__/ReactEventIndependence-test.js b/src/renderers/dom/client/__tests__/ReactEventIndependence-test.js
index e652e9e1ca6a..ed5ce813f7b0 100644
--- a/src/renderers/dom/client/__tests__/ReactEventIndependence-test.js
+++ b/src/renderers/dom/client/__tests__/ReactEventIndependence-test.js
@@ -15,8 +15,8 @@ var React;
 var ReactDOM;
 var ReactTestUtils;
 
-describe('ReactEventIndependence', function() {
-  beforeEach(function() {
+describe('ReactEventIndependence', () => {
+  beforeEach(() => {
     jest.resetModuleRegistry();
 
     React = require('React');
@@ -24,7 +24,7 @@ describe('ReactEventIndependence', function() {
     ReactTestUtils = require('ReactTestUtils');
   });
 
-  it('does not crash with other react inside', function() {
+  it('does not crash with other react inside', () => {
     var clicks = 0;
     var div = ReactTestUtils.renderIntoDocument(
       <div
@@ -32,30 +32,30 @@ describe('ReactEventIndependence', function() {
         dangerouslySetInnerHTML={{
           __html: '<button data-reactid=".z">click me</div>',
         }}
-      />
+      />,
     );
     ReactTestUtils.SimulateNative.click(div.firstChild);
     expect(clicks).toBe(1);
   });
 
-  it('does not crash with other react outside', function() {
+  it('does not crash with other react outside', () => {
     var clicks = 0;
     var outer = document.createElement('div');
     outer.setAttribute('data-reactid', '.z');
     var inner = ReactDOM.render(
       <button onClick={() => clicks++}>click me</button>,
-      outer
+      outer,
     );
     ReactTestUtils.SimulateNative.click(inner);
     expect(clicks).toBe(1);
   });
 
-  it('does not when event fired on unmounted tree', function() {
+  it('does not when event fired on unmounted tree', () => {
     var clicks = 0;
     var container = document.createElement('div');
     var button = ReactDOM.render(
       <button onClick={() => clicks++}>click me</button>,
-      container
+      container,
     );
 
     // Now we unmount the component, as if caused by a non-React event handler
@@ -66,5 +66,4 @@ describe('ReactEventIndependence', function() {
     // Since the tree is unmounted, we don't dispatch the click event.
     expect(clicks).toBe(0);
   });
-
 });
diff --git a/src/renderers/dom/client/__tests__/ReactEventListener-test.js b/src/renderers/dom/client/__tests__/ReactEventListener-test.js
index 49d4f195d5b9..598da2c6f12a 100644
--- a/src/renderers/dom/client/__tests__/ReactEventListener-test.js
+++ b/src/renderers/dom/client/__tests__/ReactEventListener-test.js
@@ -11,10 +11,9 @@
 
 'use strict';
 
-
 var EVENT_TARGET_PARAM = 1;
 
-describe('ReactEventListener', function() {
+describe('ReactEventListener', () => {
   var React;
   var ReactDOM;
   var ReactDOMComponentTree;
@@ -22,7 +21,7 @@ describe('ReactEventListener', function() {
   var ReactTestUtils;
   var handleTopLevel;
 
-  beforeEach(function() {
+  beforeEach(() => {
     jest.resetModuleRegistry();
     React = require('React');
     ReactDOM = require('ReactDOM');
@@ -30,39 +29,35 @@ describe('ReactEventListener', function() {
     ReactEventListener = require('ReactEventListener');
     ReactTestUtils = require('ReactTestUtils');
 
-    handleTopLevel = jest.genMockFn();
+    handleTopLevel = jest.fn();
     ReactEventListener._handleTopLevel = handleTopLevel;
   });
 
-  it('should dispatch events from outside React tree', function() {
+  it('should dispatch events from outside React tree', () => {
     var otherNode = document.createElement('h1');
     var component = ReactDOM.render(<div />, document.createElement('div'));
     expect(handleTopLevel.mock.calls.length).toBe(0);
-    ReactEventListener.dispatchEvent(
-      'topMouseOut',
-      {
-        type: 'mouseout',
-        fromElement: otherNode,
-        target: otherNode,
-        srcElement: otherNode,
-        toElement: ReactDOM.findDOMNode(component),
-        relatedTarget: ReactDOM.findDOMNode(component),
-        view: window,
-        path: [otherNode, otherNode],
-      },
-    );
+    ReactEventListener.dispatchEvent('topMouseOut', {
+      type: 'mouseout',
+      fromElement: otherNode,
+      target: otherNode,
+      srcElement: otherNode,
+      toElement: ReactDOM.findDOMNode(component),
+      relatedTarget: ReactDOM.findDOMNode(component),
+      view: window,
+      path: [otherNode, otherNode],
+    });
     expect(handleTopLevel.mock.calls.length).toBe(1);
   });
 
-  describe('Propagation', function() {
-    it('should propagate events one level down', function() {
+  describe('Propagation', () => {
+    it('should propagate events one level down', () => {
       var childContainer = document.createElement('div');
       var childControl = <div>Child</div>;
       var parentContainer = document.createElement('div');
       var parentControl = <div>Parent</div>;
       childControl = ReactDOM.render(childControl, childContainer);
-      parentControl =
-        ReactDOM.render(parentControl, parentContainer);
+      parentControl = ReactDOM.render(parentControl, parentContainer);
       ReactDOM.findDOMNode(parentControl).appendChild(childContainer);
 
       var callback = ReactEventListener.dispatchEvent.bind(null, 'test');
@@ -72,13 +67,15 @@ describe('ReactEventListener', function() {
 
       var calls = handleTopLevel.mock.calls;
       expect(calls.length).toBe(2);
-      expect(calls[0][EVENT_TARGET_PARAM])
-        .toBe(ReactDOMComponentTree.getInstanceFromNode(childControl));
-      expect(calls[1][EVENT_TARGET_PARAM])
-        .toBe(ReactDOMComponentTree.getInstanceFromNode(parentControl));
+      expect(calls[0][EVENT_TARGET_PARAM]).toBe(
+        ReactDOMComponentTree.getInstanceFromNode(childControl),
+      );
+      expect(calls[1][EVENT_TARGET_PARAM]).toBe(
+        ReactDOMComponentTree.getInstanceFromNode(parentControl),
+      );
     });
 
-    it('should propagate events two levels down', function() {
+    it('should propagate events two levels down', () => {
       var childContainer = document.createElement('div');
       var childControl = <div>Child</div>;
       var parentContainer = document.createElement('div');
@@ -86,10 +83,11 @@ describe('ReactEventListener', function() {
       var grandParentContainer = document.createElement('div');
       var grandParentControl = <div>Parent</div>;
       childControl = ReactDOM.render(childControl, childContainer);
-      parentControl =
-        ReactDOM.render(parentControl, parentContainer);
-      grandParentControl =
-        ReactDOM.render(grandParentControl, grandParentContainer);
+      parentControl = ReactDOM.render(parentControl, parentContainer);
+      grandParentControl = ReactDOM.render(
+        grandParentControl,
+        grandParentContainer,
+      );
       ReactDOM.findDOMNode(parentControl).appendChild(childContainer);
       ReactDOM.findDOMNode(grandParentControl).appendChild(parentContainer);
 
@@ -100,22 +98,24 @@ describe('ReactEventListener', function() {
 
       var calls = handleTopLevel.mock.calls;
       expect(calls.length).toBe(3);
-      expect(calls[0][EVENT_TARGET_PARAM])
-        .toBe(ReactDOMComponentTree.getInstanceFromNode(childControl));
-      expect(calls[1][EVENT_TARGET_PARAM])
-        .toBe(ReactDOMComponentTree.getInstanceFromNode(parentControl));
-      expect(calls[2][EVENT_TARGET_PARAM])
-        .toBe(ReactDOMComponentTree.getInstanceFromNode(grandParentControl));
+      expect(calls[0][EVENT_TARGET_PARAM]).toBe(
+        ReactDOMComponentTree.getInstanceFromNode(childControl),
+      );
+      expect(calls[1][EVENT_TARGET_PARAM]).toBe(
+        ReactDOMComponentTree.getInstanceFromNode(parentControl),
+      );
+      expect(calls[2][EVENT_TARGET_PARAM]).toBe(
+        ReactDOMComponentTree.getInstanceFromNode(grandParentControl),
+      );
     });
 
-    it('should not get confused by disappearing elements', function() {
+    it('should not get confused by disappearing elements', () => {
       var childContainer = document.createElement('div');
       var childControl = <div>Child</div>;
       var parentContainer = document.createElement('div');
       var parentControl = <div>Parent</div>;
       childControl = ReactDOM.render(childControl, childContainer);
-      parentControl =
-        ReactDOM.render(parentControl, parentContainer);
+      parentControl = ReactDOM.render(parentControl, parentContainer);
       ReactDOM.findDOMNode(parentControl).appendChild(childContainer);
 
       // ReactBrowserEventEmitter.handleTopLevel might remove the
@@ -123,13 +123,16 @@ describe('ReactEventListener', function() {
       // node when the first event handlers are called; we'll still
       // expect to receive a second call for the parent control.
       var childNode = ReactDOM.findDOMNode(childControl);
-      handleTopLevel.mockImplementation(
-        function(topLevelType, topLevelTarget, topLevelTargetID, nativeEvent) {
-          if (topLevelTarget === childNode) {
-            ReactDOM.unmountComponentAtNode(childContainer);
-          }
+      handleTopLevel.mockImplementation(function(
+        topLevelType,
+        topLevelTarget,
+        topLevelTargetID,
+        nativeEvent,
+      ) {
+        if (topLevelTarget === childNode) {
+          ReactDOM.unmountComponentAtNode(childContainer);
         }
-      );
+      });
 
       var callback = ReactEventListener.dispatchEvent.bind(null, 'test');
       callback({
@@ -138,41 +141,42 @@ describe('ReactEventListener', function() {
 
       var calls = handleTopLevel.mock.calls;
       expect(calls.length).toBe(2);
-      expect(calls[0][EVENT_TARGET_PARAM])
-        .toBe(ReactDOMComponentTree.getInstanceFromNode(childNode));
-      expect(calls[1][EVENT_TARGET_PARAM])
-        .toBe(ReactDOMComponentTree.getInstanceFromNode(parentControl));
+      expect(calls[0][EVENT_TARGET_PARAM]).toBe(
+        ReactDOMComponentTree.getInstanceFromNode(childNode),
+      );
+      expect(calls[1][EVENT_TARGET_PARAM]).toBe(
+        ReactDOMComponentTree.getInstanceFromNode(parentControl),
+      );
     });
 
-    it('should batch between handlers from different roots', function() {
+    it('should batch between handlers from different roots', () => {
       var childContainer = document.createElement('div');
       var parentContainer = document.createElement('div');
-      var childControl = ReactDOM.render(
-        <div>Child</div>,
-        childContainer
-      );
-      var parentControl = ReactDOM.render(
-        <div>Parent</div>,
-        parentContainer
-      );
+      var childControl = ReactDOM.render(<div>Child</div>, childContainer);
+      var parentControl = ReactDOM.render(<div>Parent</div>, parentContainer);
       ReactDOM.findDOMNode(parentControl).appendChild(childContainer);
 
       // Suppose an event handler in each root enqueues an update to the
       // childControl element -- the two updates should get batched together.
       var childNode = ReactDOM.findDOMNode(childControl);
-      handleTopLevel.mockImplementation(
-        function(topLevelType, topLevelTarget, topLevelTargetID, nativeEvent) {
-          ReactDOM.render(
-            <div>{topLevelTarget === childNode ? '1' : '2'}</div>,
-            childContainer
-          );
-          // Since we're batching, neither update should yet have gone through.
-          expect(childNode.textContent).toBe('Child');
-        }
-      );
+      handleTopLevel.mockImplementation(function(
+        topLevelType,
+        topLevelTarget,
+        topLevelTargetID,
+        nativeEvent,
+      ) {
+        ReactDOM.render(
+          <div>{topLevelTarget === childNode ? '1' : '2'}</div>,
+          childContainer,
+        );
+        // Since we're batching, neither update should yet have gone through.
+        expect(childNode.textContent).toBe('Child');
+      });
 
-      var callback =
-        ReactEventListener.dispatchEvent.bind(ReactEventListener, 'test');
+      var callback = ReactEventListener.dispatchEvent.bind(
+        ReactEventListener,
+        'test',
+      );
       callback({
         target: childNode,
       });
@@ -183,19 +187,17 @@ describe('ReactEventListener', function() {
     });
   });
 
-  it('should not fire duplicate events for a React DOM tree', function() {
-    var Wrapper = React.createClass({
-
-      getInner: function() {
+  it('should not fire duplicate events for a React DOM tree', () => {
+    class Wrapper extends React.Component {
+      getInner = () => {
         return this.refs.inner;
-      },
+      };
 
-      render: function() {
+      render() {
         var inner = <div ref="inner">Inner</div>;
         return <div><div id="outer">{inner}</div></div>;
-      },
-
-    });
+      }
+    }
 
     var instance = ReactTestUtils.renderIntoDocument(<Wrapper />);
 
@@ -206,7 +208,8 @@ describe('ReactEventListener', function() {
 
     var calls = handleTopLevel.mock.calls;
     expect(calls.length).toBe(1);
-    expect(calls[0][EVENT_TARGET_PARAM])
-      .toBe(ReactDOMComponentTree.getInstanceFromNode(instance.getInner()));
+    expect(calls[0][EVENT_TARGET_PARAM]).toBe(
+      ReactDOMComponentTree.getInstanceFromNode(instance.getInner()),
+    );
   });
 });
diff --git a/src/renderers/dom/client/__tests__/ReactMount-test.js b/src/renderers/dom/client/__tests__/ReactMount-test.js
index 06b1c1641535..d83bd1108bd9 100644
--- a/src/renderers/dom/client/__tests__/ReactMount-test.js
+++ b/src/renderers/dom/client/__tests__/ReactMount-test.js
@@ -18,8 +18,8 @@ var ReactMount;
 var ReactTestUtils;
 var WebComponents;
 
-describe('ReactMount', function() {
-  beforeEach(function() {
+describe('ReactMount', () => {
+  beforeEach(() => {
     jest.resetModuleRegistry();
 
     React = require('React');
@@ -39,64 +39,65 @@ describe('ReactMount', function() {
     }
   });
 
-  describe('unmountComponentAtNode', function() {
-    it('throws when given a non-node', function() {
+  describe('unmountComponentAtNode', () => {
+    it('throws when given a non-node', () => {
       var nodeArray = document.getElementsByTagName('div');
       expect(function() {
         ReactDOM.unmountComponentAtNode(nodeArray);
-      }).toThrow(
-        'unmountComponentAtNode(...): Target container is not a DOM element.'
+      }).toThrowError(
+        'unmountComponentAtNode(...): Target container is not a DOM element.',
       );
     });
   });
 
-  it('throws when given a string', function() {
+  it('throws when given a string', () => {
     expect(function() {
       ReactTestUtils.renderIntoDocument('div');
-    }).toThrow(
+    }).toThrowError(
       'ReactDOM.render(): Invalid component element. Instead of passing a ' +
-      'string like \'div\', pass React.createElement(\'div\') or <div />.'
+        "string like 'div', pass React.createElement('div') or <div />.",
     );
   });
 
-  it('throws when given a factory', function() {
-    var Component = React.createClass({
-      render: function() {
+  it('throws when given a factory', () => {
+    class Component extends React.Component {
+      render() {
         return <div />;
-      },
-    });
+      }
+    }
+
     expect(function() {
       ReactTestUtils.renderIntoDocument(Component);
-    }).toThrow(
+    }).toThrowError(
       'ReactDOM.render(): Invalid component element. Instead of passing a ' +
-      'class like Foo, pass React.createElement(Foo) or <Foo />.'
+        'class like Foo, pass React.createElement(Foo) or <Foo />.',
     );
   });
 
-  it('should render different components in same root', function() {
+  it('should render different components in same root', () => {
     var container = document.createElement('container');
     document.body.appendChild(container);
 
-    ReactMount.render(<div></div>, container);
+    ReactMount.render(<div />, container);
     expect(container.firstChild.nodeName).toBe('DIV');
 
-    ReactMount.render(<span></span>, container);
+    ReactMount.render(<span />, container);
     expect(container.firstChild.nodeName).toBe('SPAN');
   });
 
-  it('should unmount and remount if the key changes', function() {
+  it('should unmount and remount if the key changes', () => {
     var container = document.createElement('container');
 
-    var mockMount = jest.genMockFn();
-    var mockUnmount = jest.genMockFn();
+    var mockMount = jest.fn();
+    var mockUnmount = jest.fn();
 
-    var Component = React.createClass({
-      componentDidMount: mockMount,
-      componentWillUnmount: mockUnmount,
-      render: function() {
+    class Component extends React.Component {
+      componentDidMount = mockMount;
+      componentWillUnmount = mockUnmount;
+      render() {
         return <span>{this.props.text}</span>;
-      },
-    });
+      }
+    }
 
     expect(mockMount.mock.calls.length).toBe(0);
     expect(mockUnmount.mock.calls.length).toBe(0);
@@ -119,7 +120,7 @@ describe('ReactMount', function() {
     expect(mockUnmount.mock.calls.length).toBe(1);
   });
 
-  it('should reuse markup if rendering to the same target twice', function() {
+  it('should reuse markup if rendering to the same target twice', () => {
     var container = document.createElement('container');
     var instance1 = ReactDOM.render(<div />, container);
     var instance2 = ReactDOM.render(<div />, container);
@@ -127,62 +128,63 @@ describe('ReactMount', function() {
     expect(instance1 === instance2).toBe(true);
   });
 
-  it('should warn if mounting into dirty rendered markup', function() {
+  it('should warn if mounting into dirty rendered markup', () => {
     var container = document.createElement('container');
     container.innerHTML = ReactDOMServer.renderToString(<div />) + ' ';
 
     spyOn(console, 'error');
     ReactMount.render(<div />, container);
-    expect(console.error.calls.length).toBe(1);
+    expect(console.error.calls.count()).toBe(1);
 
     container.innerHTML = ' ' + ReactDOMServer.renderToString(<div />);
 
     ReactMount.render(<div />, container);
-    expect(console.error.calls.length).toBe(2);
+    expect(console.error.calls.count()).toBe(2);
   });
 
-  it('should not warn if mounting into non-empty node', function() {
+  it('should not warn if mounting into non-empty node', () => {
     var container = document.createElement('container');
     container.innerHTML = '<div></div>';
 
     spyOn(console, 'error');
     ReactMount.render(<div />, container);
-    expect(console.error.calls.length).toBe(0);
+    expect(console.error.calls.count()).toBe(0);
   });
 
-  it('should warn when mounting into document.body', function() {
+  it('should warn when mounting into document.body', () => {
     var iFrame = document.createElement('iframe');
     document.body.appendChild(iFrame);
     spyOn(console, 'error');
 
     ReactMount.render(<div />, iFrame.contentDocument.body);
 
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
-      'Rendering components directly into document.body is discouraged'
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'Rendering components directly into document.body is discouraged',
     );
   });
 
-  it('should account for escaping on a checksum mismatch', function() {
+  it('should account for escaping on a checksum mismatch', () => {
     var div = document.createElement('div');
     var markup = ReactDOMServer.renderToString(
-      <div>This markup contains an nbsp entity: &nbsp; server text</div>);
+      <div>This markup contains an nbsp entity: &nbsp; server text</div>,
+    );
     div.innerHTML = markup;
 
     spyOn(console, 'error');
     ReactDOM.render(
       <div>This markup contains an nbsp entity: &nbsp; client text</div>,
-      div
+      div,
     );
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
       ' (client) nbsp entity: &nbsp; client text</div>\n' +
-      ' (server) nbsp entity: &nbsp; server text</div>'
+        ' (server) nbsp entity: &nbsp; server text</div>',
     );
   });
 
   if (WebComponents !== undefined) {
-    it('should allow mounting/unmounting to document fragment container', function() {
+    it('should allow mounting/unmounting to document fragment container', () => {
       var shadowRoot;
       var proto = Object.create(HTMLElement.prototype, {
         createdCallback: {
@@ -204,29 +206,59 @@ describe('ReactMount', function() {
     });
   }
 
-  it('should warn if render removes React-rendered children', function() {
+  it('should warn if render removes React-rendered children', () => {
     var container = document.createElement('container');
-    var Component = React.createClass({
-      render: function() {
+
+    class Component extends React.Component {
+      render() {
         return <div><div /></div>;
-      },
-    });
+      }
+    }
+
     ReactDOM.render(<Component />, container);
 
     // Test that blasting away children throws a warning
     spyOn(console, 'error');
     var rootNode = container.firstChild;
     ReactDOM.render(<span />, rootNode);
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
       'Warning: 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.'
+        '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.',
     );
   });
 
-  it('passes the correct callback context', function() {
+  it('should warn if the unmounted node was rendered by another copy of React', () => {
+    jest.resetModuleRegistry();
+    var ReactDOMOther = require('ReactDOM');
+    var container = document.createElement('div');
+
+    class Component extends React.Component {
+      render() {
+        return <div><div /></div>;
+      }
+    }
+
+    ReactDOM.render(<Component />, container);
+    // Make sure ReactDOM and ReactDOMOther are different copies
+    expect(ReactDOM).not.toEqual(ReactDOMOther);
+
+    spyOn(console, 'error');
+    ReactDOMOther.unmountComponentAtNode(container);
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      "Warning: unmountComponentAtNode(): The node you're attempting to unmount " +
+        'was rendered by another copy of React.',
+    );
+
+    // Don't throw a warning if the correct React copy unmounts the node
+    ReactDOM.unmountComponentAtNode(container);
+    expect(console.error.calls.count()).toBe(1);
+  });
+
+  it('passes the correct callback context', () => {
     var container = document.createElement('div');
     var calls = 0;
 
@@ -266,7 +298,7 @@ describe('ReactMount', function() {
     expect(calls).toBe(5);
   });
 
-  it('tracks root instances', function() {
+  it('tracks root instances', () => {
     // Used by devtools.
     expect(Object.keys(ReactMount._instancesByReactRootID).length).toBe(0);
     ReactTestUtils.renderIntoDocument(<span />);
@@ -278,20 +310,20 @@ describe('ReactMount', function() {
     expect(Object.keys(ReactMount._instancesByReactRootID).length).toBe(1);
   });
 
-  it('marks top-level mounts', function() {
+  it('marks top-level mounts', () => {
     var ReactFeatureFlags = require('ReactFeatureFlags');
 
-    var Foo = React.createClass({
-      render: function() {
+    class Foo extends React.Component {
+      render() {
         return <Bar />;
-      },
-    });
+      }
+    }
 
-    var Bar = React.createClass({
-      render: function() {
+    class Bar extends React.Component {
+      render() {
         return <div />;
-      },
-    });
+      }
+    }
 
     try {
       ReactFeatureFlags.logTopLevelRenders = true;
@@ -300,10 +332,10 @@ describe('ReactMount', function() {
 
       ReactTestUtils.renderIntoDocument(<Foo />);
 
-      expect(console.time.argsForCall.length).toBe(1);
-      expect(console.time.argsForCall[0][0]).toBe('React mount: Foo');
-      expect(console.timeEnd.argsForCall.length).toBe(1);
-      expect(console.timeEnd.argsForCall[0][0]).toBe('React mount: Foo');
+      expect(console.time.calls.count()).toBe(1);
+      expect(console.time.calls.argsFor(0)[0]).toBe('React mount: Foo');
+      expect(console.timeEnd.calls.count()).toBe(1);
+      expect(console.timeEnd.calls.argsFor(0)[0]).toBe('React mount: Foo');
     } finally {
       ReactFeatureFlags.logTopLevelRenders = false;
     }
diff --git a/src/renderers/dom/client/__tests__/ReactMountDestruction-test.js b/src/renderers/dom/client/__tests__/ReactMountDestruction-test.js
index a4d8e3997310..37cc4f5b9dba 100644
--- a/src/renderers/dom/client/__tests__/ReactMountDestruction-test.js
+++ b/src/renderers/dom/client/__tests__/ReactMountDestruction-test.js
@@ -14,8 +14,8 @@
 var React = require('React');
 var ReactDOM = require('ReactDOM');
 
-describe('ReactMount', function() {
-  it('should destroy a react root upon request', function() {
+describe('ReactMount', () => {
+  it('should destroy a react root upon request', () => {
     var mainContainerDiv = document.createElement('div');
     document.body.appendChild(mainContainerDiv);
 
@@ -40,49 +40,51 @@ describe('ReactMount', function() {
     expect(secondRootDiv.firstChild).toBeNull();
   });
 
-  it('should warn when unmounting a non-container root node', function() {
+  it('should warn when unmounting a non-container root node', () => {
     var mainContainerDiv = document.createElement('div');
 
-    var component =
+    var component = (
       <div>
         <div />
-      </div>;
+      </div>
+    );
     ReactDOM.render(component, mainContainerDiv);
 
     // Test that unmounting at a root node gives a helpful warning
     var rootDiv = mainContainerDiv.firstChild;
     spyOn(console, 'error');
     ReactDOM.unmountComponentAtNode(rootDiv);
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: unmountComponentAtNode(): The node you\'re attempting to ' +
-      'unmount was rendered by React and is not a top-level container. You ' +
-      'may have accidentally passed in a React root node instead of its ' +
-      'container.'
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      "Warning: unmountComponentAtNode(): The node you're attempting to " +
+        'unmount was rendered by React and is not a top-level container. You ' +
+        'may have accidentally passed in a React root node instead of its ' +
+        'container.',
     );
   });
 
-  it('should warn when unmounting a non-container, non-root node', function() {
+  it('should warn when unmounting a non-container, non-root node', () => {
     var mainContainerDiv = document.createElement('div');
 
-    var component =
+    var component = (
       <div>
         <div>
           <div />
         </div>
-      </div>;
+      </div>
+    );
     ReactDOM.render(component, mainContainerDiv);
 
     // Test that unmounting at a non-root node gives a different warning
     var nonRootDiv = mainContainerDiv.firstChild.firstChild;
     spyOn(console, 'error');
     ReactDOM.unmountComponentAtNode(nonRootDiv);
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: unmountComponentAtNode(): The node you\'re attempting to ' +
-      'unmount was rendered by React and is not a top-level container. ' +
-      'Instead, have the parent component update its state and rerender in ' +
-      'order to remove this component.'
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      "Warning: unmountComponentAtNode(): The node you're attempting to " +
+        'unmount was rendered by React and is not a top-level container. ' +
+        'Instead, have the parent component update its state and rerender in ' +
+        'order to remove this component.',
     );
   });
 });
diff --git a/src/renderers/dom/client/__tests__/ReactRenderDocument-test.js b/src/renderers/dom/client/__tests__/ReactRenderDocument-test.js
index 1d96826626c4..8150a17f70d6 100644
--- a/src/renderers/dom/client/__tests__/ReactRenderDocument-test.js
+++ b/src/renderers/dom/client/__tests__/ReactRenderDocument-test.js
@@ -26,8 +26,8 @@ var UNMOUNT_INVARIANT_MESSAGE =
   'efficiently. To fix this, have a single top-level component that ' +
   'never unmounts render these elements.';
 
-describe('rendering React components at document', function() {
-  beforeEach(function() {
+describe('rendering React components at document', () => {
+  beforeEach(() => {
     jest.resetModuleRegistry();
 
     React = require('React');
@@ -38,11 +38,11 @@ describe('rendering React components at document', function() {
     testDocument = getTestDocument();
   });
 
-  it('should be able to adopt server markup', function() {
+  it('should be able to adopt server markup', () => {
     expect(testDocument).not.toBeUndefined();
 
-    var Root = React.createClass({
-      render: function() {
+    class Root extends React.Component {
+      render() {
         return (
           <html>
             <head>
@@ -53,8 +53,8 @@ describe('rendering React components at document', function() {
             </body>
           </html>
         );
-      },
-    });
+      }
+    }
 
     var markup = ReactDOMServer.renderToString(<Root hello="world" />);
     testDocument = getTestDocument(markup);
@@ -69,11 +69,11 @@ describe('rendering React components at document', function() {
     expect(body).toBe(testDocument.body);
   });
 
-  it('should not be able to unmount component from document node', function() {
+  it('should not be able to unmount component from document node', () => {
     expect(testDocument).not.toBeUndefined();
 
-    var Root = React.createClass({
-      render: function() {
+    class Root extends React.Component {
+      render() {
         return (
           <html>
             <head>
@@ -84,8 +84,8 @@ describe('rendering React components at document', function() {
             </body>
           </html>
         );
-      },
-    });
+      }
+    }
 
     var markup = ReactDOMServer.renderToString(<Root />);
     testDocument = getTestDocument(markup);
@@ -94,16 +94,16 @@ describe('rendering React components at document', function() {
 
     expect(function() {
       ReactDOM.unmountComponentAtNode(testDocument);
-    }).toThrow(UNMOUNT_INVARIANT_MESSAGE);
+    }).toThrowError(UNMOUNT_INVARIANT_MESSAGE);
 
     expect(testDocument.body.innerHTML).toBe('Hello world');
   });
 
-  it('should not be able to switch root constructors', function() {
+  it('should not be able to switch root constructors', () => {
     expect(testDocument).not.toBeUndefined();
 
-    var Component = React.createClass({
-      render: function() {
+    class Component extends React.Component {
+      render() {
         return (
           <html>
             <head>
@@ -114,11 +114,11 @@ describe('rendering React components at document', function() {
             </body>
           </html>
         );
-      },
-    });
+      }
+    }
 
-    var Component2 = React.createClass({
-      render: function() {
+    class Component2 extends React.Component {
+      render() {
         return (
           <html>
             <head>
@@ -129,8 +129,8 @@ describe('rendering React components at document', function() {
             </body>
           </html>
         );
-      },
-    });
+      }
+    }
 
     var markup = ReactDOMServer.renderToString(<Component />);
     testDocument = getTestDocument(markup);
@@ -142,16 +142,16 @@ describe('rendering React components at document', function() {
     // Reactive update
     expect(function() {
       ReactDOM.render(<Component2 />, testDocument);
-    }).toThrow(UNMOUNT_INVARIANT_MESSAGE);
+    }).toThrowError(UNMOUNT_INVARIANT_MESSAGE);
 
     expect(testDocument.body.innerHTML).toBe('Hello world');
   });
 
-  it('should be able to mount into document', function() {
+  it('should be able to mount into document', () => {
     expect(testDocument).not.toBeUndefined();
 
-    var Component = React.createClass({
-      render: function() {
+    class Component extends React.Component {
+      render() {
         return (
           <html>
             <head>
@@ -162,11 +162,11 @@ describe('rendering React components at document', function() {
             </body>
           </html>
         );
-      },
-    });
+      }
+    }
 
     var markup = ReactDOMServer.renderToString(
-      <Component text="Hello world" />
+      <Component text="Hello world" />,
     );
     testDocument = getTestDocument(markup);
 
@@ -175,11 +175,11 @@ describe('rendering React components at document', function() {
     expect(testDocument.body.innerHTML).toBe('Hello world');
   });
 
-  it('should give helpful errors on state desync', function() {
+  it('should give helpful errors on state desync', () => {
     expect(testDocument).not.toBeUndefined();
 
-    var Component = React.createClass({
-      render: function() {
+    class Component extends React.Component {
+      render() {
         return (
           <html>
             <head>
@@ -190,38 +190,38 @@ describe('rendering React components at document', function() {
             </body>
           </html>
         );
-      },
-    });
+      }
+    }
 
     var markup = ReactDOMServer.renderToString(
-      <Component text="Goodbye world" />
+      <Component text="Goodbye world" />,
     );
     testDocument = getTestDocument(markup);
 
     expect(function() {
       // Notice the text is different!
       ReactDOM.render(<Component text="Hello world" />, testDocument);
-    }).toThrow(
-      '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' +
-      ' (client) dy data-reactid="4">Hello world</body></\n' +
-      ' (server) dy data-reactid="4">Goodbye world</body>'
+    }).toThrowError(
+      "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' +
+        ' (client) dy data-reactid="4">Hello world</body></\n' +
+        ' (server) dy data-reactid="4">Goodbye world</body>',
     );
   });
 
-  it('should throw on full document render w/ no markup', function() {
+  it('should throw on full document render w/ no markup', () => {
     expect(testDocument).not.toBeUndefined();
 
     var container = testDocument;
 
-    var Component = React.createClass({
-      render: function() {
+    class Component extends React.Component {
+      render() {
         return (
           <html>
             <head>
@@ -232,21 +232,21 @@ describe('rendering React components at document', function() {
             </body>
           </html>
         );
-      },
-    });
+      }
+    }
 
     expect(function() {
       ReactDOM.render(<Component />, container);
-    }).toThrow(
-      '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.'
+    }).toThrowError(
+      "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.',
     );
   });
 
-  it('supports findDOMNode on full-page components', function() {
-    var tree =
+  it('supports findDOMNode on full-page components', () => {
+    var tree = (
       <html>
         <head>
           <title>Hello World</title>
@@ -254,7 +254,8 @@ describe('rendering React components at document', function() {
         <body>
           Hello world
         </body>
-      </html>;
+      </html>
+    );
 
     var markup = ReactDOMServer.renderToString(tree);
     testDocument = getTestDocument(markup);
diff --git a/src/renderers/dom/client/__tests__/findDOMNode-test.js b/src/renderers/dom/client/__tests__/findDOMNode-test.js
index 1f861dd3454c..502e24fe70f0 100644
--- a/src/renderers/dom/client/__tests__/findDOMNode-test.js
+++ b/src/renderers/dom/client/__tests__/findDOMNode-test.js
@@ -15,17 +15,17 @@ var React = require('React');
 var ReactDOM = require('ReactDOM');
 var ReactTestUtils = require('ReactTestUtils');
 
-describe('findDOMNode', function() {
-  it('findDOMNode should return null if passed null', function() {
+describe('findDOMNode', () => {
+  it('findDOMNode should return null if passed null', () => {
     expect(ReactDOM.findDOMNode(null)).toBe(null);
   });
 
-  it('findDOMNode should find dom element', function() {
-    var MyNode = React.createClass({
-      render: function() {
+  it('findDOMNode should find dom element', () => {
+    class MyNode extends React.Component {
+      render() {
         return <div><span>Noise</span></div>;
-      },
-    });
+      }
+    }
 
     var myNode = ReactTestUtils.renderIntoDocument(<MyNode />);
     var myDiv = ReactDOM.findDOMNode(myNode);
@@ -34,41 +34,41 @@ describe('findDOMNode', function() {
     expect(mySameDiv).toBe(myDiv);
   });
 
-  it('findDOMNode should reject random objects', function() {
+  it('findDOMNode should reject random objects', () => {
     expect(function() {
       ReactDOM.findDOMNode({foo: 'bar'});
-    }).toThrow(
-      'Element appears to be neither ReactComponent nor DOMNode (keys: foo)'
+    }).toThrowError(
+      'Element appears to be neither ReactComponent nor DOMNode (keys: foo)',
     );
   });
 
-  it('findDOMNode should reject unmounted objects with render func', function() {
-    var Foo = React.createClass({
-      render: function() {
+  it('findDOMNode should reject unmounted objects with render func', () => {
+    class Foo extends React.Component {
+      render() {
         return <div />;
-      },
-    });
+      }
+    }
 
     var container = document.createElement('div');
     var inst = ReactDOM.render(<Foo />, container);
     ReactDOM.unmountComponentAtNode(container);
 
-    expect(() => ReactDOM.findDOMNode(inst)).toThrow(
-      'findDOMNode was called on an unmounted component.'
+    expect(() => ReactDOM.findDOMNode(inst)).toThrowError(
+      'findDOMNode was called on an unmounted component.',
     );
   });
 
-  it('findDOMNode should not throw an error when called within a component that is not mounted', function() {
-    var Bar = React.createClass({
-      componentWillMount: function() {
+  it('findDOMNode should not throw an error when called within a component that is not mounted', () => {
+    class Bar extends React.Component {
+      componentWillMount() {
         expect(ReactDOM.findDOMNode(this)).toBeNull();
-      },
-      render: function() {
-        return <div/>;
-      },
-    });
+      }
 
-    expect(() => ReactTestUtils.renderIntoDocument(<Bar/>)).not.toThrow();
-  });
+      render() {
+        return <div />;
+      }
+    }
 
+    expect(() => ReactTestUtils.renderIntoDocument(<Bar />)).not.toThrow();
+  });
 });
diff --git a/src/renderers/dom/client/__tests__/inputValueTracking-test.js b/src/renderers/dom/client/__tests__/inputValueTracking-test.js
new file mode 100644
index 000000000000..103964cc1d74
--- /dev/null
+++ b/src/renderers/dom/client/__tests__/inputValueTracking-test.js
@@ -0,0 +1,158 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+'use strict';
+
+var React = require('React');
+var ReactTestUtils = require('ReactTestUtils');
+var inputValueTracking = require('inputValueTracking');
+
+describe('inputValueTracking', function() {
+  var input, checkbox, mockComponent;
+
+  beforeEach(function() {
+    input = document.createElement('input');
+    input.type = 'text';
+    checkbox = document.createElement('input');
+    checkbox.type = 'checkbox';
+    mockComponent = {_hostNode: input, _wrapperState: {}};
+  });
+
+  it('should attach tracker to wrapper state', function() {
+    inputValueTracking.track(mockComponent);
+
+    expect(mockComponent._wrapperState.hasOwnProperty('valueTracker')).toBe(
+      true,
+    );
+  });
+
+  it('should define `value` on the instance node', function() {
+    inputValueTracking.track(mockComponent);
+
+    expect(input.hasOwnProperty('value')).toBe(true);
+  });
+
+  it('should define `checked` on the instance node', function() {
+    mockComponent._hostNode = checkbox;
+    inputValueTracking.track(mockComponent);
+
+    expect(checkbox.hasOwnProperty('checked')).toBe(true);
+  });
+
+  it('should initialize with the current value', function() {
+    input.value = 'foo';
+
+    inputValueTracking.track(mockComponent);
+
+    var tracker = mockComponent._wrapperState.valueTracker;
+
+    expect(tracker.getValue()).toEqual('foo');
+  });
+
+  it('should initialize with the current `checked`', function() {
+    mockComponent._hostNode = checkbox;
+    checkbox.checked = true;
+    inputValueTracking.track(mockComponent);
+
+    var tracker = mockComponent._wrapperState.valueTracker;
+
+    expect(tracker.getValue()).toEqual('true');
+  });
+
+  it('should track value changes', function() {
+    input.value = 'foo';
+
+    inputValueTracking.track(mockComponent);
+
+    var tracker = mockComponent._wrapperState.valueTracker;
+
+    input.value = 'bar';
+    expect(tracker.getValue()).toEqual('bar');
+  });
+
+  it('should tracked`checked` changes', function() {
+    mockComponent._hostNode = checkbox;
+    checkbox.checked = true;
+    inputValueTracking.track(mockComponent);
+
+    var tracker = mockComponent._wrapperState.valueTracker;
+
+    checkbox.checked = false;
+    expect(tracker.getValue()).toEqual('false');
+  });
+
+  it('should update value manually', function() {
+    input.value = 'foo';
+    inputValueTracking.track(mockComponent);
+
+    var tracker = mockComponent._wrapperState.valueTracker;
+
+    tracker.setValue('bar');
+    expect(tracker.getValue()).toEqual('bar');
+  });
+
+  it('should coerce value to a string', function() {
+    input.value = 'foo';
+    inputValueTracking.track(mockComponent);
+
+    var tracker = mockComponent._wrapperState.valueTracker;
+
+    tracker.setValue(500);
+    expect(tracker.getValue()).toEqual('500');
+  });
+
+  it('should update value if it changed and return result', function() {
+    inputValueTracking.track(mockComponent);
+    input.value = 'foo';
+
+    var tracker = mockComponent._wrapperState.valueTracker;
+
+    expect(inputValueTracking.updateValueIfChanged(mockComponent)).toBe(false);
+
+    tracker.setValue('bar');
+
+    expect(inputValueTracking.updateValueIfChanged(mockComponent)).toBe(true);
+
+    expect(tracker.getValue()).toEqual('foo');
+  });
+
+  it('should track value and return true when updating untracked instance', function() {
+    input.value = 'foo';
+
+    expect(inputValueTracking.updateValueIfChanged(mockComponent)).toBe(true);
+
+    var tracker = mockComponent._wrapperState.valueTracker;
+    expect(tracker.getValue()).toEqual('foo');
+  });
+
+  it('should return tracker from node', function() {
+    var node = ReactTestUtils.renderIntoDocument(
+      <input type="text" defaultValue="foo" />,
+    );
+    var tracker = inputValueTracking._getTrackerFromNode(node);
+    expect(tracker.getValue()).toEqual('foo');
+  });
+
+  it('should stop tracking', function() {
+    inputValueTracking.track(mockComponent);
+
+    expect(mockComponent._wrapperState.hasOwnProperty('valueTracker')).toBe(
+      true,
+    );
+
+    inputValueTracking.stopTracking(mockComponent);
+
+    expect(mockComponent._wrapperState.hasOwnProperty('valueTracker')).toBe(
+      false,
+    );
+
+    expect(input.hasOwnProperty('value')).toBe(false);
+  });
+});
diff --git a/src/renderers/dom/client/__tests__/validateDOMNesting-test.js b/src/renderers/dom/client/__tests__/validateDOMNesting-test.js
index e0bdfe959f2b..97aac29a5fd8 100644
--- a/src/renderers/dom/client/__tests__/validateDOMNesting-test.js
+++ b/src/renderers/dom/client/__tests__/validateDOMNesting-test.js
@@ -15,22 +15,107 @@ var validateDOMNesting;
 
 // 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',
+  '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#formatting
 var formattingTags = [
-  'a', 'b', 'big', 'code', 'em', 'font', 'i', 'nobr', 's', 'small', 'strike',
-  'strong', 'tt', 'u',
+  'a',
+  'b',
+  'big',
+  'code',
+  'em',
+  'font',
+  'i',
+  'nobr',
+  's',
+  'small',
+  'strike',
+  'strong',
+  'tt',
+  'u',
 ];
 
 function isTagStackValid(stack) {
@@ -39,20 +124,23 @@ function isTagStackValid(stack) {
     if (!validateDOMNesting.isTagValidInContext(stack[i], ancestorInfo)) {
       return false;
     }
-    ancestorInfo =
-      validateDOMNesting.updatedAncestorInfo(ancestorInfo, stack[i], null);
+    ancestorInfo = validateDOMNesting.updatedAncestorInfo(
+      ancestorInfo,
+      stack[i],
+      null,
+    );
   }
   return true;
 }
 
-describe('ReactContextValidator', function() {
-  beforeEach(function() {
+describe('ReactContextValidator', () => {
+  beforeEach(() => {
     jest.resetModuleRegistry();
 
     validateDOMNesting = require('validateDOMNesting');
   });
 
-  it('allows any tag with no context', function() {
+  it('allows any tag with no context', () => {
     // With renderToString (for example), we don't know where we're mounting the
     // tag so we must err on the side of leniency.
     var allTags = [].concat(specialTags, formattingTags, ['mysterytag']);
@@ -61,7 +149,7 @@ describe('ReactContextValidator', function() {
     });
   });
 
-  it('allows valid nestings', function() {
+  it('allows valid nestings', () => {
     expect(isTagStackValid(['table', 'tbody', 'tr', 'td', 'b'])).toBe(true);
     expect(isTagStackValid(['body', 'datalist', 'option'])).toBe(true);
     expect(isTagStackValid(['div', 'a', 'object', 'a'])).toBe(true);
@@ -76,12 +164,14 @@ describe('ReactContextValidator', function() {
     expect(isTagStackValid(['div', 'ul', 'li', 'dd', 'li'])).toBe(true);
   });
 
-  it('prevents problematic nestings', function() {
+  it('prevents problematic nestings', () => {
     expect(isTagStackValid(['a', 'a'])).toBe(false);
     expect(isTagStackValid(['form', 'form'])).toBe(false);
     expect(isTagStackValid(['p', 'p'])).toBe(false);
     expect(isTagStackValid(['table', 'tr'])).toBe(false);
     expect(isTagStackValid(['div', 'ul', 'li', 'div', 'li'])).toBe(false);
     expect(isTagStackValid(['div', 'html'])).toBe(false);
+    expect(isTagStackValid(['body', 'body'])).toBe(false);
+    expect(isTagStackValid(['svg', 'foreignObject', 'body', 'p'])).toBe(false);
   });
 });
diff --git a/src/renderers/dom/client/eventPlugins/BeforeInputEventPlugin.js b/src/renderers/dom/client/eventPlugins/BeforeInputEventPlugin.js
index 794e13661d2e..5f0df7e4704d 100644
--- a/src/renderers/dom/client/eventPlugins/BeforeInputEventPlugin.js
+++ b/src/renderers/dom/client/eventPlugins/BeforeInputEventPlugin.js
@@ -11,22 +11,19 @@
 
 'use strict';
 
-var EventConstants = require('EventConstants');
 var EventPropagators = require('EventPropagators');
 var ExecutionEnvironment = require('ExecutionEnvironment');
 var FallbackCompositionState = require('FallbackCompositionState');
 var SyntheticCompositionEvent = require('SyntheticCompositionEvent');
 var SyntheticInputEvent = require('SyntheticInputEvent');
 
-var keyOf = require('keyOf');
+import type {TopLevelTypes} from 'EventConstants';
 
 var END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space
 var START_KEYCODE = 229;
 
-var canUseCompositionEvent = (
-  ExecutionEnvironment.canUseDOM &&
-  'CompositionEvent' in window
-);
+var canUseCompositionEvent =
+  ExecutionEnvironment.canUseDOM && 'CompositionEvent' in window;
 
 var documentMode = null;
 if (ExecutionEnvironment.canUseDOM && 'documentMode' in document) {
@@ -36,23 +33,19 @@ if (ExecutionEnvironment.canUseDOM && 'documentMode' in document) {
 // 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 = (
+var canUseTextInputEvent =
   ExecutionEnvironment.canUseDOM &&
   'TextEvent' in window &&
   !documentMode &&
-  !isPresto()
-);
+  !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 = (
+var useFallbackCompositionData =
   ExecutionEnvironment.canUseDOM &&
-  (
-    !canUseCompositionEvent ||
-    (documentMode && documentMode > 8 && documentMode <= 11)
-  )
-);
+  (!canUseCompositionEvent ||
+    (documentMode && documentMode > 8 && documentMode <= 11));
 
 /**
  * Opera <= 12 includes TextEvent in window, but does not fire
@@ -70,62 +63,60 @@ function isPresto() {
 var SPACEBAR_CODE = 32;
 var SPACEBAR_CHAR = String.fromCharCode(SPACEBAR_CODE);
 
-var topLevelTypes = EventConstants.topLevelTypes;
-
 // Events and their corresponding property names.
 var eventTypes = {
   beforeInput: {
     phasedRegistrationNames: {
-      bubbled: keyOf({onBeforeInput: null}),
-      captured: keyOf({onBeforeInputCapture: null}),
+      bubbled: 'onBeforeInput',
+      captured: 'onBeforeInputCapture',
     },
     dependencies: [
-      topLevelTypes.topCompositionEnd,
-      topLevelTypes.topKeyPress,
-      topLevelTypes.topTextInput,
-      topLevelTypes.topPaste,
+      'topCompositionEnd',
+      'topKeyPress',
+      'topTextInput',
+      'topPaste',
     ],
   },
   compositionEnd: {
     phasedRegistrationNames: {
-      bubbled: keyOf({onCompositionEnd: null}),
-      captured: keyOf({onCompositionEndCapture: null}),
+      bubbled: 'onCompositionEnd',
+      captured: 'onCompositionEndCapture',
     },
     dependencies: [
-      topLevelTypes.topBlur,
-      topLevelTypes.topCompositionEnd,
-      topLevelTypes.topKeyDown,
-      topLevelTypes.topKeyPress,
-      topLevelTypes.topKeyUp,
-      topLevelTypes.topMouseDown,
+      'topBlur',
+      'topCompositionEnd',
+      'topKeyDown',
+      'topKeyPress',
+      'topKeyUp',
+      'topMouseDown',
     ],
   },
   compositionStart: {
     phasedRegistrationNames: {
-      bubbled: keyOf({onCompositionStart: null}),
-      captured: keyOf({onCompositionStartCapture: null}),
+      bubbled: 'onCompositionStart',
+      captured: 'onCompositionStartCapture',
     },
     dependencies: [
-      topLevelTypes.topBlur,
-      topLevelTypes.topCompositionStart,
-      topLevelTypes.topKeyDown,
-      topLevelTypes.topKeyPress,
-      topLevelTypes.topKeyUp,
-      topLevelTypes.topMouseDown,
+      'topBlur',
+      'topCompositionStart',
+      'topKeyDown',
+      'topKeyPress',
+      'topKeyUp',
+      'topMouseDown',
     ],
   },
   compositionUpdate: {
     phasedRegistrationNames: {
-      bubbled: keyOf({onCompositionUpdate: null}),
-      captured: keyOf({onCompositionUpdateCapture: null}),
+      bubbled: 'onCompositionUpdate',
+      captured: 'onCompositionUpdateCapture',
     },
     dependencies: [
-      topLevelTypes.topBlur,
-      topLevelTypes.topCompositionUpdate,
-      topLevelTypes.topKeyDown,
-      topLevelTypes.topKeyPress,
-      topLevelTypes.topKeyUp,
-      topLevelTypes.topMouseDown,
+      'topBlur',
+      'topCompositionUpdate',
+      'topKeyDown',
+      'topKeyPress',
+      'topKeyUp',
+      'topMouseDown',
     ],
   },
 };
@@ -146,7 +137,6 @@ function isKeypressCommand(nativeEvent) {
   );
 }
 
-
 /**
  * Translate native top level events into event types.
  *
@@ -155,11 +145,11 @@ function isKeypressCommand(nativeEvent) {
  */
 function getCompositionEventType(topLevelType) {
   switch (topLevelType) {
-    case topLevelTypes.topCompositionStart:
+    case 'topCompositionStart':
       return eventTypes.compositionStart;
-    case topLevelTypes.topCompositionEnd:
+    case 'topCompositionEnd':
       return eventTypes.compositionEnd;
-    case topLevelTypes.topCompositionUpdate:
+    case 'topCompositionUpdate':
       return eventTypes.compositionUpdate;
   }
 }
@@ -173,10 +163,7 @@ function getCompositionEventType(topLevelType) {
  * @return {boolean}
  */
 function isFallbackCompositionStart(topLevelType, nativeEvent) {
-  return (
-    topLevelType === topLevelTypes.topKeyDown &&
-    nativeEvent.keyCode === START_KEYCODE
-  );
+  return topLevelType === 'topKeyDown' && nativeEvent.keyCode === START_KEYCODE;
 }
 
 /**
@@ -188,16 +175,16 @@ function isFallbackCompositionStart(topLevelType, nativeEvent) {
  */
 function isFallbackCompositionEnd(topLevelType, nativeEvent) {
   switch (topLevelType) {
-    case topLevelTypes.topKeyUp:
+    case 'topKeyUp':
       // Command keys insert or clear IME input.
-      return (END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1);
-    case topLevelTypes.topKeyDown:
+      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 topLevelTypes.topKeyPress:
-    case topLevelTypes.topMouseDown:
-    case topLevelTypes.topBlur:
+      return nativeEvent.keyCode !== START_KEYCODE;
+    case 'topKeyPress':
+    case 'topMouseDown':
+    case 'topBlur':
       // Events are not possible without cancelling IME.
       return true;
     default:
@@ -232,7 +219,7 @@ function extractCompositionEvent(
   topLevelType,
   targetInst,
   nativeEvent,
-  nativeEventTarget
+  nativeEventTarget,
 ) {
   var eventType;
   var fallbackData;
@@ -255,8 +242,9 @@ function extractCompositionEvent(
     // The current composition is stored statically and must not be
     // overwritten while composition continues.
     if (!currentComposition && eventType === eventTypes.compositionStart) {
-      currentComposition =
-        FallbackCompositionState.getPooled(nativeEventTarget);
+      currentComposition = FallbackCompositionState.getPooled(
+        nativeEventTarget,
+      );
     } else if (eventType === eventTypes.compositionEnd) {
       if (currentComposition) {
         fallbackData = currentComposition.getData();
@@ -268,7 +256,7 @@ function extractCompositionEvent(
     eventType,
     targetInst,
     nativeEvent,
-    nativeEventTarget
+    nativeEventTarget,
   );
 
   if (fallbackData) {
@@ -291,11 +279,11 @@ function extractCompositionEvent(
  * @param {object} nativeEvent Native browser event.
  * @return {?string} The string corresponding to this `beforeInput` event.
  */
-function getNativeBeforeInputChars(topLevelType, nativeEvent) {
+function getNativeBeforeInputChars(topLevelType: TopLevelTypes, nativeEvent) {
   switch (topLevelType) {
-    case topLevelTypes.topCompositionEnd:
+    case 'topCompositionEnd':
       return getDataFromCustomEvent(nativeEvent);
-    case topLevelTypes.topKeyPress:
+    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.
@@ -318,7 +306,7 @@ function getNativeBeforeInputChars(topLevelType, nativeEvent) {
       hasSpaceKeypress = true;
       return SPACEBAR_CHAR;
 
-    case topLevelTypes.topTextInput:
+    case 'topTextInput':
       // Record the characters to be added to the DOM.
       var chars = nativeEvent.data;
 
@@ -345,13 +333,16 @@ function getNativeBeforeInputChars(topLevelType, nativeEvent) {
  * @param {object} nativeEvent Native browser event.
  * @return {?string} The fallback string for this `beforeInput` event.
  */
-function getFallbackBeforeInputChars(topLevelType, nativeEvent) {
+function getFallbackBeforeInputChars(topLevelType: TopLevelTypes, 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 === topLevelTypes.topCompositionEnd ||
-      isFallbackCompositionEnd(topLevelType, nativeEvent)
+      topLevelType === 'topCompositionEnd' ||
+      (!canUseCompositionEvent &&
+        isFallbackCompositionEnd(topLevelType, nativeEvent))
     ) {
       var chars = currentComposition.getData();
       FallbackCompositionState.release(currentComposition);
@@ -362,11 +353,11 @@ function getFallbackBeforeInputChars(topLevelType, nativeEvent) {
   }
 
   switch (topLevelType) {
-    case topLevelTypes.topPaste:
+    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 topLevelTypes.topKeyPress:
+    case 'topKeyPress':
       /**
        * As of v27, Firefox may fire keypress events even when no character
        * will be inserted. A few possibilities:
@@ -387,7 +378,7 @@ function getFallbackBeforeInputChars(topLevelType, nativeEvent) {
         return String.fromCharCode(nativeEvent.which);
       }
       return null;
-    case topLevelTypes.topCompositionEnd:
+    case 'topCompositionEnd':
       return useFallbackCompositionData ? null : nativeEvent.data;
     default:
       return null;
@@ -404,7 +395,7 @@ function extractBeforeInputEvent(
   topLevelType,
   targetInst,
   nativeEvent,
-  nativeEventTarget
+  nativeEventTarget,
 ) {
   var chars;
 
@@ -424,7 +415,7 @@ function extractBeforeInputEvent(
     eventTypes.beforeInput,
     targetInst,
     nativeEvent,
-    nativeEventTarget
+    nativeEventTarget,
   );
 
   event.data = chars;
@@ -451,27 +442,26 @@ function extractBeforeInputEvent(
  * `composition` event types.
  */
 var BeforeInputEventPlugin = {
-
   eventTypes: eventTypes,
 
   extractEvents: function(
     topLevelType,
     targetInst,
     nativeEvent,
-    nativeEventTarget
+    nativeEventTarget,
   ) {
     return [
       extractCompositionEvent(
         topLevelType,
         targetInst,
         nativeEvent,
-        nativeEventTarget
+        nativeEventTarget,
       ),
       extractBeforeInputEvent(
         topLevelType,
         targetInst,
         nativeEvent,
-        nativeEventTarget
+        nativeEventTarget,
       ),
     ];
   },
diff --git a/src/renderers/dom/client/eventPlugins/ChangeEventPlugin.js b/src/renderers/dom/client/eventPlugins/ChangeEventPlugin.js
index 1a6855d2860d..473aef515356 100644
--- a/src/renderers/dom/client/eventPlugins/ChangeEventPlugin.js
+++ b/src/renderers/dom/client/eventPlugins/ChangeEventPlugin.js
@@ -11,7 +11,6 @@
 
 'use strict';
 
-var EventConstants = require('EventConstants');
 var EventPluginHub = require('EventPluginHub');
 var EventPropagators = require('EventPropagators');
 var ExecutionEnvironment = require('ExecutionEnvironment');
@@ -19,39 +18,46 @@ var ReactDOMComponentTree = require('ReactDOMComponentTree');
 var ReactUpdates = require('ReactUpdates');
 var SyntheticEvent = require('SyntheticEvent');
 
+var inputValueTracking = require('inputValueTracking');
 var getEventTarget = require('getEventTarget');
 var isEventSupported = require('isEventSupported');
 var isTextInputElement = require('isTextInputElement');
-var keyOf = require('keyOf');
-
-var topLevelTypes = EventConstants.topLevelTypes;
 
 var eventTypes = {
   change: {
     phasedRegistrationNames: {
-      bubbled: keyOf({onChange: null}),
-      captured: keyOf({onChangeCapture: null}),
+      bubbled: 'onChange',
+      captured: 'onChangeCapture',
     },
     dependencies: [
-      topLevelTypes.topBlur,
-      topLevelTypes.topChange,
-      topLevelTypes.topClick,
-      topLevelTypes.topFocus,
-      topLevelTypes.topInput,
-      topLevelTypes.topKeyDown,
-      topLevelTypes.topKeyUp,
-      topLevelTypes.topSelectionChange,
+      '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;
-var activeElementValue = null;
-var activeElementValueProp = null;
 
 /**
  * SECTION: handle `change` event
@@ -59,27 +65,24 @@ var activeElementValueProp = null;
 function shouldUseChangeEvent(elem) {
   var nodeName = elem.nodeName && elem.nodeName.toLowerCase();
   return (
-    nodeName === 'select' ||
-    (nodeName === 'input' && elem.type === 'file')
+    nodeName === 'select' || (nodeName === 'input' && elem.type === 'file')
   );
 }
 
 var doesChangeEventBubble = false;
 if (ExecutionEnvironment.canUseDOM) {
   // See `handleChange` comment below
-  doesChangeEventBubble = isEventSupported('change') && (
-    !('documentMode' in document) || document.documentMode > 8
-  );
+  doesChangeEventBubble =
+    isEventSupported('change') &&
+    (!document.documentMode || document.documentMode > 8);
 }
 
 function manualDispatchChangeEvent(nativeEvent) {
-  var event = SyntheticEvent.getPooled(
-    eventTypes.change,
+  var event = createAndAccumulateChangeEvent(
     activeElementInst,
     nativeEvent,
-    getEventTarget(nativeEvent)
+    getEventTarget(nativeEvent),
   );
-  EventPropagators.accumulateTwoPhaseDispatches(event);
 
   // If change and propertychange bubbled, we'd just bind to it like all the
   // other events and have it go through ReactBrowserEventEmitter. Since it
@@ -115,30 +118,34 @@ function stopWatchingForChangeEventIE8() {
   activeElementInst = null;
 }
 
-function getTargetInstForChangeEvent(
-  topLevelType,
-  targetInst
-) {
-  if (topLevelType === topLevelTypes.topChange) {
+function getInstIfValueChanged(targetInst, nativeEvent) {
+  var updated = inputValueTracking.updateValueIfChanged(targetInst);
+  var simulated =
+    nativeEvent.simulated === true &&
+    ChangeEventPlugin._allowSimulatedPassThrough;
+
+  if (updated || simulated) {
     return targetInst;
   }
 }
-function handleEventsForChangeEventIE8(
-  topLevelType,
-  target,
-  targetInst
-) {
-  if (topLevelType === topLevelTypes.topFocus) {
+
+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 === topLevelTypes.topBlur) {
+  } else if (topLevelType === 'topBlur') {
     stopWatchingForChangeEventIE8();
   }
 }
 
-
 /**
  * SECTION: handle `input` event
  */
@@ -146,117 +153,56 @@ 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.
-  // IE10+ fire input events to often, such when a placeholder
-  // changes or when an input with a placeholder is focused.
-  isInputEventSupported = isEventSupported('input') && (
-    !('documentMode' in document) || document.documentMode > 11
-  );
-}
 
-/**
- * (For IE <=11) Replacement getter/setter for the `value` property that gets
- * set on the active element.
- */
-var newValueProp = {
-  get: function() {
-    return activeElementValueProp.get.call(this);
-  },
-  set: function(val) {
-    // Cast to a string so we can do equality checks.
-    activeElementValue = '' + val;
-    activeElementValueProp.set.call(this, val);
-  },
-};
+  isInputEventSupported =
+    isEventSupported('input') &&
+    (!('documentMode' in document) || document.documentMode > 9);
+}
 
 /**
- * (For IE <=11) Starts tracking propertychange events on the passed-in element
+ * (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;
-  activeElementValue = target.value;
-  activeElementValueProp = Object.getOwnPropertyDescriptor(
-    target.constructor.prototype,
-    'value'
-  );
-
-  // Not guarded in a canDefineProperty check: IE8 supports defineProperty only
-  // on DOM elements
-  Object.defineProperty(activeElement, 'value', newValueProp);
-  if (activeElement.attachEvent) {
-    activeElement.attachEvent('onpropertychange', handlePropertyChange);
-  } else {
-    activeElement.addEventListener('propertychange', handlePropertyChange, false);
-  }
+  activeElement.attachEvent('onpropertychange', handlePropertyChange);
 }
 
 /**
- * (For IE <=11) Removes the event listeners from the currently-tracked element,
+ * (For IE <=9) Removes the event listeners from the currently-tracked element,
  * if any exists.
  */
 function stopWatchingForValueChange() {
   if (!activeElement) {
     return;
   }
-
-  // delete restores the original property definition
-  delete activeElement.value;
-
-  if (activeElement.detachEvent) {
-    activeElement.detachEvent('onpropertychange', handlePropertyChange);
-  } else {
-    activeElement.removeEventListener('propertychange', handlePropertyChange, false);
-  }
+  activeElement.detachEvent('onpropertychange', handlePropertyChange);
 
   activeElement = null;
   activeElementInst = null;
-  activeElementValue = null;
-  activeElementValueProp = null;
 }
 
 /**
- * (For IE <=11) Handles a propertychange event, sending a `change` event if
+ * (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;
   }
-  var value = nativeEvent.srcElement.value;
-  if (value === activeElementValue) {
-    return;
-  }
-  activeElementValue = value;
-
-  manualDispatchChangeEvent(nativeEvent);
-}
-
-/**
- * If a `change` event should be fired, returns the target's ID.
- */
-function getTargetInstForInputEvent(
-  topLevelType,
-  targetInst
-) {
-  if (topLevelType === topLevelTypes.topInput) {
-    // In modern browsers (i.e., not IE8 or IE9), the input event is exactly
-    // what we want so fall through here and trigger an abstract event
-    return targetInst;
+  if (getInstIfValueChanged(activeElementInst, nativeEvent)) {
+    manualDispatchChangeEvent(nativeEvent);
   }
 }
 
-function handleEventsForInputEventIE(
-  topLevelType,
-  target,
-  targetInst
-) {
-  if (topLevelType === topLevelTypes.topFocus) {
+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-11, propertychange fires for most input events but is buggy and
+    // 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
@@ -268,19 +214,22 @@ function handleEventsForInputEventIE(
     // missed a blur event somehow.
     stopWatchingForValueChange();
     startWatchingForValueChange(target, targetInst);
-  } else if (topLevelType === topLevelTypes.topBlur) {
+  } else if (topLevelType === 'topBlur') {
     stopWatchingForValueChange();
   }
 }
 
 // For IE8 and IE9.
-function getTargetInstForInputEventIE(
+function getTargetInstForInputEventPolyfill(
   topLevelType,
-  targetInst
+  targetInst,
+  nativeEvent,
 ) {
-  if (topLevelType === topLevelTypes.topSelectionChange ||
-      topLevelType === topLevelTypes.topKeyUp ||
-      topLevelType === topLevelTypes.topKeyDown) {
+  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.
     //
@@ -291,14 +240,10 @@ function getTargetInstForInputEventIE(
     // 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.
-    if (activeElement && activeElement.value !== activeElementValue) {
-      activeElementValue = activeElement.value;
-      return activeElementInst;
-    }
+    return getInstIfValueChanged(activeElementInst, nativeEvent);
   }
 }
 
-
 /**
  * SECTION: handle `click` event
  */
@@ -306,18 +251,47 @@ 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 (
-    (elem.nodeName && elem.nodeName.toLowerCase() === 'input') &&
+    nodeName &&
+    nodeName.toLowerCase() === 'input' &&
     (elem.type === 'checkbox' || elem.type === 'radio')
   );
 }
 
-function getTargetInstForClickEvent(
+function getTargetInstForClickEvent(topLevelType, targetInst, nativeEvent) {
+  if (topLevelType === 'topClick') {
+    return getInstIfValueChanged(targetInst, nativeEvent);
+  }
+}
+
+function getTargetInstForInputOrChangeEvent(
   topLevelType,
-  targetInst
+  targetInst,
+  nativeEvent,
 ) {
-  if (topLevelType === topLevelTypes.topClick) {
-    return targetInst;
+  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
+  let 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
+  let value = '' + node.value;
+  if (node.getAttribute('value') !== value) {
+    node.setAttribute('value', value);
   }
 }
 
@@ -332,17 +306,20 @@ function getTargetInstForClickEvent(
  * - select
  */
 var ChangeEventPlugin = {
-
   eventTypes: eventTypes,
 
+  _allowSimulatedPassThrough: true,
+  _isInputEventSupported: isInputEventSupported,
+
   extractEvents: function(
     topLevelType,
     targetInst,
     nativeEvent,
-    nativeEventTarget
+    nativeEventTarget,
   ) {
-    var targetNode = targetInst ?
-      ReactDOMComponentTree.getNodeFromInstance(targetInst) : window;
+    var targetNode = targetInst
+      ? ReactDOMComponentTree.getNodeFromInstance(targetInst)
+      : window;
 
     var getTargetInstFunc, handleEventFunc;
     if (shouldUseChangeEvent(targetNode)) {
@@ -353,39 +330,36 @@ var ChangeEventPlugin = {
       }
     } else if (isTextInputElement(targetNode)) {
       if (isInputEventSupported) {
-        getTargetInstFunc = getTargetInstForInputEvent;
+        getTargetInstFunc = getTargetInstForInputOrChangeEvent;
       } else {
-        getTargetInstFunc = getTargetInstForInputEventIE;
-        handleEventFunc = handleEventsForInputEventIE;
+        getTargetInstFunc = getTargetInstForInputEventPolyfill;
+        handleEventFunc = handleEventsForInputEventPolyfill;
       }
     } else if (shouldUseClickEvent(targetNode)) {
       getTargetInstFunc = getTargetInstForClickEvent;
     }
 
     if (getTargetInstFunc) {
-      var inst = getTargetInstFunc(topLevelType, targetInst);
+      var inst = getTargetInstFunc(topLevelType, targetInst, nativeEvent);
       if (inst) {
-        var event = SyntheticEvent.getPooled(
-          eventTypes.change,
+        var event = createAndAccumulateChangeEvent(
           inst,
           nativeEvent,
-          nativeEventTarget
+          nativeEventTarget,
         );
-        event.type = 'change';
-        EventPropagators.accumulateTwoPhaseDispatches(event);
         return event;
       }
     }
 
     if (handleEventFunc) {
-      handleEventFunc(
-        topLevelType,
-        targetNode,
-        targetInst
-      );
+      handleEventFunc(topLevelType, targetNode, targetInst);
     }
-  },
 
+    // When blurring, set the value attribute for number inputs
+    if (topLevelType === 'topBlur') {
+      handleControlledInputBlur(targetInst, targetNode);
+    }
+  },
 };
 
 module.exports = ChangeEventPlugin;
diff --git a/src/renderers/dom/client/eventPlugins/DefaultEventPluginOrder.js b/src/renderers/dom/client/eventPlugins/DefaultEventPluginOrder.js
index a57172105d86..a04c61244670 100644
--- a/src/renderers/dom/client/eventPlugins/DefaultEventPluginOrder.js
+++ b/src/renderers/dom/client/eventPlugins/DefaultEventPluginOrder.js
@@ -11,8 +11,6 @@
 
 'use strict';
 
-var keyOf = require('keyOf');
-
 /**
  * Module that is injectable into `EventPluginHub`, that specifies a
  * deterministic ordering of `EventPlugin`s. A convenient way to reason about
@@ -23,13 +21,13 @@ var keyOf = require('keyOf');
  * preventing default on events is convenient in `SimpleEventPlugin` handlers.
  */
 var DefaultEventPluginOrder = [
-  keyOf({ResponderEventPlugin: null}),
-  keyOf({SimpleEventPlugin: null}),
-  keyOf({TapEventPlugin: null}),
-  keyOf({EnterLeaveEventPlugin: null}),
-  keyOf({ChangeEventPlugin: null}),
-  keyOf({SelectEventPlugin: null}),
-  keyOf({BeforeInputEventPlugin: null}),
+  'ResponderEventPlugin',
+  'SimpleEventPlugin',
+  'TapEventPlugin',
+  'EnterLeaveEventPlugin',
+  'ChangeEventPlugin',
+  'SelectEventPlugin',
+  'BeforeInputEventPlugin',
 ];
 
 module.exports = DefaultEventPluginOrder;
diff --git a/src/renderers/dom/client/eventPlugins/EnterLeaveEventPlugin.js b/src/renderers/dom/client/eventPlugins/EnterLeaveEventPlugin.js
index d50b0d37002d..fa9925f1448c 100644
--- a/src/renderers/dom/client/eventPlugins/EnterLeaveEventPlugin.js
+++ b/src/renderers/dom/client/eventPlugins/EnterLeaveEventPlugin.js
@@ -11,34 +11,22 @@
 
 'use strict';
 
-var EventConstants = require('EventConstants');
 var EventPropagators = require('EventPropagators');
 var ReactDOMComponentTree = require('ReactDOMComponentTree');
 var SyntheticMouseEvent = require('SyntheticMouseEvent');
 
-var keyOf = require('keyOf');
-
-var topLevelTypes = EventConstants.topLevelTypes;
-
 var eventTypes = {
   mouseEnter: {
-    registrationName: keyOf({onMouseEnter: null}),
-    dependencies: [
-      topLevelTypes.topMouseOut,
-      topLevelTypes.topMouseOver,
-    ],
+    registrationName: 'onMouseEnter',
+    dependencies: ['topMouseOut', 'topMouseOver'],
   },
   mouseLeave: {
-    registrationName: keyOf({onMouseLeave: null}),
-    dependencies: [
-      topLevelTypes.topMouseOut,
-      topLevelTypes.topMouseOver,
-    ],
+    registrationName: 'onMouseLeave',
+    dependencies: ['topMouseOut', 'topMouseOver'],
   },
 };
 
 var EnterLeaveEventPlugin = {
-
   eventTypes: eventTypes,
 
   /**
@@ -52,14 +40,15 @@ var EnterLeaveEventPlugin = {
     topLevelType,
     targetInst,
     nativeEvent,
-    nativeEventTarget
+    nativeEventTarget,
   ) {
-    if (topLevelType === topLevelTypes.topMouseOver &&
-        (nativeEvent.relatedTarget || nativeEvent.fromElement)) {
+    if (
+      topLevelType === 'topMouseOver' &&
+      (nativeEvent.relatedTarget || nativeEvent.fromElement)
+    ) {
       return null;
     }
-    if (topLevelType !== topLevelTypes.topMouseOut &&
-        topLevelType !== topLevelTypes.topMouseOver) {
+    if (topLevelType !== 'topMouseOut' && topLevelType !== 'topMouseOver') {
       // Must not be a mouse in or mouse out - ignoring.
       return null;
     }
@@ -80,11 +69,12 @@ var EnterLeaveEventPlugin = {
 
     var from;
     var to;
-    if (topLevelType === topLevelTypes.topMouseOut) {
+    if (topLevelType === 'topMouseOut') {
       from = targetInst;
       var related = nativeEvent.relatedTarget || nativeEvent.toElement;
-      to = related ?
-        ReactDOMComponentTree.getClosestInstanceFromNode(related) : null;
+      to = related
+        ? ReactDOMComponentTree.getClosestInstanceFromNode(related)
+        : null;
     } else {
       // Moving to a node from outside the window.
       from = null;
@@ -96,16 +86,18 @@ var EnterLeaveEventPlugin = {
       return null;
     }
 
-    var fromNode =
-      from == null ? win : ReactDOMComponentTree.getNodeFromInstance(from);
-    var toNode =
-      to == null ? win : ReactDOMComponentTree.getNodeFromInstance(to);
+    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
+      nativeEventTarget,
     );
     leave.type = 'mouseleave';
     leave.target = fromNode;
@@ -115,7 +107,7 @@ var EnterLeaveEventPlugin = {
       eventTypes.mouseEnter,
       to,
       nativeEvent,
-      nativeEventTarget
+      nativeEventTarget,
     );
     enter.type = 'mouseenter';
     enter.target = toNode;
@@ -125,7 +117,6 @@ var EnterLeaveEventPlugin = {
 
     return [leave, enter];
   },
-
 };
 
 module.exports = EnterLeaveEventPlugin;
diff --git a/src/renderers/dom/client/eventPlugins/SelectEventPlugin.js b/src/renderers/dom/client/eventPlugins/SelectEventPlugin.js
index 9aa84b213025..8b89dc377af4 100644
--- a/src/renderers/dom/client/eventPlugins/SelectEventPlugin.js
+++ b/src/renderers/dom/client/eventPlugins/SelectEventPlugin.js
@@ -11,7 +11,6 @@
 
 'use strict';
 
-var EventConstants = require('EventConstants');
 var EventPropagators = require('EventPropagators');
 var ExecutionEnvironment = require('ExecutionEnvironment');
 var ReactDOMComponentTree = require('ReactDOMComponentTree');
@@ -20,31 +19,28 @@ var SyntheticEvent = require('SyntheticEvent');
 
 var getActiveElement = require('getActiveElement');
 var isTextInputElement = require('isTextInputElement');
-var keyOf = require('keyOf');
 var shallowEqual = require('shallowEqual');
 
-var topLevelTypes = EventConstants.topLevelTypes;
-
-var skipSelectionChangeEvent = (
+var skipSelectionChangeEvent =
   ExecutionEnvironment.canUseDOM &&
   'documentMode' in document &&
-  document.documentMode <= 11
-);
+  document.documentMode <= 11;
 
 var eventTypes = {
   select: {
     phasedRegistrationNames: {
-      bubbled: keyOf({onSelect: null}),
-      captured: keyOf({onSelectCapture: null}),
+      bubbled: 'onSelect',
+      captured: 'onSelectCapture',
     },
     dependencies: [
-      topLevelTypes.topBlur,
-      topLevelTypes.topContextMenu,
-      topLevelTypes.topFocus,
-      topLevelTypes.topKeyDown,
-      topLevelTypes.topMouseDown,
-      topLevelTypes.topMouseUp,
-      topLevelTypes.topSelectionChange,
+      'topBlur',
+      'topContextMenu',
+      'topFocus',
+      'topKeyDown',
+      'topKeyUp',
+      'topMouseDown',
+      'topMouseUp',
+      'topSelectionChange',
     ],
   },
 };
@@ -57,7 +53,6 @@ var mouseDown = false;
 // Track whether a listener exists for this plugin. If none exist, we do
 // not extract events. See #3639.
 var hasListener = false;
-var ON_SELECT_KEY = keyOf({onSelect: null});
 
 /**
  * Get an object which is a unique representation of the current selection.
@@ -69,8 +64,10 @@ var ON_SELECT_KEY = keyOf({onSelect: null});
  * @return {object}
  */
 function getSelection(node) {
-  if ('selectionStart' in node &&
-      ReactInputSelection.hasSelectionCapabilities(node)) {
+  if (
+    'selectionStart' in node &&
+    ReactInputSelection.hasSelectionCapabilities(node)
+  ) {
     return {
       start: node.selectionStart,
       end: node.selectionEnd,
@@ -105,9 +102,11 @@ function constructSelectEvent(nativeEvent, nativeEventTarget) {
   // 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()) {
+  if (
+    mouseDown ||
+    activeElement == null ||
+    activeElement !== getActiveElement()
+  ) {
     return null;
   }
 
@@ -120,7 +119,7 @@ function constructSelectEvent(nativeEvent, nativeEventTarget) {
       eventTypes.select,
       activeElementInst,
       nativeEvent,
-      nativeEventTarget
+      nativeEventTarget,
     );
 
     syntheticEvent.type = 'select';
@@ -149,48 +148,48 @@ function constructSelectEvent(nativeEvent, nativeEventTarget) {
  * - Fires after user input.
  */
 var SelectEventPlugin = {
-
   eventTypes: eventTypes,
 
   extractEvents: function(
     topLevelType,
     targetInst,
     nativeEvent,
-    nativeEventTarget
+    nativeEventTarget,
   ) {
     if (!hasListener) {
       return null;
     }
 
-    var targetNode = targetInst ?
-      ReactDOMComponentTree.getNodeFromInstance(targetInst) : window;
+    var targetNode = targetInst
+      ? ReactDOMComponentTree.getNodeFromInstance(targetInst)
+      : window;
 
     switch (topLevelType) {
       // Track the input node that has focus.
-      case topLevelTypes.topFocus:
-        if (isTextInputElement(targetNode) ||
-            targetNode.contentEditable === 'true') {
+      case 'topFocus':
+        if (
+          isTextInputElement(targetNode) ||
+          targetNode.contentEditable === 'true'
+        ) {
           activeElement = targetNode;
           activeElementInst = targetInst;
           lastSelection = null;
         }
         break;
-      case topLevelTypes.topBlur:
+      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 topLevelTypes.topMouseDown:
+      case 'topMouseDown':
         mouseDown = true;
         break;
-      case topLevelTypes.topContextMenu:
-      case topLevelTypes.topMouseUp:
+      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.
@@ -200,13 +199,13 @@ var SelectEventPlugin = {
       // 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 topLevelTypes.topSelectionChange:
+      case 'topSelectionChange':
         if (skipSelectionChangeEvent) {
           break;
         }
-        // falls through
-      case topLevelTypes.topKeyDown:
-      case topLevelTypes.topKeyUp:
+      // falls through
+      case 'topKeyDown':
+      case 'topKeyUp':
         return constructSelectEvent(nativeEvent, nativeEventTarget);
     }
 
@@ -214,7 +213,7 @@ var SelectEventPlugin = {
   },
 
   didPutListener: function(inst, registrationName, listener) {
-    if (registrationName === ON_SELECT_KEY) {
+    if (registrationName === 'onSelect') {
       hasListener = true;
     }
   },
diff --git a/src/renderers/dom/client/eventPlugins/SimpleEventPlugin.js b/src/renderers/dom/client/eventPlugins/SimpleEventPlugin.js
index f790e3fe9b44..6acaf74a5a04 100644
--- a/src/renderers/dom/client/eventPlugins/SimpleEventPlugin.js
+++ b/src/renderers/dom/client/eventPlugins/SimpleEventPlugin.js
@@ -7,11 +7,11 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule SimpleEventPlugin
+ * @flow
  */
 
 'use strict';
 
-var EventConstants = require('EventConstants');
 var EventListener = require('EventListener');
 var EventPropagators = require('EventPropagators');
 var ReactDOMComponentTree = require('ReactDOMComponentTree');
@@ -30,616 +30,296 @@ var SyntheticWheelEvent = require('SyntheticWheelEvent');
 var emptyFunction = require('emptyFunction');
 var getEventCharCode = require('getEventCharCode');
 var invariant = require('invariant');
-var keyOf = require('keyOf');
 
-var topLevelTypes = EventConstants.topLevelTypes;
+import type {TopLevelTypes} from 'EventConstants';
+import type {
+  DispatchConfig,
+  ReactSyntheticEvent,
+} from 'ReactSyntheticEventType';
+import type {ReactInstance} from 'ReactInstanceType';
+import type {EventTypes, PluginModule} from 'PluginModuleType';
 
-var eventTypes = {
-  abort: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onAbort: true}),
-      captured: keyOf({onAbortCapture: true}),
-    },
-  },
-  animationEnd: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onAnimationEnd: true}),
-      captured: keyOf({onAnimationEndCapture: true}),
-    },
-  },
-  animationIteration: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onAnimationIteration: true}),
-      captured: keyOf({onAnimationIterationCapture: true}),
-    },
-  },
-  animationStart: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onAnimationStart: true}),
-      captured: keyOf({onAnimationStartCapture: true}),
-    },
-  },
-  blur: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onBlur: true}),
-      captured: keyOf({onBlurCapture: true}),
-    },
-  },
-  canPlay: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onCanPlay: true}),
-      captured: keyOf({onCanPlayCapture: true}),
-    },
-  },
-  canPlayThrough: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onCanPlayThrough: true}),
-      captured: keyOf({onCanPlayThroughCapture: true}),
-    },
-  },
-  click: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onClick: true}),
-      captured: keyOf({onClickCapture: true}),
-    },
-  },
-  contextMenu: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onContextMenu: true}),
-      captured: keyOf({onContextMenuCapture: true}),
-    },
-  },
-  copy: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onCopy: true}),
-      captured: keyOf({onCopyCapture: true}),
-    },
-  },
-  cut: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onCut: true}),
-      captured: keyOf({onCutCapture: true}),
-    },
-  },
-  doubleClick: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onDoubleClick: true}),
-      captured: keyOf({onDoubleClickCapture: true}),
-    },
-  },
-  drag: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onDrag: true}),
-      captured: keyOf({onDragCapture: true}),
-    },
-  },
-  dragEnd: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onDragEnd: true}),
-      captured: keyOf({onDragEndCapture: true}),
-    },
-  },
-  dragEnter: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onDragEnter: true}),
-      captured: keyOf({onDragEnterCapture: true}),
-    },
-  },
-  dragExit: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onDragExit: true}),
-      captured: keyOf({onDragExitCapture: true}),
-    },
-  },
-  dragLeave: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onDragLeave: true}),
-      captured: keyOf({onDragLeaveCapture: true}),
-    },
-  },
-  dragOver: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onDragOver: true}),
-      captured: keyOf({onDragOverCapture: true}),
-    },
-  },
-  dragStart: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onDragStart: true}),
-      captured: keyOf({onDragStartCapture: true}),
-    },
-  },
-  drop: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onDrop: true}),
-      captured: keyOf({onDropCapture: true}),
-    },
-  },
-  durationChange: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onDurationChange: true}),
-      captured: keyOf({onDurationChangeCapture: true}),
-    },
-  },
-  emptied: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onEmptied: true}),
-      captured: keyOf({onEmptiedCapture: true}),
-    },
-  },
-  encrypted: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onEncrypted: true}),
-      captured: keyOf({onEncryptedCapture: true}),
-    },
-  },
-  ended: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onEnded: true}),
-      captured: keyOf({onEndedCapture: true}),
-    },
-  },
-  error: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onError: true}),
-      captured: keyOf({onErrorCapture: true}),
-    },
-  },
-  focus: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onFocus: true}),
-      captured: keyOf({onFocusCapture: true}),
-    },
-  },
-  input: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onInput: true}),
-      captured: keyOf({onInputCapture: true}),
-    },
-  },
-  invalid: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onInvalid: true}),
-      captured: keyOf({onInvalidCapture: true}),
-    },
-  },
-  keyDown: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onKeyDown: true}),
-      captured: keyOf({onKeyDownCapture: true}),
-    },
-  },
-  keyPress: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onKeyPress: true}),
-      captured: keyOf({onKeyPressCapture: true}),
-    },
-  },
-  keyUp: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onKeyUp: true}),
-      captured: keyOf({onKeyUpCapture: true}),
-    },
-  },
-  load: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onLoad: true}),
-      captured: keyOf({onLoadCapture: true}),
-    },
-  },
-  loadedData: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onLoadedData: true}),
-      captured: keyOf({onLoadedDataCapture: true}),
-    },
-  },
-  loadedMetadata: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onLoadedMetadata: true}),
-      captured: keyOf({onLoadedMetadataCapture: true}),
-    },
-  },
-  loadStart: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onLoadStart: true}),
-      captured: keyOf({onLoadStartCapture: true}),
-    },
-  },
-  // Note: We do not allow listening to mouseOver events. Instead, use the
-  // onMouseEnter/onMouseLeave created by `EnterLeaveEventPlugin`.
-  mouseDown: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onMouseDown: true}),
-      captured: keyOf({onMouseDownCapture: true}),
-    },
-  },
-  mouseMove: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onMouseMove: true}),
-      captured: keyOf({onMouseMoveCapture: true}),
-    },
-  },
-  mouseOut: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onMouseOut: true}),
-      captured: keyOf({onMouseOutCapture: true}),
-    },
-  },
-  mouseOver: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onMouseOver: true}),
-      captured: keyOf({onMouseOverCapture: true}),
-    },
-  },
-  mouseUp: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onMouseUp: true}),
-      captured: keyOf({onMouseUpCapture: true}),
-    },
-  },
-  paste: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onPaste: true}),
-      captured: keyOf({onPasteCapture: true}),
-    },
-  },
-  pause: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onPause: true}),
-      captured: keyOf({onPauseCapture: true}),
-    },
-  },
-  play: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onPlay: true}),
-      captured: keyOf({onPlayCapture: true}),
-    },
-  },
-  playing: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onPlaying: true}),
-      captured: keyOf({onPlayingCapture: true}),
-    },
-  },
-  progress: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onProgress: true}),
-      captured: keyOf({onProgressCapture: true}),
-    },
-  },
-  rateChange: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onRateChange: true}),
-      captured: keyOf({onRateChangeCapture: true}),
-    },
-  },
-  reset: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onReset: true}),
-      captured: keyOf({onResetCapture: true}),
-    },
-  },
-  scroll: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onScroll: true}),
-      captured: keyOf({onScrollCapture: true}),
-    },
-  },
-  seeked: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onSeeked: true}),
-      captured: keyOf({onSeekedCapture: true}),
-    },
-  },
-  seeking: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onSeeking: true}),
-      captured: keyOf({onSeekingCapture: true}),
-    },
-  },
-  stalled: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onStalled: true}),
-      captured: keyOf({onStalledCapture: true}),
-    },
-  },
-  submit: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onSubmit: true}),
-      captured: keyOf({onSubmitCapture: true}),
-    },
-  },
-  suspend: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onSuspend: true}),
-      captured: keyOf({onSuspendCapture: true}),
-    },
-  },
-  timeUpdate: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onTimeUpdate: true}),
-      captured: keyOf({onTimeUpdateCapture: true}),
-    },
-  },
-  touchCancel: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onTouchCancel: true}),
-      captured: keyOf({onTouchCancelCapture: true}),
-    },
-  },
-  touchEnd: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onTouchEnd: true}),
-      captured: keyOf({onTouchEndCapture: true}),
-    },
-  },
-  touchMove: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onTouchMove: true}),
-      captured: keyOf({onTouchMoveCapture: true}),
-    },
-  },
-  touchStart: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onTouchStart: true}),
-      captured: keyOf({onTouchStartCapture: true}),
-    },
-  },
-  transitionEnd: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onTransitionEnd: true}),
-      captured: keyOf({onTransitionEndCapture: true}),
-    },
-  },
-  volumeChange: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onVolumeChange: true}),
-      captured: keyOf({onVolumeChangeCapture: true}),
-    },
-  },
-  waiting: {
-    phasedRegistrationNames: {
-      bubbled: keyOf({onWaiting: true}),
-      captured: keyOf({onWaitingCapture: true}),
-    },
-  },
-  wheel: {
+/**
+ * Turns
+ * ['abort', ...]
+ * into
+ * eventTypes = {
+ *   'abort': {
+ *     phasedRegistrationNames: {
+ *       bubbled: 'onAbort',
+ *       captured: 'onAbortCapture',
+ *     },
+ *     dependencies: ['topAbort'],
+ *   },
+ *   ...
+ * };
+ * topLevelEventsToDispatchConfig = {
+ *   'topAbort': { sameConfig }
+ * };
+ */
+var eventTypes: EventTypes = {};
+var topLevelEventsToDispatchConfig: {[key: TopLevelTypes]: DispatchConfig} = {};
+[
+  '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(event => {
+  var capitalizedEvent = event[0].toUpperCase() + event.slice(1);
+  var onEvent = 'on' + capitalizedEvent;
+  var topEvent = 'top' + capitalizedEvent;
+
+  var type = {
     phasedRegistrationNames: {
-      bubbled: keyOf({onWheel: true}),
-      captured: keyOf({onWheelCapture: true}),
+      bubbled: onEvent,
+      captured: onEvent + 'Capture',
     },
-  },
-};
+    dependencies: [topEvent],
+  };
+  eventTypes[event] = type;
+  topLevelEventsToDispatchConfig[topEvent] = type;
+});
 
-var topLevelEventsToDispatchConfig = {
-  topAbort:           eventTypes.abort,
-  topAnimationEnd:    eventTypes.animationEnd,
-  topAnimationIteration: eventTypes.animationIteration,
-  topAnimationStart:  eventTypes.animationStart,
-  topBlur:            eventTypes.blur,
-  topCanPlay:         eventTypes.canPlay,
-  topCanPlayThrough:  eventTypes.canPlayThrough,
-  topClick:           eventTypes.click,
-  topContextMenu:     eventTypes.contextMenu,
-  topCopy:            eventTypes.copy,
-  topCut:             eventTypes.cut,
-  topDoubleClick:     eventTypes.doubleClick,
-  topDrag:            eventTypes.drag,
-  topDragEnd:         eventTypes.dragEnd,
-  topDragEnter:       eventTypes.dragEnter,
-  topDragExit:        eventTypes.dragExit,
-  topDragLeave:       eventTypes.dragLeave,
-  topDragOver:        eventTypes.dragOver,
-  topDragStart:       eventTypes.dragStart,
-  topDrop:            eventTypes.drop,
-  topDurationChange:  eventTypes.durationChange,
-  topEmptied:         eventTypes.emptied,
-  topEncrypted:       eventTypes.encrypted,
-  topEnded:           eventTypes.ended,
-  topError:           eventTypes.error,
-  topFocus:           eventTypes.focus,
-  topInput:           eventTypes.input,
-  topInvalid:         eventTypes.invalid,
-  topKeyDown:         eventTypes.keyDown,
-  topKeyPress:        eventTypes.keyPress,
-  topKeyUp:           eventTypes.keyUp,
-  topLoad:            eventTypes.load,
-  topLoadedData:      eventTypes.loadedData,
-  topLoadedMetadata:  eventTypes.loadedMetadata,
-  topLoadStart:       eventTypes.loadStart,
-  topMouseDown:       eventTypes.mouseDown,
-  topMouseMove:       eventTypes.mouseMove,
-  topMouseOut:        eventTypes.mouseOut,
-  topMouseOver:       eventTypes.mouseOver,
-  topMouseUp:         eventTypes.mouseUp,
-  topPaste:           eventTypes.paste,
-  topPause:           eventTypes.pause,
-  topPlay:            eventTypes.play,
-  topPlaying:         eventTypes.playing,
-  topProgress:        eventTypes.progress,
-  topRateChange:      eventTypes.rateChange,
-  topReset:           eventTypes.reset,
-  topScroll:          eventTypes.scroll,
-  topSeeked:          eventTypes.seeked,
-  topSeeking:         eventTypes.seeking,
-  topStalled:         eventTypes.stalled,
-  topSubmit:          eventTypes.submit,
-  topSuspend:         eventTypes.suspend,
-  topTimeUpdate:      eventTypes.timeUpdate,
-  topTouchCancel:     eventTypes.touchCancel,
-  topTouchEnd:        eventTypes.touchEnd,
-  topTouchMove:       eventTypes.touchMove,
-  topTouchStart:      eventTypes.touchStart,
-  topTransitionEnd:   eventTypes.transitionEnd,
-  topVolumeChange:    eventTypes.volumeChange,
-  topWaiting:         eventTypes.waiting,
-  topWheel:           eventTypes.wheel,
-};
+var onClickListeners = {};
 
-for (var type in topLevelEventsToDispatchConfig) {
-  topLevelEventsToDispatchConfig[type].dependencies = [type];
+function getDictionaryKey(inst: ReactInstance): string {
+  // Prevents V8 performance issue:
+  // https://github.com/facebook/react/pull/7232
+  return '.' + inst._rootNodeID;
 }
 
-var ON_CLICK_KEY = keyOf({onClick: null});
-var onClickListeners = {};
-
-var SimpleEventPlugin = {
+function isInteractive(tag) {
+  return (
+    tag === 'button' ||
+    tag === 'input' ||
+    tag === 'select' ||
+    tag === 'textarea'
+  );
+}
 
+var SimpleEventPlugin: PluginModule<MouseEvent> = {
   eventTypes: eventTypes,
 
   extractEvents: function(
-    topLevelType,
-    targetInst,
-    nativeEvent,
-    nativeEventTarget
-  ) {
+    topLevelType: TopLevelTypes,
+    targetInst: ReactInstance,
+    nativeEvent: MouseEvent,
+    nativeEventTarget: EventTarget,
+  ): null | ReactSyntheticEvent {
     var dispatchConfig = topLevelEventsToDispatchConfig[topLevelType];
     if (!dispatchConfig) {
       return null;
     }
     var EventConstructor;
     switch (topLevelType) {
-      case topLevelTypes.topAbort:
-      case topLevelTypes.topCanPlay:
-      case topLevelTypes.topCanPlayThrough:
-      case topLevelTypes.topDurationChange:
-      case topLevelTypes.topEmptied:
-      case topLevelTypes.topEncrypted:
-      case topLevelTypes.topEnded:
-      case topLevelTypes.topError:
-      case topLevelTypes.topInput:
-      case topLevelTypes.topInvalid:
-      case topLevelTypes.topLoad:
-      case topLevelTypes.topLoadedData:
-      case topLevelTypes.topLoadedMetadata:
-      case topLevelTypes.topLoadStart:
-      case topLevelTypes.topPause:
-      case topLevelTypes.topPlay:
-      case topLevelTypes.topPlaying:
-      case topLevelTypes.topProgress:
-      case topLevelTypes.topRateChange:
-      case topLevelTypes.topReset:
-      case topLevelTypes.topSeeked:
-      case topLevelTypes.topSeeking:
-      case topLevelTypes.topStalled:
-      case topLevelTypes.topSubmit:
-      case topLevelTypes.topSuspend:
-      case topLevelTypes.topTimeUpdate:
-      case topLevelTypes.topVolumeChange:
-      case topLevelTypes.topWaiting:
+      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 topLevelTypes.topKeyPress:
+      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 topLevelTypes.topKeyDown:
-      case topLevelTypes.topKeyUp:
+      /* falls through */
+      case 'topKeyDown':
+      case 'topKeyUp':
         EventConstructor = SyntheticKeyboardEvent;
         break;
-      case topLevelTypes.topBlur:
-      case topLevelTypes.topFocus:
+      case 'topBlur':
+      case 'topFocus':
         EventConstructor = SyntheticFocusEvent;
         break;
-      case topLevelTypes.topClick:
+      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 topLevelTypes.topContextMenu:
-      case topLevelTypes.topDoubleClick:
-      case topLevelTypes.topMouseDown:
-      case topLevelTypes.topMouseMove:
-      case topLevelTypes.topMouseOut:
-      case topLevelTypes.topMouseOver:
-      case topLevelTypes.topMouseUp:
+      /* 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 topLevelTypes.topDrag:
-      case topLevelTypes.topDragEnd:
-      case topLevelTypes.topDragEnter:
-      case topLevelTypes.topDragExit:
-      case topLevelTypes.topDragLeave:
-      case topLevelTypes.topDragOver:
-      case topLevelTypes.topDragStart:
-      case topLevelTypes.topDrop:
+      case 'topDrag':
+      case 'topDragEnd':
+      case 'topDragEnter':
+      case 'topDragExit':
+      case 'topDragLeave':
+      case 'topDragOver':
+      case 'topDragStart':
+      case 'topDrop':
         EventConstructor = SyntheticDragEvent;
         break;
-      case topLevelTypes.topTouchCancel:
-      case topLevelTypes.topTouchEnd:
-      case topLevelTypes.topTouchMove:
-      case topLevelTypes.topTouchStart:
+      case 'topTouchCancel':
+      case 'topTouchEnd':
+      case 'topTouchMove':
+      case 'topTouchStart':
         EventConstructor = SyntheticTouchEvent;
         break;
-      case topLevelTypes.topAnimationEnd:
-      case topLevelTypes.topAnimationIteration:
-      case topLevelTypes.topAnimationStart:
+      case 'topAnimationEnd':
+      case 'topAnimationIteration':
+      case 'topAnimationStart':
         EventConstructor = SyntheticAnimationEvent;
         break;
-      case topLevelTypes.topTransitionEnd:
+      case 'topTransitionEnd':
         EventConstructor = SyntheticTransitionEvent;
         break;
-      case topLevelTypes.topScroll:
+      case 'topScroll':
         EventConstructor = SyntheticUIEvent;
         break;
-      case topLevelTypes.topWheel:
+      case 'topWheel':
         EventConstructor = SyntheticWheelEvent;
         break;
-      case topLevelTypes.topCopy:
-      case topLevelTypes.topCut:
-      case topLevelTypes.topPaste:
+      case 'topCopy':
+      case 'topCut':
+      case 'topPaste':
         EventConstructor = SyntheticClipboardEvent;
         break;
     }
     invariant(
       EventConstructor,
       'SimpleEventPlugin: Unhandled event type, `%s`.',
-      topLevelType
+      topLevelType,
     );
     var event = EventConstructor.getPooled(
       dispatchConfig,
       targetInst,
       nativeEvent,
-      nativeEventTarget
+      nativeEventTarget,
     );
     EventPropagators.accumulateTwoPhaseDispatches(event);
     return event;
   },
 
-  didPutListener: function(inst, registrationName, listener) {
+  didPutListener: function(
+    inst: ReactInstance,
+    registrationName: string,
+    listener: () => void,
+  ): void {
     // 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.
-    if (registrationName === ON_CLICK_KEY) {
-      var id = inst._rootNodeID;
+    // 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[id]) {
-        onClickListeners[id] = EventListener.listen(
+      if (!onClickListeners[key]) {
+        onClickListeners[key] = EventListener.listen(
           node,
           'click',
-          emptyFunction
+          emptyFunction,
         );
       }
     }
   },
 
-  willDeleteListener: function(inst, registrationName) {
-    if (registrationName === ON_CLICK_KEY) {
-      var id = inst._rootNodeID;
-      onClickListeners[id].remove();
-      delete onClickListeners[id];
+  willDeleteListener: function(
+    inst: ReactInstance,
+    registrationName: string,
+  ): void {
+    if (registrationName === 'onClick' && !isInteractive(inst._tag)) {
+      var key = getDictionaryKey(inst);
+      onClickListeners[key].remove();
+      delete onClickListeners[key];
     }
   },
-
 };
 
 module.exports = SimpleEventPlugin;
diff --git a/src/renderers/dom/client/eventPlugins/TapEventPlugin.js b/src/renderers/dom/client/eventPlugins/TapEventPlugin.js
index 670eb936a397..a5b46a07eba9 100644
--- a/src/renderers/dom/client/eventPlugins/TapEventPlugin.js
+++ b/src/renderers/dom/client/eventPlugins/TapEventPlugin.js
@@ -7,72 +7,103 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule TapEventPlugin
+ * @flow
  */
 
 'use strict';
 
-var EventConstants = require('EventConstants');
 var EventPluginUtils = require('EventPluginUtils');
 var EventPropagators = require('EventPropagators');
 var SyntheticUIEvent = require('SyntheticUIEvent');
 var TouchEventUtils = require('TouchEventUtils');
 var ViewportMetrics = require('ViewportMetrics');
 
-var keyOf = require('keyOf');
-var topLevelTypes = EventConstants.topLevelTypes;
-
 var isStartish = EventPluginUtils.isStartish;
 var isEndish = EventPluginUtils.isEndish;
 
+import type {EventTypes, PluginModule} from 'PluginModuleType';
+import type {ReactInstance} from 'ReactInstanceType';
+import type {TopLevelTypes} from 'EventConstants';
+
+/**
+ * We are extending the Flow 'Touch' declaration to enable using bracket
+ * notation to access properties.
+ * Without this adjustment Flow throws
+ * "Indexable signature not found in Touch".
+ * See https://github.com/facebook/flow/issues/1323
+ */
+type TouchPropertyKey = 'clientX' | 'clientY' | 'pageX' | 'pageY';
+
+declare class _Touch extends Touch {
+  [key: TouchPropertyKey]: number,
+}
+
+type AxisCoordinateData = {
+  page: TouchPropertyKey,
+  client: TouchPropertyKey,
+  envScroll: 'currentPageScrollLeft' | 'currentPageScrollTop',
+};
+
+type AxisType = {
+  x: AxisCoordinateData,
+  y: AxisCoordinateData,
+};
+
+type CoordinatesType = {
+  x: number,
+  y: number,
+};
+
 /**
  * Number of pixels that are tolerated in between a `touchStart` and `touchEnd`
  * in order to still be considered a 'tap' event.
  */
 var tapMoveThreshold = 10;
-var startCoords = {x: null, y: null};
+var startCoords: CoordinatesType = {x: 0, y: 0};
 
-var Axis = {
+var Axis: AxisType = {
   x: {page: 'pageX', client: 'clientX', envScroll: 'currentPageScrollLeft'},
   y: {page: 'pageY', client: 'clientY', envScroll: 'currentPageScrollTop'},
 };
 
-function getAxisCoordOfEvent(axis, nativeEvent) {
+function getAxisCoordOfEvent(
+  axis: AxisCoordinateData,
+  nativeEvent: _Touch,
+): number {
   var singleTouch = TouchEventUtils.extractSingleTouch(nativeEvent);
   if (singleTouch) {
     return singleTouch[axis.page];
   }
-  return axis.page in nativeEvent ?
-    nativeEvent[axis.page] :
-    nativeEvent[axis.client] + ViewportMetrics[axis.envScroll];
+  return axis.page in nativeEvent
+    ? nativeEvent[axis.page]
+    : nativeEvent[axis.client] + ViewportMetrics[axis.envScroll];
 }
 
-function getDistance(coords, nativeEvent) {
+function getDistance(coords: CoordinatesType, nativeEvent: _Touch): number {
   var pageX = getAxisCoordOfEvent(Axis.x, nativeEvent);
   var pageY = getAxisCoordOfEvent(Axis.y, nativeEvent);
   return Math.pow(
     Math.pow(pageX - coords.x, 2) + Math.pow(pageY - coords.y, 2),
-    0.5
+    0.5,
   );
 }
 
 var touchEvents = [
-  topLevelTypes.topTouchStart,
-  topLevelTypes.topTouchCancel,
-  topLevelTypes.topTouchEnd,
-  topLevelTypes.topTouchMove,
+  'topTouchStart',
+  'topTouchCancel',
+  'topTouchEnd',
+  'topTouchMove',
 ];
 
-var dependencies = [
-  topLevelTypes.topMouseDown,
-  topLevelTypes.topMouseMove,
-  topLevelTypes.topMouseUp,
-].concat(touchEvents);
+var dependencies = ['topMouseDown', 'topMouseMove', 'topMouseUp'].concat(
+  touchEvents,
+);
 
-var eventTypes = {
+var eventTypes: EventTypes = {
   touchTap: {
     phasedRegistrationNames: {
-      bubbled: keyOf({onTouchTap: null}),
-      captured: keyOf({onTouchTapCapture: null}),
+      bubbled: 'onTouchTap',
+      captured: 'onTouchTapCapture',
     },
     dependencies: dependencies,
   },
@@ -82,17 +113,16 @@ var usedTouch = false;
 var usedTouchTime = 0;
 var TOUCH_DELAY = 1000;
 
-var TapEventPlugin = {
-
+var TapEventPlugin: PluginModule<_Touch> = {
   tapMoveThreshold: tapMoveThreshold,
 
   eventTypes: eventTypes,
 
   extractEvents: function(
-    topLevelType,
-    targetInst,
-    nativeEvent,
-    nativeEventTarget
+    topLevelType: TopLevelTypes,
+    targetInst: ReactInstance,
+    nativeEvent: _Touch,
+    nativeEventTarget: EventTarget,
   ) {
     if (!isStartish(topLevelType) && !isEndish(topLevelType)) {
       return null;
@@ -104,7 +134,7 @@ var TapEventPlugin = {
       usedTouch = true;
       usedTouchTime = Date.now();
     } else {
-      if (usedTouch && (Date.now() - usedTouchTime < TOUCH_DELAY)) {
+      if (usedTouch && Date.now() - usedTouchTime < TOUCH_DELAY) {
         return null;
       }
     }
@@ -115,7 +145,7 @@ var TapEventPlugin = {
         eventTypes.touchTap,
         targetInst,
         nativeEvent,
-        nativeEventTarget
+        nativeEventTarget,
       );
     }
     if (isStartish(topLevelType)) {
@@ -128,7 +158,6 @@ var TapEventPlugin = {
     EventPropagators.accumulateTwoPhaseDispatches(event);
     return event;
   },
-
 };
 
 module.exports = TapEventPlugin;
diff --git a/src/renderers/dom/client/eventPlugins/__tests__/BeforeInputEventPlugin-test.js b/src/renderers/dom/client/eventPlugins/__tests__/BeforeInputEventPlugin-test.js
new file mode 100644
index 000000000000..265ca820bc47
--- /dev/null
+++ b/src/renderers/dom/client/eventPlugins/__tests__/BeforeInputEventPlugin-test.js
@@ -0,0 +1,240 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var React = require('React');
+var ReactTestUtils = require('ReactTestUtils');
+
+var EventMapping = {
+  compositionstart: 'topCompositionStart',
+  compositionend: 'topCompositionEnd',
+  keyup: 'topKeyUp',
+  keydown: 'topKeyDown',
+  textInput: 'topTextInput',
+  textinput: null, // Not defined now
+};
+
+describe('BeforeInputEventPlugin', function() {
+  var ModuleCache;
+
+  function simulateIE11() {
+    document.documentMode = 11;
+    window.CompositionEvent = {};
+    delete window.TextEvent;
+  }
+
+  function simulateWebkit() {
+    delete document.documentMode;
+    window.CompositionEvent = {};
+    window.TextEvent = {};
+  }
+
+  function initialize(simulator) {
+    // Need to delete cached modules before executing simulator
+    jest.resetModuleRegistry();
+
+    // Initialize variables in the scope of BeforeInputEventPlugin
+    simulator();
+
+    // Modules which have dependency on BeforeInputEventPlugin are stored
+    // in ModuleCache so that we can use these modules ouside test functions.
+    this.ReactDOM = require('ReactDOM');
+    this.ReactDOMComponentTree = require('ReactDOMComponentTree');
+    this.SyntheticCompositionEvent = require('SyntheticCompositionEvent');
+    this.SyntheticInputEvent = require('SyntheticInputEvent');
+    this.BeforeInputEventPlugin = require('BeforeInputEventPlugin');
+  }
+
+  function extract(node, eventType, optionalData) {
+    var evt = document.createEvent('HTMLEvents');
+    evt.initEvent(eventType, true, true);
+    evt = Object.assign(evt, optionalData);
+    return ModuleCache.BeforeInputEventPlugin.extractEvents(
+      EventMapping[eventType],
+      ModuleCache.ReactDOMComponentTree.getInstanceFromNode(node),
+      evt,
+      node,
+    );
+  }
+
+  function setElementText(node) {
+    return args => (node.innerHTML = args);
+  }
+
+  function accumulateEvents(node, events) {
+    // We don't use accumulateInto module to apply partial application.
+    return function() {
+      var newArgs = [node].concat(Array.prototype.slice.call(arguments));
+      var newEvents = extract.apply(this, newArgs);
+      Array.prototype.push.apply(events, newEvents);
+    };
+  }
+
+  function EventMismatchError(idx, message) {
+    this.name = 'EventMismatchError';
+    this.message = '[' + idx + '] ' + message;
+  }
+  EventMismatchError.prototype = Object.create(Error.prototype);
+
+  function verifyEvents(actualEvents, expectedEvents) {
+    expect(actualEvents.length).toBe(expectedEvents.length);
+    expectedEvents.forEach(function(expected, idx) {
+      var actual = actualEvents[idx];
+      expect(function() {
+        if (actual === null && expected.type === null) {
+          // Both are null.  Expected.
+        } else if (actual === null) {
+          throw new EventMismatchError(idx, 'Expected not to be null');
+        } else if (
+          expected.type === null ||
+          !(actual instanceof expected.type)
+        ) {
+          throw new EventMismatchError(idx, 'Unexpected type: ' + actual);
+        } else {
+          // Type match.
+          Object.keys(expected.data).forEach(function(expectedKey) {
+            if (!(expectedKey in actual)) {
+              throw new EventMismatchError(idx, 'KeyNotFound: ' + expectedKey);
+            } else if (actual[expectedKey] !== expected.data[expectedKey]) {
+              throw new EventMismatchError(
+                idx,
+                'ValueMismatch: ' + actual[expectedKey],
+              );
+            }
+          });
+        }
+      }).not.toThrow();
+    });
+  }
+
+  // IE fires an event named `textinput` with all lowercase characters,
+  // instead of a standard name `textInput`.  As of now, React does not have
+  // a corresponding topEvent to IE's textinput, but both events are added to
+  // this scenario data for future use.
+  var Scenario_Composition = [
+    {run: accumulateEvents, arg: ['compositionstart', {data: ''}]},
+    {run: accumulateEvents, arg: ['textInput', {data: 'A'}]},
+    {run: accumulateEvents, arg: ['textinput', {data: 'A'}]},
+    {run: accumulateEvents, arg: ['keyup', {keyCode: 65}]},
+    {run: setElementText, arg: ['ABC']},
+    {run: accumulateEvents, arg: ['textInput', {data: 'abc'}]},
+    {run: accumulateEvents, arg: ['textinput', {data: 'abc'}]},
+    {run: accumulateEvents, arg: ['keyup', {keyCode: 32}]},
+    {run: setElementText, arg: ['XYZ']},
+    {run: accumulateEvents, arg: ['textInput', {data: 'xyz'}]},
+    {run: accumulateEvents, arg: ['textinput', {data: 'xyz'}]},
+    {run: accumulateEvents, arg: ['keyup', {keyCode: 32}]},
+    {run: accumulateEvents, arg: ['compositionend', {data: 'Hello'}]},
+  ];
+
+  /* Defined expected results as a factory of result data because we need
+     lazy evaluation for event modules.
+     Event modules are reloaded to simulate a different platform per testcase.
+     If we define expected results as a simple dictionary here, the comparison
+     of 'instanceof' fails after module cache is reset.  */
+
+  // Webkit behavior is simple.  We expect SyntheticInputEvent at each
+  // textInput, SyntheticCompositionEvent at composition, and nothing from
+  // keyUp.
+  var Expected_Webkit = () => [
+    {type: ModuleCache.SyntheticCompositionEvent, data: {}},
+    {type: null},
+    {type: null},
+    {type: ModuleCache.SyntheticInputEvent, data: {data: 'A'}},
+    {type: null},
+    {type: null}, // textinput of A
+    {type: null},
+    {type: null}, // keyUp of 65
+    {type: null},
+    {type: ModuleCache.SyntheticInputEvent, data: {data: 'abc'}},
+    {type: null},
+    {type: null}, // textinput of abc
+    {type: null},
+    {type: null}, // keyUp of 32
+    {type: null},
+    {type: ModuleCache.SyntheticInputEvent, data: {data: 'xyz'}},
+    {type: null},
+    {type: null}, // textinput of xyz
+    {type: null},
+    {type: null}, // keyUp of 32
+    {type: ModuleCache.SyntheticCompositionEvent, data: {data: 'Hello'}},
+    {type: null},
+  ];
+
+  // For IE11, we use fallback data instead of IE's textinput events.
+  // We expect no SyntheticInputEvent from textinput. Fallback beforeInput is
+  // expected to be triggered at compositionend with a text of the target
+  // element, not event data.
+  var Expected_IE11 = () => [
+    {type: ModuleCache.SyntheticCompositionEvent, data: {}},
+    {type: null},
+    {type: null},
+    {type: null}, // textInput of A
+    {type: null},
+    {type: null}, // textinput of A
+    {type: null},
+    {type: null}, // keyUp of 65
+    {type: null},
+    {type: null}, // textInput of abc
+    {type: null},
+    {type: null}, // textinput of abc
+
+    // fallbackData should NOT be set at keyUp with any of END_KEYCODES
+    {type: null},
+    {type: null}, // keyUp of 32
+
+    {type: null},
+    {type: null}, // textInput of xyz
+    {type: null},
+    {type: null}, // textinput of xyz
+    {type: null},
+    {type: null}, // keyUp of 32
+
+    // fallbackData is retrieved from the element, which is XYZ,
+    // at a time of compositionend
+    {type: ModuleCache.SyntheticCompositionEvent, data: {}},
+    {type: ModuleCache.SyntheticInputEvent, data: {data: 'XYZ'}},
+  ];
+
+  function TestEditableReactComponent(Emulator, Scenario, ExpectedResult) {
+    ModuleCache = new initialize(Emulator);
+
+    class EditableDiv extends React.Component {
+      render() {
+        return <div contentEditable="true" />;
+      }
+    }
+    var rendered = ReactTestUtils.renderIntoDocument(<EditableDiv />);
+
+    var node = ModuleCache.ReactDOM.findDOMNode(rendered);
+    var events = [];
+
+    Scenario.forEach(el => el.run.call(this, node, events).apply(this, el.arg));
+    verifyEvents(events, ExpectedResult());
+  }
+
+  it('extract onBeforeInput from native textinput events', function() {
+    TestEditableReactComponent(
+      simulateWebkit,
+      Scenario_Composition,
+      Expected_Webkit,
+    );
+  });
+
+  it('extract onBeforeInput from fallback objects', function() {
+    TestEditableReactComponent(
+      simulateIE11,
+      Scenario_Composition,
+      Expected_IE11,
+    );
+  });
+});
diff --git a/src/renderers/dom/client/eventPlugins/__tests__/ChangeEventPlugin-test.js b/src/renderers/dom/client/eventPlugins/__tests__/ChangeEventPlugin-test.js
index 0d29c6664a03..d85970cec56a 100644
--- a/src/renderers/dom/client/eventPlugins/__tests__/ChangeEventPlugin-test.js
+++ b/src/renderers/dom/client/eventPlugins/__tests__/ChangeEventPlugin-test.js
@@ -12,10 +12,43 @@
 'use strict';
 
 var React = require('React');
+var ReactDOM = require('ReactDOM');
 var ReactTestUtils = require('ReactTestUtils');
+var ChangeEventPlugin = require('ChangeEventPlugin');
+var inputValueTracking = require('inputValueTracking');
 
-describe('ChangeEventPlugin', function() {
-  it('should fire change for checkbox input', function() {
+function getTrackedValue(elem) {
+  var tracker = inputValueTracking._getTrackerFromNode(elem);
+  return tracker.getValue();
+}
+
+function setTrackedValue(elem, value) {
+  var tracker = inputValueTracking._getTrackerFromNode(elem);
+  tracker.setValue(value);
+}
+
+function setUntrackedValue(elem, value) {
+  var tracker = inputValueTracking._getTrackerFromNode(elem);
+  var current = tracker.getValue();
+
+  if (elem.type === 'checkbox' || elem.type === 'radio') {
+    elem.checked = value;
+  } else {
+    elem.value = value;
+  }
+  tracker.setValue(current);
+}
+
+describe('ChangeEventPlugin', () => {
+  beforeEach(() => {
+    ChangeEventPlugin._allowSimulatedPassThrough = false;
+  });
+
+  afterEach(() => {
+    ChangeEventPlugin._allowSimulatedPassThrough = true;
+  });
+
+  it('should fire change for checkbox input', () => {
     var called = 0;
 
     function cb(e) {
@@ -23,8 +56,176 @@ describe('ChangeEventPlugin', function() {
       expect(e.type).toBe('change');
     }
 
-    var input = ReactTestUtils.renderIntoDocument(<input type="checkbox" onChange={cb}/>);
+    var input = ReactTestUtils.renderIntoDocument(
+      <input type="checkbox" onChange={cb} />,
+    );
+
+    setUntrackedValue(input, true);
+    ReactTestUtils.SimulateNative.click(input);
+
+    expect(called).toBe(1);
+  });
+
+  it('should catch setting the value programmatically', function() {
+    var input = ReactTestUtils.renderIntoDocument(
+      <input type="text" defaultValue="foo" />,
+    );
+
+    input.value = 'bar';
+    expect(getTrackedValue(input)).toBe('bar');
+  });
+
+  it('should not fire change when setting the value programmatically', function() {
+    var called = 0;
+
+    function cb(e) {
+      called += 1;
+      expect(e.type).toBe('change');
+    }
+
+    var input = ReactTestUtils.renderIntoDocument(
+      <input type="text" onChange={cb} defaultValue="foo" />,
+    );
+
+    input.value = 'bar';
+    ReactTestUtils.SimulateNative.change(input);
+    expect(called).toBe(0);
+
+    setUntrackedValue(input, 'foo');
+    ReactTestUtils.SimulateNative.change(input);
+
+    expect(called).toBe(1);
+  });
+
+  it('should not fire change when setting checked programmatically', function() {
+    var called = 0;
+
+    function cb(e) {
+      called += 1;
+      expect(e.type).toBe('change');
+    }
+
+    var input = ReactTestUtils.renderIntoDocument(
+      <input type="checkbox" onChange={cb} defaultChecked={true} />,
+    );
+
+    input.checked = true;
     ReactTestUtils.SimulateNative.click(input);
+    expect(called).toBe(0);
+
+    input.checked = false;
+    setTrackedValue(input, undefined);
+    ReactTestUtils.SimulateNative.click(input);
+
     expect(called).toBe(1);
   });
+
+  it('should unmount', function() {
+    var container = document.createElement('div');
+    var input = ReactDOM.render(<input />, container);
+
+    ReactDOM.unmountComponentAtNode(container);
+  });
+
+  it('should only fire change for checked radio button once', function() {
+    var called = 0;
+
+    function cb(e) {
+      called += 1;
+    }
+
+    var input = ReactTestUtils.renderIntoDocument(
+      <input type="radio" onChange={cb} />,
+    );
+    setUntrackedValue(input, true);
+    ReactTestUtils.SimulateNative.click(input);
+    ReactTestUtils.SimulateNative.click(input);
+    expect(called).toBe(1);
+  });
+
+  it('should deduplicate input value change events', function() {
+    var input;
+    var called = 0;
+
+    function cb(e) {
+      called += 1;
+      expect(e.type).toBe('change');
+    }
+
+    [
+      <input type="text" onChange={cb} />,
+      <input type="number" onChange={cb} />,
+      <input type="range" onChange={cb} />,
+    ].forEach(function(element) {
+      called = 0;
+      input = ReactTestUtils.renderIntoDocument(element);
+
+      setUntrackedValue(input, '40');
+      ReactTestUtils.SimulateNative.change(input);
+      ReactTestUtils.SimulateNative.change(input);
+      expect(called).toBe(1);
+
+      called = 0;
+      input = ReactTestUtils.renderIntoDocument(element);
+      setUntrackedValue(input, '40');
+      ReactTestUtils.SimulateNative.input(input);
+      ReactTestUtils.SimulateNative.input(input);
+      expect(called).toBe(1);
+
+      called = 0;
+      input = ReactTestUtils.renderIntoDocument(element);
+      setUntrackedValue(input, '40');
+      ReactTestUtils.SimulateNative.input(input);
+      ReactTestUtils.SimulateNative.change(input);
+      expect(called).toBe(1);
+    });
+  });
+
+  it('should listen for both change and input events when supported', function() {
+    var called = 0;
+
+    function cb(e) {
+      called += 1;
+      expect(e.type).toBe('change');
+    }
+
+    if (!ChangeEventPlugin._isInputEventSupported) {
+      return;
+    }
+
+    var input = ReactTestUtils.renderIntoDocument(
+      <input type="range" onChange={cb} />,
+    );
+    setUntrackedValue(input, 'bar');
+
+    ReactTestUtils.SimulateNative.input(input);
+
+    setUntrackedValue(input, 'foo');
+
+    ReactTestUtils.SimulateNative.change(input);
+
+    expect(called).toBe(2);
+  });
+
+  it('should only fire events when the value changes for range inputs', function() {
+    var called = 0;
+
+    function cb(e) {
+      called += 1;
+      expect(e.type).toBe('change');
+    }
+
+    var input = ReactTestUtils.renderIntoDocument(
+      <input type="range" onChange={cb} />,
+    );
+    setUntrackedValue(input, '40');
+    ReactTestUtils.SimulateNative.input(input);
+    ReactTestUtils.SimulateNative.change(input);
+
+    setUntrackedValue(input, 'foo');
+
+    ReactTestUtils.SimulateNative.input(input);
+    ReactTestUtils.SimulateNative.change(input);
+    expect(called).toBe(2);
+  });
 });
diff --git a/src/renderers/dom/client/eventPlugins/__tests__/EnterLeaveEventPlugin-test.js b/src/renderers/dom/client/eventPlugins/__tests__/EnterLeaveEventPlugin-test.js
index 68606ead4ac8..5fbf0689345f 100644
--- a/src/renderers/dom/client/eventPlugins/__tests__/EnterLeaveEventPlugin-test.js
+++ b/src/renderers/dom/client/eventPlugins/__tests__/EnterLeaveEventPlugin-test.js
@@ -12,45 +12,42 @@
 'use strict';
 
 var EnterLeaveEventPlugin;
-var EventConstants;
 var React;
 var ReactDOM;
 var ReactDOMComponentTree;
 
-var topLevelTypes;
-
-describe('EnterLeaveEventPlugin', function() {
-  beforeEach(function() {
+describe('EnterLeaveEventPlugin', () => {
+  beforeEach(() => {
     jest.resetModuleRegistry();
 
     EnterLeaveEventPlugin = require('EnterLeaveEventPlugin');
-    EventConstants = require('EventConstants');
     React = require('React');
     ReactDOM = require('ReactDOM');
     ReactDOMComponentTree = require('ReactDOMComponentTree');
-
-    topLevelTypes = EventConstants.topLevelTypes;
   });
 
-  it('should set relatedTarget properly in iframe', function() {
+  it('should set relatedTarget properly in iframe', () => {
     var iframe = document.createElement('iframe');
     document.body.appendChild(iframe);
 
     var iframeDocument = iframe.contentDocument;
 
     iframeDocument.write(
-      '<!DOCTYPE html><html><head></head><body><div></div></body></html>'
+      '<!DOCTYPE html><html><head></head><body><div></div></body></html>',
     );
     iframeDocument.close();
 
-    var component = ReactDOM.render(<div />, iframeDocument.body.getElementsByTagName('div')[0]);
+    var component = ReactDOM.render(
+      <div />,
+      iframeDocument.body.getElementsByTagName('div')[0],
+    );
     var div = ReactDOM.findDOMNode(component);
 
     var extracted = EnterLeaveEventPlugin.extractEvents(
-      topLevelTypes.topMouseOver,
+      'topMouseOver',
       ReactDOMComponentTree.getInstanceFromNode(div),
       {target: div},
-      div
+      div,
     );
     expect(extracted.length).toBe(2);
 
diff --git a/src/renderers/dom/client/eventPlugins/__tests__/FallbackCompositionState-test.js b/src/renderers/dom/client/eventPlugins/__tests__/FallbackCompositionState-test.js
index 04e09ea28972..35eca38ac933 100644
--- a/src/renderers/dom/client/eventPlugins/__tests__/FallbackCompositionState-test.js
+++ b/src/renderers/dom/client/eventPlugins/__tests__/FallbackCompositionState-test.js
@@ -11,12 +11,12 @@
 
 'use strict';
 
-describe('FallbackCompositionState', function() {
+describe('FallbackCompositionState', () => {
   var FallbackCompositionState;
 
   var TEXT = 'Hello world';
 
-  beforeEach(function() {
+  beforeEach(() => {
     FallbackCompositionState = require('FallbackCompositionState');
   });
 
@@ -48,7 +48,7 @@ describe('FallbackCompositionState', function() {
     FallbackCompositionState.release(composition);
   }
 
-  it('extracts value via `getText()`', function() {
+  it('extracts value via `getText()`', () => {
     var composition = FallbackCompositionState.getPooled(getInput());
     expect(composition.getText()).toBe(TEXT);
     FallbackCompositionState.release(composition);
@@ -62,30 +62,30 @@ describe('FallbackCompositionState', function() {
     FallbackCompositionState.release(composition);
   });
 
-  describe('Extract fallback data inserted at collapsed cursor', function() {
-    it('extracts when inserted at start of text', function() {
+  describe('Extract fallback data inserted at collapsed cursor', () => {
+    it('extracts when inserted at start of text', () => {
       assertExtractedData('XXXHello world', 'XXX');
     });
 
-    it('extracts when inserted within text', function() {
+    it('extracts when inserted within text', () => {
       assertExtractedData('Hello XXXworld', 'XXX');
     });
 
-    it('extracts when inserted at end of text', function() {
+    it('extracts when inserted at end of text', () => {
       assertExtractedData('Hello worldXXX', 'XXX');
     });
   });
 
-  describe('Extract fallback data for non-collapsed range', function() {
-    it('extracts when inserted at start of text', function() {
+  describe('Extract fallback data for non-collapsed range', () => {
+    it('extracts when inserted at start of text', () => {
       assertExtractedData('XXX world', 'XXX');
     });
 
-    it('extracts when inserted within text', function() {
+    it('extracts when inserted within text', () => {
       assertExtractedData('HelXXXrld', 'XXX');
     });
 
-    it('extracts when inserted at end of text', function() {
+    it('extracts when inserted at end of text', () => {
       assertExtractedData('Hello XXX', 'XXX');
     });
   });
diff --git a/src/renderers/dom/client/eventPlugins/__tests__/SelectEventPlugin-test.js b/src/renderers/dom/client/eventPlugins/__tests__/SelectEventPlugin-test.js
index 0f032902d482..41707da4f693 100644
--- a/src/renderers/dom/client/eventPlugins/__tests__/SelectEventPlugin-test.js
+++ b/src/renderers/dom/client/eventPlugins/__tests__/SelectEventPlugin-test.js
@@ -11,65 +11,59 @@
 
 'use strict';
 
-var EventConstants;
 var React;
 var ReactDOM;
 var ReactDOMComponentTree;
 var ReactTestUtils;
 var SelectEventPlugin;
 
-var topLevelTypes;
-
-describe('SelectEventPlugin', function() {
+describe('SelectEventPlugin', () => {
   function extract(node, topLevelEvent) {
     return SelectEventPlugin.extractEvents(
       topLevelEvent,
       ReactDOMComponentTree.getInstanceFromNode(node),
       {target: node},
-      node
+      node,
     );
   }
 
-  beforeEach(function() {
-    EventConstants = require('EventConstants');
+  beforeEach(() => {
     React = require('React');
     ReactDOM = require('ReactDOM');
     ReactDOMComponentTree = require('ReactDOMComponentTree');
     ReactTestUtils = require('ReactTestUtils');
     SelectEventPlugin = require('SelectEventPlugin');
-
-    topLevelTypes = EventConstants.topLevelTypes;
   });
 
-  it('should skip extraction if no listeners are present', function() {
-    var WithoutSelect = React.createClass({
-      render: function() {
+  it('should skip extraction if no listeners are present', () => {
+    class WithoutSelect extends React.Component {
+      render() {
         return <input type="text" />;
-      },
-    });
+      }
+    }
 
     var rendered = ReactTestUtils.renderIntoDocument(<WithoutSelect />);
     var node = ReactDOM.findDOMNode(rendered);
     node.focus();
 
-    var mousedown = extract(node, topLevelTypes.topMouseDown);
+    var mousedown = extract(node, 'topMouseDown');
     expect(mousedown).toBe(null);
 
-    var mouseup = extract(node, topLevelTypes.topMouseUp);
+    var mouseup = extract(node, 'topMouseUp');
     expect(mouseup).toBe(null);
   });
 
-  it('should extract if an `onSelect` listener is present', function() {
-    var WithSelect = React.createClass({
-      render: function() {
+  it('should extract if an `onSelect` listener is present', () => {
+    class WithSelect extends React.Component {
+      render() {
         return <input type="text" onSelect={this.props.onSelect} />;
-      },
-    });
+      }
+    }
 
-    var cb = jest.genMockFn();
+    var cb = jest.fn();
 
     var rendered = ReactTestUtils.renderIntoDocument(
-      <WithSelect onSelect={cb} />
+      <WithSelect onSelect={cb} />,
     );
     var node = ReactDOM.findDOMNode(rendered);
 
@@ -77,13 +71,13 @@ describe('SelectEventPlugin', function() {
     node.selectionEnd = 0;
     node.focus();
 
-    var focus = extract(node, topLevelTypes.topFocus);
+    var focus = extract(node, 'topFocus');
     expect(focus).toBe(null);
 
-    var mousedown = extract(node, topLevelTypes.topMouseDown);
+    var mousedown = extract(node, 'topMouseDown');
     expect(mousedown).toBe(null);
 
-    var mouseup = extract(node, topLevelTypes.topMouseUp);
+    var mouseup = extract(node, 'topMouseUp');
     expect(mouseup).not.toBe(null);
     expect(typeof mouseup).toBe('object');
     expect(mouseup.type).toBe('select');
diff --git a/src/renderers/dom/client/eventPlugins/__tests__/SimpleEventPlugin-test.js b/src/renderers/dom/client/eventPlugins/__tests__/SimpleEventPlugin-test.js
new file mode 100644
index 000000000000..09dbea866519
--- /dev/null
+++ b/src/renderers/dom/client/eventPlugins/__tests__/SimpleEventPlugin-test.js
@@ -0,0 +1,188 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+describe('SimpleEventPlugin', function() {
+  var React;
+  var ReactDOM;
+  var ReactTestUtils;
+
+  var onClick;
+
+  function expectClickThru(element) {
+    ReactTestUtils.SimulateNative.click(ReactDOM.findDOMNode(element));
+    expect(onClick.mock.calls.length).toBe(1);
+  }
+
+  function expectNoClickThru(element) {
+    ReactTestUtils.SimulateNative.click(ReactDOM.findDOMNode(element));
+    expect(onClick.mock.calls.length).toBe(0);
+  }
+
+  function mounted(element) {
+    element = ReactTestUtils.renderIntoDocument(element);
+    return element;
+  }
+
+  beforeEach(function() {
+    React = require('React');
+    ReactDOM = require('ReactDOM');
+    ReactTestUtils = require('ReactTestUtils');
+
+    onClick = jest.fn();
+  });
+
+  it('A non-interactive tags click when disabled', function() {
+    var element = <div onClick={onClick} />;
+    expectClickThru(mounted(element));
+  });
+
+  it('A non-interactive tags clicks bubble when disabled', function() {
+    var element = ReactTestUtils.renderIntoDocument(
+      <div onClick={onClick}><div /></div>,
+    );
+    var child = ReactDOM.findDOMNode(element).firstChild;
+
+    ReactTestUtils.SimulateNative.click(child);
+    expect(onClick.mock.calls.length).toBe(1);
+  });
+
+  it('does not register a click when clicking a child of a disabled element', function() {
+    var element = ReactTestUtils.renderIntoDocument(
+      <button onClick={onClick} disabled={true}><span /></button>,
+    );
+    var child = ReactDOM.findDOMNode(element).querySelector('span');
+
+    ReactTestUtils.SimulateNative.click(child);
+    expect(onClick.mock.calls.length).toBe(0);
+  });
+
+  it('triggers click events for children of disabled elements', function() {
+    var element = ReactTestUtils.renderIntoDocument(
+      <button disabled={true}><span onClick={onClick} /></button>,
+    );
+    var child = ReactDOM.findDOMNode(element).querySelector('span');
+
+    ReactTestUtils.SimulateNative.click(child);
+    expect(onClick.mock.calls.length).toBe(1);
+  });
+
+  it('triggers parent captured click events when target is a child of a disabled elements', function() {
+    var element = ReactTestUtils.renderIntoDocument(
+      <div onClickCapture={onClick}>
+        <button disabled={true}><span /></button>
+      </div>,
+    );
+    var child = ReactDOM.findDOMNode(element).querySelector('span');
+
+    ReactTestUtils.SimulateNative.click(child);
+    expect(onClick.mock.calls.length).toBe(1);
+  });
+
+  it('triggers captured click events for children of disabled elements', function() {
+    var element = ReactTestUtils.renderIntoDocument(
+      <button disabled={true}><span onClickCapture={onClick} /></button>,
+    );
+    var child = ReactDOM.findDOMNode(element).querySelector('span');
+
+    ReactTestUtils.SimulateNative.click(child);
+    expect(onClick.mock.calls.length).toBe(1);
+  });
+
+  ['button', 'input', 'select', 'textarea'].forEach(function(tagName) {
+    describe(tagName, function() {
+      it('should forward clicks when it starts out not disabled', () => {
+        var element = React.createElement(tagName, {
+          onClick: onClick,
+        });
+
+        expectClickThru(mounted(element));
+      });
+
+      it('should not forward clicks when it starts out disabled', () => {
+        var element = React.createElement(tagName, {
+          onClick: onClick,
+          disabled: true,
+        });
+
+        expectNoClickThru(mounted(element));
+      });
+
+      it('should forward clicks when it becomes not disabled', () => {
+        var container = document.createElement('div');
+        var element = ReactDOM.render(
+          React.createElement(tagName, {onClick: onClick, disabled: true}),
+          container,
+        );
+        element = ReactDOM.render(
+          React.createElement(tagName, {onClick: onClick}),
+          container,
+        );
+        expectClickThru(element);
+      });
+
+      it('should not forward clicks when it becomes disabled', () => {
+        var container = document.createElement('div');
+        var element = ReactDOM.render(
+          React.createElement(tagName, {onClick: onClick}),
+          container,
+        );
+        element = ReactDOM.render(
+          React.createElement(tagName, {onClick: onClick, disabled: true}),
+          container,
+        );
+        expectNoClickThru(element);
+      });
+
+      it('should work correctly if the listener is changed', () => {
+        var container = document.createElement('div');
+        var element = ReactDOM.render(
+          React.createElement(tagName, {onClick: onClick, disabled: true}),
+          container,
+        );
+        element = ReactDOM.render(
+          React.createElement(tagName, {onClick: onClick, disabled: false}),
+          container,
+        );
+        expectClickThru(element);
+      });
+    });
+  });
+
+  describe('iOS bubbling click fix', function() {
+    // See http://www.quirksmode.org/blog/archives/2010/09/click_event_del.html
+
+    it('does not add a local click to interactive elements', function() {
+      var container = document.createElement('div');
+
+      ReactDOM.render(<button onClick={onClick} />, container);
+
+      var node = container.firstChild;
+
+      node.dispatchEvent(new MouseEvent('click'));
+
+      expect(onClick.mock.calls.length).toBe(0);
+    });
+
+    it('adds a local click listener to non-interactive elements', function() {
+      var container = document.createElement('div');
+
+      ReactDOM.render(<div onClick={onClick} />, container);
+
+      var node = container.firstChild;
+
+      node.dispatchEvent(new MouseEvent('click'));
+
+      expect(onClick.mock.calls.length).toBe(0);
+    });
+  });
+});
diff --git a/src/renderers/dom/client/findDOMNode.js b/src/renderers/dom/client/findDOMNode.js
index 65c80700938a..9af446e20e8a 100644
--- a/src/renderers/dom/client/findDOMNode.js
+++ b/src/renderers/dom/client/findDOMNode.js
@@ -15,13 +15,15 @@ var ReactCurrentOwner = require('ReactCurrentOwner');
 var ReactDOMComponentTree = require('ReactDOMComponentTree');
 var ReactInstanceMap = require('ReactInstanceMap');
 
-var getNativeComponentFromComposite = require('getNativeComponentFromComposite');
+var getHostComponentFromComposite = require('getHostComponentFromComposite');
 var invariant = require('invariant');
 var warning = require('warning');
 
 /**
  * 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.
  */
@@ -32,11 +34,11 @@ function findDOMNode(componentOrElement) {
       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'
+          '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',
       );
       owner._warnedAboutRefsInRender = true;
     }
@@ -50,20 +52,17 @@ function findDOMNode(componentOrElement) {
 
   var inst = ReactInstanceMap.get(componentOrElement);
   if (inst) {
-    inst = getNativeComponentFromComposite(inst);
+    inst = getHostComponentFromComposite(inst);
     return inst ? ReactDOMComponentTree.getNodeFromInstance(inst) : null;
   }
 
   if (typeof componentOrElement.render === 'function') {
-    invariant(
-      false,
-      'findDOMNode was called on an unmounted component.'
-    );
+    invariant(false, 'findDOMNode was called on an unmounted component.');
   } else {
     invariant(
       false,
       'Element appears to be neither ReactComponent nor DOMNode (keys: %s)',
-      Object.keys(componentOrElement)
+      Object.keys(componentOrElement),
     );
   }
 }
diff --git a/src/renderers/dom/client/inputValueTracking.js b/src/renderers/dom/client/inputValueTracking.js
new file mode 100644
index 000000000000..f0086f03a153
--- /dev/null
+++ b/src/renderers/dom/client/inputValueTracking.js
@@ -0,0 +1,135 @@
+/**
+ * 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 inputValueTracking
+ */
+
+'use strict';
+var ReactDOMComponentTree = require('ReactDOMComponentTree');
+
+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) {
+  delete inst._wrapperState.valueTracker;
+}
+
+function getValueFromNode(node) {
+  var value;
+  if (node) {
+    value = isCheckable(node) ? '' + node.checked : node.value;
+  }
+  return value;
+}
+
+var inputValueTracking = {
+  // exposed for testing
+  _getTrackerFromNode(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() {
+        return currentValue;
+      },
+      setValue(value) {
+        currentValue = '' + value;
+      },
+      stopTracking() {
+        detachTracker(inst);
+        delete node[valueField];
+      },
+    });
+  },
+
+  updateValueIfChanged(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(inst) {
+    var tracker = getTracker(inst);
+    if (tracker) {
+      tracker.stopTracking();
+    }
+  },
+};
+
+module.exports = inputValueTracking;
diff --git a/src/addons/renderSubtreeIntoContainer.js b/src/renderers/dom/client/renderSubtreeIntoContainer.js
similarity index 89%
rename from src/addons/renderSubtreeIntoContainer.js
rename to src/renderers/dom/client/renderSubtreeIntoContainer.js
index e1e7e3f0991d..d47e2ad2e12c 100644
--- a/src/addons/renderSubtreeIntoContainer.js
+++ b/src/renderers/dom/client/renderSubtreeIntoContainer.js
@@ -6,8 +6,8 @@
  * 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 renderSubtreeIntoContainer
-*/
+ * @providesModule renderSubtreeIntoContainer
+ */
 
 'use strict';
 
diff --git a/src/renderers/dom/client/syntheticEvents/SyntheticAnimationEvent.js b/src/renderers/dom/client/syntheticEvents/SyntheticAnimationEvent.js
index 17b6f368b179..1a6925a11bab 100644
--- a/src/renderers/dom/client/syntheticEvents/SyntheticAnimationEvent.js
+++ b/src/renderers/dom/client/syntheticEvents/SyntheticAnimationEvent.js
@@ -34,14 +34,17 @@ function SyntheticAnimationEvent(
   dispatchConfig,
   dispatchMarker,
   nativeEvent,
-  nativeEventTarget
+  nativeEventTarget,
 ) {
-  return SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
+  return SyntheticEvent.call(
+    this,
+    dispatchConfig,
+    dispatchMarker,
+    nativeEvent,
+    nativeEventTarget,
+  );
 }
 
-SyntheticEvent.augmentClass(
-  SyntheticAnimationEvent,
-  AnimationEventInterface
-);
+SyntheticEvent.augmentClass(SyntheticAnimationEvent, AnimationEventInterface);
 
 module.exports = SyntheticAnimationEvent;
diff --git a/src/renderers/dom/client/syntheticEvents/SyntheticClipboardEvent.js b/src/renderers/dom/client/syntheticEvents/SyntheticClipboardEvent.js
index cd0d4b226435..e277334b6416 100644
--- a/src/renderers/dom/client/syntheticEvents/SyntheticClipboardEvent.js
+++ b/src/renderers/dom/client/syntheticEvents/SyntheticClipboardEvent.js
@@ -19,11 +19,9 @@ var SyntheticEvent = require('SyntheticEvent');
  */
 var ClipboardEventInterface = {
   clipboardData: function(event) {
-    return (
-      'clipboardData' in event ?
-        event.clipboardData :
-        window.clipboardData
-    );
+    return 'clipboardData' in event
+      ? event.clipboardData
+      : window.clipboardData;
   },
 };
 
@@ -33,8 +31,19 @@ var ClipboardEventInterface = {
  * @param {object} nativeEvent Native browser event.
  * @extends {SyntheticUIEvent}
  */
-function SyntheticClipboardEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) {
-  return SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
+function SyntheticClipboardEvent(
+  dispatchConfig,
+  dispatchMarker,
+  nativeEvent,
+  nativeEventTarget,
+) {
+  return SyntheticEvent.call(
+    this,
+    dispatchConfig,
+    dispatchMarker,
+    nativeEvent,
+    nativeEventTarget,
+  );
 }
 
 SyntheticEvent.augmentClass(SyntheticClipboardEvent, ClipboardEventInterface);
diff --git a/src/renderers/dom/client/syntheticEvents/SyntheticCompositionEvent.js b/src/renderers/dom/client/syntheticEvents/SyntheticCompositionEvent.js
index 35b7f7ce18b7..77c53c5c9d6f 100644
--- a/src/renderers/dom/client/syntheticEvents/SyntheticCompositionEvent.js
+++ b/src/renderers/dom/client/syntheticEvents/SyntheticCompositionEvent.js
@@ -31,14 +31,20 @@ function SyntheticCompositionEvent(
   dispatchConfig,
   dispatchMarker,
   nativeEvent,
-  nativeEventTarget
+  nativeEventTarget,
 ) {
-  return SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
+  return SyntheticEvent.call(
+    this,
+    dispatchConfig,
+    dispatchMarker,
+    nativeEvent,
+    nativeEventTarget,
+  );
 }
 
 SyntheticEvent.augmentClass(
   SyntheticCompositionEvent,
-  CompositionEventInterface
+  CompositionEventInterface,
 );
 
 module.exports = SyntheticCompositionEvent;
diff --git a/src/renderers/dom/client/syntheticEvents/SyntheticDragEvent.js b/src/renderers/dom/client/syntheticEvents/SyntheticDragEvent.js
index f5d97420b33b..3f74638f93a1 100644
--- a/src/renderers/dom/client/syntheticEvents/SyntheticDragEvent.js
+++ b/src/renderers/dom/client/syntheticEvents/SyntheticDragEvent.js
@@ -27,8 +27,19 @@ var DragEventInterface = {
  * @param {object} nativeEvent Native browser event.
  * @extends {SyntheticUIEvent}
  */
-function SyntheticDragEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) {
-  return SyntheticMouseEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
+function SyntheticDragEvent(
+  dispatchConfig,
+  dispatchMarker,
+  nativeEvent,
+  nativeEventTarget,
+) {
+  return SyntheticMouseEvent.call(
+    this,
+    dispatchConfig,
+    dispatchMarker,
+    nativeEvent,
+    nativeEventTarget,
+  );
 }
 
 SyntheticMouseEvent.augmentClass(SyntheticDragEvent, DragEventInterface);
diff --git a/src/renderers/dom/client/syntheticEvents/SyntheticFocusEvent.js b/src/renderers/dom/client/syntheticEvents/SyntheticFocusEvent.js
index e145b8a434ad..de0616834bea 100644
--- a/src/renderers/dom/client/syntheticEvents/SyntheticFocusEvent.js
+++ b/src/renderers/dom/client/syntheticEvents/SyntheticFocusEvent.js
@@ -27,8 +27,19 @@ var FocusEventInterface = {
  * @param {object} nativeEvent Native browser event.
  * @extends {SyntheticUIEvent}
  */
-function SyntheticFocusEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) {
-  return SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
+function SyntheticFocusEvent(
+  dispatchConfig,
+  dispatchMarker,
+  nativeEvent,
+  nativeEventTarget,
+) {
+  return SyntheticUIEvent.call(
+    this,
+    dispatchConfig,
+    dispatchMarker,
+    nativeEvent,
+    nativeEventTarget,
+  );
 }
 
 SyntheticUIEvent.augmentClass(SyntheticFocusEvent, FocusEventInterface);
diff --git a/src/renderers/dom/client/syntheticEvents/SyntheticInputEvent.js b/src/renderers/dom/client/syntheticEvents/SyntheticInputEvent.js
index ba99c7c894c6..2639d3b53b38 100644
--- a/src/renderers/dom/client/syntheticEvents/SyntheticInputEvent.js
+++ b/src/renderers/dom/client/syntheticEvents/SyntheticInputEvent.js
@@ -32,14 +32,17 @@ function SyntheticInputEvent(
   dispatchConfig,
   dispatchMarker,
   nativeEvent,
-  nativeEventTarget
+  nativeEventTarget,
 ) {
-  return SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
+  return SyntheticEvent.call(
+    this,
+    dispatchConfig,
+    dispatchMarker,
+    nativeEvent,
+    nativeEventTarget,
+  );
 }
 
-SyntheticEvent.augmentClass(
-  SyntheticInputEvent,
-  InputEventInterface
-);
+SyntheticEvent.augmentClass(SyntheticInputEvent, InputEventInterface);
 
 module.exports = SyntheticInputEvent;
diff --git a/src/renderers/dom/client/syntheticEvents/SyntheticKeyboardEvent.js b/src/renderers/dom/client/syntheticEvents/SyntheticKeyboardEvent.js
index ce71c17ca86f..8cc554b9361e 100644
--- a/src/renderers/dom/client/syntheticEvents/SyntheticKeyboardEvent.js
+++ b/src/renderers/dom/client/syntheticEvents/SyntheticKeyboardEvent.js
@@ -75,8 +75,19 @@ var KeyboardEventInterface = {
  * @param {object} nativeEvent Native browser event.
  * @extends {SyntheticUIEvent}
  */
-function SyntheticKeyboardEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) {
-  return SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
+function SyntheticKeyboardEvent(
+  dispatchConfig,
+  dispatchMarker,
+  nativeEvent,
+  nativeEventTarget,
+) {
+  return SyntheticUIEvent.call(
+    this,
+    dispatchConfig,
+    dispatchMarker,
+    nativeEvent,
+    nativeEventTarget,
+  );
 }
 
 SyntheticUIEvent.augmentClass(SyntheticKeyboardEvent, KeyboardEventInterface);
diff --git a/src/renderers/dom/client/syntheticEvents/SyntheticMouseEvent.js b/src/renderers/dom/client/syntheticEvents/SyntheticMouseEvent.js
index e8962b9adecb..786d20c79f23 100644
--- a/src/renderers/dom/client/syntheticEvents/SyntheticMouseEvent.js
+++ b/src/renderers/dom/client/syntheticEvents/SyntheticMouseEvent.js
@@ -46,22 +46,23 @@ var MouseEventInterface = {
   },
   buttons: null,
   relatedTarget: function(event) {
-    return event.relatedTarget || (
-      event.fromElement === event.srcElement ?
-        event.toElement :
-        event.fromElement
+    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;
+    return 'pageX' in event
+      ? event.pageX
+      : event.clientX + ViewportMetrics.currentScrollLeft;
   },
   pageY: function(event) {
-    return 'pageY' in event ?
-      event.pageY :
-      event.clientY + ViewportMetrics.currentScrollTop;
+    return 'pageY' in event
+      ? event.pageY
+      : event.clientY + ViewportMetrics.currentScrollTop;
   },
 };
 
@@ -71,8 +72,19 @@ var MouseEventInterface = {
  * @param {object} nativeEvent Native browser event.
  * @extends {SyntheticUIEvent}
  */
-function SyntheticMouseEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) {
-  return SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
+function SyntheticMouseEvent(
+  dispatchConfig,
+  dispatchMarker,
+  nativeEvent,
+  nativeEventTarget,
+) {
+  return SyntheticUIEvent.call(
+    this,
+    dispatchConfig,
+    dispatchMarker,
+    nativeEvent,
+    nativeEventTarget,
+  );
 }
 
 SyntheticUIEvent.augmentClass(SyntheticMouseEvent, MouseEventInterface);
diff --git a/src/renderers/dom/client/syntheticEvents/SyntheticTouchEvent.js b/src/renderers/dom/client/syntheticEvents/SyntheticTouchEvent.js
index 38078a732c75..a954c9fec17f 100644
--- a/src/renderers/dom/client/syntheticEvents/SyntheticTouchEvent.js
+++ b/src/renderers/dom/client/syntheticEvents/SyntheticTouchEvent.js
@@ -36,8 +36,19 @@ var TouchEventInterface = {
  * @param {object} nativeEvent Native browser event.
  * @extends {SyntheticUIEvent}
  */
-function SyntheticTouchEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) {
-  return SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
+function SyntheticTouchEvent(
+  dispatchConfig,
+  dispatchMarker,
+  nativeEvent,
+  nativeEventTarget,
+) {
+  return SyntheticUIEvent.call(
+    this,
+    dispatchConfig,
+    dispatchMarker,
+    nativeEvent,
+    nativeEventTarget,
+  );
 }
 
 SyntheticUIEvent.augmentClass(SyntheticTouchEvent, TouchEventInterface);
diff --git a/src/renderers/dom/client/syntheticEvents/SyntheticTransitionEvent.js b/src/renderers/dom/client/syntheticEvents/SyntheticTransitionEvent.js
index 982410f78697..4b9087a1cb71 100644
--- a/src/renderers/dom/client/syntheticEvents/SyntheticTransitionEvent.js
+++ b/src/renderers/dom/client/syntheticEvents/SyntheticTransitionEvent.js
@@ -34,14 +34,17 @@ function SyntheticTransitionEvent(
   dispatchConfig,
   dispatchMarker,
   nativeEvent,
-  nativeEventTarget
+  nativeEventTarget,
 ) {
-  return SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
+  return SyntheticEvent.call(
+    this,
+    dispatchConfig,
+    dispatchMarker,
+    nativeEvent,
+    nativeEventTarget,
+  );
 }
 
-SyntheticEvent.augmentClass(
-  SyntheticTransitionEvent,
-  TransitionEventInterface
-);
+SyntheticEvent.augmentClass(SyntheticTransitionEvent, TransitionEventInterface);
 
 module.exports = SyntheticTransitionEvent;
diff --git a/src/renderers/dom/client/syntheticEvents/SyntheticUIEvent.js b/src/renderers/dom/client/syntheticEvents/SyntheticUIEvent.js
index b0eae7bed3e1..308d190481b0 100644
--- a/src/renderers/dom/client/syntheticEvents/SyntheticUIEvent.js
+++ b/src/renderers/dom/client/syntheticEvents/SyntheticUIEvent.js
@@ -26,7 +26,7 @@ var UIEventInterface = {
     }
 
     var target = getEventTarget(event);
-    if (target != null && target.window === target) {
+    if (target.window === target) {
       // target is a window object
       return target;
     }
@@ -50,8 +50,19 @@ var UIEventInterface = {
  * @param {object} nativeEvent Native browser event.
  * @extends {SyntheticEvent}
  */
-function SyntheticUIEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) {
-  return SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
+function SyntheticUIEvent(
+  dispatchConfig,
+  dispatchMarker,
+  nativeEvent,
+  nativeEventTarget,
+) {
+  return SyntheticEvent.call(
+    this,
+    dispatchConfig,
+    dispatchMarker,
+    nativeEvent,
+    nativeEventTarget,
+  );
 }
 
 SyntheticEvent.augmentClass(SyntheticUIEvent, UIEventInterface);
diff --git a/src/renderers/dom/client/syntheticEvents/SyntheticWheelEvent.js b/src/renderers/dom/client/syntheticEvents/SyntheticWheelEvent.js
index eea628e33e1e..e1359a250632 100644
--- a/src/renderers/dom/client/syntheticEvents/SyntheticWheelEvent.js
+++ b/src/renderers/dom/client/syntheticEvents/SyntheticWheelEvent.js
@@ -19,20 +19,19 @@ var SyntheticMouseEvent = require('SyntheticMouseEvent');
  */
 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
-    );
+    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
-    );
+    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,
 
@@ -49,8 +48,19 @@ var WheelEventInterface = {
  * @param {object} nativeEvent Native browser event.
  * @extends {SyntheticMouseEvent}
  */
-function SyntheticWheelEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) {
-  return SyntheticMouseEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
+function SyntheticWheelEvent(
+  dispatchConfig,
+  dispatchMarker,
+  nativeEvent,
+  nativeEventTarget,
+) {
+  return SyntheticMouseEvent.call(
+    this,
+    dispatchConfig,
+    dispatchMarker,
+    nativeEvent,
+    nativeEventTarget,
+  );
 }
 
 SyntheticMouseEvent.augmentClass(SyntheticWheelEvent, WheelEventInterface);
diff --git a/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticClipboardEvent-test.js b/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticClipboardEvent-test.js
index 7776f5420034..97f1a47f0ce1 100644
--- a/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticClipboardEvent-test.js
+++ b/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticClipboardEvent-test.js
@@ -13,10 +13,10 @@
 
 var SyntheticClipboardEvent;
 
-describe('SyntheticClipboardEvent', function() {
+describe('SyntheticClipboardEvent', () => {
   var createEvent;
 
-  beforeEach(function() {
+  beforeEach(() => {
     SyntheticClipboardEvent = require('SyntheticClipboardEvent');
     createEvent = function(nativeEvent) {
       var target = require('getEventTarget')(nativeEvent);
@@ -24,25 +24,28 @@ describe('SyntheticClipboardEvent', function() {
     };
   });
 
-  describe('ClipboardEvent interface', function() {
-    describe('clipboardData', function() {
-      describe('when event has clipboardData', function() {
-        it("returns event's clipboardData", function() {
+  describe('ClipboardEvent interface', () => {
+    describe('clipboardData', () => {
+      describe('when event has clipboardData', () => {
+        it("returns event's clipboardData", () => {
           // Mock clipboardData since native implementation doesn't have a constructor
-          var clipboardData = jasmine.createSpyObj(
-            'clipboardData',
-            ['dropEffect', 'effectAllowed', 'files', 'items', 'types']
-          );
+          var clipboardData = jasmine.createSpyObj('clipboardData', [
+            'dropEffect',
+            'effectAllowed',
+            'files',
+            'items',
+            'types',
+          ]);
           var clipboardEvent = createEvent({clipboardData: clipboardData});
-          
+
           expect(clipboardEvent.clipboardData).toBe(clipboardData);
         });
       });
     });
   });
 
-  describe('EventInterface', function() {
-    it('normalizes properties from the Event interface', function() {
+  describe('EventInterface', () => {
+    it('normalizes properties from the Event interface', () => {
       var target = document.createElement('div');
       var syntheticEvent = createEvent({srcElement: target});
 
@@ -50,7 +53,7 @@ describe('SyntheticClipboardEvent', function() {
       expect(syntheticEvent.type).toBe(undefined);
     });
 
-    it('is able to `preventDefault` and `stopPropagation`', function() {
+    it('is able to `preventDefault` and `stopPropagation`', () => {
       var nativeEvent = {};
       var syntheticEvent = createEvent(nativeEvent);
 
@@ -63,7 +66,7 @@ describe('SyntheticClipboardEvent', function() {
       expect(syntheticEvent.isPropagationStopped()).toBe(true);
     });
 
-    it('is able to `persist`', function() {
+    it('is able to `persist`', () => {
       var syntheticEvent = createEvent({});
 
       expect(syntheticEvent.isPersistent()).toBe(false);
diff --git a/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticEvent-test.js b/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticEvent-test.js
index a8799c8f87ad..d5c678201465 100644
--- a/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticEvent-test.js
+++ b/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticEvent-test.js
@@ -16,10 +16,10 @@ var React;
 var ReactDOM;
 var ReactTestUtils;
 
-describe('SyntheticEvent', function() {
+describe('SyntheticEvent', () => {
   var createEvent;
 
-  beforeEach(function() {
+  beforeEach(() => {
     SyntheticEvent = require('SyntheticEvent');
     React = require('React');
     ReactDOM = require('ReactDOM');
@@ -31,7 +31,7 @@ describe('SyntheticEvent', function() {
     };
   });
 
-  it('should normalize `target` from the nativeEvent', function() {
+  it('should normalize `target` from the nativeEvent', () => {
     var target = document.createElement('div');
     var syntheticEvent = createEvent({srcElement: target});
 
@@ -39,7 +39,7 @@ describe('SyntheticEvent', function() {
     expect(syntheticEvent.type).toBe(undefined);
   });
 
-  it('should be able to `preventDefault`', function() {
+  it('should be able to `preventDefault`', () => {
     var nativeEvent = {};
     var syntheticEvent = createEvent(nativeEvent);
 
@@ -52,14 +52,14 @@ describe('SyntheticEvent', function() {
     expect(nativeEvent.returnValue).toBe(false);
   });
 
-  it('should be prevented if nativeEvent is prevented', function() {
-    expect(
-      createEvent({defaultPrevented: true}).isDefaultPrevented()
-    ).toBe(true);
+  it('should be prevented if nativeEvent is prevented', () => {
+    expect(createEvent({defaultPrevented: true}).isDefaultPrevented()).toBe(
+      true,
+    );
     expect(createEvent({returnValue: false}).isDefaultPrevented()).toBe(true);
   });
 
-  it('should be able to `stopPropagation`', function() {
+  it('should be able to `stopPropagation`', () => {
     var nativeEvent = {};
     var syntheticEvent = createEvent(nativeEvent);
 
@@ -70,7 +70,7 @@ describe('SyntheticEvent', function() {
     expect(nativeEvent.cancelBubble).toBe(true);
   });
 
-  it('should be able to `persist`', function() {
+  it('should be able to `persist`', () => {
     var syntheticEvent = createEvent({});
 
     expect(syntheticEvent.isPersistent()).toBe(false);
@@ -78,7 +78,7 @@ describe('SyntheticEvent', function() {
     expect(syntheticEvent.isPersistent()).toBe(true);
   });
 
-  it('should be nullified if the synthetic event has called destructor and log warnings', function() {
+  it('should be nullified if the synthetic event has called destructor and log warnings', () => {
     spyOn(console, 'error');
     var target = document.createElement('div');
     var syntheticEvent = createEvent({srcElement: target});
@@ -87,106 +87,109 @@ describe('SyntheticEvent', function() {
     expect(syntheticEvent.nativeEvent).toBe(null);
     expect(syntheticEvent.target).toBe(null);
     // once for each property accessed
-    expect(console.error.calls.length).toBe(3);
+    expect(console.error.calls.count()).toBe(3);
     // assert the first warning for accessing `type`
-    expect(console.error.argsForCall[0][0]).toBe(
+    expect(console.error.calls.argsFor(0)[0]).toBe(
       'Warning: This synthetic event is reused for performance reasons. If ' +
-      'you\'re seeing this, you\'re accessing the property `type` on a ' +
-      'released/nullified synthetic event. This is set to null. If you must ' +
-      'keep the original synthetic event around, use event.persist(). ' +
-      'See https://fb.me/react-event-pooling for more information.'
+        "you're seeing this, you're accessing the property `type` on a " +
+        'released/nullified synthetic event. This is set to null. If you must ' +
+        'keep the original synthetic event around, use event.persist(). ' +
+        'See https://fb.me/react-event-pooling for more information.',
     );
   });
 
-  it('should warn when setting properties of a destructored synthetic event', function() {
+  it('should warn when setting properties of a destructored synthetic event', () => {
     spyOn(console, 'error');
     var target = document.createElement('div');
     var syntheticEvent = createEvent({srcElement: target});
     syntheticEvent.destructor();
-    expect(syntheticEvent.type = 'MouseEvent').toBe('MouseEvent');
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
+    expect((syntheticEvent.type = 'MouseEvent')).toBe('MouseEvent');
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
       'Warning: This synthetic event is reused for performance reasons. If ' +
-      'you\'re seeing this, you\'re setting the property `type` on a ' +
-      'released/nullified synthetic event. This is effectively a no-op. If you must ' +
-      'keep the original synthetic event around, use event.persist(). ' +
-      'See https://fb.me/react-event-pooling for more information.'
+        "you're seeing this, you're setting the property `type` on a " +
+        'released/nullified synthetic event. This is effectively a no-op. If you must ' +
+        'keep the original synthetic event around, use event.persist(). ' +
+        'See https://fb.me/react-event-pooling for more information.',
     );
   });
 
-  it('should warn if the synthetic event has been released when calling `preventDefault`', function() {
+  it('should warn if the synthetic event has been released when calling `preventDefault`', () => {
     spyOn(console, 'error');
     var syntheticEvent = createEvent({});
     SyntheticEvent.release(syntheticEvent);
     syntheticEvent.preventDefault();
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
       'Warning: This synthetic event is reused for performance reasons. If ' +
-      'you\'re seeing this, you\'re accessing the method `preventDefault` on a ' +
-      'released/nullified synthetic event. This is a no-op function. If you must ' +
-      'keep the original synthetic event around, use event.persist(). ' +
-      'See https://fb.me/react-event-pooling for more information.'
+        "you're seeing this, you're accessing the method `preventDefault` on a " +
+        'released/nullified synthetic event. This is a no-op function. If you must ' +
+        'keep the original synthetic event around, use event.persist(). ' +
+        'See https://fb.me/react-event-pooling for more information.',
     );
   });
 
-  it('should warn if the synthetic event has been released when calling `stopPropagation`', function() {
+  it('should warn if the synthetic event has been released when calling `stopPropagation`', () => {
     spyOn(console, 'error');
     var syntheticEvent = createEvent({});
     SyntheticEvent.release(syntheticEvent);
     syntheticEvent.stopPropagation();
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
       'Warning: This synthetic event is reused for performance reasons. If ' +
-      'you\'re seeing this, you\'re accessing the method `stopPropagation` on a ' +
-      'released/nullified synthetic event. This is a no-op function. If you must ' +
-      'keep the original synthetic event around, use event.persist(). ' +
-      'See https://fb.me/react-event-pooling for more information.'
+        "you're seeing this, you're accessing the method `stopPropagation` on a " +
+        'released/nullified synthetic event. This is a no-op function. If you must ' +
+        'keep the original synthetic event around, use event.persist(). ' +
+        'See https://fb.me/react-event-pooling for more information.',
     );
   });
 
   // TODO: reenable this test. We are currently silencing these warnings when
   // using TestUtils.Simulate to avoid spurious warnings that result from the
   // way we simulate events.
-  xit('should properly log warnings when events simulated with rendered components', function() {
-    spyOn(console, 'error');
-    var event;
-    var element = document.createElement('div');
-    function assignEvent(e) {
-      event = e;
-    }
-    var instance = ReactDOM.render(<div onClick={assignEvent} />, element);
-    ReactTestUtils.Simulate.click(ReactDOM.findDOMNode(instance));
-    expect(console.error.calls.length).toBe(0);
-
-    // access a property to cause the warning
-    event.nativeEvent; // eslint-disable-line no-unused-expressions
-
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: This synthetic event is reused for performance reasons. If ' +
-      'you\'re seeing this, you\'re accessing the property `nativeEvent` on a ' +
-      'released/nullified synthetic event. This is set to null. If you must ' +
-      'keep the original synthetic event around, use event.persist(). ' +
-      'See https://fb.me/react-event-pooling for more information.'
-    );
-  });
+  xit(
+    'should properly log warnings when events simulated with rendered components',
+    () => {
+      spyOn(console, 'error');
+      var event;
+      var element = document.createElement('div');
+      function assignEvent(e) {
+        event = e;
+      }
+      var instance = ReactDOM.render(<div onClick={assignEvent} />, element);
+      ReactTestUtils.Simulate.click(ReactDOM.findDOMNode(instance));
+      expect(console.error.calls.count()).toBe(0);
+
+      // access a property to cause the warning
+      event.nativeEvent; // eslint-disable-line no-unused-expressions
+
+      expect(console.error.calls.count()).toBe(1);
+      expect(console.error.calls.argsFor(0)[0]).toBe(
+        'Warning: This synthetic event is reused for performance reasons. If ' +
+          "you're seeing this, you're accessing the property `nativeEvent` on a " +
+          'released/nullified synthetic event. This is set to null. If you must ' +
+          'keep the original synthetic event around, use event.persist(). ' +
+          'See https://fb.me/react-event-pooling for more information.',
+      );
+    },
+  );
 
-  it('should warn if Proxy is supported and the synthetic event is added a property', function() {
+  it('should warn if Proxy is supported and the synthetic event is added a property', () => {
     spyOn(console, 'error');
     var syntheticEvent = createEvent({});
     syntheticEvent.foo = 'bar';
     SyntheticEvent.release(syntheticEvent);
     expect(syntheticEvent.foo).toBe('bar');
     if (typeof Proxy === 'function') {
-      expect(console.error.calls.length).toBe(1);
-      expect(console.error.argsForCall[0][0]).toBe(
+      expect(console.error.calls.count()).toBe(1);
+      expect(console.error.calls.argsFor(0)[0]).toBe(
         'Warning: 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.'
+          "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.',
       );
     } else {
-      expect(console.error.calls.length).toBe(0);
+      expect(console.error.calls.count()).toBe(0);
     }
   });
 });
diff --git a/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticKeyboardEvent-test.js b/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticKeyboardEvent-test.js
index 9c75a7096408..3b433e91842b 100644
--- a/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticKeyboardEvent-test.js
+++ b/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticKeyboardEvent-test.js
@@ -14,10 +14,10 @@
 var SyntheticKeyboardEvent;
 var getEventCharCode;
 
-describe('SyntheticKeyboardEvent', function() {
+describe('SyntheticKeyboardEvent', () => {
   var createEvent;
 
-  beforeEach(function() {
+  beforeEach(() => {
     // Mock getEventCharCode for proper unit testing
     jest.mock('getEventCharCode');
     getEventCharCode = require('getEventCharCode');
@@ -29,10 +29,10 @@ describe('SyntheticKeyboardEvent', function() {
     };
   });
 
-  describe('KeyboardEvent interface', function() {
-    describe('charCode', function() {
-      describe('when event is `keypress`', function() {
-        it('returns whatever getEventCharCode returns', function() {
+  describe('KeyboardEvent interface', () => {
+    describe('charCode', () => {
+      describe('when event is `keypress`', () => {
+        it('returns whatever getEventCharCode returns', () => {
           getEventCharCode.mockReturnValue(100500);
           var keyboardEvent = createEvent({type: 'keypress', charCode: 50});
 
@@ -40,33 +40,33 @@ describe('SyntheticKeyboardEvent', function() {
         });
       });
 
-      describe('when event is not `keypress`', function() {
-        it('returns 0', function() {
+      describe('when event is not `keypress`', () => {
+        it('returns 0', () => {
           var keyboardEvent = createEvent({type: 'keyup', charCode: 50});
           expect(keyboardEvent.charCode).toBe(0);
         });
       });
     });
 
-    describe('keyCode', function() {
-      describe('when event is `keydown` or `keyup`', function() {
-        it('returns a passed keyCode', function() {
+    describe('keyCode', () => {
+      describe('when event is `keydown` or `keyup`', () => {
+        it('returns a passed keyCode', () => {
           var keyboardEvent = createEvent({type: 'keyup', keyCode: 40});
           expect(keyboardEvent.keyCode).toBe(40);
         });
       });
 
-      describe('when event is `keypress`', function() {
-        it('returns 0', function() {
+      describe('when event is `keypress`', () => {
+        it('returns 0', () => {
           var keyboardEvent = createEvent({type: 'keypress', charCode: 40});
           expect(keyboardEvent.keyCode).toBe(0);
         });
       });
     });
 
-    describe('which', function() {
-      describe('when event is `keypress`', function() {
-        it('returns whatever getEventCharCode returns', function() {
+    describe('which', () => {
+      describe('when event is `keypress`', () => {
+        it('returns whatever getEventCharCode returns', () => {
           getEventCharCode.mockReturnValue(9001);
           var keyboardEvent = createEvent({type: 'keypress', charCode: 50});
 
@@ -74,15 +74,15 @@ describe('SyntheticKeyboardEvent', function() {
         });
       });
 
-      describe('when event is `keydown` or `keyup`', function() {
-        it('returns a passed keyCode', function() {
+      describe('when event is `keydown` or `keyup`', () => {
+        it('returns a passed keyCode', () => {
           var keyboardEvent = createEvent({type: 'keyup', keyCode: 40});
           expect(keyboardEvent.which).toBe(40);
         });
       });
 
-      describe('when event type is unknown', function() {
-        it('returns 0', function() {
+      describe('when event type is unknown', () => {
+        it('returns 0', () => {
           var keyboardEvent = createEvent({type: 'keysmack', keyCode: 40});
           expect(keyboardEvent.which).toBe(0);
         });
@@ -90,8 +90,8 @@ describe('SyntheticKeyboardEvent', function() {
     });
   });
 
-  describe('EventInterface', function() {
-    it('normalizes properties from the Event interface', function() {
+  describe('EventInterface', () => {
+    it('normalizes properties from the Event interface', () => {
       var target = document.createElement('div');
       var syntheticEvent = createEvent({srcElement: target});
 
@@ -99,7 +99,7 @@ describe('SyntheticKeyboardEvent', function() {
       expect(syntheticEvent.type).toBe(undefined);
     });
 
-    it('is able to `preventDefault` and `stopPropagation`', function() {
+    it('is able to `preventDefault` and `stopPropagation`', () => {
       var nativeEvent = {};
       var syntheticEvent = createEvent(nativeEvent);
 
@@ -112,7 +112,7 @@ describe('SyntheticKeyboardEvent', function() {
       expect(syntheticEvent.isPropagationStopped()).toBe(true);
     });
 
-    it('is able to `persist`', function() {
+    it('is able to `persist`', () => {
       var syntheticEvent = createEvent({});
 
       expect(syntheticEvent.isPersistent()).toBe(false);
diff --git a/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticWheelEvent-test.js b/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticWheelEvent-test.js
index 6ad4b488c06a..393ccf3fc6c2 100644
--- a/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticWheelEvent-test.js
+++ b/src/renderers/dom/client/syntheticEvents/__tests__/SyntheticWheelEvent-test.js
@@ -13,10 +13,10 @@
 
 var SyntheticWheelEvent;
 
-describe('SyntheticWheelEvent', function() {
+describe('SyntheticWheelEvent', () => {
   var createEvent;
 
-  beforeEach(function() {
+  beforeEach(() => {
     SyntheticWheelEvent = require('SyntheticWheelEvent');
 
     createEvent = function(nativeEvent) {
@@ -25,7 +25,7 @@ describe('SyntheticWheelEvent', function() {
     };
   });
 
-  it('should normalize properties from the Event interface', function() {
+  it('should normalize properties from the Event interface', () => {
     var target = document.createElement('div');
     var syntheticEvent = createEvent({srcElement: target});
 
@@ -33,11 +33,11 @@ describe('SyntheticWheelEvent', function() {
     expect(syntheticEvent.type).toBe(undefined);
   });
 
-  it('should normalize properties from the MouseEvent interface', function() {
+  it('should normalize properties from the MouseEvent interface', () => {
     expect(createEvent({which: 2, button: 1}).button).toBe(1);
   });
 
-  it('should normalize properties from the WheelEvent interface', function() {
+  it('should normalize properties from the WheelEvent interface', () => {
     var standardEvent = createEvent({deltaX: 10, deltaY: -50});
     expect(standardEvent.deltaX).toBe(10);
     expect(standardEvent.deltaY).toBe(-50);
@@ -47,7 +47,7 @@ describe('SyntheticWheelEvent', function() {
     expect(webkitEvent.deltaY).toBe(-50);
   });
 
-  it('should be able to `preventDefault` and `stopPropagation`', function() {
+  it('should be able to `preventDefault` and `stopPropagation`', () => {
     var nativeEvent = {};
     var syntheticEvent = createEvent(nativeEvent);
 
@@ -60,12 +60,11 @@ describe('SyntheticWheelEvent', function() {
     expect(syntheticEvent.isPropagationStopped()).toBe(true);
   });
 
-  it('should be able to `persist`', function() {
+  it('should be able to `persist`', () => {
     var syntheticEvent = createEvent({});
 
     expect(syntheticEvent.isPersistent()).toBe(false);
     syntheticEvent.persist();
     expect(syntheticEvent.isPersistent()).toBe(true);
   });
-
 });
diff --git a/src/renderers/dom/client/utils/DOMChildrenOperations.js b/src/renderers/dom/client/utils/DOMChildrenOperations.js
index f123aef6ba51..b7e4e1e105d8 100644
--- a/src/renderers/dom/client/utils/DOMChildrenOperations.js
+++ b/src/renderers/dom/client/utils/DOMChildrenOperations.js
@@ -13,8 +13,8 @@
 
 var DOMLazyTree = require('DOMLazyTree');
 var Danger = require('Danger');
-var ReactMultiChildUpdateTypes = require('ReactMultiChildUpdateTypes');
-var ReactPerf = require('ReactPerf');
+var ReactDOMComponentTree = require('ReactDOMComponentTree');
+var ReactInstrumentation = require('ReactInstrumentation');
 
 var createMicrosoftUnsafeLocalFunction = require('createMicrosoftUnsafeLocalFunction');
 var setInnerHTML = require('setInnerHTML');
@@ -22,7 +22,7 @@ var setTextContent = require('setTextContent');
 
 function getNodeAfter(parentNode, node) {
   // Special case for text components, which return [open, close] comments
-  // from getNativeNode.
+  // from getHostNode.
   if (Array.isArray(node)) {
     node = node[1];
   }
@@ -37,14 +37,16 @@ function getNodeAfter(parentNode, node) {
  * @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);
-  }
-);
+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);
@@ -72,7 +74,7 @@ function moveDelimitedText(
   parentNode,
   openingComment,
   closingComment,
-  referenceNode
+  referenceNode,
 ) {
   var node = openingComment;
   while (true) {
@@ -107,7 +109,7 @@ function replaceDelimitedText(openingComment, closingComment, stringText) {
       insertChildAt(
         parentNode,
         document.createTextNode(stringText),
-        nodeAfterComment
+        nodeAfterComment,
       );
     }
   } else {
@@ -120,14 +122,45 @@ function replaceDelimitedText(openingComment, closingComment, stringText) {
       removeDelimitedText(parentNode, openingComment, closingComment);
     }
   }
+
+  if (__DEV__) {
+    ReactInstrumentation.debugTool.onHostOperation({
+      instanceID: ReactDOMComponentTree.getInstanceFromNode(openingComment)
+        ._debugID,
+      type: 'replace text',
+      payload: stringText,
+    });
+  }
+}
+
+var dangerouslyReplaceNodeWithMarkup = Danger.dangerouslyReplaceNodeWithMarkup;
+if (__DEV__) {
+  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: Danger.dangerouslyReplaceNodeWithMarkup,
+  dangerouslyReplaceNodeWithMarkup: dangerouslyReplaceNodeWithMarkup,
 
   replaceDelimitedText: replaceDelimitedText,
 
@@ -139,46 +172,79 @@ var DOMChildrenOperations = {
    * @internal
    */
   processUpdates: function(parentNode, updates) {
+    if (__DEV__) {
+      var parentNodeDebugID = ReactDOMComponentTree.getInstanceFromNode(
+        parentNode,
+      )._debugID;
+    }
+
     for (var k = 0; k < updates.length; k++) {
       var update = updates[k];
       switch (update.type) {
-        case ReactMultiChildUpdateTypes.INSERT_MARKUP:
+        case 'INSERT_MARKUP':
           insertLazyTreeChildAt(
             parentNode,
             update.content,
-            getNodeAfter(parentNode, update.afterNode)
+            getNodeAfter(parentNode, update.afterNode),
           );
+          if (__DEV__) {
+            ReactInstrumentation.debugTool.onHostOperation({
+              instanceID: parentNodeDebugID,
+              type: 'insert child',
+              payload: {
+                toIndex: update.toIndex,
+                content: update.content.toString(),
+              },
+            });
+          }
           break;
-        case ReactMultiChildUpdateTypes.MOVE_EXISTING:
+        case 'MOVE_EXISTING':
           moveChild(
             parentNode,
             update.fromNode,
-            getNodeAfter(parentNode, update.afterNode)
+            getNodeAfter(parentNode, update.afterNode),
           );
+          if (__DEV__) {
+            ReactInstrumentation.debugTool.onHostOperation({
+              instanceID: parentNodeDebugID,
+              type: 'move child',
+              payload: {fromIndex: update.fromIndex, toIndex: update.toIndex},
+            });
+          }
           break;
-        case ReactMultiChildUpdateTypes.SET_MARKUP:
-          setInnerHTML(
-            parentNode,
-            update.content
-          );
+        case 'SET_MARKUP':
+          setInnerHTML(parentNode, update.content);
+          if (__DEV__) {
+            ReactInstrumentation.debugTool.onHostOperation({
+              instanceID: parentNodeDebugID,
+              type: 'replace children',
+              payload: update.content.toString(),
+            });
+          }
           break;
-        case ReactMultiChildUpdateTypes.TEXT_CONTENT:
-          setTextContent(
-            parentNode,
-            update.content
-          );
+        case 'TEXT_CONTENT':
+          setTextContent(parentNode, update.content);
+          if (__DEV__) {
+            ReactInstrumentation.debugTool.onHostOperation({
+              instanceID: parentNodeDebugID,
+              type: 'replace text',
+              payload: update.content.toString(),
+            });
+          }
           break;
-        case ReactMultiChildUpdateTypes.REMOVE_NODE:
+        case 'REMOVE_NODE':
           removeChild(parentNode, update.fromNode);
+          if (__DEV__) {
+            ReactInstrumentation.debugTool.onHostOperation({
+              instanceID: parentNodeDebugID,
+              type: 'remove child',
+              payload: {fromIndex: update.fromIndex},
+            });
+          }
           break;
       }
     }
   },
-
 };
 
-ReactPerf.measureMethods(DOMChildrenOperations, 'DOMChildrenOperations', {
-  replaceDelimitedText: 'replaceDelimitedText',
-});
-
 module.exports = DOMChildrenOperations;
diff --git a/src/renderers/dom/client/utils/DOMLazyTree.js b/src/renderers/dom/client/utils/DOMLazyTree.js
index 249eb475c5c4..b9401c28b80d 100644
--- a/src/renderers/dom/client/utils/DOMLazyTree.js
+++ b/src/renderers/dom/client/utils/DOMLazyTree.js
@@ -11,9 +11,15 @@
 
 'use strict';
 
+var DOMNamespaces = require('DOMNamespaces');
+var setInnerHTML = require('setInnerHTML');
+
 var createMicrosoftUnsafeLocalFunction = require('createMicrosoftUnsafeLocalFunction');
 var setTextContent = require('setTextContent');
 
+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
@@ -25,14 +31,12 @@ var setTextContent = require('setTextContent');
  *
  * 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)
-);
+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) {
@@ -45,27 +49,37 @@ function insertTreeChildren(tree) {
       insertTreeBefore(node, children[i], null);
     }
   } else if (tree.html != null) {
-    node.innerHTML = tree.html;
+    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.
-    if (tree.node.nodeType === 11) {
-      insertTreeChildren(tree);
-      parentNode.insertBefore(tree.node, referenceNode);
-    } else {
-      parentNode.insertBefore(tree.node, referenceNode);
-      insertTreeChildren(tree);
-    }
+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);
@@ -84,7 +98,7 @@ function queueHTML(tree, html) {
   if (enableLazy) {
     tree.html = html;
   } else {
-    tree.node.innerHTML = html;
+    setInnerHTML(tree.node, html);
   }
 }
 
@@ -96,12 +110,17 @@ function queueText(tree, text) {
   }
 }
 
+function toString() {
+  return this.node.nodeName;
+}
+
 function DOMLazyTree(node) {
   return {
     node: node,
     children: [],
     html: null,
     text: null,
+    toString,
   };
 }
 
diff --git a/src/renderers/dom/client/utils/ViewportMetrics.js b/src/renderers/dom/client/utils/ViewportMetrics.js
index d5508e0019cc..c23d0275c3fe 100644
--- a/src/renderers/dom/client/utils/ViewportMetrics.js
+++ b/src/renderers/dom/client/utils/ViewportMetrics.js
@@ -12,7 +12,6 @@
 'use strict';
 
 var ViewportMetrics = {
-
   currentScrollLeft: 0,
 
   currentScrollTop: 0,
@@ -21,7 +20,6 @@ var ViewportMetrics = {
     ViewportMetrics.currentScrollLeft = scrollPosition.x;
     ViewportMetrics.currentScrollTop = scrollPosition.y;
   },
-
 };
 
 module.exports = ViewportMetrics;
diff --git a/src/renderers/dom/client/utils/__tests__/getEventCharCode-test.js b/src/renderers/dom/client/utils/__tests__/getEventCharCode-test.js
index c375ffa15b20..f619093b8b47 100644
--- a/src/renderers/dom/client/utils/__tests__/getEventCharCode-test.js
+++ b/src/renderers/dom/client/utils/__tests__/getEventCharCode-test.js
@@ -13,38 +13,39 @@
 
 var getEventCharCode = require('getEventCharCode');
 
-describe('getEventCharCode', function() {
-  describe('when charCode is present in nativeEvent', function() {
-    describe('when charCode is 0 and keyCode is 13', function() {
-      it('returns 13', function() {
-        var nativeEvent = new KeyboardEvent(
-          'keypress', {charCode: 0, keyCode: 13}
-        );
+describe('getEventCharCode', () => {
+  describe('when charCode is present in nativeEvent', () => {
+    describe('when charCode is 0 and keyCode is 13', () => {
+      it('returns 13', () => {
+        var nativeEvent = new KeyboardEvent('keypress', {
+          charCode: 0,
+          keyCode: 13,
+        });
 
         expect(getEventCharCode(nativeEvent)).toBe(13);
       });
     });
 
-    describe('when charCode is not 0 and/or keyCode is not 13', function() {
-      describe('when charCode is 32 or bigger', function() {
-        it('returns charCode', function() {
+    describe('when charCode is not 0 and/or keyCode is not 13', () => {
+      describe('when charCode is 32 or bigger', () => {
+        it('returns charCode', () => {
           var nativeEvent = new KeyboardEvent('keypress', {charCode: 32});
 
           expect(getEventCharCode(nativeEvent)).toBe(32);
         });
       });
 
-      describe('when charCode is smaller than 32', function() {
-        describe('when charCode is 13', function() {
-          it('returns 13', function() {
+      describe('when charCode is smaller than 32', () => {
+        describe('when charCode is 13', () => {
+          it('returns 13', () => {
             var nativeEvent = new KeyboardEvent('keypress', {charCode: 13});
 
             expect(getEventCharCode(nativeEvent)).toBe(13);
           });
         });
 
-        describe('when charCode is not 13', function() {
-          it('returns 0', function() {
+        describe('when charCode is not 13', () => {
+          it('returns 0', () => {
             var nativeEvent = new KeyboardEvent('keypress', {charCode: 31});
 
             expect(getEventCharCode(nativeEvent)).toBe(0);
@@ -59,27 +60,27 @@ describe('getEventCharCode', function() {
     KeyboardEvent's 'charCode' event key cannot be deleted to simulate a missing
     charCode key.
   */
-  describe('when charCode is not present in nativeEvent', function() {
-    describe('when keyCode is 32 or bigger', function() {
-      it('returns keyCode', function() {
-        var nativeEvent = {'keyCode': 32};
+  describe('when charCode is not present in nativeEvent', () => {
+    describe('when keyCode is 32 or bigger', () => {
+      it('returns keyCode', () => {
+        var nativeEvent = {keyCode: 32};
 
         expect(getEventCharCode(nativeEvent)).toBe(32);
       });
     });
 
-    describe('when keyCode is smaller than 32', function() {
-      describe('when keyCode is 13', function() {
-        it('returns 13', function() {
-          var nativeEvent = {'keyCode': 13};
+    describe('when keyCode is smaller than 32', () => {
+      describe('when keyCode is 13', () => {
+        it('returns 13', () => {
+          var nativeEvent = {keyCode: 13};
 
           expect(getEventCharCode(nativeEvent)).toBe(13);
         });
       });
 
-      describe('when keyCode is not 13', function() {
-        it('returns 0', function() {
-          var nativeEvent = {'keyCode': 31};
+      describe('when keyCode is not 13', () => {
+        it('returns 0', () => {
+          var nativeEvent = {keyCode: 31};
 
           expect(getEventCharCode(nativeEvent)).toBe(0);
         });
diff --git a/src/renderers/dom/client/utils/__tests__/getEventKey-test.js b/src/renderers/dom/client/utils/__tests__/getEventKey-test.js
index 09644c6e503f..81b370255d15 100644
--- a/src/renderers/dom/client/utils/__tests__/getEventKey-test.js
+++ b/src/renderers/dom/client/utils/__tests__/getEventKey-test.js
@@ -13,18 +13,18 @@
 
 var getEventKey = require('getEventKey');
 
-describe('getEventKey', function() {
-  describe('when key is implemented in a browser', function() {
-    describe('when key is not normalized', function() {
-      it('returns a normalized value', function() {
+describe('getEventKey', () => {
+  describe('when key is implemented in a browser', () => {
+    describe('when key is not normalized', () => {
+      it('returns a normalized value', () => {
         var nativeEvent = new KeyboardEvent('keypress', {key: 'Del'});
 
         expect(getEventKey(nativeEvent)).toBe('Delete');
       });
     });
 
-    describe('when key is normalized', function() {
-      it('returns a key', function() {
+    describe('when key is normalized', () => {
+      it('returns a key', () => {
         var nativeEvent = new KeyboardEvent('keypress', {key: 'f'});
 
         expect(getEventKey(nativeEvent)).toBe('f');
@@ -32,18 +32,18 @@ describe('getEventKey', function() {
     });
   });
 
-  describe('when key is not implemented in a browser', function() {
-    describe('when event type is keypress', function() {
-      describe('when charCode is 13', function() {
-        it("returns 'Enter'", function() {
+  describe('when key is not implemented in a browser', () => {
+    describe('when event type is keypress', () => {
+      describe('when charCode is 13', () => {
+        it("returns 'Enter'", () => {
           var nativeEvent = new KeyboardEvent('keypress', {charCode: 13});
 
           expect(getEventKey(nativeEvent)).toBe('Enter');
         });
       });
 
-      describe('when charCode is not 13', function() {
-        it('returns a string from a charCode', function() {
+      describe('when charCode is not 13', () => {
+        it('returns a string from a charCode', () => {
           var nativeEvent = new KeyboardEvent('keypress', {charCode: 65});
 
           expect(getEventKey(nativeEvent)).toBe('A');
@@ -51,17 +51,17 @@ describe('getEventKey', function() {
       });
     });
 
-    describe('when event type is keydown or keyup', function() {
-      describe('when keyCode is recognized', function() {
-        it('returns a translated key', function() {
+    describe('when event type is keydown or keyup', () => {
+      describe('when keyCode is recognized', () => {
+        it('returns a translated key', () => {
           var nativeEvent = new KeyboardEvent('keydown', {keyCode: 45});
 
           expect(getEventKey(nativeEvent)).toBe('Insert');
         });
       });
 
-      describe('when keyCode is not recognized', function() {
-        it('returns Unidentified', function() {
+      describe('when keyCode is not recognized', () => {
+        it('returns Unidentified', () => {
           var nativeEvent = new KeyboardEvent('keydown', {keyCode: 1337});
 
           expect(getEventKey(nativeEvent)).toBe('Unidentified');
@@ -69,8 +69,8 @@ describe('getEventKey', function() {
       });
     });
 
-    describe('when event type is unknown', function() {
-      it('returns an empty string', function() {
+    describe('when event type is unknown', () => {
+      it('returns an empty string', () => {
         var nativeEvent = new KeyboardEvent('keysmack');
 
         expect(getEventKey(nativeEvent)).toBe('');
diff --git a/src/renderers/dom/client/utils/__tests__/getNodeForCharacterOffset-test.js b/src/renderers/dom/client/utils/__tests__/getNodeForCharacterOffset-test.js
index d0f9a5501f8b..27c7d1cd2db4 100644
--- a/src/renderers/dom/client/utils/__tests__/getNodeForCharacterOffset-test.js
+++ b/src/renderers/dom/client/utils/__tests__/getNodeForCharacterOffset-test.js
@@ -28,36 +28,36 @@ function expectNodeOffset(result, textContent, nodeOffset) {
   expect(result.offset).toBe(nodeOffset);
 }
 
-describe('getNodeForCharacterOffset', function() {
-  it('should handle siblings', function() {
+describe('getNodeForCharacterOffset', () => {
+  it('should handle siblings', () => {
     var node = createNode('<i>123</i><i>456</i><i>789</i>');
 
     expectNodeOffset(getNodeForCharacterOffset(node, 0), '123', 0);
     expectNodeOffset(getNodeForCharacterOffset(node, 4), '456', 1);
   });
 
-  it('should handle trailing chars', function() {
+  it('should handle trailing chars', () => {
     var node = createNode('<i>123</i><i>456</i><i>789</i>');
 
     expectNodeOffset(getNodeForCharacterOffset(node, 3), '123', 3);
     expectNodeOffset(getNodeForCharacterOffset(node, 9), '789', 3);
   });
 
-  it('should handle trees', function() {
+  it('should handle trees', () => {
     var node = createNode(
       '<i>' +
         '<i>1</i>' +
         '<i>' +
-          '<i>' +
-            '<i>2</i>' +
-            '<i></i>' +
-          '</i>' +
+        '<i>' +
+        '<i>2</i>' +
+        '<i></i>' +
+        '</i>' +
         '</i>' +
         '<i>' +
-          '3' +
-          '<i>45</i>' +
+        '3' +
+        '<i>45</i>' +
         '</i>' +
-      '</i>'
+        '</i>',
     );
 
     expectNodeOffset(getNodeForCharacterOffset(node, 3), '3', 1);
@@ -65,7 +65,7 @@ describe('getNodeForCharacterOffset', function() {
     expect(getNodeForCharacterOffset(node, 10)).toBeUndefined();
   });
 
-  it('should handle non-existent offset', function() {
+  it('should handle non-existent offset', () => {
     var node = createNode('<i>123</i>');
 
     expect(getNodeForCharacterOffset(node, -1)).toBeUndefined();
diff --git a/src/renderers/dom/client/utils/__tests__/setInnerHTML-test.js b/src/renderers/dom/client/utils/__tests__/setInnerHTML-test.js
new file mode 100644
index 000000000000..e89f9f142b3e
--- /dev/null
+++ b/src/renderers/dom/client/utils/__tests__/setInnerHTML-test.js
@@ -0,0 +1,48 @@
+/**
+ * Copyright 2016-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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var setInnerHTML = require('setInnerHTML');
+var DOMNamespaces = require('DOMNamespaces');
+
+describe('setInnerHTML', () => {
+  describe('when the node has innerHTML property', () => {
+    it('sets innerHTML on it', () => {
+      var node = document.createElement('div');
+      var html = '<h1>hello</h1>';
+      setInnerHTML(node, html);
+      expect(node.innerHTML).toBe(html);
+    });
+  });
+
+  describe('when the node does not have an innerHTML property', () => {
+    // Disabled. JSDOM doesn't seem to remove nodes when using appendChild to
+    // move existing nodes.
+    xit('sets innerHTML on it', () => {
+      // Create a mock node that looks like an SVG in IE (without innerHTML)
+      var node = {
+        namespaceURI: DOMNamespaces.svg,
+        appendChild: jasmine.createSpy(),
+      };
+
+      var html = '<circle></circle><rect></rect>';
+      setInnerHTML(node, html);
+
+      expect(node.appendChild.calls.argsFor(0)[0].outerHTML).toBe(
+        '<circle></circle>',
+      );
+      expect(node.appendChild.calls.argsFor(1)[0].outerHTML).toBe(
+        '<rect></rect>',
+      );
+    });
+  });
+});
diff --git a/src/renderers/dom/client/utils/getEventKey.js b/src/renderers/dom/client/utils/getEventKey.js
index 6a33da9caafb..19786e778ddd 100644
--- a/src/renderers/dom/client/utils/getEventKey.js
+++ b/src/renderers/dom/client/utils/getEventKey.js
@@ -18,18 +18,18 @@ var getEventCharCode = require('getEventCharCode');
  * @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',
+  Esc: 'Escape',
+  Spacebar: ' ',
+  Left: 'ArrowLeft',
+  Up: 'ArrowUp',
+  Right: 'ArrowRight',
+  Down: 'ArrowDown',
+  Del: 'Delete',
+  Win: 'OS',
+  Menu: 'ContextMenu',
+  Apps: 'ContextMenu',
+  Scroll: 'ScrollLock',
+  MozPrintableKey: 'Unidentified',
 };
 
 /**
@@ -59,8 +59,18 @@ var translateToKey = {
   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',
+  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',
diff --git a/src/renderers/dom/client/utils/getEventModifierState.js b/src/renderers/dom/client/utils/getEventModifierState.js
index 16c6e2b545e6..cafcf69e4b50 100644
--- a/src/renderers/dom/client/utils/getEventModifierState.js
+++ b/src/renderers/dom/client/utils/getEventModifierState.js
@@ -17,10 +17,10 @@
  */
 
 var modifierKeyToProp = {
-  'Alt': 'altKey',
-  'Control': 'ctrlKey',
-  'Meta': 'metaKey',
-  'Shift': 'shiftKey',
+  Alt: 'altKey',
+  Control: 'ctrlKey',
+  Meta: 'metaKey',
+  Shift: 'shiftKey',
 };
 
 // IE8 does not implement getModifierState so we simply map it to the only
diff --git a/src/renderers/dom/client/utils/getTextContentAccessor.js b/src/renderers/dom/client/utils/getTextContentAccessor.js
index 198e6bbb6ad6..7f79f013abd1 100644
--- a/src/renderers/dom/client/utils/getTextContentAccessor.js
+++ b/src/renderers/dom/client/utils/getTextContentAccessor.js
@@ -25,9 +25,9 @@ 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';
+    contentKey = 'textContent' in document.documentElement
+      ? 'textContent'
+      : 'innerText';
   }
   return contentKey;
 }
diff --git a/src/renderers/dom/client/utils/getVendorPrefixedEventName.js b/src/renderers/dom/client/utils/getVendorPrefixedEventName.js
index 25fa2aed8a5f..dc3f518de8ac 100644
--- a/src/renderers/dom/client/utils/getVendorPrefixedEventName.js
+++ b/src/renderers/dom/client/utils/getVendorPrefixedEventName.js
@@ -83,7 +83,6 @@ if (ExecutionEnvironment.canUseDOM) {
 function getVendorPrefixedEventName(eventName) {
   if (prefixedEventNames[eventName]) {
     return prefixedEventNames[eventName];
-
   } else if (!vendorPrefixes[eventName]) {
     return eventName;
   }
@@ -92,7 +91,7 @@ function getVendorPrefixedEventName(eventName) {
 
   for (var styleProp in prefixMap) {
     if (prefixMap.hasOwnProperty(styleProp) && styleProp in style) {
-      return prefixedEventNames[eventName] = prefixMap[styleProp];
+      return (prefixedEventNames[eventName] = prefixMap[styleProp]);
     }
   }
 
diff --git a/src/renderers/dom/client/utils/isEventSupported.js b/src/renderers/dom/client/utils/isEventSupported.js
index f73857641154..ad3436a65fa2 100644
--- a/src/renderers/dom/client/utils/isEventSupported.js
+++ b/src/renderers/dom/client/utils/isEventSupported.js
@@ -38,8 +38,10 @@ if (ExecutionEnvironment.canUseDOM) {
  * @license Modernizr 3.0.0pre (Custom Build) | MIT
  */
 function isEventSupported(eventNameSuffix, capture) {
-  if (!ExecutionEnvironment.canUseDOM ||
-      capture && !('addEventListener' in document)) {
+  if (
+    !ExecutionEnvironment.canUseDOM ||
+    (capture && !('addEventListener' in document))
+  ) {
     return false;
   }
 
diff --git a/src/renderers/dom/client/utils/setInnerHTML.js b/src/renderers/dom/client/utils/setInnerHTML.js
index 1e491bfaf382..c4da196e62b5 100644
--- a/src/renderers/dom/client/utils/setInnerHTML.js
+++ b/src/renderers/dom/client/utils/setInnerHTML.js
@@ -12,12 +12,16 @@
 'use strict';
 
 var ExecutionEnvironment = require('ExecutionEnvironment');
+var DOMNamespaces = require('DOMNamespaces');
 
 var WHITESPACE_TEST = /^[ \r\n\t\f]/;
 var NONVISIBLE_TEST = /<(!--|link|noscript|meta|script|style)[ \r\n\t\f\/>]/;
 
 var createMicrosoftUnsafeLocalFunction = require('createMicrosoftUnsafeLocalFunction');
 
+// SVG temp container for IE lacking innerHTML
+var reusableSVGContainer;
+
 /**
  * Set the innerHTML property of a node, ensuring that whitespace is preserved
  * even in IE8.
@@ -26,11 +30,22 @@ var createMicrosoftUnsafeLocalFunction = require('createMicrosoftUnsafeLocalFunc
  * @param {string} html
  * @internal
  */
-var setInnerHTML = createMicrosoftUnsafeLocalFunction(
-  function(node, html) {
+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
@@ -56,15 +71,17 @@ if (ExecutionEnvironment.canUseDOM) {
       // 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)) {
+      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;
+        node.innerHTML = String.fromCharCode(0xfeff) + html;
 
         // deleteData leaves an empty `TextNode` which offsets the index of all
         // children. Definitely want to avoid this.
diff --git a/src/renderers/dom/client/utils/setTextContent.js b/src/renderers/dom/client/utils/setTextContent.js
index d15ce89eac9f..833256601dc9 100644
--- a/src/renderers/dom/client/utils/setTextContent.js
+++ b/src/renderers/dom/client/utils/setTextContent.js
@@ -26,12 +26,28 @@ var setInnerHTML = require('setInnerHTML');
  * @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));
     };
   }
diff --git a/src/renderers/dom/client/validateDOMNesting.js b/src/renderers/dom/client/validateDOMNesting.js
index 431d80fd2d5d..9cca776e8e8d 100644
--- a/src/renderers/dom/client/validateDOMNesting.js
+++ b/src/renderers/dom/client/validateDOMNesting.js
@@ -30,36 +30,125 @@ if (__DEV__) {
 
   // 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',
+    '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',
+    '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',
+    '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 impliedEndTags = [
+    'dd',
+    'dt',
+    'li',
+    'option',
+    'optgroup',
+    'p',
+    'rp',
+    'rt',
+  ];
 
   var emptyAncestorInfo = {
     current: null,
@@ -91,7 +180,9 @@ if (__DEV__) {
     // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inbody
     if (
       specialTags.indexOf(tag) !== -1 &&
-      tag !== 'address' && tag !== 'div' && tag !== 'p'
+      tag !== 'address' &&
+      tag !== 'div' &&
+      tag !== 'p'
     ) {
       ancestorInfo.listItemTagAutoclosing = null;
       ancestorInfo.dlItemTagAutoclosing = null;
@@ -139,7 +230,6 @@ if (__DEV__) {
       // 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
@@ -148,40 +238,52 @@ if (__DEV__) {
       // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intr
       case 'tr':
         return (
-          tag === 'th' || tag === 'td' || tag === 'style' || tag === 'script' ||
+          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 === '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'
+          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'
+          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';
@@ -200,14 +302,19 @@ if (__DEV__) {
       case 'h5':
       case 'h6':
         return (
-          parentTag !== 'h1' && parentTag !== 'h2' && parentTag !== 'h3' &&
-          parentTag !== 'h4' && parentTag !== 'h5' && parentTag !== 'h6'
+          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':
@@ -259,16 +366,11 @@ if (__DEV__) {
       case 'section':
       case 'summary':
       case 'ul':
-
       case 'pre':
       case 'listing':
-
       case 'table':
-
       case 'hr':
-
       case 'xmp':
-
       case 'h1':
       case 'h2':
       case 'h3':
@@ -321,15 +423,30 @@ if (__DEV__) {
 
   var didWarn = {};
 
-  validateDOMNesting = function(childTag, childInstance, ancestorInfo) {
+  validateDOMNesting = function(
+    childTag,
+    childText,
+    childInstance,
+    ancestorInfo,
+  ) {
     ancestorInfo = ancestorInfo || emptyAncestorInfo;
     var parentInfo = ancestorInfo.current;
     var parentTag = parentInfo && parentInfo.tag;
 
-    var invalidParent =
-      isTagValidWithParent(childTag, parentTag) ? null : parentInfo;
-    var invalidAncestor =
-      invalidParent ? null : findInvalidAncestorForTag(childTag, ancestorInfo);
+    if (childText != null) {
+      warning(
+        childTag == null,
+        'validateDOMNesting: when childText is passed, childTag should be null',
+      );
+      childTag = '#text';
+    }
+
+    var invalidParent = isTagValidWithParent(childTag, parentTag)
+      ? null
+      : parentInfo;
+    var invalidAncestor = invalidParent
+      ? null
+      : findInvalidAncestorForTag(childTag, ancestorInfo);
     var problematic = invalidParent || invalidAncestor;
 
     if (problematic) {
@@ -356,25 +473,27 @@ if (__DEV__) {
       }
 
       var UNKNOWN = '(unknown)';
-      var childOwnerNames = childOwners.slice(deepestCommon + 1).map(
-        (inst) => inst.getName() || UNKNOWN
-      );
-      var ancestorOwnerNames = ancestorOwners.slice(deepestCommon + 1).map(
-        (inst) => 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 childOwnerNames = childOwners
+        .slice(deepestCommon + 1)
+        .map(inst => inst.getName() || UNKNOWN);
+      var ancestorOwnerNames = ancestorOwners
+        .slice(deepestCommon + 1)
+        .map(inst => 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;
@@ -384,7 +503,17 @@ if (__DEV__) {
       didWarn[warnKey] = true;
 
       var tagDisplayName = childTag;
-      if (childTag !== '#text') {
+      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 + '>';
       }
 
@@ -397,21 +526,22 @@ if (__DEV__) {
         }
         warning(
           false,
-          'validateDOMNesting(...): %s cannot appear as a child of <%s>. ' +
-          'See %s.%s',
+          'validateDOMNesting(...): %s cannot appear as a child of <%s>.%s ' +
+            'See %s.%s',
           tagDisplayName,
           ancestorTag,
+          whitespaceInfo,
           ownerInfo,
-          info
+          info,
         );
       } else {
         warning(
           false,
           'validateDOMNesting(...): %s cannot appear as a descendant of ' +
-          '<%s>. See %s.',
+            '<%s>. See %s.',
           tagDisplayName,
           ancestorTag,
-          ownerInfo
+          ownerInfo,
         );
       }
     }
diff --git a/src/renderers/dom/client/wrappers/LinkedValueUtils.js b/src/renderers/dom/client/wrappers/LinkedValueUtils.js
index ae3afb98d234..00e0af6f70d7 100644
--- a/src/renderers/dom/client/wrappers/LinkedValueUtils.js
+++ b/src/renderers/dom/client/wrappers/LinkedValueUtils.js
@@ -11,27 +11,30 @@
 
 'use strict';
 
-var ReactPropTypes = require('ReactPropTypes');
-var ReactPropTypeLocations = require('ReactPropTypeLocations');
+var ReactPropTypesSecret = require('ReactPropTypesSecret');
+var propTypesFactory = require('prop-types/factory');
+
+var React = require('React');
+var PropTypes = propTypesFactory(React.isValidElement);
 
 var invariant = require('invariant');
 var warning = require('warning');
 
 var hasReadOnlyValue = {
-  'button': true,
-  'checkbox': true,
-  'image': true,
-  'hidden': true,
-  'radio': true,
-  'reset': true,
-  'submit': true,
+  button: true,
+  checkbox: true,
+  image: true,
+  hidden: true,
+  radio: true,
+  reset: true,
+  submit: true,
 };
 
 function _assertSingleLink(inputProps) {
   invariant(
     inputProps.checkedLink == null || inputProps.valueLink == null,
     'Cannot provide a checkedLink and a valueLink. If you want to use ' +
-    'checkedLink, you probably don\'t want to use valueLink and vice versa.'
+      "checkedLink, you probably don't want to use valueLink and vice versa.",
   );
 }
 function _assertValueLink(inputProps) {
@@ -39,7 +42,7 @@ function _assertValueLink(inputProps) {
   invariant(
     inputProps.value == null && inputProps.onChange == null,
     '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.'
+      "to use value or onChange, you probably don't want to use valueLink.",
   );
 }
 
@@ -48,42 +51,46 @@ function _assertCheckedLink(inputProps) {
   invariant(
     inputProps.checked == null && inputProps.onChange == null,
     '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'
+      "If you want to use checked or onChange, you probably don't want to " +
+      'use checkedLink',
   );
 }
 
 var propTypes = {
   value: function(props, propName, componentName) {
-    if (!props[propName] ||
-        hasReadOnlyValue[props.type] ||
-        props.onChange ||
-        props.readOnly ||
-        props.disabled) {
+    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`.'
+        '`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) {
+    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` handler. This will render a read-only field. If ' +
+        'the field should be mutable use `defaultChecked`. Otherwise, ' +
+        'set either `onChange` or `readOnly`.',
     );
   },
-  onChange: ReactPropTypes.func,
+  onChange: PropTypes.func,
 };
 
 var loggedTypeFailures = {};
@@ -109,7 +116,9 @@ var LinkedValueUtils = {
           props,
           propName,
           tagName,
-          ReactPropTypeLocations.prop
+          'prop',
+          null,
+          ReactPropTypesSecret,
         );
       }
       if (error instanceof Error && !(error.message in loggedTypeFailures)) {
diff --git a/src/renderers/dom/client/wrappers/ReactDOMButton.js b/src/renderers/dom/client/wrappers/ReactDOMButton.js
deleted file mode 100644
index bf32c4560052..000000000000
--- a/src/renderers/dom/client/wrappers/ReactDOMButton.js
+++ /dev/null
@@ -1,50 +0,0 @@
-/**
- * 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 ReactDOMButton
- */
-
-'use strict';
-
-var mouseListenerNames = {
-  onClick: true,
-  onDoubleClick: true,
-  onMouseDown: true,
-  onMouseMove: true,
-  onMouseUp: true,
-
-  onClickCapture: true,
-  onDoubleClickCapture: true,
-  onMouseDownCapture: true,
-  onMouseMoveCapture: true,
-  onMouseUpCapture: true,
-};
-
-/**
- * Implements a <button> native component that does not receive mouse events
- * when `disabled` is set.
- */
-var ReactDOMButton = {
-  getNativeProps: function(inst, props) {
-    if (!props.disabled) {
-      return props;
-    }
-
-    // Copy the props, except the mouse listeners
-    var nativeProps = {};
-    for (var key in props) {
-      if (props.hasOwnProperty(key) && !mouseListenerNames[key]) {
-        nativeProps[key] = props[key];
-      }
-    }
-
-    return nativeProps;
-  },
-};
-
-module.exports = ReactDOMButton;
diff --git a/src/renderers/dom/client/wrappers/ReactDOMInput.js b/src/renderers/dom/client/wrappers/ReactDOMInput.js
index 234aee1b58f6..73ae197dc2c2 100644
--- a/src/renderers/dom/client/wrappers/ReactDOMInput.js
+++ b/src/renderers/dom/client/wrappers/ReactDOMInput.js
@@ -21,7 +21,6 @@ var warning = require('warning');
 
 var didWarnValueLink = false;
 var didWarnCheckedLink = false;
-var didWarnValueNull = false;
 var didWarnValueDefaultValue = false;
 var didWarnCheckedDefaultChecked = false;
 var didWarnControlledToUncontrolled = false;
@@ -34,21 +33,13 @@ function forceUpdateIfMounted() {
   }
 }
 
-function warnIfValueIsNull(props) {
-  if (props != null && props.value === null && !didWarnValueNull) {
-    warning(
-      false,
-      '`value` prop on `input` should not be null. ' +
-      'Consider using the empty string to clear the component or `undefined` ' +
-      'for uncontrolled components.'
-    );
-
-    didWarnValueNull = true;
-  }
+function isControlled(props) {
+  var usesChecked = props.type === 'checkbox' || props.type === 'radio';
+  return usesChecked ? props.checked != null : props.value != null;
 }
 
 /**
- * Implements an <input> native component that allows setting these optional
+ * 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
@@ -64,23 +55,34 @@ function warnIfValueIsNull(props) {
  * @see http://www.w3.org/TR/2012/WD-html5-20121025/the-input-element.html
  */
 var ReactDOMInput = {
-  getNativeProps: function(inst, props) {
+  getHostProps: function(inst, props) {
     var value = LinkedValueUtils.getValue(props);
     var checked = LinkedValueUtils.getChecked(props);
 
-    var nativeProps = Object.assign({
-      // Make sure we set .type before any other properties (setting .value
-      // before .type means .value is lost in IE11 and below)
-      type: 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 nativeProps;
+    var hostProps = Object.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) {
@@ -88,20 +90,22 @@ var ReactDOMInput = {
       LinkedValueUtils.checkPropTypes(
         'input',
         props,
-        inst._currentElement._owner
+        inst._currentElement._owner,
       );
 
+      var owner = inst._currentElement._owner;
+
       if (props.valueLink !== undefined && !didWarnValueLink) {
         warning(
           false,
-          '`valueLink` prop on `input` is deprecated; set `value` and `onChange` instead.'
+          '`valueLink` prop on `input` is deprecated; set `value` and `onChange` instead.',
         );
         didWarnValueLink = true;
       }
       if (props.checkedLink !== undefined && !didWarnCheckedLink) {
         warning(
           false,
-          '`checkedLink` prop on `input` is deprecated; set `value` and `onChange` instead.'
+          '`checkedLink` prop on `input` is deprecated; set `value` and `onChange` instead.',
         );
         didWarnCheckedLink = true;
       }
@@ -112,11 +116,14 @@ var ReactDOMInput = {
       ) {
         warning(
           false,
-          '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'
+          '%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,
         );
         didWarnCheckedDefaultChecked = true;
       }
@@ -127,69 +134,67 @@ var ReactDOMInput = {
       ) {
         warning(
           false,
-          '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'
+          '%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,
         );
         didWarnValueDefaultValue = true;
       }
-      warnIfValueIsNull(props);
     }
 
     var defaultValue = props.defaultValue;
     inst._wrapperState = {
-      initialChecked: props.defaultChecked || false,
-      initialValue: defaultValue != null ? defaultValue : null,
+      initialChecked: props.checked != null
+        ? props.checked
+        : props.defaultChecked,
+      initialValue: props.value != null ? props.value : defaultValue,
       listeners: null,
       onChange: _handleChange.bind(inst),
+      controlled: isControlled(props),
     };
-
-    if (__DEV__) {
-      inst._wrapperState.controlled = props.checked !== undefined || props.value !== undefined;
-    }
   },
 
   updateWrapper: function(inst) {
     var props = inst._currentElement.props;
 
     if (__DEV__) {
-      warnIfValueIsNull(props);
-
-      var initialValue = inst._wrapperState.initialChecked || inst._wrapperState.initialValue;
-      var defaultValue = props.defaultChecked || props.defaultValue;
-      var controlled = props.checked !== undefined || props.value !== undefined;
+      var controlled = isControlled(props);
       var owner = inst._currentElement._owner;
 
       if (
-        (initialValue || !inst._wrapperState.controlled) &&
-        controlled && !didWarnUncontrolledToControlled
+        !inst._wrapperState.controlled &&
+        controlled &&
+        !didWarnUncontrolledToControlled
       ) {
         warning(
           false,
-          '%s is changing a 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
+          '%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,
         );
         didWarnUncontrolledToControlled = true;
       }
       if (
         inst._wrapperState.controlled &&
-        (defaultValue || !controlled) &&
+        !controlled &&
         !didWarnControlledToUncontrolled
       ) {
         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
+            '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,
         );
         didWarnControlledToUncontrolled = true;
       }
@@ -201,19 +206,102 @@ var ReactDOMInput = {
       DOMPropertyOperations.setValueForProperty(
         ReactDOMComponentTree.getNodeFromInstance(inst),
         'checked',
-        checked || false
+        checked || false,
       );
     }
 
+    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.
-      DOMPropertyOperations.setValueForProperty(
-        ReactDOMComponentTree.getNodeFromInstance(inst),
-        'value',
-        '' + value
-      );
+      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;
     }
   },
 };
@@ -244,12 +332,12 @@ function _handleChange(event) {
     // 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"]');
+      '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) {
+      if (otherNode === rootNode || otherNode.form !== rootNode.form) {
         continue;
       }
       // This will throw if radio buttons rendered by different copies of React
@@ -260,7 +348,7 @@ function _handleChange(event) {
       invariant(
         otherInstance,
         'ReactDOMInput: Mixing React and non-React radio inputs with the ' +
-        'same `name` is not supported.'
+          'same `name` is not supported.',
       );
       // 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
diff --git a/src/renderers/dom/client/wrappers/ReactDOMOption.js b/src/renderers/dom/client/wrappers/ReactDOMOption.js
index 917ed0ee4a16..d8f48d4049f4 100644
--- a/src/renderers/dom/client/wrappers/ReactDOMOption.js
+++ b/src/renderers/dom/client/wrappers/ReactDOMOption.js
@@ -11,86 +11,120 @@
 
 'use strict';
 
-var ReactChildren = require('ReactChildren');
+var React = require('React');
+var ReactDOMComponentTree = require('ReactDOMComponentTree');
 var ReactDOMSelect = require('ReactDOMSelect');
 
 var warning = require('warning');
+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;
+      warning(
+        false,
+        'Only strings and numbers are supported as <option> children.',
+      );
+    }
+  });
+
+  return content;
+}
 
 /**
- * Implements an <option> native component that warns when `selected` is set.
+ * Implements an <option> host component that warns when `selected` is set.
  */
 var ReactDOMOption = {
-  mountWrapper: function(inst, props, nativeParent) {
+  mountWrapper: function(inst, props, hostParent) {
     // TODO (yungsters): Remove support for `selected` in <option>.
     if (__DEV__) {
       warning(
         props.selected == null,
         'Use the `defaultValue` or `value` props on <select> instead of ' +
-        'setting `selected` on <option>.'
+          'setting `selected` on <option>.',
       );
     }
 
     // Look up whether this option is 'selected'
     var selectValue = null;
-    if (nativeParent != null && nativeParent._tag === 'select') {
-      selectValue = ReactDOMSelect.getSelectValueContext(nativeParent);
+    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] === '' + props.value) {
+          if ('' + selectValue[i] === value) {
             selected = true;
             break;
           }
         }
       } else {
-        selected = ('' + selectValue === '' + props.value);
+        selected = '' + selectValue === value;
       }
     }
 
     inst._wrapperState = {selected: selected};
   },
 
-  getNativeProps: function(inst, props) {
-    var nativeProps = Object.assign({selected: undefined, children: undefined}, props);
+  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 = Object.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) {
-      nativeProps.selected = inst._wrapperState.selected;
+      hostProps.selected = inst._wrapperState.selected;
     }
 
-    var content = '';
-
-    // Flatten children and warn if they aren't strings or numbers;
-    // invalid types are ignored.
-    ReactChildren.forEach(props.children, function(child) {
-      if (child == null) {
-        return;
-      }
-      if (typeof child === 'string' || typeof child === 'number') {
-        content += child;
-      } else {
-        warning(
-          false,
-          'Only strings and numbers are supported as <option> children.'
-        );
-      }
-    });
+    var content = flattenChildren(props.children);
 
     if (content) {
-      nativeProps.children = content;
+      hostProps.children = content;
     }
 
-    return nativeProps;
+    return hostProps;
   },
-
 };
 
 module.exports = ReactDOMOption;
diff --git a/src/renderers/dom/client/wrappers/ReactDOMSelect.js b/src/renderers/dom/client/wrappers/ReactDOMSelect.js
index 2247fb6775e1..e0b9f6a89f26 100644
--- a/src/renderers/dom/client/wrappers/ReactDOMSelect.js
+++ b/src/renderers/dom/client/wrappers/ReactDOMSelect.js
@@ -18,7 +18,6 @@ var ReactUpdates = require('ReactUpdates');
 var warning = require('warning');
 
 var didWarnValueLink = false;
-var didWarnValueNull = false;
 var didWarnValueDefaultValue = false;
 
 function updateOptionsIfPendingUpdateAndMounted() {
@@ -44,19 +43,6 @@ function getDeclarationErrorAddendum(owner) {
   return '';
 }
 
-function warnIfValueIsNull(props) {
-  if (props != null && props.value === null && !didWarnValueNull) {
-    warning(
-      false,
-      '`value` prop on `select` should not be null. ' +
-      'Consider using the empty string to clear the component or `undefined` ' +
-      'for uncontrolled components.'
-    );
-
-    didWarnValueNull = true;
-  }
-}
-
 var valuePropNames = ['value', 'defaultValue'];
 
 /**
@@ -65,16 +51,12 @@ var valuePropNames = ['value', 'defaultValue'];
  */
 function checkSelectPropTypes(inst, props) {
   var owner = inst._currentElement._owner;
-  LinkedValueUtils.checkPropTypes(
-    'select',
-    props,
-    owner
-  );
+  LinkedValueUtils.checkPropTypes('select', props, owner);
 
   if (props.valueLink !== undefined && !didWarnValueLink) {
     warning(
       false,
-      '`valueLink` prop on `select` is deprecated; set `value` and `onChange` instead.'
+      '`valueLink` prop on `select` is deprecated; set `value` and `onChange` instead.',
     );
     didWarnValueLink = true;
   }
@@ -84,21 +66,22 @@ function checkSelectPropTypes(inst, props) {
     if (props[propName] == null) {
       continue;
     }
-    if (props.multiple) {
+    var isArray = Array.isArray(props[propName]);
+    if (props.multiple && !isArray) {
       warning(
-        Array.isArray(props[propName]),
+        false,
         'The `%s` prop supplied to <select> must be an array if ' +
-        '`multiple` is true.%s',
+          '`multiple` is true.%s',
         propName,
-        getDeclarationErrorAddendum(owner)
+        getDeclarationErrorAddendum(owner),
       );
-    } else {
+    } else if (!props.multiple && isArray) {
       warning(
-        !Array.isArray(props[propName]),
+        false,
         'The `%s` prop supplied to <select> must be a scalar ' +
-        'value if `multiple` is false.%s',
+          'value if `multiple` is false.%s',
         propName,
-        getDeclarationErrorAddendum(owner)
+        getDeclarationErrorAddendum(owner),
       );
     }
   }
@@ -142,7 +125,7 @@ function updateOptions(inst, multiple, propValue) {
 }
 
 /**
- * Implements a <select> native component that allows optionally setting the
+ * 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.
  *
@@ -157,7 +140,7 @@ function updateOptions(inst, multiple, propValue) {
  * selected.
  */
 var ReactDOMSelect = {
-  getNativeProps: function(inst, props) {
+  getHostProps: function(inst, props) {
     return Object.assign({}, props, {
       onChange: inst._wrapperState.onChange,
       value: undefined,
@@ -167,7 +150,6 @@ var ReactDOMSelect = {
   mountWrapper: function(inst, props) {
     if (__DEV__) {
       checkSelectPropTypes(inst, props);
-      warnIfValueIsNull(props);
     }
 
     var value = LinkedValueUtils.getValue(props);
@@ -187,10 +169,10 @@ var ReactDOMSelect = {
       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'
+          '(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',
       );
       didWarnValueDefaultValue = true;
     }
@@ -204,9 +186,6 @@ var ReactDOMSelect = {
 
   postUpdateWrapper: function(inst) {
     var props = inst._currentElement.props;
-    if (__DEV__) {
-      warnIfValueIsNull(props);
-    }
 
     // After the initial mount, we control selected-ness manually so don't pass
     // this value down
diff --git a/src/renderers/dom/client/wrappers/ReactDOMTextarea.js b/src/renderers/dom/client/wrappers/ReactDOMTextarea.js
index bf5508b7d80a..c528bb3aa726 100644
--- a/src/renderers/dom/client/wrappers/ReactDOMTextarea.js
+++ b/src/renderers/dom/client/wrappers/ReactDOMTextarea.js
@@ -11,7 +11,6 @@
 
 'use strict';
 
-var DOMPropertyOperations = require('DOMPropertyOperations');
 var LinkedValueUtils = require('LinkedValueUtils');
 var ReactDOMComponentTree = require('ReactDOMComponentTree');
 var ReactUpdates = require('ReactUpdates');
@@ -20,7 +19,6 @@ var invariant = require('invariant');
 var warning = require('warning');
 
 var didWarnValueLink = false;
-var didWarnValueNull = false;
 var didWarnValDefaultVal = false;
 
 function forceUpdateIfMounted() {
@@ -30,21 +28,8 @@ function forceUpdateIfMounted() {
   }
 }
 
-function warnIfValueIsNull(props) {
-  if (props != null && props.value === null && !didWarnValueNull) {
-    warning(
-      false,
-      '`value` prop on `textarea` should not be null. ' +
-      'Consider using the empty string to clear the component or `undefined` ' +
-      'for uncontrolled components.'
-    );
-
-    didWarnValueNull = true;
-  }
-}
-
 /**
- * Implements a <textarea> native component that allows setting `value`, and
+ * 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.
  *
@@ -59,22 +44,25 @@ function warnIfValueIsNull(props) {
  * `defaultValue` if specified, or the children content (deprecated).
  */
 var ReactDOMTextarea = {
-  getNativeProps: function(inst, props) {
+  getHostProps: function(inst, props) {
     invariant(
       props.dangerouslySetInnerHTML == null,
-      '`dangerouslySetInnerHTML` does not make sense on <textarea>.'
+      '`dangerouslySetInnerHTML` does not make sense on <textarea>.',
     );
 
     // Always set children to the same thing. In IE9, the selection range will
-    // get reset if `textContent` is mutated.
-    var nativeProps = Object.assign({}, props, {
-      defaultValue: undefined,
+    // 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 = Object.assign({}, props, {
       value: undefined,
-      children: inst._wrapperState.initialValue,
+      defaultValue: undefined,
+      children: '' + inst._wrapperState.initialValue,
       onChange: inst._wrapperState.onChange,
     });
 
-    return nativeProps;
+    return hostProps;
   },
 
   mountWrapper: function(inst, props) {
@@ -82,12 +70,12 @@ var ReactDOMTextarea = {
       LinkedValueUtils.checkPropTypes(
         'textarea',
         props,
-        inst._currentElement._owner
+        inst._currentElement._owner,
       );
       if (props.valueLink !== undefined && !didWarnValueLink) {
         warning(
           false,
-          '`valueLink` prop on `textarea` is deprecated; set `value` and `onChange` instead.'
+          '`valueLink` prop on `textarea` is deprecated; set `value` and `onChange` instead.',
         );
         didWarnValueLink = true;
       }
@@ -99,51 +87,53 @@ var ReactDOMTextarea = {
         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'
+            '(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',
         );
         didWarnValDefaultVal = true;
       }
-      warnIfValueIsNull(props);
     }
 
-    var defaultValue = props.defaultValue;
-    // TODO (yungsters): Remove support for children content in <textarea>.
-    var children = props.children;
-    if (children != null) {
-      if (__DEV__) {
-        warning(
-          false,
-          'Use the `defaultValue` or `value` props instead of setting ' +
-          'children on <textarea>.'
-        );
-      }
-      invariant(
-        defaultValue == null,
-        'If you supply `defaultValue` on a <textarea>, do not pass children.'
-      );
-      if (Array.isArray(children)) {
+    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 (__DEV__) {
+          warning(
+            false,
+            'Use the `defaultValue` or `value` props instead of setting ' +
+              'children on <textarea>.',
+          );
+        }
         invariant(
-          children.length <= 1,
-          '<textarea> can only have at most one child.'
+          defaultValue == null,
+          'If you supply `defaultValue` on a <textarea>, do not pass children.',
         );
-        children = children[0];
+        if (Array.isArray(children)) {
+          invariant(
+            children.length <= 1,
+            '<textarea> can only have at most one child.',
+          );
+          children = children[0];
+        }
+
+        defaultValue = '' + children;
       }
-
-      defaultValue = '' + children;
-    }
-    if (defaultValue == null) {
-      defaultValue = '';
+      if (defaultValue == null) {
+        defaultValue = '';
+      }
+      initialValue = defaultValue;
     }
-    var value = LinkedValueUtils.getValue(props);
+
     inst._wrapperState = {
-      // We save the initial value so that `ReactDOMComponent` doesn't update
-      // `textContent` (unnecessary since we update value).
-      // The initial value can be a boolean or object so that's why it's
-      // forced to be a string.
-      initialValue: '' + (value != null ? value : defaultValue),
+      initialValue: '' + initialValue,
       listeners: null,
       onChange: _handleChange.bind(inst),
     };
@@ -152,19 +142,38 @@ var ReactDOMTextarea = {
   updateWrapper: function(inst) {
     var props = inst._currentElement.props;
 
-    if (__DEV__) {
-      warnIfValueIsNull(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.
-      DOMPropertyOperations.setValueForProperty(
-        ReactDOMComponentTree.getNodeFromInstance(inst),
-        'value',
-        '' + value
-      );
+      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;
     }
   },
 };
diff --git a/src/renderers/dom/client/wrappers/__tests__/ReactDOMButton-test.js b/src/renderers/dom/client/wrappers/__tests__/ReactDOMButton-test.js
deleted file mode 100644
index 5e674be1914d..000000000000
--- a/src/renderers/dom/client/wrappers/__tests__/ReactDOMButton-test.js
+++ /dev/null
@@ -1,93 +0,0 @@
-/**
- * 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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-
-describe('ReactDOMButton', function() {
-  var React;
-  var ReactDOM;
-  var ReactTestUtils;
-
-  var onClick = jest.genMockFn();
-
-  function expectClickThru(button) {
-    onClick.mockClear();
-    ReactTestUtils.Simulate.click(ReactDOM.findDOMNode(button));
-    expect(onClick.mock.calls.length).toBe(1);
-  }
-
-  function expectNoClickThru(button) {
-    onClick.mockClear();
-    ReactTestUtils.Simulate.click(ReactDOM.findDOMNode(button));
-    expect(onClick.mock.calls.length).toBe(0);
-  }
-
-  function mounted(button) {
-    button = ReactTestUtils.renderIntoDocument(button);
-    return button;
-  }
-
-  beforeEach(function() {
-    React = require('React');
-    ReactDOM = require('ReactDOM');
-    ReactTestUtils = require('ReactTestUtils');
-  });
-
-  it('should forward clicks when it starts out not disabled', function() {
-    expectClickThru(mounted(<button onClick={onClick} />));
-  });
-
-  it('should not forward clicks when it starts out disabled', function() {
-    expectNoClickThru(
-      mounted(<button disabled={true} onClick={onClick} />)
-    );
-  });
-
-  it('should forward clicks when it becomes not disabled', function() {
-    var container = document.createElement('div');
-    var btn = ReactDOM.render(
-      <button disabled={true} onClick={onClick} />,
-      container
-    );
-    btn = ReactDOM.render(
-      <button onClick={onClick} />,
-      container
-    );
-    expectClickThru(btn);
-  });
-
-  it('should not forward clicks when it becomes disabled', function() {
-    var container = document.createElement('div');
-    var btn = ReactDOM.render(
-      <button onClick={onClick} />,
-      container
-    );
-    btn = ReactDOM.render(
-      <button disabled={true} onClick={onClick} />,
-      container
-    );
-    expectNoClickThru(btn);
-  });
-
-  it('should work correctly if the listener is changed', function() {
-    var container = document.createElement('div');
-    var btn = ReactDOM.render(
-      <button disabled={true} onClick={function() {}} />,
-      container
-    );
-    btn = ReactDOM.render(
-      <button disabled={false} onClick={onClick} />,
-      container
-    );
-    expectClickThru(btn);
-  });
-});
diff --git a/src/renderers/dom/client/wrappers/__tests__/ReactDOMIframe-test.js b/src/renderers/dom/client/wrappers/__tests__/ReactDOMIframe-test.js
index 918e07c621da..b8e734397577 100644
--- a/src/renderers/dom/client/wrappers/__tests__/ReactDOMIframe-test.js
+++ b/src/renderers/dom/client/wrappers/__tests__/ReactDOMIframe-test.js
@@ -11,18 +11,18 @@
 
 'use strict';
 
-describe('ReactDOMIframe', function() {
+describe('ReactDOMIframe', () => {
   var React;
   var ReactDOM;
   var ReactTestUtils;
 
-  beforeEach(function() {
+  beforeEach(() => {
     React = require('React');
     ReactDOM = require('ReactDOM');
     ReactTestUtils = require('ReactTestUtils');
   });
 
-  it('should trigger load events', function() {
+  it('should trigger load events', () => {
     var onLoadSpy = jasmine.createSpy();
     var iframe = React.createElement('iframe', {onLoad: onLoadSpy});
     iframe = ReactTestUtils.renderIntoDocument(iframe);
diff --git a/src/renderers/dom/client/wrappers/__tests__/ReactDOMInput-test.js b/src/renderers/dom/client/wrappers/__tests__/ReactDOMInput-test.js
index 7a1f57dd0d37..4c099ee9dfcf 100644
--- a/src/renderers/dom/client/wrappers/__tests__/ReactDOMInput-test.js
+++ b/src/renderers/dom/client/wrappers/__tests__/ReactDOMInput-test.js
@@ -11,37 +11,132 @@
 
 'use strict';
 
-
 var emptyFunction = require('emptyFunction');
 
-describe('ReactDOMInput', function() {
-  var EventConstants;
+describe('ReactDOMInput', () => {
   var React;
   var ReactDOM;
+  var ReactDOMServer;
   var ReactDOMFeatureFlags;
   var ReactLink;
   var ReactTestUtils;
 
-  beforeEach(function() {
+  beforeEach(() => {
     jest.resetModuleRegistry();
-    EventConstants = require('EventConstants');
     React = require('React');
     ReactDOM = require('ReactDOM');
+    ReactDOMServer = require('ReactDOMServer');
     ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
     ReactLink = require('ReactLink');
     ReactTestUtils = require('ReactTestUtils');
     spyOn(console, 'error');
   });
 
-  it('should display `defaultValue` of number 0', function() {
+  describe('switching text inputs between numeric and string numbers', () => {
+    it('does change the number 2 to "2.0" with no change handler', () => {
+      var stub = <input type="text" value={2} onChange={jest.fn()} />;
+      stub = ReactTestUtils.renderIntoDocument(stub);
+      var node = ReactDOM.findDOMNode(stub);
+
+      node.value = '2.0';
+
+      ReactTestUtils.Simulate.change(stub);
+
+      expect(node.getAttribute('value')).toBe('2');
+      expect(node.value).toBe('2');
+    });
+
+    it('does change the string "2" to "2.0" with no change handler', () => {
+      var stub = <input type="text" value={'2'} onChange={jest.fn()} />;
+      stub = ReactTestUtils.renderIntoDocument(stub);
+      var node = ReactDOM.findDOMNode(stub);
+
+      node.value = '2.0';
+
+      ReactTestUtils.Simulate.change(stub);
+
+      expect(node.getAttribute('value')).toBe('2');
+      expect(node.value).toBe('2');
+    });
+
+    it('changes the number 2 to "2.0" using a change handler', () => {
+      class Stub extends React.Component {
+        state = {
+          value: 2,
+        };
+        onChange = event => {
+          this.setState({value: event.target.value});
+        };
+        render() {
+          const {value} = this.state;
+
+          return <input type="text" value={value} onChange={this.onChange} />;
+        }
+      }
+
+      var stub = ReactTestUtils.renderIntoDocument(<Stub />);
+      var node = ReactDOM.findDOMNode(stub);
+
+      node.value = '2.0';
+
+      ReactTestUtils.Simulate.change(node);
+
+      expect(node.getAttribute('value')).toBe('2.0');
+      expect(node.value).toBe('2.0');
+    });
+  });
+
+  it('does change the string ".98" to "0.98" with no change handler', () => {
+    class Stub extends React.Component {
+      state = {
+        value: '.98',
+      };
+      render() {
+        return <input type="number" value={this.state.value} />;
+      }
+    }
+
+    var stub = ReactTestUtils.renderIntoDocument(<Stub />);
+    var node = ReactDOM.findDOMNode(stub);
+    stub.setState({value: '0.98'});
+
+    expect(node.value).toEqual('0.98');
+  });
+
+  it('should display `defaultValue` of number 0', () => {
     var stub = <input type="text" defaultValue={0} />;
     stub = ReactTestUtils.renderIntoDocument(stub);
     var node = ReactDOM.findDOMNode(stub);
 
+    expect(node.getAttribute('value')).toBe('0');
     expect(node.value).toBe('0');
   });
 
-  it('should display "true" for `defaultValue` of `true`', function() {
+  it('only assigns defaultValue if it changes', () => {
+    class Test extends React.Component {
+      render() {
+        return <input defaultValue="0" />;
+      }
+    }
+
+    var component = ReactTestUtils.renderIntoDocument(<Test />);
+    var node = ReactDOM.findDOMNode(component);
+
+    Object.defineProperty(node, 'defaultValue', {
+      get() {
+        return '0';
+      },
+      set(value) {
+        throw new Error(
+          `defaultValue was assigned ${value}, but it did not change!`,
+        );
+      },
+    });
+
+    component.forceUpdate();
+  });
+
+  it('should display "true" for `defaultValue` of `true`', () => {
     var stub = <input type="text" defaultValue={true} />;
     stub = ReactTestUtils.renderIntoDocument(stub);
     var node = ReactDOM.findDOMNode(stub);
@@ -49,7 +144,7 @@ describe('ReactDOMInput', function() {
     expect(node.value).toBe('true');
   });
 
-  it('should display "false" for `defaultValue` of `false`', function() {
+  it('should display "false" for `defaultValue` of `false`', () => {
     var stub = <input type="text" defaultValue={false} />;
     stub = ReactTestUtils.renderIntoDocument(stub);
     var node = ReactDOM.findDOMNode(stub);
@@ -57,7 +152,104 @@ describe('ReactDOMInput', function() {
     expect(node.value).toBe('false');
   });
 
-  it('should display "foobar" for `defaultValue` of `objToString`', function() {
+  it('should update `defaultValue` for uncontrolled input', () => {
+    var container = document.createElement('div');
+
+    var node = ReactDOM.render(
+      <input type="text" defaultValue="0" />,
+      container,
+    );
+
+    expect(node.value).toBe('0');
+
+    ReactDOM.render(<input type="text" defaultValue="1" />, container);
+
+    expect(node.value).toBe('0');
+    expect(node.defaultValue).toBe('1');
+  });
+
+  it('should update `defaultValue` for uncontrolled date/time input', () => {
+    var container = document.createElement('div');
+
+    var node = ReactDOM.render(
+      <input type="date" defaultValue="1980-01-01" />,
+      container,
+    );
+
+    expect(node.value).toBe('1980-01-01');
+
+    ReactDOM.render(<input type="date" defaultValue="2000-01-01" />, container);
+
+    expect(node.value).toBe('1980-01-01');
+    expect(node.defaultValue).toBe('2000-01-01');
+
+    ReactDOM.render(<input type="date" />, container);
+  });
+
+  it('should take `defaultValue` when changing to uncontrolled input', () => {
+    var container = document.createElement('div');
+
+    var node = ReactDOM.render(
+      <input type="text" value="0" readOnly="true" />,
+      container,
+    );
+
+    expect(node.value).toBe('0');
+
+    ReactDOM.render(<input type="text" defaultValue="1" />, container);
+
+    expect(node.value).toBe('0');
+  });
+
+  it('should render defaultValue for SSR', () => {
+    var markup = ReactDOMServer.renderToString(
+      <input type="text" defaultValue="1" />,
+    );
+    var div = document.createElement('div');
+    div.innerHTML = markup;
+    expect(div.firstChild.getAttribute('value')).toBe('1');
+    expect(div.firstChild.getAttribute('defaultValue')).toBe(null);
+  });
+
+  it('should render value for SSR', () => {
+    var element = <input type="text" value="1" onChange={function() {}} />;
+    var markup = ReactDOMServer.renderToString(element);
+    var div = document.createElement('div');
+    div.innerHTML = markup;
+    expect(div.firstChild.getAttribute('value')).toBe('1');
+    expect(div.firstChild.getAttribute('defaultValue')).toBe(null);
+  });
+
+  it('should render name attribute if it is supplied', () => {
+    var container = document.createElement('div');
+    var node = ReactDOM.render(<input type="text" name="name" />, container);
+    expect(node.name).toBe('name');
+    expect(container.firstChild.getAttribute('name')).toBe('name');
+  });
+
+  it('should render name attribute if it is supplied for SSR', () => {
+    var element = <input type="text" name="name" />;
+    var markup = ReactDOMServer.renderToString(element);
+    var div = document.createElement('div');
+    div.innerHTML = markup;
+    expect(div.firstChild.getAttribute('name')).toBe('name');
+  });
+
+  it('should not render name attribute if it is not supplied', () => {
+    var container = document.createElement('div');
+    ReactDOM.render(<input type="text" />, container);
+    expect(container.firstChild.getAttribute('name')).toBe(null);
+  });
+
+  it('should not render name attribute if it is not supplied for SSR', () => {
+    var element = <input type="text" />;
+    var markup = ReactDOMServer.renderToString(element);
+    var div = document.createElement('div');
+    div.innerHTML = markup;
+    expect(div.firstChild.getAttribute('name')).toBe(null);
+  });
+
+  it('should display "foobar" for `defaultValue` of `objToString`', () => {
     var objToString = {
       toString: function() {
         return 'foobar';
@@ -71,7 +263,7 @@ describe('ReactDOMInput', function() {
     expect(node.value).toBe('foobar');
   });
 
-  it('should display `value` of number 0', function() {
+  it('should display `value` of number 0', () => {
     var stub = <input type="text" value={0} />;
     stub = ReactTestUtils.renderIntoDocument(stub);
     var node = ReactDOM.findDOMNode(stub);
@@ -79,41 +271,38 @@ describe('ReactDOMInput', function() {
     expect(node.value).toBe('0');
   });
 
-  it('should allow setting `value` to `true`', function() {
+  it('should allow setting `value` to `true`', () => {
     var container = document.createElement('div');
     var stub = <input type="text" value="yolo" onChange={emptyFunction} />;
-    stub = ReactDOM.render(stub, container);
-    var node = ReactDOM.findDOMNode(stub);
+    var node = ReactDOM.render(stub, container);
 
     expect(node.value).toBe('yolo');
 
     stub = ReactDOM.render(
       <input type="text" value={true} onChange={emptyFunction} />,
-      container
+      container,
     );
     expect(node.value).toEqual('true');
   });
 
-  it('should allow setting `value` to `false`', function() {
+  it('should allow setting `value` to `false`', () => {
     var container = document.createElement('div');
     var stub = <input type="text" value="yolo" onChange={emptyFunction} />;
-    stub = ReactDOM.render(stub, container);
-    var node = ReactDOM.findDOMNode(stub);
+    var node = ReactDOM.render(stub, container);
 
     expect(node.value).toBe('yolo');
 
     stub = ReactDOM.render(
       <input type="text" value={false} onChange={emptyFunction} />,
-      container
+      container,
     );
     expect(node.value).toEqual('false');
   });
 
-  it('should allow setting `value` to `objToString`', function() {
+  it('should allow setting `value` to `objToString`', () => {
     var container = document.createElement('div');
     var stub = <input type="text" value="foo" onChange={emptyFunction} />;
-    stub = ReactDOM.render(stub, container);
-    var node = ReactDOM.findDOMNode(stub);
+    var node = ReactDOM.render(stub, container);
 
     expect(node.value).toBe('foo');
 
@@ -124,12 +313,75 @@ describe('ReactDOMInput', function() {
     };
     stub = ReactDOM.render(
       <input type="text" value={objToString} onChange={emptyFunction} />,
-      container
+      container,
     );
     expect(node.value).toEqual('foobar');
   });
 
-  it('should properly control a value of number `0`', function() {
+  it('should not incur unnecessary DOM mutations', () => {
+    var container = document.createElement('div');
+    ReactDOM.render(<input value="a" />, container);
+
+    var node = container.firstChild;
+    var nodeValue = 'a';
+    var nodeValueSetter = jest.genMockFn();
+    Object.defineProperty(node, 'value', {
+      get: function() {
+        return nodeValue;
+      },
+      set: nodeValueSetter.mockImplementation(function(newValue) {
+        nodeValue = newValue;
+      }),
+    });
+
+    ReactDOM.render(<input value="a" />, container);
+    expect(nodeValueSetter.mock.calls.length).toBe(0);
+
+    ReactDOM.render(<input value="b" />, container);
+    expect(nodeValueSetter.mock.calls.length).toBe(1);
+  });
+
+  it('should not incur unnecessary DOM mutations for numeric type conversion', () => {
+    var container = document.createElement('div');
+    ReactDOM.render(<input value="0" />, container);
+
+    var node = container.firstChild;
+    var nodeValue = '0';
+    var nodeValueSetter = jest.genMockFn();
+    Object.defineProperty(node, 'value', {
+      get: function() {
+        return nodeValue;
+      },
+      set: nodeValueSetter.mockImplementation(function(newValue) {
+        nodeValue = newValue;
+      }),
+    });
+
+    ReactDOM.render(<input value={0} />, container);
+    expect(nodeValueSetter.mock.calls.length).toBe(0);
+  });
+
+  it('should not incur unnecessary DOM mutations for the boolean type conversion', () => {
+    var container = document.createElement('div');
+    ReactDOM.render(<input value="true" />, container);
+
+    var node = container.firstChild;
+    var nodeValue = 'true';
+    var nodeValueSetter = jest.genMockFn();
+    Object.defineProperty(node, 'value', {
+      get: function() {
+        return nodeValue;
+      },
+      set: nodeValueSetter.mockImplementation(function(newValue) {
+        nodeValue = newValue;
+      }),
+    });
+
+    ReactDOM.render(<input value={true} />, container);
+    expect(nodeValueSetter.mock.calls.length).toBe(0);
+  });
+
+  it('should properly control a value of number `0`', () => {
     var stub = <input type="text" value={0} onChange={emptyFunction} />;
     stub = ReactTestUtils.renderIntoDocument(stub);
     var node = ReactDOM.findDOMNode(stub);
@@ -139,7 +391,49 @@ describe('ReactDOMInput', function() {
     expect(node.value).toBe('0');
   });
 
-  it('should have the correct target value', function() {
+  it('should properly control 0.0 for a text input', () => {
+    var stub = <input type="text" value={0} onChange={emptyFunction} />;
+    stub = ReactTestUtils.renderIntoDocument(stub);
+    var node = ReactDOM.findDOMNode(stub);
+
+    node.value = '0.0';
+    ReactTestUtils.Simulate.change(node, {target: {value: '0.0'}});
+    expect(node.value).toBe('0');
+  });
+
+  it('should properly control 0.0 for a number input', () => {
+    var stub = <input type="number" value={0} onChange={emptyFunction} />;
+    stub = ReactTestUtils.renderIntoDocument(stub);
+    var node = ReactDOM.findDOMNode(stub);
+
+    node.value = '0.0';
+    ReactTestUtils.Simulate.change(node, {target: {value: '0.0'}});
+    expect(node.value).toBe('0.0');
+  });
+
+  it('should properly transition from an empty value to 0', function() {
+    var container = document.createElement('div');
+
+    ReactDOM.render(<input type="text" value="" />, container);
+    ReactDOM.render(<input type="text" value={0} />, container);
+
+    var node = container.firstChild;
+
+    expect(node.value).toBe('0');
+  });
+
+  it('should properly transition from 0 to an empty value', function() {
+    var container = document.createElement('div');
+
+    ReactDOM.render(<input type="text" value={0} />, container);
+    ReactDOM.render(<input type="text" value="" />, container);
+
+    var node = container.firstChild;
+
+    expect(node.value).toBe('');
+  });
+
+  it('should have the correct target value', () => {
     var handled = false;
     var handler = function(event) {
       expect(event.target.nodeName).toBe('INPUT');
@@ -151,19 +445,15 @@ describe('ReactDOMInput', function() {
 
     node.value = 'giraffe';
 
-    var fakeNativeEvent = new function() {};
+    var fakeNativeEvent = function() {};
     fakeNativeEvent.target = node;
     fakeNativeEvent.path = [node, container];
-    ReactTestUtils.simulateNativeEventOnNode(
-      EventConstants.topLevelTypes.topInput,
-      node,
-      fakeNativeEvent
-    );
+    ReactTestUtils.simulateNativeEventOnNode('topInput', node, fakeNativeEvent);
 
     expect(handled).toBe(true);
   });
 
-  it('should not set a value for submit buttons unnecessarily', function() {
+  it('should not set a value for submit buttons unnecessarily', () => {
     var stub = <input type="submit" />;
     stub = ReactTestUtils.renderIntoDocument(stub);
     var node = ReactDOM.findDOMNode(stub);
@@ -173,13 +463,13 @@ describe('ReactDOMInput', function() {
     // report this as not having a `value` attribute at all; IE reports it as
     // the actual label that the user sees.
     expect(
-      !node.hasAttribute('value') || node.getAttribute('value').length > 0
+      !node.hasAttribute('value') || node.getAttribute('value').length > 0,
     ).toBe(true);
   });
 
-  it('should control radio buttons', function() {
-    var RadioGroup = React.createClass({
-      render: function() {
+  it('should control radio buttons', () => {
+    class RadioGroup extends React.Component {
+      render() {
         return (
           <div>
             <input
@@ -188,13 +478,10 @@ describe('ReactDOMInput', function() {
               name="fruit"
               checked={true}
               onChange={emptyFunction}
-            />A
-            <input
-              ref="b"
-              type="radio"
-              name="fruit"
-              onChange={emptyFunction}
-            />B
+            />
+            A
+            <input ref="b" type="radio" name="fruit" onChange={emptyFunction} />
+            B
 
             <form>
               <input
@@ -207,8 +494,8 @@ describe('ReactDOMInput', function() {
             </form>
           </div>
         );
-      },
-    });
+      }
+    }
 
     var stub = ReactTestUtils.renderIntoDocument(<RadioGroup />);
     var aNode = ReactDOM.findDOMNode(stub.refs.a);
@@ -235,8 +522,8 @@ describe('ReactDOMInput', function() {
     expect(cNode.checked).toBe(true);
   });
 
-  it('should support ReactLink', function() {
-    var link = new ReactLink('yolo', jest.genMockFn());
+  it('should support ReactLink', () => {
+    var link = new ReactLink('yolo', jest.fn());
     var instance = <input type="text" valueLink={link} />;
 
     instance = ReactTestUtils.renderIntoDocument(instance);
@@ -252,35 +539,35 @@ describe('ReactDOMInput', function() {
     expect(link.requestChange.mock.calls[0][0]).toEqual('test');
   });
 
-  it('should warn with value and no onChange handler', function() {
-    var link = new ReactLink('yolo', jest.genMockFn());
+  it('should warn with value and no onChange handler', () => {
+    var link = new ReactLink('yolo', jest.fn());
     ReactTestUtils.renderIntoDocument(<input type="text" valueLink={link} />);
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
-      '`valueLink` prop on `input` is deprecated; set `value` and `onChange` instead.'
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      '`valueLink` prop on `input` is deprecated; set `value` and `onChange` instead.',
     );
 
     ReactTestUtils.renderIntoDocument(
-      <input type="text" value="zoink" onChange={jest.genMockFn()} />
+      <input type="text" value="zoink" onChange={jest.fn()} />,
     );
-    expect(console.error.argsForCall.length).toBe(1);
+    expect(console.error.calls.count()).toBe(1);
     ReactTestUtils.renderIntoDocument(<input type="text" value="zoink" />);
-    expect(console.error.argsForCall.length).toBe(2);
+    expect(console.error.calls.count()).toBe(2);
   });
 
-  it('should warn with value and no onChange handler and readOnly specified', function() {
+  it('should warn with value and no onChange handler and readOnly specified', () => {
     ReactTestUtils.renderIntoDocument(
-      <input type="text" value="zoink" readOnly={true} />
+      <input type="text" value="zoink" readOnly={true} />,
     );
-    expect(console.error.argsForCall.length).toBe(0);
+    expect(console.error.calls.count()).toBe(0);
 
     ReactTestUtils.renderIntoDocument(
-      <input type="text" value="zoink" readOnly={false} />
+      <input type="text" value="zoink" readOnly={false} />,
     );
-    expect(console.error.argsForCall.length).toBe(1);
+    expect(console.error.calls.count()).toBe(1);
   });
 
-  it('should have a this value of undefined if bind is not used', function() {
+  it('should have a this value of undefined if bind is not used', () => {
     var unboundInputOnChange = function() {
       expect(this).toBe(undefined);
     };
@@ -291,29 +578,29 @@ describe('ReactDOMInput', function() {
     ReactTestUtils.Simulate.change(instance);
   });
 
-  it('should throw if both value and valueLink are provided', function() {
+  it('should throw if both value and valueLink are provided', () => {
     var node = document.createElement('div');
-    var link = new ReactLink('yolo', jest.genMockFn());
+    var link = new ReactLink('yolo', jest.fn());
     var instance = <input type="text" valueLink={link} />;
 
     expect(() => ReactDOM.render(instance, node)).not.toThrow();
 
-    instance =
+    instance = (
       <input
         type="text"
         valueLink={link}
         value="test"
         onChange={emptyFunction}
-      />;
+      />
+    );
     expect(() => ReactDOM.render(instance, node)).toThrow();
 
     instance = <input type="text" valueLink={link} onChange={emptyFunction} />;
     expect(() => ReactDOM.render(instance, node)).toThrow();
-
   });
 
-  it('should support checkedLink', function() {
-    var link = new ReactLink(true, jest.genMockFn());
+  it('should support checkedLink', () => {
+    var link = new ReactLink(true, jest.fn());
     var instance = <input type="checkbox" checkedLink={link} />;
 
     instance = ReactTestUtils.renderIntoDocument(instance);
@@ -329,70 +616,76 @@ describe('ReactDOMInput', function() {
     expect(link.requestChange.mock.calls[0][0]).toEqual(false);
   });
 
-  it('should warn with checked and no onChange handler', function() {
+  it('should warn with checked and no onChange handler', () => {
     var node = document.createElement('div');
-    var link = new ReactLink(true, jest.genMockFn());
+    var link = new ReactLink(true, jest.fn());
     ReactDOM.render(<input type="checkbox" checkedLink={link} />, node);
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
-      '`checkedLink` prop on `input` is deprecated; set `value` and `onChange` instead.'
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      '`checkedLink` prop on `input` is deprecated; set `value` and `onChange` instead.',
     );
 
     ReactTestUtils.renderIntoDocument(
-      <input
-        type="checkbox"
-        checked="false"
-        onChange={jest.genMockFn()}
-      />
+      <input type="checkbox" checked="false" onChange={jest.fn()} />,
     );
-    expect(console.error.argsForCall.length).toBe(1);
+    expect(console.error.calls.count()).toBe(1);
 
     ReactTestUtils.renderIntoDocument(
-      <input type="checkbox" checked="false" readOnly={true} />
+      <input type="checkbox" checked="false" readOnly={true} />,
     );
-    expect(console.error.argsForCall.length).toBe(1);
+    expect(console.error.calls.count()).toBe(1);
 
-    ReactTestUtils.renderIntoDocument(<input type="checkbox" checked="false" />);
-    expect(console.error.argsForCall.length).toBe(2);
+    ReactTestUtils.renderIntoDocument(
+      <input type="checkbox" checked="false" />,
+    );
+    expect(console.error.calls.count()).toBe(2);
   });
 
-  it('should warn with checked and no onChange handler with readOnly specified', function() {
+  it('should warn with checked and no onChange handler with readOnly specified', () => {
     ReactTestUtils.renderIntoDocument(
-      <input type="checkbox" checked="false" readOnly={true} />
+      <input type="checkbox" checked="false" readOnly={true} />,
     );
-    expect(console.error.argsForCall.length).toBe(0);
+    expect(console.error.calls.count()).toBe(0);
 
     ReactTestUtils.renderIntoDocument(
-      <input type="checkbox" checked="false" readOnly={false} />
+      <input type="checkbox" checked="false" readOnly={false} />,
     );
-    expect(console.error.argsForCall.length).toBe(1);
+    expect(console.error.calls.count()).toBe(1);
   });
 
-  it('should throw if both checked and checkedLink are provided', function() {
+  it('should throw if both checked and checkedLink are provided', () => {
     var node = document.createElement('div');
-    var link = new ReactLink(true, jest.genMockFn());
+    var link = new ReactLink(true, jest.fn());
     var instance = <input type="checkbox" checkedLink={link} />;
 
     expect(() => ReactDOM.render(instance, node)).not.toThrow();
 
-    instance =
+    instance = (
       <input
         type="checkbox"
         checkedLink={link}
         checked="false"
         onChange={emptyFunction}
-      />;
+      />
+    );
     expect(() => ReactDOM.render(instance, node)).toThrow();
 
-    instance =
-      <input type="checkbox" checkedLink={link} onChange={emptyFunction} />;
+    instance = (
+      <input type="checkbox" checkedLink={link} onChange={emptyFunction} />
+    );
     expect(() => ReactDOM.render(instance, node)).toThrow();
+  });
 
+  it('should update defaultValue to empty string', () => {
+    var container = document.createElement('div');
+    ReactDOM.render(<input type="text" defaultValue={'foo'} />, container);
+    ReactDOM.render(<input type="text" defaultValue={''} />, container);
+    expect(container.firstChild.defaultValue).toBe('');
   });
 
-  it('should throw if both checkedLink and valueLink are provided', function() {
+  it('should throw if both checkedLink and valueLink are provided', () => {
     var node = document.createElement('div');
-    var link = new ReactLink(true, jest.genMockFn());
+    var link = new ReactLink(true, jest.fn());
     var instance = <input type="checkbox" checkedLink={link} />;
 
     expect(() => ReactDOM.render(instance, node)).not.toThrow();
@@ -400,192 +693,359 @@ describe('ReactDOMInput', function() {
     instance = <input type="checkbox" valueLink={link} />;
     expect(() => ReactDOM.render(instance, node)).not.toThrow();
 
-    instance =
-      <input type="checkbox" checkedLink={link} valueLink={emptyFunction} />;
+    instance = (
+      <input type="checkbox" checkedLink={link} valueLink={emptyFunction} />
+    );
     expect(() => ReactDOM.render(instance, node)).toThrow();
   });
 
-  it('should warn if value is null', function() {
+  it('should warn if value is null', () => {
     ReactTestUtils.renderIntoDocument(<input type="text" value={null} />);
-    expect(console.error.argsForCall[0][0]).toContain(
+    expect(console.error.calls.argsFor(0)[0]).toContain(
       '`value` prop on `input` should not be null. ' +
-      'Consider using the empty string to clear the component or `undefined` ' +
-      'for uncontrolled components.'
+        'Consider using the empty string to clear the component or `undefined` ' +
+        'for uncontrolled components.',
     );
 
     ReactTestUtils.renderIntoDocument(<input type="text" value={null} />);
-    expect(console.error.argsForCall.length).toBe(1);
+    expect(console.error.calls.count()).toBe(1);
   });
 
-  it('should warn if checked and defaultChecked props are specified', function() {
+  it('should warn if checked and defaultChecked props are specified', () => {
     ReactTestUtils.renderIntoDocument(
-      <input type="radio" checked={true} defaultChecked={true} readOnly={true} />
+      <input
+        type="radio"
+        checked={true}
+        defaultChecked={true}
+        readOnly={true}
+      />,
     );
-    expect(console.error.argsForCall[0][0]).toContain(
-      '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'
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'A component contains an input of type radio 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',
     );
 
     ReactTestUtils.renderIntoDocument(
-      <input type="radio" checked={true} defaultChecked={true} readOnly={true} />
+      <input
+        type="radio"
+        checked={true}
+        defaultChecked={true}
+        readOnly={true}
+      />,
     );
-    expect(console.error.argsForCall.length).toBe(1);
+    expect(console.error.calls.count()).toBe(1);
   });
 
-  it('should warn if value and defaultValue props are specified', function() {
+  it('should warn if value and defaultValue props are specified', () => {
     ReactTestUtils.renderIntoDocument(
-      <input type="text" value="foo" defaultValue="bar" readOnly={true} />
+      <input type="text" value="foo" defaultValue="bar" readOnly={true} />,
     );
-    expect(console.error.argsForCall[0][0]).toContain(
-      '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'
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'A component contains an input of type text 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',
     );
 
     ReactTestUtils.renderIntoDocument(
-      <input type="text" value="foo" defaultValue="bar" readOnly={true} />
+      <input type="text" value="foo" defaultValue="bar" readOnly={true} />,
     );
-    expect(console.error.argsForCall.length).toBe(1);
+    expect(console.error.calls.count()).toBe(1);
   });
 
-  it('should warn if controlled input switches to uncontrolled', function() {
-    var stub = <input type="text" value="controlled" onChange={emptyFunction} />;
+  it('should warn if controlled input switches to uncontrolled (value is undefined)', () => {
+    var stub = (
+      <input type="text" value="controlled" onChange={emptyFunction} />
+    );
     var container = document.createElement('div');
     ReactDOM.render(stub, container);
     ReactDOM.render(<input type="text" />, container);
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
       'A component is changing a controlled input of type text 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'
+        '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',
     );
   });
 
-  it('should warn if controlled input switches to uncontrolled with defaultValue', function() {
-    var stub = <input type="text" value="controlled" onChange={emptyFunction} />;
+  it('should warn if controlled input switches to uncontrolled (value is null)', () => {
+    var stub = (
+      <input type="text" value="controlled" onChange={emptyFunction} />
+    );
     var container = document.createElement('div');
     ReactDOM.render(stub, container);
-    ReactDOM.render(<input type="text" defaultValue="uncontrolled" />, container);
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
+    ReactDOM.render(<input type="text" value={null} />, container);
+    expect(console.error.calls.count()).toBeGreaterThan(0);
+    expect(console.error.calls.argsFor(1)[0]).toContain(
+      'A component is changing a controlled input of type text 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',
+    );
+  });
+
+  it('should warn if controlled input switches to uncontrolled with defaultValue', () => {
+    var stub = (
+      <input type="text" value="controlled" onChange={emptyFunction} />
+    );
+    var container = document.createElement('div');
+    ReactDOM.render(stub, container);
+    ReactDOM.render(
+      <input type="text" defaultValue="uncontrolled" />,
+      container,
+    );
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
       'A component is changing a controlled input of type text 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'
+        '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',
     );
   });
 
-  it('should warn if uncontrolled input switches to controlled', function() {
+  it('should warn if uncontrolled input (value is undefined) switches to controlled', () => {
     var stub = <input type="text" />;
     var container = document.createElement('div');
     ReactDOM.render(stub, container);
     ReactDOM.render(<input type="text" value="controlled" />, container);
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
-      'A component is changing a uncontrolled input of type text 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'
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'A component is changing an uncontrolled input of type text 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',
     );
   });
 
-  it('should warn if controlled checkbox switches to uncontrolled', function() {
-    var stub = <input type="checkbox" checked={true} onChange={emptyFunction} />;
+  it('should warn if uncontrolled input (value is null) switches to controlled', () => {
+    var stub = <input type="text" value={null} />;
+    var container = document.createElement('div');
+    ReactDOM.render(stub, container);
+    ReactDOM.render(<input type="text" value="controlled" />, container);
+    expect(console.error.calls.count()).toBeGreaterThan(0);
+    expect(console.error.calls.argsFor(1)[0]).toContain(
+      'A component is changing an uncontrolled input of type text 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',
+    );
+  });
+
+  it('should warn if controlled checkbox switches to uncontrolled (checked is undefined)', () => {
+    var stub = (
+      <input type="checkbox" checked={true} onChange={emptyFunction} />
+    );
     var container = document.createElement('div');
     ReactDOM.render(stub, container);
     ReactDOM.render(<input type="checkbox" />, container);
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
       'A component is changing a controlled input of type checkbox 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'
+        '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',
     );
   });
 
-  it('should warn if controlled checkbox switches to uncontrolled with defaultChecked', function() {
-    var stub = <input type="checkbox" checked={true} onChange={emptyFunction} />;
+  it('should warn if controlled checkbox switches to uncontrolled (checked is null)', () => {
+    var stub = (
+      <input type="checkbox" checked={true} onChange={emptyFunction} />
+    );
+    var container = document.createElement('div');
+    ReactDOM.render(stub, container);
+    ReactDOM.render(<input type="checkbox" checked={null} />, container);
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'A component is changing a controlled input of type checkbox 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',
+    );
+  });
+
+  it('should warn if controlled checkbox switches to uncontrolled with defaultChecked', () => {
+    var stub = (
+      <input type="checkbox" checked={true} onChange={emptyFunction} />
+    );
     var container = document.createElement('div');
     ReactDOM.render(stub, container);
     ReactDOM.render(<input type="checkbox" defaultChecked={true} />, container);
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
       'A component is changing a controlled input of type checkbox 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'
+        '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',
     );
   });
 
-  it('should warn if uncontrolled checkbox switches to controlled', function() {
+  it('should warn if uncontrolled checkbox (checked is undefined) switches to controlled', () => {
     var stub = <input type="checkbox" />;
     var container = document.createElement('div');
     ReactDOM.render(stub, container);
     ReactDOM.render(<input type="checkbox" checked={true} />, container);
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
-      'A component is changing a uncontrolled input of type checkbox 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'
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'A component is changing an uncontrolled input of type checkbox 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',
+    );
+  });
+
+  it('should warn if uncontrolled checkbox (checked is null) switches to controlled', () => {
+    var stub = <input type="checkbox" checked={null} />;
+    var container = document.createElement('div');
+    ReactDOM.render(stub, container);
+    ReactDOM.render(<input type="checkbox" checked={true} />, container);
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'A component is changing an uncontrolled input of type checkbox 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',
     );
   });
 
-  it('should warn if controlled radio switches to uncontrolled', function() {
+  it('should warn if controlled radio switches to uncontrolled (checked is undefined)', () => {
     var stub = <input type="radio" checked={true} onChange={emptyFunction} />;
     var container = document.createElement('div');
     ReactDOM.render(stub, container);
     ReactDOM.render(<input type="radio" />, container);
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
       'A component is changing a controlled input of type radio 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'
+        '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',
     );
   });
 
-  it('should warn if controlled radio switches to uncontrolled with defaultChecked', function() {
+  it('should warn if controlled radio switches to uncontrolled (checked is null)', () => {
+    var stub = <input type="radio" checked={true} onChange={emptyFunction} />;
+    var container = document.createElement('div');
+    ReactDOM.render(stub, container);
+    ReactDOM.render(<input type="radio" checked={null} />, container);
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'A component is changing a controlled input of type radio 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',
+    );
+  });
+
+  it('should warn if controlled radio switches to uncontrolled with defaultChecked', () => {
     var stub = <input type="radio" checked={true} onChange={emptyFunction} />;
     var container = document.createElement('div');
     ReactDOM.render(stub, container);
     ReactDOM.render(<input type="radio" defaultChecked={true} />, container);
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
       'A component is changing a controlled input of type radio 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'
+        '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',
     );
   });
 
-  it('should warn if uncontrolled radio switches to controlled', function() {
+  it('should warn if uncontrolled radio (checked is undefined) switches to controlled', () => {
     var stub = <input type="radio" />;
     var container = document.createElement('div');
     ReactDOM.render(stub, container);
     ReactDOM.render(<input type="radio" checked={true} />, container);
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
-      'A component is changing a uncontrolled input of type radio 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'
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'A component is changing an uncontrolled input of type radio 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',
     );
   });
 
-  it('sets type before value always', function() {
+  it('should warn if uncontrolled radio (checked is null) switches to controlled', () => {
+    var stub = <input type="radio" checked={null} />;
+    var container = document.createElement('div');
+    ReactDOM.render(stub, container);
+    ReactDOM.render(<input type="radio" checked={true} />, container);
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'A component is changing an uncontrolled input of type radio 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',
+    );
+  });
+
+  it('should not warn if radio value changes but never becomes controlled', () => {
+    var container = document.createElement('div');
+    ReactDOM.render(<input type="radio" value="value" />, container);
+    ReactDOM.render(<input type="radio" />, container);
+    ReactDOM.render(
+      <input type="radio" value="value" defaultChecked={true} />,
+      container,
+    );
+    ReactDOM.render(
+      <input type="radio" value="value" onChange={() => null} />,
+      container,
+    );
+    ReactDOM.render(<input type="radio" />, container);
+    expect(console.error.calls.count()).toBe(0);
+  });
+
+  it('should not warn if radio value changes but never becomes uncontrolled', () => {
+    var container = document.createElement('div');
+    ReactDOM.render(
+      <input type="radio" checked={false} onChange={() => null} />,
+      container,
+    );
+    ReactDOM.render(
+      <input
+        type="radio"
+        value="value"
+        defaultChecked={true}
+        checked={false}
+        onChange={() => null}
+      />,
+      container,
+    );
+    expect(console.error.calls.count()).toBe(0);
+  });
+
+  it('should warn if radio checked false changes to become uncontrolled', () => {
+    var container = document.createElement('div');
+    ReactDOM.render(
+      <input
+        type="radio"
+        value="value"
+        checked={false}
+        onChange={() => null}
+      />,
+      container,
+    );
+    ReactDOM.render(<input type="radio" value="value" />, container);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'A component is changing a controlled input of type radio 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',
+    );
+  });
+
+  it('sets type, step, min, max before value always', () => {
     if (!ReactDOMFeatureFlags.useCreateElement) {
       return;
     }
     var log = [];
     var originalCreateElement = document.createElement;
-    spyOn(document, 'createElement').andCallFake(function(type) {
+    spyOn(document, 'createElement').and.callFake(function(type) {
       var el = originalCreateElement.apply(this, arguments);
       if (type === 'input') {
         Object.defineProperty(el, 'value', {
@@ -594,26 +1054,175 @@ describe('ReactDOMInput', function() {
             log.push('set value');
           },
         });
-        spyOn(el, 'setAttribute').andCallFake(function(name, value) {
+        spyOn(el, 'setAttribute').and.callFake(function(name, value) {
           log.push('set ' + name);
         });
       }
       return el;
     });
 
-    ReactTestUtils.renderIntoDocument(<input value="hi" type="radio" />);
-    // Setting value before type does bad things. Make sure we set type first.
+    ReactTestUtils.renderIntoDocument(
+      <input value="0" type="range" min="0" max="100" step="1" />,
+    );
     expect(log).toEqual([
       'set data-reactroot',
       'set type',
+      'set step',
+      'set min',
+      'set max',
       'set value',
+      'set value',
+      'set checked',
+      'set checked',
     ]);
   });
 
-  it('sets value properly with type coming later in props', function() {
+  it('sets value properly with type coming later in props', () => {
     var input = ReactTestUtils.renderIntoDocument(
-      <input value="hi" type="radio" />
+      <input value="hi" type="radio" />,
     );
     expect(input.value).toBe('hi');
   });
+
+  it('does not raise a validation warning when it switches types', () => {
+    class Input extends React.Component {
+      state = {type: 'number', value: 1000};
+
+      render() {
+        var {value, type} = this.state;
+        return <input onChange={() => {}} type={type} value={value} />;
+      }
+    }
+
+    var input = ReactTestUtils.renderIntoDocument(<Input />);
+    var node = ReactDOM.findDOMNode(input);
+
+    // If the value is set before the type, a validation warning will raise and
+    // the value will not be assigned.
+    input.setState({type: 'text', value: 'Test'});
+    expect(node.value).toEqual('Test');
+  });
+
+  it('resets value of date/time input to fix bugs in iOS Safari', () => {
+    // https://github.com/facebook/react/issues/7233
+    if (!ReactDOMFeatureFlags.useCreateElement) {
+      return;
+    }
+
+    function strify(x) {
+      return JSON.stringify(x, null, 2);
+    }
+
+    var log = [];
+    var originalCreateElement = document.createElement;
+    spyOn(document, 'createElement').and.callFake(function(type) {
+      var el = originalCreateElement.apply(this, arguments);
+      if (type === 'input') {
+        Object.defineProperty(el, 'value', {
+          set: function(val) {
+            log.push(`node.value = ${strify(val)}`);
+          },
+        });
+        spyOn(el, 'setAttribute').and.callFake(function(name, val) {
+          log.push(`node.setAttribute(${strify(name)}, ${strify(val)})`);
+        });
+      }
+      return el;
+    });
+
+    ReactTestUtils.renderIntoDocument(
+      <input type="date" defaultValue="1980-01-01" />,
+    );
+    expect(log).toEqual([
+      'node.setAttribute("data-reactroot", "")',
+      'node.setAttribute("type", "date")',
+      'node.setAttribute("value", "1980-01-01")',
+      'node.value = ""',
+      'node.value = ""',
+      'node.setAttribute("checked", "")',
+      'node.setAttribute("checked", "")',
+    ]);
+  });
+
+  describe('assigning the value attribute on controlled inputs', function() {
+    function getTestInput() {
+      return class extends React.Component {
+        state = {
+          value: this.props.value == null ? '' : this.props.value,
+        };
+        onChange = event => {
+          this.setState({value: event.target.value});
+        };
+        render() {
+          var type = this.props.type;
+          var value = this.state.value;
+
+          return <input type={type} value={value} onChange={this.onChange} />;
+        }
+      };
+    }
+
+    it('always sets the attribute when values change on text inputs', function() {
+      var Input = getTestInput();
+      var stub = ReactTestUtils.renderIntoDocument(<Input type="text" />);
+      var node = ReactDOM.findDOMNode(stub);
+
+      ReactTestUtils.Simulate.change(node, {target: {value: '2'}});
+
+      expect(node.getAttribute('value')).toBe('2');
+    });
+
+    it('does not set the value attribute on number inputs if focused', () => {
+      var Input = getTestInput();
+      var stub = ReactTestUtils.renderIntoDocument(
+        <Input type="number" value="1" />,
+      );
+      var node = ReactDOM.findDOMNode(stub);
+
+      node.focus();
+
+      ReactTestUtils.Simulate.change(node, {target: {value: '2'}});
+
+      expect(node.getAttribute('value')).toBe('1');
+    });
+
+    it('sets the value attribute on number inputs on blur', () => {
+      var Input = getTestInput();
+      var stub = ReactTestUtils.renderIntoDocument(
+        <Input type="number" value="1" />,
+      );
+      var node = ReactDOM.findDOMNode(stub);
+
+      ReactTestUtils.Simulate.change(node, {target: {value: '2'}});
+      ReactTestUtils.SimulateNative.blur(node);
+
+      expect(node.getAttribute('value')).toBe('2');
+    });
+
+    it('an uncontrolled number input will not update the value attribute on blur', () => {
+      var stub = ReactTestUtils.renderIntoDocument(
+        <input type="number" defaultValue="1" />,
+      );
+      var node = ReactDOM.findDOMNode(stub);
+
+      node.value = 4;
+
+      ReactTestUtils.SimulateNative.blur(node);
+
+      expect(node.getAttribute('value')).toBe('1');
+    });
+
+    it('an uncontrolled text input will not update the value attribute on blur', () => {
+      var stub = ReactTestUtils.renderIntoDocument(
+        <input type="text" defaultValue="1" />,
+      );
+      var node = ReactDOM.findDOMNode(stub);
+
+      node.value = 4;
+
+      ReactTestUtils.SimulateNative.blur(node);
+
+      expect(node.getAttribute('value')).toBe('1');
+    });
+  });
 });
diff --git a/src/renderers/dom/client/wrappers/__tests__/ReactDOMOption-test.js b/src/renderers/dom/client/wrappers/__tests__/ReactDOMOption-test.js
index 0d52d83df373..924df9d96d2a 100644
--- a/src/renderers/dom/client/wrappers/__tests__/ReactDOMOption-test.js
+++ b/src/renderers/dom/client/wrappers/__tests__/ReactDOMOption-test.js
@@ -11,19 +11,18 @@
 
 'use strict';
 
-
-describe('ReactDOMOption', function() {
+describe('ReactDOMOption', () => {
   var React;
   var ReactDOM;
   var ReactTestUtils;
 
-  beforeEach(function() {
+  beforeEach(() => {
     React = require('React');
     ReactDOM = require('ReactDOM');
     ReactTestUtils = require('ReactTestUtils');
   });
 
-  it('should flatten children to a string', function() {
+  it('should flatten children to a string', () => {
     var stub = <option>{1} {'foo'}</option>;
     stub = ReactTestUtils.renderIntoDocument(stub);
     var node = ReactDOM.findDOMNode(stub);
@@ -31,44 +30,67 @@ describe('ReactDOMOption', function() {
     expect(node.innerHTML).toBe('1 foo');
   });
 
-  it('should ignore invalid children types', function() {
+  it('should ignore and warn invalid children types', () => {
     spyOn(console, 'error');
     var stub = <option>{1} <div /> {2}</option>;
     stub = ReactTestUtils.renderIntoDocument(stub);
     var node = ReactDOM.findDOMNode(stub);
-
     expect(node.innerHTML).toBe('1  2');
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain('Only strings and numbers are supported as <option> children.');
-  });
-
-  it('should warn when passing invalid children', function() {
-    var stub = <option>{1} <div /></option>;
-    spyOn(console, 'error');
-    stub = ReactTestUtils.renderIntoDocument(stub);
-
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
-      'Only strings and numbers are supported as <option> children.'
+    ReactTestUtils.renderIntoDocument(<option>{1} <div /> {2}</option>);
+    // only warn once
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'Only strings and numbers are supported as <option> children.',
     );
   });
 
-  it('should ignore null/undefined/false children without warning', function() {
+  it('should ignore null/undefined/false children without warning', () => {
     var stub = <option>{1} {false}{true}{null}{undefined} {2}</option>;
     spyOn(console, 'error');
     stub = ReactTestUtils.renderIntoDocument(stub);
 
     var node = ReactDOM.findDOMNode(stub);
 
-    expect(console.error.calls.length).toBe(0);
+    expect(console.error.calls.count()).toBe(0);
     expect(node.innerHTML).toBe('1  2');
   });
 
-  it('should be able to use dangerouslySetInnerHTML on option', function() {
-    var stub = <option dangerouslySetInnerHTML={{ __html: 'foobar' }} />;
+  it('should be able to use dangerouslySetInnerHTML on option', () => {
+    var stub = <option dangerouslySetInnerHTML={{__html: 'foobar'}} />;
     stub = ReactTestUtils.renderIntoDocument(stub);
 
     var node = ReactDOM.findDOMNode(stub);
     expect(node.innerHTML).toBe('foobar');
   });
+
+  it('should set attribute for empty value', () => {
+    var container = document.createElement('div');
+    var option = ReactDOM.render(<option value="" />, container);
+    expect(option.hasAttribute('value')).toBe(true);
+    expect(option.getAttribute('value')).toBe('');
+
+    ReactDOM.render(<option value="lava" />, container);
+    expect(option.hasAttribute('value')).toBe(true);
+    expect(option.getAttribute('value')).toBe('lava');
+  });
+
+  it('should allow ignoring `value` on option', () => {
+    var a = 'a';
+    var stub = (
+      <select value="giraffe" onChange={() => {}}>
+        <option>monkey</option>
+        <option>gir{a}ffe</option>
+        <option>gorill{a}</option>
+      </select>
+    );
+    var options = stub.props.children;
+    var container = document.createElement('div');
+    stub = ReactDOM.render(stub, container);
+    var node = ReactDOM.findDOMNode(stub);
+
+    expect(node.selectedIndex).toBe(1);
+
+    ReactDOM.render(<select value="gorilla">{options}</select>, container);
+    expect(node.selectedIndex).toEqual(2);
+  });
 });
diff --git a/src/renderers/dom/client/wrappers/__tests__/ReactDOMSelect-test.js b/src/renderers/dom/client/wrappers/__tests__/ReactDOMSelect-test.js
index 97736bc99a55..c3c7f98e8074 100644
--- a/src/renderers/dom/client/wrappers/__tests__/ReactDOMSelect-test.js
+++ b/src/renderers/dom/client/wrappers/__tests__/ReactDOMSelect-test.js
@@ -11,8 +11,7 @@
 
 'use strict';
 
-
-describe('ReactDOMSelect', function() {
+describe('ReactDOMSelect', () => {
   var React;
   var ReactDOM;
   var ReactDOMServer;
@@ -21,7 +20,7 @@ describe('ReactDOMSelect', function() {
 
   var noop = function() {};
 
-  beforeEach(function() {
+  beforeEach(() => {
     React = require('React');
     ReactDOM = require('ReactDOM');
     ReactDOMServer = require('ReactDOMServer');
@@ -29,13 +28,14 @@ describe('ReactDOMSelect', function() {
     ReactTestUtils = require('ReactTestUtils');
   });
 
-  it('should allow setting `defaultValue`', function() {
-    var stub =
+  it('should allow setting `defaultValue`', () => {
+    var stub = (
       <select defaultValue="giraffe">
         <option value="monkey">A monkey!</option>
         <option value="giraffe">A giraffe!</option>
         <option value="gorilla">A gorilla!</option>
-      </select>;
+      </select>
+    );
     var options = stub.props.children;
     var container = document.createElement('div');
     stub = ReactDOM.render(stub, container);
@@ -46,26 +46,27 @@ describe('ReactDOMSelect', function() {
     // Changing `defaultValue` should do nothing.
     ReactDOM.render(
       <select defaultValue="gorilla">{options}</select>,
-      container
+      container,
     );
     expect(node.value).toEqual('giraffe');
   });
 
-  it('should not throw with `defaultValue` and without children', function() {
-    var stub = <select defaultValue="dummy"></select>;
+  it('should not throw with `defaultValue` and without children', () => {
+    var stub = <select defaultValue="dummy" />;
 
     expect(() => {
       ReactTestUtils.renderIntoDocument(stub);
     }).not.toThrow();
   });
 
-  it('should not control when using `defaultValue`', function() {
-    var el =
+  it('should not control when using `defaultValue`', () => {
+    var el = (
       <select defaultValue="giraffe">
         <option value="monkey">A monkey!</option>
         <option value="giraffe">A giraffe!</option>
         <option value="gorilla">A gorilla!</option>
-      </select>;
+      </select>
+    );
     var container = document.createElement('div');
     var stub = ReactDOM.render(el, container);
     var node = ReactDOM.findDOMNode(stub);
@@ -78,40 +79,42 @@ describe('ReactDOMSelect', function() {
     expect(node.value).toEqual('monkey');
   });
 
-  it('should allow setting `defaultValue` with multiple', function() {
-    var stub =
+  it('should allow setting `defaultValue` with multiple', () => {
+    var stub = (
       <select multiple={true} defaultValue={['giraffe', 'gorilla']}>
         <option value="monkey">A monkey!</option>
         <option value="giraffe">A giraffe!</option>
         <option value="gorilla">A gorilla!</option>
-      </select>;
+      </select>
+    );
     var options = stub.props.children;
     var container = document.createElement('div');
     stub = ReactDOM.render(stub, container);
     var node = ReactDOM.findDOMNode(stub);
 
-    expect(node.options[0].selected).toBe(false);  // monkey
-    expect(node.options[1].selected).toBe(true);  // giraffe
-    expect(node.options[2].selected).toBe(true);  // gorilla
+    expect(node.options[0].selected).toBe(false); // monkey
+    expect(node.options[1].selected).toBe(true); // giraffe
+    expect(node.options[2].selected).toBe(true); // gorilla
 
     // Changing `defaultValue` should do nothing.
     ReactDOM.render(
       <select multiple={true} defaultValue={['monkey']}>{options}</select>,
-      container
+      container,
     );
 
-    expect(node.options[0].selected).toBe(false);  // monkey
-    expect(node.options[1].selected).toBe(true);  // giraffe
-    expect(node.options[2].selected).toBe(true);  // gorilla
+    expect(node.options[0].selected).toBe(false); // monkey
+    expect(node.options[1].selected).toBe(true); // giraffe
+    expect(node.options[2].selected).toBe(true); // gorilla
   });
 
-  it('should allow setting `value`', function() {
-    var stub =
+  it('should allow setting `value`', () => {
+    var stub = (
       <select value="giraffe" onChange={noop}>
         <option value="monkey">A monkey!</option>
         <option value="giraffe">A giraffe!</option>
         <option value="gorilla">A gorilla!</option>
-      </select>;
+      </select>
+    );
     var options = stub.props.children;
     var container = document.createElement('div');
     stub = ReactDOM.render(stub, container);
@@ -122,64 +125,66 @@ describe('ReactDOMSelect', function() {
     // Changing the `value` prop should change the selected option.
     ReactDOM.render(
       <select value="gorilla" onChange={noop}>{options}</select>,
-      container
+      container,
     );
     expect(node.value).toEqual('gorilla');
   });
 
-  it('should not throw with `value` and without children', function() {
-    var stub = <select value="dummy" onChange={noop}></select>;
+  it('should not throw with `value` and without children', () => {
+    var stub = <select value="dummy" onChange={noop} />;
 
     expect(() => {
       ReactTestUtils.renderIntoDocument(stub);
     }).not.toThrow();
   });
 
-  it('should allow setting `value` with multiple', function() {
-    var stub =
+  it('should allow setting `value` with multiple', () => {
+    var stub = (
       <select multiple={true} value={['giraffe', 'gorilla']} onChange={noop}>
         <option value="monkey">A monkey!</option>
         <option value="giraffe">A giraffe!</option>
         <option value="gorilla">A gorilla!</option>
-      </select>;
+      </select>
+    );
     var options = stub.props.children;
     var container = document.createElement('div');
     stub = ReactDOM.render(stub, container);
     var node = ReactDOM.findDOMNode(stub);
 
-    expect(node.options[0].selected).toBe(false);  // monkey
-    expect(node.options[1].selected).toBe(true);  // giraffe
-    expect(node.options[2].selected).toBe(true);  // gorilla
+    expect(node.options[0].selected).toBe(false); // monkey
+    expect(node.options[1].selected).toBe(true); // giraffe
+    expect(node.options[2].selected).toBe(true); // gorilla
 
     // Changing the `value` prop should change the selected options.
     ReactDOM.render(
       <select multiple={true} value={['monkey']} onChange={noop}>
         {options}
       </select>,
-      container
+      container,
     );
 
-    expect(node.options[0].selected).toBe(true);  // monkey
-    expect(node.options[1].selected).toBe(false);  // giraffe
-    expect(node.options[2].selected).toBe(false);  // gorilla
+    expect(node.options[0].selected).toBe(true); // monkey
+    expect(node.options[1].selected).toBe(false); // giraffe
+    expect(node.options[2].selected).toBe(false); // gorilla
   });
 
-  it('should not select other options automatically', function() {
-    var stub =
+  it('should not select other options automatically', () => {
+    var stub = (
       <select multiple={true} value={['12']} onChange={noop}>
         <option value="1">one</option>
         <option value="2">two</option>
         <option value="12">twelve</option>
-      </select>;
+      </select>
+    );
     stub = ReactTestUtils.renderIntoDocument(stub);
     var node = ReactDOM.findDOMNode(stub);
 
-    expect(node.options[0].selected).toBe(false);  // one
-    expect(node.options[1].selected).toBe(false);  // two
-    expect(node.options[2].selected).toBe(true);  // twelve
+    expect(node.options[0].selected).toBe(false); // one
+    expect(node.options[1].selected).toBe(false); // two
+    expect(node.options[2].selected).toBe(true); // twelve
   });
 
-  it('should reset child options selected when they are changed and `value` is set', function() {
+  it('should reset child options selected when they are changed and `value` is set', () => {
     var stub = <select multiple={true} value={['a', 'b']} onChange={noop} />;
     var container = document.createElement('div');
     stub = ReactDOM.render(stub, container);
@@ -190,17 +195,17 @@ describe('ReactDOMSelect', function() {
         <option value="b">b</option>
         <option value="c">c</option>
       </select>,
-      container
+      container,
     );
 
     var node = ReactDOM.findDOMNode(stub);
 
-    expect(node.options[0].selected).toBe(true);  // a
-    expect(node.options[1].selected).toBe(true);  // b
-    expect(node.options[2].selected).toBe(false);  // c
+    expect(node.options[0].selected).toBe(true); // a
+    expect(node.options[1].selected).toBe(true); // b
+    expect(node.options[2].selected).toBe(false); // c
   });
 
-  it('should allow setting `value` with `objectToString`', function() {
+  it('should allow setting `value` with `objectToString`', () => {
     var objectToString = {
       animal: 'giraffe',
       toString: function() {
@@ -208,124 +213,129 @@ describe('ReactDOMSelect', function() {
       },
     };
 
-    var el =
+    var el = (
       <select multiple={true} value={[objectToString]} onChange={noop}>
         <option value="monkey">A monkey!</option>
         <option value="giraffe">A giraffe!</option>
         <option value="gorilla">A gorilla!</option>
-      </select>;
+      </select>
+    );
     var container = document.createElement('div');
     var stub = ReactDOM.render(el, container);
     var node = ReactDOM.findDOMNode(stub);
 
-    expect(node.options[0].selected).toBe(false);  // monkey
-    expect(node.options[1].selected).toBe(true);  // giraffe
-    expect(node.options[2].selected).toBe(false);  // gorilla
+    expect(node.options[0].selected).toBe(false); // monkey
+    expect(node.options[1].selected).toBe(true); // giraffe
+    expect(node.options[2].selected).toBe(false); // gorilla
 
     // Changing the `value` prop should change the selected options.
     objectToString.animal = 'monkey';
 
-    var el2 =
+    var el2 = (
       <select multiple={true} value={[objectToString]}>
         <option value="monkey">A monkey!</option>
         <option value="giraffe">A giraffe!</option>
         <option value="gorilla">A gorilla!</option>
-      </select>;
+      </select>
+    );
     ReactDOM.render(el2, container);
 
-    expect(node.options[0].selected).toBe(true);  // monkey
-    expect(node.options[1].selected).toBe(false);  // giraffe
-    expect(node.options[2].selected).toBe(false);  // gorilla
+    expect(node.options[0].selected).toBe(true); // monkey
+    expect(node.options[1].selected).toBe(false); // giraffe
+    expect(node.options[2].selected).toBe(false); // gorilla
   });
 
-  it('should allow switching to multiple', function() {
-    var stub =
+  it('should allow switching to multiple', () => {
+    var stub = (
       <select defaultValue="giraffe">
         <option value="monkey">A monkey!</option>
         <option value="giraffe">A giraffe!</option>
         <option value="gorilla">A gorilla!</option>
-      </select>;
+      </select>
+    );
     var options = stub.props.children;
     var container = document.createElement('div');
     stub = ReactDOM.render(stub, container);
     var node = ReactDOM.findDOMNode(stub);
 
-    expect(node.options[0].selected).toBe(false);  // monkey
-    expect(node.options[1].selected).toBe(true);  // giraffe
-    expect(node.options[2].selected).toBe(false);  // gorilla
+    expect(node.options[0].selected).toBe(false); // monkey
+    expect(node.options[1].selected).toBe(true); // giraffe
+    expect(node.options[2].selected).toBe(false); // gorilla
 
     // When making it multiple, giraffe and gorilla should be selected
     ReactDOM.render(
       <select multiple={true} defaultValue={['giraffe', 'gorilla']}>
         {options}
       </select>,
-      container
+      container,
     );
 
-    expect(node.options[0].selected).toBe(false);  // monkey
-    expect(node.options[1].selected).toBe(true);  // giraffe
-    expect(node.options[2].selected).toBe(true);  // gorilla
+    expect(node.options[0].selected).toBe(false); // monkey
+    expect(node.options[1].selected).toBe(true); // giraffe
+    expect(node.options[2].selected).toBe(true); // gorilla
   });
 
-  it('should allow switching from multiple', function() {
-    var stub =
+  it('should allow switching from multiple', () => {
+    var stub = (
       <select multiple={true} defaultValue={['giraffe', 'gorilla']}>
         <option value="monkey">A monkey!</option>
         <option value="giraffe">A giraffe!</option>
         <option value="gorilla">A gorilla!</option>
-      </select>;
+      </select>
+    );
     var options = stub.props.children;
     var container = document.createElement('div');
     stub = ReactDOM.render(stub, container);
     var node = ReactDOM.findDOMNode(stub);
 
-    expect(node.options[0].selected).toBe(false);  // monkey
-    expect(node.options[1].selected).toBe(true);  // giraffe
-    expect(node.options[2].selected).toBe(true);  // gorilla
+    expect(node.options[0].selected).toBe(false); // monkey
+    expect(node.options[1].selected).toBe(true); // giraffe
+    expect(node.options[2].selected).toBe(true); // gorilla
 
     // When removing multiple, defaultValue is applied again, being omitted
     // means that "monkey" will be selected
     ReactDOM.render(
       <select defaultValue="gorilla">{options}</select>,
-      container
+      container,
     );
 
-
-    expect(node.options[0].selected).toBe(false);  // monkey
-    expect(node.options[1].selected).toBe(false);  // giraffe
-    expect(node.options[2].selected).toBe(true);  // gorilla
+    expect(node.options[0].selected).toBe(false); // monkey
+    expect(node.options[1].selected).toBe(false); // giraffe
+    expect(node.options[2].selected).toBe(true); // gorilla
   });
 
-  it('should remember value when switching to uncontrolled', function() {
-    var stub =
+  it('should remember value when switching to uncontrolled', () => {
+    var stub = (
       <select value={'giraffe'} onChange={noop}>
         <option value="monkey">A monkey!</option>
         <option value="giraffe">A giraffe!</option>
         <option value="gorilla">A gorilla!</option>
-      </select>;
+      </select>
+    );
     var options = stub.props.children;
     var container = document.createElement('div');
     stub = ReactDOM.render(stub, container);
     var node = ReactDOM.findDOMNode(stub);
 
-    expect(node.options[0].selected).toBe(false);  // monkey
-    expect(node.options[1].selected).toBe(true);  // giraffe
-    expect(node.options[2].selected).toBe(false);  // gorilla
+    expect(node.options[0].selected).toBe(false); // monkey
+    expect(node.options[1].selected).toBe(true); // giraffe
+    expect(node.options[2].selected).toBe(false); // gorilla
 
     ReactDOM.render(<select>{options}</select>, container);
 
-    expect(node.options[0].selected).toBe(false);  // monkey
-    expect(node.options[1].selected).toBe(true);  // giraffe
-    expect(node.options[2].selected).toBe(false);  // gorilla
+    expect(node.options[0].selected).toBe(false); // monkey
+    expect(node.options[1].selected).toBe(true); // giraffe
+    expect(node.options[2].selected).toBe(false); // gorilla
   });
 
-  it('should remember updated value when switching to uncontrolled', function() {
-    var stub =
+  it('should remember updated value when switching to uncontrolled', () => {
+    var stub = (
       <select value={'giraffe'} onChange={noop}>
         <option value="monkey">A monkey!</option>
         <option value="giraffe">A giraffe!</option>
         <option value="gorilla">A gorilla!</option>
-      </select>;
+      </select>
+    );
     var options = stub.props.children;
     var container = document.createElement('div');
     stub = ReactDOM.render(stub, container);
@@ -333,43 +343,44 @@ describe('ReactDOMSelect', function() {
 
     ReactDOM.render(
       <select value="gorilla" onChange={noop}>{options}</select>,
-      container
+      container,
     );
 
-    expect(node.options[0].selected).toBe(false);  // monkey
-    expect(node.options[1].selected).toBe(false);  // giraffe
-    expect(node.options[2].selected).toBe(true);  // gorilla
+    expect(node.options[0].selected).toBe(false); // monkey
+    expect(node.options[1].selected).toBe(false); // giraffe
+    expect(node.options[2].selected).toBe(true); // gorilla
 
     ReactDOM.render(<select>{options}</select>, container);
 
-    expect(node.options[0].selected).toBe(false);  // monkey
-    expect(node.options[1].selected).toBe(false);  // giraffe
-    expect(node.options[2].selected).toBe(true);  // gorilla
+    expect(node.options[0].selected).toBe(false); // monkey
+    expect(node.options[1].selected).toBe(false); // giraffe
+    expect(node.options[2].selected).toBe(true); // gorilla
   });
 
-  it('should support ReactLink', function() {
-    var link = new ReactLink('giraffe', jest.genMockFn());
-    var stub =
+  it('should support ReactLink', () => {
+    var link = new ReactLink('giraffe', jest.fn());
+    var stub = (
       <select valueLink={link}>
         <option value="monkey">A monkey!</option>
         <option value="giraffe">A giraffe!</option>
         <option value="gorilla">A gorilla!</option>
-      </select>;
+      </select>
+    );
 
     spyOn(console, 'error');
 
     stub = ReactTestUtils.renderIntoDocument(stub);
 
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
-      '`valueLink` prop on `select` is deprecated; set `value` and `onChange` instead.'
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      '`valueLink` prop on `select` is deprecated; set `value` and `onChange` instead.',
     );
 
     var node = ReactDOM.findDOMNode(stub);
 
-    expect(node.options[0].selected).toBe(false);  // monkey
-    expect(node.options[1].selected).toBe(true);  // giraffe
-    expect(node.options[2].selected).toBe(false);  // gorilla
+    expect(node.options[0].selected).toBe(false); // monkey
+    expect(node.options[1].selected).toBe(true); // giraffe
+    expect(node.options[2].selected).toBe(false); // gorilla
     expect(link.requestChange.mock.calls.length).toBe(0);
 
     node.options[1].selected = false;
@@ -378,49 +389,51 @@ describe('ReactDOMSelect', function() {
 
     expect(link.requestChange.mock.calls.length).toBe(1);
     expect(link.requestChange.mock.calls[0][0]).toEqual('gorilla');
-
   });
 
-  it('should support server-side rendering', function() {
-    var stub =
+  it('should support server-side rendering', () => {
+    var stub = (
       <select value="giraffe" onChange={noop}>
         <option value="monkey">A monkey!</option>
         <option value="giraffe">A giraffe!</option>
         <option value="gorilla">A gorilla!</option>
-      </select>;
+      </select>
+    );
     var markup = ReactDOMServer.renderToString(stub);
     expect(markup).toContain('<option selected="" value="giraffe"');
     expect(markup).not.toContain('<option selected="" value="monkey"');
     expect(markup).not.toContain('<option selected="" value="gorilla"');
   });
 
-  it('should support server-side rendering with defaultValue', function() {
-    var stub =
+  it('should support server-side rendering with defaultValue', () => {
+    var stub = (
       <select defaultValue="giraffe">
         <option value="monkey">A monkey!</option>
         <option value="giraffe">A giraffe!</option>
         <option value="gorilla">A gorilla!</option>
-      </select>;
+      </select>
+    );
     var markup = ReactDOMServer.renderToString(stub);
     expect(markup).toContain('<option selected="" value="giraffe"');
     expect(markup).not.toContain('<option selected="" value="monkey"');
     expect(markup).not.toContain('<option selected="" value="gorilla"');
   });
 
-  it('should support server-side rendering with multiple', function() {
-    var stub =
+  it('should support server-side rendering with multiple', () => {
+    var stub = (
       <select multiple={true} value={['giraffe', 'gorilla']} onChange={noop}>
         <option value="monkey">A monkey!</option>
         <option value="giraffe">A giraffe!</option>
         <option value="gorilla">A gorilla!</option>
-      </select>;
+      </select>
+    );
     var markup = ReactDOMServer.renderToString(stub);
     expect(markup).toContain('<option selected="" value="giraffe"');
     expect(markup).toContain('<option selected="" value="gorilla"');
     expect(markup).not.toContain('<option selected="" value="monkey"');
   });
 
-  it('should not control defaultValue if readding options', function() {
+  it('should not control defaultValue if readding options', () => {
     var container = document.createElement('div');
 
     var select = ReactDOM.render(
@@ -429,24 +442,24 @@ describe('ReactDOMSelect', function() {
         <option key="giraffe" value="giraffe">A giraffe!</option>
         <option key="gorilla" value="gorilla">A gorilla!</option>
       </select>,
-      container
+      container,
     );
     var node = ReactDOM.findDOMNode(select);
 
-    expect(node.options[0].selected).toBe(false);  // monkey
-    expect(node.options[1].selected).toBe(true);  // giraffe
-    expect(node.options[2].selected).toBe(false);  // gorilla
+    expect(node.options[0].selected).toBe(false); // monkey
+    expect(node.options[1].selected).toBe(true); // giraffe
+    expect(node.options[2].selected).toBe(false); // gorilla
 
     ReactDOM.render(
       <select multiple={true} defaultValue={['giraffe']}>
         <option key="monkey" value="monkey">A monkey!</option>
         <option key="gorilla" value="gorilla">A gorilla!</option>
       </select>,
-      container
+      container,
     );
 
-    expect(node.options[0].selected).toBe(false);  // monkey
-    expect(node.options[1].selected).toBe(false);  // gorilla
+    expect(node.options[0].selected).toBe(false); // monkey
+    expect(node.options[1].selected).toBe(false); // gorilla
 
     ReactDOM.render(
       <select multiple={true} defaultValue={['giraffe']}>
@@ -454,35 +467,40 @@ describe('ReactDOMSelect', function() {
         <option key="giraffe" value="giraffe">A giraffe!</option>
         <option key="gorilla" value="gorilla">A gorilla!</option>
       </select>,
-      container
+      container,
     );
 
-    expect(node.options[0].selected).toBe(false);  // monkey
-    expect(node.options[1].selected).toBe(false);  // giraffe
-    expect(node.options[2].selected).toBe(false);  // gorilla
+    expect(node.options[0].selected).toBe(false); // monkey
+    expect(node.options[1].selected).toBe(false); // giraffe
+    expect(node.options[2].selected).toBe(false); // gorilla
   });
 
-  it('should warn if value is null', function() {
+  it('should warn if value is null', () => {
     spyOn(console, 'error');
 
-    ReactTestUtils.renderIntoDocument(<select value={null}><option value="test"/></select>);
-    expect(console.error.argsForCall[0][0]).toContain(
+    ReactTestUtils.renderIntoDocument(
+      <select value={null}><option value="test" /></select>,
+    );
+    expect(console.error.calls.argsFor(0)[0]).toContain(
       '`value` prop on `select` should not be null. ' +
-      'Consider using the empty string to clear the component or `undefined` ' +
-      'for uncontrolled components.'
+        'Consider using the empty string to clear the component or `undefined` ' +
+        'for uncontrolled components.',
     );
 
-    ReactTestUtils.renderIntoDocument(<select value={null}><option value="test"/></select>);
-    expect(console.error.argsForCall.length).toBe(1);
+    ReactTestUtils.renderIntoDocument(
+      <select value={null}><option value="test" /></select>,
+    );
+    expect(console.error.calls.count()).toBe(1);
   });
 
-  it('should refresh state on change', function() {
-    var stub =
+  it('should refresh state on change', () => {
+    var stub = (
       <select value="giraffe" onChange={noop}>
         <option value="monkey">A monkey!</option>
         <option value="giraffe">A giraffe!</option>
         <option value="gorilla">A gorilla!</option>
-      </select>;
+      </select>
+    );
     stub = ReactTestUtils.renderIntoDocument(stub);
     var node = ReactDOM.findDOMNode(stub);
 
@@ -491,21 +509,21 @@ describe('ReactDOMSelect', function() {
     expect(node.value).toBe('giraffe');
   });
 
-  it('should warn if value and defaultValue props are specified', function() {
+  it('should warn if value and defaultValue props are specified', () => {
     spyOn(console, 'error');
     ReactTestUtils.renderIntoDocument(
       <select value="giraffe" defaultValue="giraffe" readOnly={true}>
         <option value="monkey">A monkey!</option>
         <option value="giraffe">A giraffe!</option>
         <option value="gorilla">A gorilla!</option>
-      </select>
+      </select>,
     );
-    expect(console.error.argsForCall[0][0]).toContain(
+    expect(console.error.calls.argsFor(0)[0]).toContain(
       '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'
+        '(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',
     );
 
     ReactTestUtils.renderIntoDocument(
@@ -513,28 +531,47 @@ describe('ReactDOMSelect', function() {
         <option value="monkey">A monkey!</option>
         <option value="giraffe">A giraffe!</option>
         <option value="gorilla">A gorilla!</option>
-      </select>
+      </select>,
     );
-    expect(console.error.argsForCall.length).toBe(1);
+    expect(console.error.calls.count()).toBe(1);
   });
 
-  it('should be able to safely remove select onChange', function() {
+  it('should be able to safely remove select onChange', () => {
     function changeView() {
       ReactDOM.unmountComponentAtNode(container);
     }
 
     var container = document.createElement('div');
-    var stub =
+    var stub = (
       <select value="giraffe" onChange={changeView}>
         <option value="monkey">A monkey!</option>
         <option value="giraffe">A giraffe!</option>
         <option value="gorilla">A gorilla!</option>
-      </select>;
+      </select>
+    );
     stub = ReactDOM.render(stub, container);
     var node = ReactDOM.findDOMNode(stub);
 
     expect(() => ReactTestUtils.Simulate.change(node)).not.toThrow(
-      "Cannot set property 'pendingUpdate' of null"
+      "Cannot set property 'pendingUpdate' of null",
     );
   });
+
+  it('should select grandchild options nested inside an optgroup', () => {
+    var stub = (
+      <select value="b" onChange={noop}>
+        <optgroup label="group">
+          <option value="a">a</option>
+          <option value="b">b</option>
+          <option value="c">c</option>
+        </optgroup>
+      </select>
+    );
+    var container = document.createElement('div');
+    var node = ReactDOM.render(stub, container);
+
+    expect(node.options[0].selected).toBe(false); // a
+    expect(node.options[1].selected).toBe(true); // b
+    expect(node.options[2].selected).toBe(false); // c
+  });
 });
diff --git a/src/renderers/dom/client/wrappers/__tests__/ReactDOMTextarea-test.js b/src/renderers/dom/client/wrappers/__tests__/ReactDOMTextarea-test.js
index 6a8f4d5d898d..a4bfa88076c6 100644
--- a/src/renderers/dom/client/wrappers/__tests__/ReactDOMTextarea-test.js
+++ b/src/renderers/dom/client/wrappers/__tests__/ReactDOMTextarea-test.js
@@ -13,17 +13,19 @@
 
 var emptyFunction = require('emptyFunction');
 
-describe('ReactDOMTextarea', function() {
+describe('ReactDOMTextarea', () => {
   var React;
   var ReactDOM;
+  var ReactDOMServer;
   var ReactLink;
   var ReactTestUtils;
 
   var renderTextarea;
 
-  beforeEach(function() {
+  beforeEach(() => {
     React = require('React');
     ReactDOM = require('ReactDOM');
+    ReactDOMServer = require('ReactDOMServer');
     ReactLink = require('ReactLink');
     ReactTestUtils = require('ReactTestUtils');
 
@@ -31,44 +33,46 @@ describe('ReactDOMTextarea', function() {
       if (!container) {
         container = document.createElement('div');
       }
-      var stub = ReactDOM.render(component, container);
-      var node = ReactDOM.findDOMNode(stub);
+      var node = ReactDOM.render(component, container);
+
       // Fixing jsdom's quirky behavior -- in reality, the parser should strip
       // off the leading newline but we need to do it by hand here.
-      node.value = node.innerHTML.replace(/^\n/, '');
-      return stub;
+      node.defaultValue = node.innerHTML.replace(/^\n/, '');
+      return node;
     };
   });
 
-  it('should allow setting `defaultValue`', function() {
+  it('should allow setting `defaultValue`', () => {
     var container = document.createElement('div');
-    var stub = renderTextarea(<textarea defaultValue="giraffe" />, container);
-    var node = ReactDOM.findDOMNode(stub);
+    var node = renderTextarea(<textarea defaultValue="giraffe" />, container);
 
     expect(node.value).toBe('giraffe');
 
     // Changing `defaultValue` should do nothing.
-    stub = renderTextarea(<textarea defaultValue="gorilla" />, container);
+    renderTextarea(<textarea defaultValue="gorilla" />, container);
     expect(node.value).toEqual('giraffe');
+
+    node.value = 'cat';
+
+    renderTextarea(<textarea defaultValue="monkey" />, container);
+    expect(node.value).toEqual('cat');
   });
 
-  it('should display `defaultValue` of number 0', function() {
+  it('should display `defaultValue` of number 0', () => {
     var stub = <textarea defaultValue={0} />;
-    stub = renderTextarea(stub);
-    var node = ReactDOM.findDOMNode(stub);
+    var node = renderTextarea(stub);
 
     expect(node.value).toBe('0');
   });
 
-  it('should display "false" for `defaultValue` of `false`', function() {
+  it('should display "false" for `defaultValue` of `false`', () => {
     var stub = <textarea defaultValue={false} />;
-    stub = renderTextarea(stub);
-    var node = ReactDOM.findDOMNode(stub);
+    var node = renderTextarea(stub);
 
     expect(node.value).toBe('false');
   });
 
-  it('should display "foobar" for `defaultValue` of `objToString`', function() {
+  it('should display "foobar" for `defaultValue` of `objToString`', () => {
     var objToString = {
       toString: function() {
         return 'foobar';
@@ -76,78 +80,103 @@ describe('ReactDOMTextarea', function() {
     };
 
     var stub = <textarea defaultValue={objToString} />;
-    stub = renderTextarea(stub);
-    var node = ReactDOM.findDOMNode(stub);
+    var node = renderTextarea(stub);
 
     expect(node.value).toBe('foobar');
   });
 
-  it('should not render value as an attribute', function() {
+  it('should set defaultValue', () => {
+    var container = document.createElement('div');
+    ReactDOM.render(<textarea defaultValue="foo" />, container);
+    ReactDOM.render(<textarea defaultValue="bar" />, container);
+    ReactDOM.render(<textarea defaultValue="noise" />, container);
+    expect(container.firstChild.defaultValue).toBe('noise');
+  });
+
+  it('should not render value as an attribute', () => {
     var stub = <textarea value="giraffe" onChange={emptyFunction} />;
-    stub = renderTextarea(stub);
-    var node = ReactDOM.findDOMNode(stub);
+    var node = renderTextarea(stub);
 
     expect(node.getAttribute('value')).toBe(null);
   });
 
-  it('should display `value` of number 0', function() {
+  it('should display `value` of number 0', () => {
     var stub = <textarea value={0} />;
-    stub = renderTextarea(stub);
-    var node = ReactDOM.findDOMNode(stub);
+    var node = renderTextarea(stub);
 
     expect(node.value).toBe('0');
   });
 
-  it('should allow setting `value` to `giraffe`', function() {
+  it('should update defaultValue to empty string', () => {
+    var container = document.createElement('div');
+    ReactDOM.render(<textarea defaultValue={'foo'} />, container);
+    ReactDOM.render(<textarea defaultValue={''} />, container);
+    expect(container.firstChild.defaultValue).toBe('');
+  });
+
+  it('should allow setting `value` to `giraffe`', () => {
     var container = document.createElement('div');
     var stub = <textarea value="giraffe" onChange={emptyFunction} />;
-    stub = renderTextarea(stub, container);
-    var node = ReactDOM.findDOMNode(stub);
+    var node = renderTextarea(stub, container);
 
     expect(node.value).toBe('giraffe');
 
     stub = ReactDOM.render(
       <textarea value="gorilla" onChange={emptyFunction} />,
-      container
+      container,
     );
     expect(node.value).toEqual('gorilla');
   });
 
-  it('should allow setting `value` to `true`', function() {
+  it('should render defaultValue for SSR', () => {
+    var markup = ReactDOMServer.renderToString(<textarea defaultValue="1" />);
+    var div = document.createElement('div');
+    div.innerHTML = markup;
+    expect(div.firstChild.innerHTML).toBe('1');
+    expect(div.firstChild.getAttribute('defaultValue')).toBe(null);
+  });
+
+  it('should render value for SSR', () => {
+    var element = <textarea value="1" onChange={function() {}} />;
+    var markup = ReactDOMServer.renderToString(element);
+    var div = document.createElement('div');
+    div.innerHTML = markup;
+    expect(div.firstChild.innerHTML).toBe('1');
+    expect(div.firstChild.getAttribute('defaultValue')).toBe(null);
+  });
+
+  it('should allow setting `value` to `true`', () => {
     var container = document.createElement('div');
     var stub = <textarea value="giraffe" onChange={emptyFunction} />;
-    stub = renderTextarea(stub, container);
-    var node = ReactDOM.findDOMNode(stub);
+    var node = renderTextarea(stub, container);
 
     expect(node.value).toBe('giraffe');
 
     stub = ReactDOM.render(
       <textarea value={true} onChange={emptyFunction} />,
-      container
+      container,
     );
     expect(node.value).toEqual('true');
   });
 
-  it('should allow setting `value` to `false`', function() {
+  it('should allow setting `value` to `false`', () => {
     var container = document.createElement('div');
     var stub = <textarea value="giraffe" onChange={emptyFunction} />;
-    stub = renderTextarea(stub, container);
-    var node = ReactDOM.findDOMNode(stub);
+    var node = renderTextarea(stub, container);
 
     expect(node.value).toBe('giraffe');
 
     stub = ReactDOM.render(
       <textarea value={false} onChange={emptyFunction} />,
-      container
+      container,
     );
     expect(node.value).toEqual('false');
   });
 
-  it('should allow setting `value` to `objToString`', function() {
+  it('should allow setting `value` to `objToString`', () => {
     var container = document.createElement('div');
     var stub = <textarea value="giraffe" onChange={emptyFunction} />;
-    stub = renderTextarea(stub, container);
-    var node = ReactDOM.findDOMNode(stub);
+    var node = renderTextarea(stub, container);
 
     expect(node.value).toBe('giraffe');
 
@@ -158,30 +187,77 @@ describe('ReactDOMTextarea', function() {
     };
     stub = ReactDOM.render(
       <textarea value={objToString} onChange={emptyFunction} />,
-      container
+      container,
     );
     expect(node.value).toEqual('foo');
   });
 
-  it('should properly control a value of number `0`', function() {
+  it('should take updates to `defaultValue` for uncontrolled textarea', () => {
+    var container = document.createElement('div');
+
+    var node = ReactDOM.render(<textarea defaultValue="0" />, container);
+
+    expect(node.value).toBe('0');
+
+    ReactDOM.render(<textarea defaultValue="1" />, container);
+
+    expect(node.value).toBe('0');
+  });
+
+  it('should take updates to children in lieu of `defaultValue` for uncontrolled textarea', () => {
+    var container = document.createElement('div');
+
+    var node = ReactDOM.render(<textarea defaultValue="0" />, container);
+
+    expect(node.value).toBe('0');
+
+    spyOn(console, 'error'); // deprecation warning for `children` content
+
+    ReactDOM.render(<textarea>1</textarea>, container);
+
+    expect(node.value).toBe('0');
+  });
+
+  it('should not incur unnecessary DOM mutations', () => {
+    var container = document.createElement('div');
+    ReactDOM.render(<textarea value="a" onChange={emptyFunction} />, container);
+
+    var node = container.firstChild;
+    var nodeValue = 'a';
+    var nodeValueSetter = jest.genMockFn();
+    Object.defineProperty(node, 'value', {
+      get: function() {
+        return nodeValue;
+      },
+      set: nodeValueSetter.mockImplementation(function(newValue) {
+        nodeValue = newValue;
+      }),
+    });
+
+    ReactDOM.render(<textarea value="a" onChange={emptyFunction} />, container);
+    expect(nodeValueSetter.mock.calls.length).toBe(0);
+
+    ReactDOM.render(<textarea value="b" onChange={emptyFunction} />, container);
+    expect(nodeValueSetter.mock.calls.length).toBe(1);
+  });
+
+  it('should properly control a value of number `0`', () => {
     var stub = <textarea value={0} onChange={emptyFunction} />;
-    stub = renderTextarea(stub);
-    var node = ReactDOM.findDOMNode(stub);
+    var node = renderTextarea(stub);
 
     node.value = 'giraffe';
     ReactTestUtils.Simulate.change(node);
     expect(node.value).toBe('0');
   });
 
-  it('should treat children like `defaultValue`', function() {
+  it('should treat children like `defaultValue`', () => {
     spyOn(console, 'error');
 
     var container = document.createElement('div');
     var stub = <textarea>giraffe</textarea>;
-    stub = renderTextarea(stub, container);
-    var node = ReactDOM.findDOMNode(stub);
+    var node = renderTextarea(stub, container);
 
-    expect(console.error.argsForCall.length).toBe(1);
+    expect(console.error.calls.count()).toBe(1);
     expect(node.value).toBe('giraffe');
 
     // Changing children should do nothing, it functions like `defaultValue`.
@@ -189,112 +265,148 @@ describe('ReactDOMTextarea', function() {
     expect(node.value).toEqual('giraffe');
   });
 
-  it('should allow numbers as children', function() {
+  it('should keep value when switching to uncontrolled element if not changed', () => {
+    var container = document.createElement('div');
+
+    var node = renderTextarea(
+      <textarea value="kitten" onChange={emptyFunction} />,
+      container,
+    );
+
+    expect(node.value).toBe('kitten');
+
+    ReactDOM.render(<textarea defaultValue="gorilla" />, container);
+
+    expect(node.value).toEqual('kitten');
+  });
+
+  it('should keep value when switching to uncontrolled element if changed', () => {
+    var container = document.createElement('div');
+
+    var node = renderTextarea(
+      <textarea value="kitten" onChange={emptyFunction} />,
+      container,
+    );
+
+    expect(node.value).toBe('kitten');
+
+    ReactDOM.render(
+      <textarea value="puppies" onChange={emptyFunction} />,
+      container,
+    );
+
+    expect(node.value).toBe('puppies');
+
+    ReactDOM.render(<textarea defaultValue="gorilla" />, container);
+
+    expect(node.value).toEqual('puppies');
+  });
+
+  it('should allow numbers as children', () => {
     spyOn(console, 'error');
-    var node = ReactDOM.findDOMNode(renderTextarea(<textarea>{17}</textarea>));
-    expect(console.error.argsForCall.length).toBe(1);
+    var node = renderTextarea(<textarea>{17}</textarea>);
+    expect(console.error.calls.count()).toBe(1);
     expect(node.value).toBe('17');
   });
 
-  it('should allow booleans as children', function() {
+  it('should allow booleans as children', () => {
     spyOn(console, 'error');
-    var node = ReactDOM.findDOMNode(renderTextarea(<textarea>{false}</textarea>));
-    expect(console.error.argsForCall.length).toBe(1);
+    var node = renderTextarea(<textarea>{false}</textarea>);
+    expect(console.error.calls.count()).toBe(1);
     expect(node.value).toBe('false');
   });
 
-  it('should allow objects as children', function() {
+  it('should allow objects as children', () => {
     spyOn(console, 'error');
     var obj = {
       toString: function() {
         return 'sharkswithlasers';
       },
     };
-    var node = ReactDOM.findDOMNode(renderTextarea(<textarea>{obj}</textarea>));
-    expect(console.error.argsForCall.length).toBe(1);
+    var node = renderTextarea(<textarea>{obj}</textarea>);
+    expect(console.error.calls.count()).toBe(1);
     expect(node.value).toBe('sharkswithlasers');
   });
 
-  it('should throw with multiple or invalid children', function() {
+  it('should throw with multiple or invalid children', () => {
     spyOn(console, 'error');
 
     expect(function() {
       ReactTestUtils.renderIntoDocument(
-        <textarea>{'hello'}{'there'}</textarea>
+        <textarea>{'hello'}{'there'}</textarea>,
       );
     }).toThrow();
 
-    expect(console.error.argsForCall.length).toBe(1);
+    expect(console.error.calls.count()).toBe(1);
 
     var node;
     expect(function() {
-      node = ReactDOM.findDOMNode(renderTextarea(<textarea><strong /></textarea>));
+      node = renderTextarea(<textarea><strong /></textarea>);
     }).not.toThrow();
 
     expect(node.value).toBe('[object Object]');
 
-    expect(console.error.argsForCall.length).toBe(2);
+    expect(console.error.calls.count()).toBe(2);
   });
 
-  it('should support ReactLink', function() {
-    var link = new ReactLink('yolo', jest.genMockFn());
+  it('should support ReactLink', () => {
+    var link = new ReactLink('yolo', jest.fn());
     var instance = <textarea valueLink={link} />;
 
     spyOn(console, 'error');
     instance = renderTextarea(instance);
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
-      '`valueLink` prop on `textarea` is deprecated; set `value` and `onChange` instead.'
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      '`valueLink` prop on `textarea` is deprecated; set `value` and `onChange` instead.',
     );
 
-
-    expect(ReactDOM.findDOMNode(instance).value).toBe('yolo');
+    expect(instance.value).toBe('yolo');
     expect(link.value).toBe('yolo');
     expect(link.requestChange.mock.calls.length).toBe(0);
 
-    ReactDOM.findDOMNode(instance).value = 'test';
-    ReactTestUtils.Simulate.change(ReactDOM.findDOMNode(instance));
+    instance.value = 'test';
+    ReactTestUtils.Simulate.change(instance);
 
     expect(link.requestChange.mock.calls.length).toBe(1);
     expect(link.requestChange.mock.calls[0][0]).toEqual('test');
   });
 
-  it('should unmount', function() {
+  it('should unmount', () => {
     var container = document.createElement('div');
     renderTextarea(<textarea />, container);
     ReactDOM.unmountComponentAtNode(container);
   });
 
-  it('should warn if value is null', function() {
+  it('should warn if value is null', () => {
     spyOn(console, 'error');
 
     ReactTestUtils.renderIntoDocument(<textarea value={null} />);
-    expect(console.error.argsForCall[0][0]).toContain(
+    expect(console.error.calls.argsFor(0)[0]).toContain(
       '`value` prop on `textarea` should not be null. ' +
-      'Consider using the empty string to clear the component or `undefined` ' +
-      'for uncontrolled components.'
+        'Consider using the empty string to clear the component or `undefined` ' +
+        'for uncontrolled components.',
     );
 
     ReactTestUtils.renderIntoDocument(<textarea value={null} />);
-    expect(console.error.argsForCall.length).toBe(1);
+    expect(console.error.calls.count()).toBe(1);
   });
 
-  it('should warn if value and defaultValue are specified', function() {
+  it('should warn if value and defaultValue are specified', () => {
     spyOn(console, 'error');
     ReactTestUtils.renderIntoDocument(
-      <textarea value="foo" defaultValue="bar" readOnly={true} />
+      <textarea value="foo" defaultValue="bar" readOnly={true} />,
     );
-    expect(console.error.argsForCall[0][0]).toContain(
+    expect(console.error.calls.argsFor(0)[0]).toContain(
       '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'
+        '(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',
     );
 
     ReactTestUtils.renderIntoDocument(
-      <textarea value="foo" defaultValue="bar" readOnly={true} />
+      <textarea value="foo" defaultValue="bar" readOnly={true} />,
     );
-    expect(console.error.argsForCall.length).toBe(1);
+    expect(console.error.calls.count()).toBe(1);
   });
 });
diff --git a/src/renderers/dom/fiber/ReactDOMFiber.js b/src/renderers/dom/fiber/ReactDOMFiber.js
new file mode 100644
index 000000000000..88a6b0cdbd7f
--- /dev/null
+++ b/src/renderers/dom/fiber/ReactDOMFiber.js
@@ -0,0 +1,136 @@
+/**
+ * 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 ReactDOMFiber
+ * @flow
+ */
+
+'use strict';
+
+import type {HostChildren} from 'ReactFiberReconciler';
+
+var ReactFiberReconciler = require('ReactFiberReconciler');
+
+var warning = require('warning');
+
+type DOMContainerElement = Element & {_reactRootContainer: ?Object};
+
+type Container = Element;
+type Props = {};
+type Instance = Element;
+
+function recursivelyAppendChildren(
+  parent: Element,
+  child: HostChildren<Instance>,
+) {
+  if (!child) {
+    return;
+  }
+  /* $FlowFixMe: Element should have this property. */
+  if (child.nodeType === 1) {
+    /* $FlowFixMe: Refinement issue. I don't know how to express different. */
+    parent.appendChild(child);
+  } else {
+    /* As a result of the refinement issue this type isn't known. */
+    let node: any = child;
+    do {
+      recursivelyAppendChildren(parent, node.output);
+    } while ((node = node.sibling));
+  }
+}
+
+var DOMRenderer = ReactFiberReconciler({
+  updateContainer(
+    container: Container,
+    children: HostChildren<Instance>,
+  ): void {
+    container.innerHTML = '';
+    recursivelyAppendChildren(container, children);
+  },
+
+  createInstance(
+    type: string,
+    props: Props,
+    children: HostChildren<Instance>,
+  ): Instance {
+    const domElement = document.createElement(type);
+    recursivelyAppendChildren(domElement, children);
+    if (typeof props.children === 'string') {
+      domElement.textContent = props.children;
+    }
+    return domElement;
+  },
+
+  prepareUpdate(
+    domElement: Instance,
+    oldProps: Props,
+    newProps: Props,
+    children: HostChildren<Instance>,
+  ): boolean {
+    return true;
+  },
+
+  commitUpdate(
+    domElement: Instance,
+    oldProps: Props,
+    newProps: Props,
+    children: HostChildren<Instance>,
+  ): void {
+    domElement.innerHTML = '';
+    recursivelyAppendChildren(domElement, children);
+    if (typeof newProps.children === 'string') {
+      domElement.textContent = newProps.children;
+    }
+  },
+
+  deleteInstance(instance: Instance): void {
+    // Noop
+  },
+
+  scheduleAnimationCallback: window.requestAnimationFrame,
+
+  scheduleDeferredCallback: window.requestIdleCallback,
+});
+
+var warned = false;
+
+function warnAboutUnstableUse() {
+  warning(
+    warned,
+    'You are using React DOM Fiber which is an experimental renderer. ' +
+      'It is likely to have bugs, breaking changes and is unsupported.',
+  );
+  warned = true;
+}
+
+var ReactDOM = {
+  render(element: ReactElement<any>, container: DOMContainerElement) {
+    warnAboutUnstableUse();
+    if (!container._reactRootContainer) {
+      container._reactRootContainer = DOMRenderer.mountContainer(
+        element,
+        container,
+      );
+    } else {
+      DOMRenderer.updateContainer(element, container._reactRootContainer);
+    }
+  },
+
+  unmountComponentAtNode(container: DOMContainerElement) {
+    warnAboutUnstableUse();
+    const root = container._reactRootContainer;
+    if (root) {
+      // TODO: Is it safe to reset this now or should I wait since this
+      // unmount could be deferred?
+      container._reactRootContainer = null;
+      DOMRenderer.unmountContainer(root);
+    }
+  },
+};
+
+module.exports = ReactDOM;
diff --git a/src/renderers/dom/server/ReactMarkupChecksum.js b/src/renderers/dom/server/ReactMarkupChecksum.js
index 8d02654263f4..09e477c47722 100644
--- a/src/renderers/dom/server/ReactMarkupChecksum.js
+++ b/src/renderers/dom/server/ReactMarkupChecksum.js
@@ -16,7 +16,6 @@ var adler32 = require('adler32');
 var TAG_END = /\/?>/;
 var COMMENT_START = /^<\!\-\-/;
 
-
 var ReactMarkupChecksum = {
   CHECKSUM_ATTR_NAME: 'data-react-checksum',
 
@@ -33,7 +32,7 @@ var ReactMarkupChecksum = {
     } else {
       return markup.replace(
         TAG_END,
-        ' ' + ReactMarkupChecksum.CHECKSUM_ATTR_NAME + '="' + checksum + '"$&'
+        ' ' + ReactMarkupChecksum.CHECKSUM_ATTR_NAME + '="' + checksum + '"$&',
       );
     }
   },
@@ -45,7 +44,7 @@ var ReactMarkupChecksum = {
    */
   canReuseMarkup: function(markup, element) {
     var existingChecksum = element.getAttribute(
-      ReactMarkupChecksum.CHECKSUM_ATTR_NAME
+      ReactMarkupChecksum.CHECKSUM_ATTR_NAME,
     );
     existingChecksum = existingChecksum && parseInt(existingChecksum, 10);
     var markupChecksum = adler32(markup);
diff --git a/src/renderers/dom/server/ReactServerRendering.js b/src/renderers/dom/server/ReactServerRendering.js
index 5a5d604b7dd8..2c7b7b5d05e9 100644
--- a/src/renderers/dom/server/ReactServerRendering.js
+++ b/src/renderers/dom/server/ReactServerRendering.js
@@ -10,19 +10,22 @@
  */
 'use strict';
 
+var React = require('React');
 var ReactDOMContainerInfo = require('ReactDOMContainerInfo');
 var ReactDefaultBatchingStrategy = require('ReactDefaultBatchingStrategy');
-var ReactElement = require('ReactElement');
+var ReactInstrumentation = require('ReactInstrumentation');
 var ReactMarkupChecksum = require('ReactMarkupChecksum');
+var ReactReconciler = require('ReactReconciler');
 var ReactServerBatchingStrategy = require('ReactServerBatchingStrategy');
-var ReactServerRenderingTransaction =
-  require('ReactServerRenderingTransaction');
+var ReactServerRenderingTransaction = require('ReactServerRenderingTransaction');
 var ReactUpdates = require('ReactUpdates');
 
 var emptyObject = require('emptyObject');
 var instantiateReactComponent = require('instantiateReactComponent');
 var invariant = require('invariant');
 
+var pendingTransactions = 0;
+
 /**
  * @param {ReactElement} element
  * @return {string} the HTML markup
@@ -34,39 +37,63 @@ function renderToStringImpl(element, makeStaticMarkup) {
 
     transaction = ReactServerRenderingTransaction.getPooled(makeStaticMarkup);
 
+    pendingTransactions++;
+
     return transaction.perform(function() {
-      var componentInstance = instantiateReactComponent(element);
-      var markup = componentInstance.mountComponent(
+      var componentInstance = instantiateReactComponent(element, true);
+      var markup = ReactReconciler.mountComponent(
+        componentInstance,
         transaction,
         null,
         ReactDOMContainerInfo(),
-        emptyObject
+        emptyObject,
+        0 /* parentDebugID */,
       );
+      if (__DEV__) {
+        ReactInstrumentation.debugTool.onUnmountComponent(
+          componentInstance._debugID,
+        );
+      }
       if (!makeStaticMarkup) {
         markup = ReactMarkupChecksum.addChecksumToMarkup(markup);
       }
       return markup;
     }, null);
   } finally {
+    pendingTransactions--;
     ReactServerRenderingTransaction.release(transaction);
     // Revert to the DOM batching strategy since these two renderers
     // currently share these stateful modules.
-    ReactUpdates.injection.injectBatchingStrategy(ReactDefaultBatchingStrategy);
+    if (!pendingTransactions) {
+      ReactUpdates.injection.injectBatchingStrategy(
+        ReactDefaultBatchingStrategy,
+      );
+    }
   }
 }
 
+/**
+ * Render a ReactElement to its initial HTML. This should only be used on the
+ * server.
+ * See https://facebook.github.io/react/docs/top-level-api.html#reactdomserver.rendertostring
+ */
 function renderToString(element) {
   invariant(
-    ReactElement.isValidElement(element),
-    'renderToString(): You must pass a valid ReactElement.'
+    React.isValidElement(element),
+    'renderToString(): You must pass a valid ReactElement.',
   );
   return renderToStringImpl(element, false);
 }
 
+/**
+ * Similar to renderToString, except this doesn't create extra DOM attributes
+ * such as data-react-id that React uses internally.
+ * See https://facebook.github.io/react/docs/top-level-api.html#reactdomserver.rendertostaticmarkup
+ */
 function renderToStaticMarkup(element) {
   invariant(
-    ReactElement.isValidElement(element),
-    'renderToStaticMarkup(): You must pass a valid ReactElement.'
+    React.isValidElement(element),
+    'renderToStaticMarkup(): You must pass a valid ReactElement.',
   );
   return renderToStringImpl(element, true);
 }
diff --git a/src/renderers/dom/server/ReactServerRenderingTransaction.js b/src/renderers/dom/server/ReactServerRenderingTransaction.js
index 176a550c599a..2fa930cc43d2 100644
--- a/src/renderers/dom/server/ReactServerRenderingTransaction.js
+++ b/src/renderers/dom/server/ReactServerRenderingTransaction.js
@@ -13,7 +13,8 @@
 
 var PooledClass = require('PooledClass');
 var Transaction = require('Transaction');
-
+var ReactInstrumentation = require('ReactInstrumentation');
+var ReactServerUpdateQueue = require('ReactServerUpdateQueue');
 
 /**
  * Executed within the scope of the `Transaction` instance. Consider these as
@@ -22,6 +23,13 @@ var Transaction = require('Transaction');
  */
 var TRANSACTION_WRAPPERS = [];
 
+if (__DEV__) {
+  TRANSACTION_WRAPPERS.push({
+    initialize: ReactInstrumentation.debugTool.onBeginFlush,
+    close: ReactInstrumentation.debugTool.onEndFlush,
+  });
+}
+
 var noopCallbackQueue = {
   enqueue: function() {},
 };
@@ -34,6 +42,7 @@ function ReactServerRenderingTransaction(renderToStaticMarkup) {
   this.reinitializeTransaction();
   this.renderToStaticMarkup = renderToStaticMarkup;
   this.useCreateElement = false;
+  this.updateQueue = new ReactServerUpdateQueue(this);
 }
 
 var Mixin = {
@@ -54,20 +63,25 @@ var Mixin = {
     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() {
-  },
-};
+  destructor: function() {},
 
+  checkpoint: function() {},
+
+  rollback: function() {},
+};
 
-Object.assign(
-  ReactServerRenderingTransaction.prototype,
-  Transaction.Mixin,
-  Mixin
-);
+Object.assign(ReactServerRenderingTransaction.prototype, Transaction, Mixin);
 
 PooledClass.addPoolingTo(ReactServerRenderingTransaction);
 
diff --git a/src/renderers/dom/server/ReactServerUpdateQueue.js b/src/renderers/dom/server/ReactServerUpdateQueue.js
new file mode 100644
index 000000000000..30ebd5bf7326
--- /dev/null
+++ b/src/renderers/dom/server/ReactServerUpdateQueue.js
@@ -0,0 +1,148 @@
+/**
+ * Copyright 2015-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 ReactServerUpdateQueue
+ * @flow
+ */
+
+'use strict';
+
+var ReactUpdateQueue = require('ReactUpdateQueue');
+
+var warning = require('warning');
+
+import type {Transaction} from 'Transaction';
+
+function warnNoop(
+  publicInstance: ReactComponent<any, any, any>,
+  callerName: string,
+) {
+  if (__DEV__) {
+    var constructor = publicInstance.constructor;
+    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',
+    );
+  }
+}
+
+/**
+ * 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
+ */
+class ReactServerUpdateQueue {
+  transaction: Transaction;
+
+  constructor(transaction: Transaction) {
+    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
+   */
+  isMounted(publicInstance: ReactComponent<any, any, any>): boolean {
+    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(
+    publicInstance: ReactComponent<any, any, any>,
+    callback?: Function,
+    callerName?: string,
+  ) {
+    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
+   */
+  enqueueForceUpdate(publicInstance: ReactComponent<any, any, any>) {
+    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
+   */
+  enqueueReplaceState(
+    publicInstance: ReactComponent<any, any, any>,
+    completeState: Object | Function,
+  ) {
+    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
+   */
+  enqueueSetState(
+    publicInstance: ReactComponent<any, any, any>,
+    partialState: Object | Function,
+  ) {
+    if (this.transaction.isInTransaction()) {
+      ReactUpdateQueue.enqueueSetState(publicInstance, partialState);
+    } else {
+      warnNoop(publicInstance, 'setState');
+    }
+  }
+}
+
+module.exports = ReactServerUpdateQueue;
diff --git a/src/renderers/dom/server/__tests__/ReactServerRendering-test.js b/src/renderers/dom/server/__tests__/ReactServerRendering-test.js
index c53b0be74237..50e3be5c85d3 100644
--- a/src/renderers/dom/server/__tests__/ReactServerRendering-test.js
+++ b/src/renderers/dom/server/__tests__/ReactServerRendering-test.js
@@ -22,8 +22,8 @@ var ReactServerRendering;
 var ID_ATTRIBUTE_NAME;
 var ROOT_ATTRIBUTE_NAME;
 
-describe('ReactServerRendering', function() {
-  beforeEach(function() {
+describe('ReactServerRendering', () => {
+  beforeEach(() => {
     jest.resetModuleRegistry();
     React = require('React');
     ReactDOM = require('ReactDOM');
@@ -40,136 +40,175 @@ describe('ReactServerRendering', function() {
     ROOT_ATTRIBUTE_NAME = DOMProperty.ROOT_ATTRIBUTE_NAME;
   });
 
-  describe('renderToString', function() {
-    it('should generate simple markup', function() {
+  describe('renderToString', () => {
+    it('should generate simple markup', () => {
       var response = ReactServerRendering.renderToString(
-        <span>hello world</span>
+        <span>hello world</span>,
       );
       expect(response).toMatch(
-        '<span ' + ROOT_ATTRIBUTE_NAME + '="" ' +
-          ID_ATTRIBUTE_NAME + '="[^"]+" ' +
-          ReactMarkupChecksum.CHECKSUM_ATTR_NAME + '="[^"]+">hello world</span>'
+        new RegExp(
+          '<span ' +
+            ROOT_ATTRIBUTE_NAME +
+            '="" ' +
+            ID_ATTRIBUTE_NAME +
+            '="[^"]+" ' +
+            ReactMarkupChecksum.CHECKSUM_ATTR_NAME +
+            '="[^"]+">hello world</span>',
+        ),
       );
     });
 
-    it('should generate simple markup for self-closing tags', function() {
-      var response = ReactServerRendering.renderToString(
-        <img />
-      );
+    it('should generate simple markup for self-closing tags', () => {
+      var response = ReactServerRendering.renderToString(<img />);
       expect(response).toMatch(
-        '<img ' + ROOT_ATTRIBUTE_NAME + '="" ' +
-          ID_ATTRIBUTE_NAME + '="[^"]+" ' +
-          ReactMarkupChecksum.CHECKSUM_ATTR_NAME + '="[^"]+"/>'
+        new RegExp(
+          '<img ' +
+            ROOT_ATTRIBUTE_NAME +
+            '="" ' +
+            ID_ATTRIBUTE_NAME +
+            '="[^"]+" ' +
+            ReactMarkupChecksum.CHECKSUM_ATTR_NAME +
+            '="[^"]+"/>',
+        ),
       );
     });
 
-    it('should generate simple markup for attribute with `>` symbol', function() {
-      var response = ReactServerRendering.renderToString(
-        <img data-attr=">" />
-      );
+    it('should generate simple markup for attribute with `>` symbol', () => {
+      var response = ReactServerRendering.renderToString(<img data-attr=">" />);
       expect(response).toMatch(
-        '<img data-attr="&gt;" ' + ROOT_ATTRIBUTE_NAME + '="" ' +
-          ID_ATTRIBUTE_NAME + '="[^"]+" ' +
-          ReactMarkupChecksum.CHECKSUM_ATTR_NAME + '="[^"]+"/>'
+        new RegExp(
+          '<img data-attr="&gt;" ' +
+            ROOT_ATTRIBUTE_NAME +
+            '="" ' +
+            ID_ATTRIBUTE_NAME +
+            '="[^"]+" ' +
+            ReactMarkupChecksum.CHECKSUM_ATTR_NAME +
+            '="[^"]+"/>',
+        ),
       );
     });
 
-    it('should generate comment markup for component returns null', function() {
-      var NullComponent = React.createClass({
-        render: function() {
+    it('should generate comment markup for component returns null', () => {
+      class NullComponent extends React.Component {
+        render() {
           return null;
-        },
-      });
+        }
+      }
+
       var response = ReactServerRendering.renderToString(<NullComponent />);
       expect(response).toBe('<!-- react-empty: 1 -->');
     });
 
-    it('should not register event listeners', function() {
+    it('should not register event listeners', () => {
       var EventPluginHub = require('EventPluginHub');
-      var cb = jest.genMockFn();
+      var cb = jest.fn();
 
       ReactServerRendering.renderToString(
-        <span onClick={cb}>hello world</span>
+        <span onClick={cb}>hello world</span>,
       );
       expect(EventPluginHub.__getListenerBank()).toEqual({});
     });
 
-    it('should render composite components', function() {
-      var Parent = React.createClass({
-        render: function() {
+    it('should render composite components', () => {
+      class Parent extends React.Component {
+        render() {
           return <div><Child name="child" /></div>;
-        },
-      });
-      var Child = React.createClass({
-        render: function() {
+        }
+      }
+
+      class Child extends React.Component {
+        render() {
           return <span>My name is {this.props.name}</span>;
-        },
-      });
-      var response = ReactServerRendering.renderToString(
-        <Parent />
-      );
+        }
+      }
+
+      var response = ReactServerRendering.renderToString(<Parent />);
       expect(response).toMatch(
-        '<div ' + ROOT_ATTRIBUTE_NAME + '="" ' +
-          ID_ATTRIBUTE_NAME + '="[^"]+" ' +
-          ReactMarkupChecksum.CHECKSUM_ATTR_NAME + '="[^"]+">' +
-          '<span ' + ID_ATTRIBUTE_NAME + '="[^"]+">' +
+        new RegExp(
+          '<div ' +
+            ROOT_ATTRIBUTE_NAME +
+            '="" ' +
+            ID_ATTRIBUTE_NAME +
+            '="[^"]+" ' +
+            ReactMarkupChecksum.CHECKSUM_ATTR_NAME +
+            '="[^"]+">' +
+            '<span ' +
+            ID_ATTRIBUTE_NAME +
+            '="[^"]+">' +
             '<!-- react-text: [0-9]+ -->My name is <!-- /react-text -->' +
             '<!-- react-text: [0-9]+ -->child<!-- /react-text -->' +
-          '</span>' +
-        '</div>'
+            '</span>' +
+            '</div>',
+        ),
       );
     });
 
-    it('should only execute certain lifecycle methods', function() {
+    it('should only execute certain lifecycle methods', () => {
       function runTest() {
         var lifecycle = [];
-        var TestComponent = React.createClass({
-          componentWillMount: function() {
+
+        class TestComponent extends React.Component {
+          constructor(props) {
+            super(props);
+            lifecycle.push('getInitialState');
+            this.state = {name: 'TestComponent'};
+          }
+
+          componentWillMount() {
             lifecycle.push('componentWillMount');
-          },
-          componentDidMount: function() {
+          }
+
+          componentDidMount() {
             lifecycle.push('componentDidMount');
-          },
-          getInitialState: function() {
-            lifecycle.push('getInitialState');
-            return {name: 'TestComponent'};
-          },
-          render: function() {
+          }
+
+          render() {
             lifecycle.push('render');
             return <span>Component name: {this.state.name}</span>;
-          },
-          componentWillUpdate: function() {
+          }
+
+          componentWillUpdate() {
             lifecycle.push('componentWillUpdate');
-          },
-          componentDidUpdate: function() {
+          }
+
+          componentDidUpdate() {
             lifecycle.push('componentDidUpdate');
-          },
-          shouldComponentUpdate: function() {
+          }
+
+          shouldComponentUpdate() {
             lifecycle.push('shouldComponentUpdate');
-          },
-          componentWillReceiveProps: function() {
+          }
+
+          componentWillReceiveProps() {
             lifecycle.push('componentWillReceiveProps');
-          },
-          componentWillUnmount: function() {
+          }
+
+          componentWillUnmount() {
             lifecycle.push('componentWillUnmount');
-          },
-        });
+          }
+        }
 
-        var response = ReactServerRendering.renderToString(
-          <TestComponent />
-        );
+        var response = ReactServerRendering.renderToString(<TestComponent />);
 
         expect(response).toMatch(
-          '<span ' + ROOT_ATTRIBUTE_NAME + '="" ' +
-            ID_ATTRIBUTE_NAME + '="[^"]+" ' +
-            ReactMarkupChecksum.CHECKSUM_ATTR_NAME + '="[^"]+">' +
-            '<!-- react-text: [0-9]+ -->Component name: <!-- /react-text -->' +
-            '<!-- react-text: [0-9]+ -->TestComponent<!-- /react-text -->' +
-          '</span>'
-        );
-        expect(lifecycle).toEqual(
-          ['getInitialState', 'componentWillMount', 'render']
+          new RegExp(
+            '<span ' +
+              ROOT_ATTRIBUTE_NAME +
+              '="" ' +
+              ID_ATTRIBUTE_NAME +
+              '="[^"]+" ' +
+              ReactMarkupChecksum.CHECKSUM_ATTR_NAME +
+              '="[^"]+">' +
+              '<!-- react-text: [0-9]+ -->Component name: <!-- /react-text -->' +
+              '<!-- react-text: [0-9]+ -->TestComponent<!-- /react-text -->' +
+              '</span>',
+          ),
         );
+        expect(lifecycle).toEqual([
+          'getInitialState',
+          'componentWillMount',
+          'render',
+        ]);
       }
 
       runTest();
@@ -179,26 +218,28 @@ describe('ReactServerRendering', function() {
       runTest();
     });
 
-    it('should have the correct mounting behavior', function() {
+    it('should have the correct mounting behavior', () => {
       // This test is testing client-side behavior.
       ExecutionEnvironment.canUseDOM = true;
 
       var mountCount = 0;
       var numClicks = 0;
 
-      var TestComponent = React.createClass({
-        componentDidMount: function() {
+      class TestComponent extends React.Component {
+        componentDidMount() {
           mountCount++;
-        },
-        click: function() {
+        }
+
+        click = () => {
           numClicks++;
-        },
-        render: function() {
+        };
+
+        render() {
           return (
             <span ref="span" onClick={this.click}>Name: {this.props.name}</span>
           );
-        },
-      });
+        }
+      }
 
       var element = document.createElement('div');
       ReactDOM.render(<TestComponent />, element);
@@ -227,14 +268,20 @@ describe('ReactServerRendering', function() {
 
       ExecutionEnvironment.canUseDOM = false;
       lastMarkup = ReactServerRendering.renderToString(
-        <TestComponent name="x" />
+        <TestComponent name="x" />,
       );
       ExecutionEnvironment.canUseDOM = true;
       element.innerHTML = lastMarkup;
 
-      ReactDOM.render(<TestComponent name="x" />, element);
+      var instance = ReactDOM.render(<TestComponent name="x" />, element);
       expect(mountCount).toEqual(3);
       expect(element.innerHTML).toBe(lastMarkup);
+
+      // Ensure the events system works after mount into server markup
+      expect(numClicks).toEqual(0);
+      ReactTestUtils.Simulate.click(ReactDOM.findDOMNode(instance.refs.span));
+      expect(numClicks).toEqual(1);
+
       ReactDOM.unmountComponentAtNode(element);
       expect(element.innerHTML).toEqual('');
 
@@ -242,118 +289,128 @@ describe('ReactServerRendering', function() {
       // warn but do the right thing.
       element.innerHTML = lastMarkup;
       spyOn(console, 'error');
-      var instance = ReactDOM.render(<TestComponent name="y" />, element);
+      instance = ReactDOM.render(<TestComponent name="y" />, element);
       expect(mountCount).toEqual(4);
-      expect(console.error.argsForCall.length).toBe(1);
+      expect(console.error.calls.count()).toBe(1);
       expect(element.innerHTML.length > 0).toBe(true);
       expect(element.innerHTML).not.toEqual(lastMarkup);
 
-      // Ensure the events system works
-      expect(numClicks).toEqual(0);
-      ReactTestUtils.Simulate.click(ReactDOM.findDOMNode(instance.refs.span));
+      // Ensure the events system works after markup mismatch.
       expect(numClicks).toEqual(1);
+      ReactTestUtils.Simulate.click(ReactDOM.findDOMNode(instance.refs.span));
+      expect(numClicks).toEqual(2);
     });
 
-    it('should throw with silly args', function() {
+    it('should throw with silly args', () => {
       expect(
         ReactServerRendering.renderToString.bind(
           ReactServerRendering,
-          'not a component'
-        )
-      ).toThrow(
-        'renderToString(): You must pass a valid ReactElement.'
-      );
+          'not a component',
+        ),
+      ).toThrowError('renderToString(): You must pass a valid ReactElement.');
     });
   });
 
-  describe('renderToStaticMarkup', function() {
-    it('should not put checksum and React ID on components', function() {
-      var NestedComponent = React.createClass({
-        render: function() {
+  describe('renderToStaticMarkup', () => {
+    it('should not put checksum and React ID on components', () => {
+      class NestedComponent extends React.Component {
+        render() {
           return <div>inner text</div>;
-        },
-      });
+        }
+      }
 
-      var TestComponent = React.createClass({
-        render: function() {
+      class TestComponent extends React.Component {
+        render() {
           return <span><NestedComponent /></span>;
-        },
-      });
+        }
+      }
 
       var response = ReactServerRendering.renderToStaticMarkup(
-        <TestComponent />
+        <TestComponent />,
       );
 
       expect(response).toBe('<span><div>inner text</div></span>');
     });
 
-    it('should not put checksum and React ID on text components', function() {
-      var TestComponent = React.createClass({
-        render: function() {
+    it('should not put checksum and React ID on text components', () => {
+      class TestComponent extends React.Component {
+        render() {
           return <span>{'hello'} {'world'}</span>;
-        },
-      });
+        }
+      }
 
       var response = ReactServerRendering.renderToStaticMarkup(
-        <TestComponent />
+        <TestComponent />,
       );
 
       expect(response).toBe('<span>hello world</span>');
     });
 
-    it('should not register event listeners', function() {
+    it('should not register event listeners', () => {
       var EventPluginHub = require('EventPluginHub');
-      var cb = jest.genMockFn();
+      var cb = jest.fn();
 
-      ReactServerRendering.renderToString(
-        <span onClick={cb}>hello world</span>
+      ReactServerRendering.renderToStaticMarkup(
+        <span onClick={cb}>hello world</span>,
       );
       expect(EventPluginHub.__getListenerBank()).toEqual({});
     });
 
-    it('should only execute certain lifecycle methods', function() {
+    it('should only execute certain lifecycle methods', () => {
       function runTest() {
         var lifecycle = [];
-        var TestComponent = React.createClass({
-          componentWillMount: function() {
+
+        class TestComponent extends React.Component {
+          constructor(props) {
+            super(props);
+            lifecycle.push('getInitialState');
+            this.state = {name: 'TestComponent'};
+          }
+
+          componentWillMount() {
             lifecycle.push('componentWillMount');
-          },
-          componentDidMount: function() {
+          }
+
+          componentDidMount() {
             lifecycle.push('componentDidMount');
-          },
-          getInitialState: function() {
-            lifecycle.push('getInitialState');
-            return {name: 'TestComponent'};
-          },
-          render: function() {
+          }
+
+          render() {
             lifecycle.push('render');
             return <span>Component name: {this.state.name}</span>;
-          },
-          componentWillUpdate: function() {
+          }
+
+          componentWillUpdate() {
             lifecycle.push('componentWillUpdate');
-          },
-          componentDidUpdate: function() {
+          }
+
+          componentDidUpdate() {
             lifecycle.push('componentDidUpdate');
-          },
-          shouldComponentUpdate: function() {
+          }
+
+          shouldComponentUpdate() {
             lifecycle.push('shouldComponentUpdate');
-          },
-          componentWillReceiveProps: function() {
+          }
+
+          componentWillReceiveProps() {
             lifecycle.push('componentWillReceiveProps');
-          },
-          componentWillUnmount: function() {
+          }
+
+          componentWillUnmount() {
             lifecycle.push('componentWillUnmount');
-          },
-        });
+          }
+        }
 
         var response = ReactServerRendering.renderToStaticMarkup(
-          <TestComponent />
+          <TestComponent />,
         );
 
         expect(response).toBe('<span>Component name: TestComponent</span>');
-        expect(lifecycle).toEqual(
-          ['getInitialState', 'componentWillMount', 'render']
-        );
+        expect(lifecycle).toEqual([
+          'getInitialState',
+          'componentWillMount',
+          'render',
+        ]);
       }
 
       runTest();
@@ -363,35 +420,137 @@ describe('ReactServerRendering', function() {
       runTest();
     });
 
-    it('should throw with silly args', function() {
+    it('should throw with silly args', () => {
       expect(
         ReactServerRendering.renderToStaticMarkup.bind(
           ReactServerRendering,
-          'not a component'
-        )
-      ).toThrow(
-        'renderToStaticMarkup(): You must pass a valid ReactElement.'
+          'not a component',
+        ),
+      ).toThrowError(
+        'renderToStaticMarkup(): You must pass a valid ReactElement.',
       );
     });
 
-    it('allows setState in componentWillMount without using DOM', function() {
-      var Component = React.createClass({
-        componentWillMount: function() {
+    it('allows setState in componentWillMount without using DOM', () => {
+      class Component extends React.Component {
+        componentWillMount() {
           this.setState({text: 'hello, world'});
-        },
-        render: function() {
+        }
+
+        render() {
           return <div>{this.state.text}</div>;
-        },
-      });
+        }
+      }
 
       ReactReconcileTransaction.prototype.perform = function() {
         // We shouldn't ever be calling this on the server
         throw new Error('Browser reconcile transaction should not be used');
       };
-      var markup = ReactServerRendering.renderToString(
-        <Component />
-      );
+      var markup = ReactServerRendering.renderToString(<Component />);
       expect(markup.indexOf('hello, world') >= 0).toBe(true);
     });
+
+    it('renders components with different batching strategies', () => {
+      class StaticComponent extends React.Component {
+        render() {
+          const staticContent = ReactServerRendering.renderToStaticMarkup(
+            <div>
+              <img src="foo-bar.jpg" />
+            </div>,
+          );
+          return <div dangerouslySetInnerHTML={{__html: staticContent}} />;
+        }
+      }
+
+      class Component extends React.Component {
+        componentWillMount() {
+          this.setState({text: 'hello, world'});
+        }
+
+        render() {
+          return <div>{this.state.text}</div>;
+        }
+      }
+
+      expect(
+        ReactServerRendering.renderToString.bind(
+          ReactServerRendering,
+          <div>
+            <StaticComponent />
+            <Component />
+          </div>,
+        ),
+      ).not.toThrow();
+    });
+  });
+
+  it('warns with a no-op when an async setState is triggered', () => {
+    class Foo extends React.Component {
+      componentWillMount() {
+        this.setState({text: 'hello'});
+        setTimeout(() => {
+          this.setState({text: 'error'});
+        });
+      }
+      render() {
+        return <div onClick={() => {}}>{this.state.text}</div>;
+      }
+    }
+
+    spyOn(console, 'error');
+    ReactServerRendering.renderToString(<Foo />);
+    jest.runOnlyPendingTimers();
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.mostRecent().args[0]).toBe(
+      'Warning: setState(...): Can only update a mounting component.' +
+        ' This usually means you called setState() outside componentWillMount() on the server.' +
+        ' This is a no-op. Please check the code for the Foo component.',
+    );
+    var markup = ReactServerRendering.renderToStaticMarkup(<Foo />);
+    expect(markup).toBe('<div>hello</div>');
+  });
+
+  it('warns with a no-op when an async forceUpdate is triggered', () => {
+    class Baz extends React.Component {
+      componentWillMount() {
+        this.forceUpdate();
+        setTimeout(() => {
+          this.forceUpdate();
+        });
+      }
+
+      render() {
+        return <div onClick={() => {}} />;
+      }
+    }
+
+    spyOn(console, 'error');
+    ReactServerRendering.renderToString(<Baz />);
+    jest.runOnlyPendingTimers();
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.mostRecent().args[0]).toBe(
+      'Warning: forceUpdate(...): Can only update a mounting component. ' +
+        'This usually means you called forceUpdate() outside componentWillMount() on the server. ' +
+        'This is a no-op. Please check the code for the Baz component.',
+    );
+    var markup = ReactServerRendering.renderToStaticMarkup(<Baz />);
+    expect(markup).toBe('<div></div>');
+  });
+
+  it('should warn when children are mutated during render', () => {
+    spyOn(console, 'error');
+    function Wrapper(props) {
+      props.children[1] = <p key={1} />; // Mutation is illegal
+      return <div>{props.children}</div>;
+    }
+    expect(() => {
+      ReactServerRendering.renderToStaticMarkup(
+        <Wrapper>
+          <span key={0} />
+          <span key={1} />
+          <span key={2} />
+        </Wrapper>,
+      );
+    }).toThrowError(/Cannot assign to read only property.*/);
   });
 });
diff --git a/src/renderers/dom/shared/ARIADOMPropertyConfig.js b/src/renderers/dom/shared/ARIADOMPropertyConfig.js
new file mode 100644
index 000000000000..108278940cd1
--- /dev/null
+++ b/src/renderers/dom/shared/ARIADOMPropertyConfig.js
@@ -0,0 +1,74 @@
+/**
+ * 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 ARIADOMPropertyConfig
+ */
+
+'use strict';
+
+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;
diff --git a/src/renderers/dom/shared/CSSProperty.js b/src/renderers/dom/shared/CSSProperty.js
index fa0645c98705..609175152964 100644
--- a/src/renderers/dom/shared/CSSProperty.js
+++ b/src/renderers/dom/shared/CSSProperty.js
@@ -30,7 +30,13 @@ var isUnitlessNumber = {
   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,
diff --git a/src/renderers/dom/shared/CSSPropertyOperations.js b/src/renderers/dom/shared/CSSPropertyOperations.js
index aac1b75f87b1..0af3b09807c2 100644
--- a/src/renderers/dom/shared/CSSPropertyOperations.js
+++ b/src/renderers/dom/shared/CSSPropertyOperations.js
@@ -13,7 +13,7 @@
 
 var CSSProperty = require('CSSProperty');
 var ExecutionEnvironment = require('ExecutionEnvironment');
-var ReactPerf = require('ReactPerf');
+var ReactInstrumentation = require('ReactInstrumentation');
 
 var camelizeStyleName = require('camelizeStyleName');
 var dangerousStyleValue = require('dangerousStyleValue');
@@ -63,7 +63,7 @@ if (__DEV__) {
       'Unsupported style property %s. Did you mean %s?%s',
       name,
       camelizeStyleName(name),
-      checkRenderMessage(owner)
+      checkRenderMessage(owner),
     );
   };
 
@@ -78,7 +78,7 @@ if (__DEV__) {
       'Unsupported vendor-prefixed style property %s. Did you mean %s?%s',
       name,
       name.charAt(0).toUpperCase() + name.slice(1),
-      checkRenderMessage(owner)
+      checkRenderMessage(owner),
     );
   };
 
@@ -90,11 +90,11 @@ if (__DEV__) {
     warnedStyleValues[value] = true;
     warning(
       false,
-      'Style property values shouldn\'t contain a semicolon.%s ' +
-      'Try "%s: %s" instead.',
+      "Style property values shouldn't contain a semicolon.%s " +
+        'Try "%s: %s" instead.',
       checkRenderMessage(owner),
       name,
-      value.replace(badStyleValueWithSemicolonPattern, '')
+      value.replace(badStyleValueWithSemicolonPattern, ''),
     );
   };
 
@@ -108,7 +108,7 @@ if (__DEV__) {
       false,
       '`NaN` is an invalid value for the `%s` css style property.%s',
       name,
-      checkRenderMessage(owner)
+      checkRenderMessage(owner),
     );
   };
 
@@ -150,7 +150,6 @@ if (__DEV__) {
  * Operations for dealing with CSS properties.
  */
 var CSSPropertyOperations = {
-
   /**
    * Serializes a mapping of style properties for use as inline styles:
    *
@@ -170,14 +169,22 @@ var CSSPropertyOperations = {
       if (!styles.hasOwnProperty(styleName)) {
         continue;
       }
+      var isCustomProperty = styleName.indexOf('--') === 0;
       var styleValue = styles[styleName];
       if (__DEV__) {
-        warnValidStyle(styleName, styleValue, component);
+        if (!isCustomProperty) {
+          warnValidStyle(styleName, styleValue, component);
+        }
       }
       if (styleValue != null) {
         serialized += processStyleName(styleName) + ':';
         serialized +=
-          dangerousStyleValue(styleName, styleValue, component) + ';';
+          dangerousStyleValue(
+            styleName,
+            styleValue,
+            component,
+            isCustomProperty,
+          ) + ';';
       }
     }
     return serialized || null;
@@ -192,23 +199,37 @@ var CSSPropertyOperations = {
    * @param {ReactDOMComponent} component
    */
   setValueForStyles: function(node, styles, component) {
+    if (__DEV__) {
+      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 (__DEV__) {
-        warnValidStyle(styleName, styles[styleName], component);
+        if (!isCustomProperty) {
+          warnValidStyle(styleName, styles[styleName], component);
+        }
       }
       var styleValue = dangerousStyleValue(
         styleName,
         styles[styleName],
-        component
+        component,
+        isCustomProperty,
       );
       if (styleName === 'float' || styleName === 'cssFloat') {
         styleName = styleFloatAccessor;
       }
-      if (styleValue) {
+      if (isCustomProperty) {
+        style.setProperty(styleName, styleValue);
+      } else if (styleValue) {
         style[styleName] = styleValue;
       } else {
         var expansion =
@@ -226,11 +247,6 @@ var CSSPropertyOperations = {
       }
     }
   },
-
 };
 
-ReactPerf.measureMethods(CSSPropertyOperations, 'CSSPropertyOperations', {
-  setValueForStyles: 'setValueForStyles',
-});
-
 module.exports = CSSPropertyOperations;
diff --git a/src/renderers/dom/shared/DOMProperty.js b/src/renderers/dom/shared/DOMProperty.js
index 814bf5045436..3d2e36cfa694 100644
--- a/src/renderers/dom/shared/DOMProperty.js
+++ b/src/renderers/dom/shared/DOMProperty.js
@@ -23,7 +23,6 @@ var DOMPropertyInjection = {
    * specifies how the associated DOM property should be accessed or rendered.
    */
   MUST_USE_PROPERTY: 0x1,
-  HAS_SIDE_EFFECTS: 0x2,
   HAS_BOOLEAN_VALUE: 0x4,
   HAS_NUMERIC_VALUE: 0x8,
   HAS_POSITIVE_NUMERIC_VALUE: 0x10 | 0x8,
@@ -67,18 +66,18 @@ var DOMPropertyInjection = {
 
     if (domPropertyConfig.isCustomAttribute) {
       DOMProperty._isCustomAttributeFunctions.push(
-        domPropertyConfig.isCustomAttribute
+        domPropertyConfig.isCustomAttribute,
       );
     }
 
     for (var propName in Properties) {
       invariant(
         !DOMProperty.properties.hasOwnProperty(propName),
-        '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
+        "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,
       );
 
       var lowerCased = propName.toLowerCase();
@@ -91,26 +90,25 @@ var DOMPropertyInjection = {
         mutationMethod: null,
 
         mustUseProperty: checkMask(propConfig, Injection.MUST_USE_PROPERTY),
-        hasSideEffects: checkMask(propConfig, Injection.HAS_SIDE_EFFECTS),
         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),
+        hasPositiveNumericValue: checkMask(
+          propConfig,
+          Injection.HAS_POSITIVE_NUMERIC_VALUE,
+        ),
+        hasOverloadedBooleanValue: checkMask(
+          propConfig,
+          Injection.HAS_OVERLOADED_BOOLEAN_VALUE,
+        ),
       };
-
-      invariant(
-        propertyInfo.mustUseProperty || !propertyInfo.hasSideEffects,
-        'DOMProperty: Properties that have side effects must use property: %s',
-        propName
-      );
       invariant(
-        propertyInfo.hasBooleanValue + propertyInfo.hasNumericValue +
-          propertyInfo.hasOverloadedBooleanValue <= 1,
+        propertyInfo.hasBooleanValue +
+          propertyInfo.hasNumericValue +
+          propertyInfo.hasOverloadedBooleanValue <=
+          1,
         'DOMProperty: Value can be one of boolean, overloaded boolean, or ' +
-        'numeric value, but not a combination: %s',
-        propName
+          'numeric value, but not a combination: %s',
+        propName,
       );
 
       if (__DEV__) {
@@ -143,10 +141,10 @@ var DOMPropertyInjection = {
 };
 
 /* 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';
+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:
  *
@@ -161,12 +159,12 @@ var ATTRIBUTE_NAME_START_CHAR = ':A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\
  * @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\\uB7\\u0300-\\u036F\\u203F-\\u2040',
+  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
@@ -183,11 +181,6 @@ var DOMProperty = {
    *   initial render.
    * mustUseProperty:
    *   Whether the property must be accessed and mutated as an object property.
-   * hasSideEffects:
-   *   Whether or not setting a value causes side effects such as triggering
-   *   resources to be loaded or text selection changes. If true, we read from
-   *   the DOM before updating to ensure that the value is only set if it has
-   *   changed.
    * hasBooleanValue:
    *   Whether the property should be removed when set to a falsey value.
    * hasNumericValue:
@@ -206,9 +199,13 @@ var DOMProperty = {
   /**
    * 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: __DEV__ ? {} : null,
+  getPossibleStandardName: __DEV__ ? {autofocus: 'autoFocus'} : null,
 
   /**
    * All of the isCustomAttribute() functions that have been injected.
diff --git a/src/renderers/dom/shared/DOMPropertyOperations.js b/src/renderers/dom/shared/DOMPropertyOperations.js
index 6108e4dd079d..524b6f5a1fdf 100644
--- a/src/renderers/dom/shared/DOMPropertyOperations.js
+++ b/src/renderers/dom/shared/DOMPropertyOperations.js
@@ -12,14 +12,18 @@
 'use strict';
 
 var DOMProperty = require('DOMProperty');
-var ReactDOMInstrumentation = require('ReactDOMInstrumentation');
-var ReactPerf = require('ReactPerf');
+var ReactDOMComponentTree = require('ReactDOMComponentTree');
+var ReactInstrumentation = require('ReactInstrumentation');
 
 var quoteAttributeValueForBrowser = require('quoteAttributeValueForBrowser');
 var warning = require('warning');
 
 var VALID_ATTRIBUTE_NAME_REGEX = new RegExp(
-  '^[' + DOMProperty.ATTRIBUTE_NAME_START_CHAR + '][' + DOMProperty.ATTRIBUTE_NAME_CHAR + ']*$'
+  '^[' +
+    DOMProperty.ATTRIBUTE_NAME_START_CHAR +
+    '][' +
+    DOMProperty.ATTRIBUTE_NAME_CHAR +
+    ']*$',
 );
 var illegalAttributeNameCache = {};
 var validatedAttributeNameCache = {};
@@ -36,27 +40,24 @@ function isAttributeNameSafe(attributeName) {
     return true;
   }
   illegalAttributeNameCache[attributeName] = true;
-  warning(
-    false,
-    'Invalid attribute name: `%s`',
-    attributeName
-  );
+  warning(false, 'Invalid attribute name: `%s`', attributeName);
   return false;
 }
 
 function shouldIgnoreValue(propertyInfo, value) {
-  return value == null ||
+  return (
+    value == null ||
     (propertyInfo.hasBooleanValue && !value) ||
     (propertyInfo.hasNumericValue && isNaN(value)) ||
-    (propertyInfo.hasPositiveNumericValue && (value < 1)) ||
-    (propertyInfo.hasOverloadedBooleanValue && value === false);
+    (propertyInfo.hasPositiveNumericValue && value < 1) ||
+    (propertyInfo.hasOverloadedBooleanValue && value === false)
+  );
 }
 
 /**
  * Operations for dealing with DOM properties.
  */
 var DOMPropertyOperations = {
-
   /**
    * Creates markup for the ID property.
    *
@@ -64,8 +65,9 @@ var DOMPropertyOperations = {
    * @return {string} Markup string.
    */
   createMarkupForID: function(id) {
-    return DOMProperty.ID_ATTRIBUTE_NAME + '=' +
-      quoteAttributeValueForBrowser(id);
+    return (
+      DOMProperty.ID_ATTRIBUTE_NAME + '=' + quoteAttributeValueForBrowser(id)
+    );
   },
 
   setAttributeForID: function(node, id) {
@@ -88,18 +90,18 @@ var DOMPropertyOperations = {
    * @return {?string} Markup string, or null if the property was invalid.
    */
   createMarkupForProperty: function(name, value) {
-    if (__DEV__) {
-      ReactDOMInstrumentation.debugTool.onCreateMarkupForProperty(name, value);
-    }
-    var propertyInfo = DOMProperty.properties.hasOwnProperty(name) ?
-        DOMProperty.properties[name] : null;
+    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)) {
+      if (
+        propertyInfo.hasBooleanValue ||
+        (propertyInfo.hasOverloadedBooleanValue && value === true)
+      ) {
         return attributeName + '=""';
       }
       return attributeName + '=' + quoteAttributeValueForBrowser(value);
@@ -134,29 +136,20 @@ var DOMPropertyOperations = {
    * @param {*} value
    */
   setValueForProperty: function(node, name, value) {
-    if (__DEV__) {
-      ReactDOMInstrumentation.debugTool.onSetValueForProperty(node, name, value);
-    }
-    var propertyInfo = DOMProperty.properties.hasOwnProperty(name) ?
-        DOMProperty.properties[name] : null;
+    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) {
-        var propName = propertyInfo.propertyName;
-        // Must explicitly cast values for HAS_SIDE_EFFECTS-properties to the
-        // property type before comparing; only `value` does and is string.
-        // Must set `value` property if it is not null and not yet set.
-        if (!propertyInfo.hasSideEffects ||
-            ('' + node[propName]) !== ('' + value) ||
-            !node.hasAttribute(propertyInfo.attributeName)) {
-          // Contrary to `setAttribute`, object properties are properly
-          // `toString`ed by IE8/9.
-          node[propName] = value;
-        }
+        // 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;
@@ -164,8 +157,10 @@ var DOMPropertyOperations = {
         // ('' + value) makes it output the correct toString()-value.
         if (namespace) {
           node.setAttributeNS(namespace, attributeName, '' + value);
-        } else if (propertyInfo.hasBooleanValue ||
-                   (propertyInfo.hasOverloadedBooleanValue && value === true)) {
+        } else if (
+          propertyInfo.hasBooleanValue ||
+          (propertyInfo.hasOverloadedBooleanValue && value === true)
+        ) {
           node.setAttribute(attributeName, '');
         } else {
           node.setAttribute(attributeName, '' + value);
@@ -173,6 +168,17 @@ var DOMPropertyOperations = {
       }
     } else if (DOMProperty.isCustomAttribute(name)) {
       DOMPropertyOperations.setValueForAttribute(node, name, value);
+      return;
+    }
+
+    if (__DEV__) {
+      var payload = {};
+      payload[name] = value;
+      ReactInstrumentation.debugTool.onHostOperation({
+        instanceID: ReactDOMComponentTree.getInstanceFromNode(node)._debugID,
+        type: 'update attribute',
+        payload: payload,
+      });
     }
   },
 
@@ -185,20 +191,45 @@ var DOMPropertyOperations = {
     } else {
       node.setAttribute(name, '' + value);
     }
+
+    if (__DEV__) {
+      var payload = {};
+      payload[name] = value;
+      ReactInstrumentation.debugTool.onHostOperation({
+        instanceID: ReactDOMComponentTree.getInstanceFromNode(node)._debugID,
+        type: 'update attribute',
+        payload: payload,
+      });
+    }
   },
 
   /**
-   * Deletes the value for a property on a node.
+   * Deletes an attributes from a node.
    *
    * @param {DOMElement} node
    * @param {string} name
    */
-  deleteValueForProperty: function(node, name) {
+  deleteValueForAttribute: function(node, name) {
+    node.removeAttribute(name);
     if (__DEV__) {
-      ReactDOMInstrumentation.debugTool.onDeleteValueForProperty(node, name);
+      ReactInstrumentation.debugTool.onHostOperation({
+        instanceID: ReactDOMComponentTree.getInstanceFromNode(node)._debugID,
+        type: 'remove attribute',
+        payload: name,
+      });
     }
-    var propertyInfo = DOMProperty.properties.hasOwnProperty(name) ?
-        DOMProperty.properties[name] : null;
+  },
+
+  /**
+   * 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) {
@@ -206,13 +237,9 @@ var DOMPropertyOperations = {
       } else if (propertyInfo.mustUseProperty) {
         var propName = propertyInfo.propertyName;
         if (propertyInfo.hasBooleanValue) {
-          // No HAS_SIDE_EFFECTS logic here, only `value` has it and is string.
           node[propName] = false;
         } else {
-          if (!propertyInfo.hasSideEffects ||
-              ('' + node[propName]) !== '') {
-            node[propName] = '';
-          }
+          node[propName] = '';
         }
       } else {
         node.removeAttribute(propertyInfo.attributeName);
@@ -220,14 +247,15 @@ var DOMPropertyOperations = {
     } else if (DOMProperty.isCustomAttribute(name)) {
       node.removeAttribute(name);
     }
-  },
 
+    if (__DEV__) {
+      ReactInstrumentation.debugTool.onHostOperation({
+        instanceID: ReactDOMComponentTree.getInstanceFromNode(node)._debugID,
+        type: 'remove attribute',
+        payload: name,
+      });
+    }
+  },
 };
 
-ReactPerf.measureMethods(DOMPropertyOperations, 'DOMPropertyOperations', {
-  setValueForProperty: 'setValueForProperty',
-  setValueForAttribute: 'setValueForAttribute',
-  deleteValueForProperty: 'deleteValueForProperty',
-});
-
 module.exports = DOMPropertyOperations;
diff --git a/src/renderers/dom/shared/Danger.js b/src/renderers/dom/shared/Danger.js
index 243261b2bded..b16b96adf679 100644
--- a/src/renderers/dom/shared/Danger.js
+++ b/src/renderers/dom/shared/Danger.js
@@ -16,137 +16,9 @@ var ExecutionEnvironment = require('ExecutionEnvironment');
 
 var createNodesFromMarkup = require('createNodesFromMarkup');
 var emptyFunction = require('emptyFunction');
-var getMarkupWrap = require('getMarkupWrap');
 var invariant = require('invariant');
 
-var OPEN_TAG_NAME_EXP = /^(<[^ \/>]+)/;
-var RESULT_INDEX_ATTR = 'data-danger-index';
-
-/**
- * Extracts the `nodeName` from a string of markup.
- *
- * NOTE: Extracting the `nodeName` does not require a regular expression match
- * because we make assumptions about React-generated markup (i.e. there are no
- * spaces surrounding the opening tag and there is at least one attribute).
- *
- * @param {string} markup String of markup.
- * @return {string} Node name of the supplied markup.
- * @see http://jsperf.com/extract-nodename
- */
-function getNodeName(markup) {
-  return markup.substring(1, markup.indexOf(' '));
-}
-
 var Danger = {
-
-  /**
-   * Renders markup into an array of nodes. The markup is expected to render
-   * into a list of root nodes. Also, the length of `resultList` and
-   * `markupList` should be the same.
-   *
-   * @param {array<string>} markupList List of markup strings to render.
-   * @return {array<DOMElement>} List of rendered nodes.
-   * @internal
-   */
-  dangerouslyRenderMarkup: function(markupList) {
-    invariant(
-      ExecutionEnvironment.canUseDOM,
-      'dangerouslyRenderMarkup(...): 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.'
-    );
-    var nodeName;
-    var markupByNodeName = {};
-    // Group markup by `nodeName` if a wrap is necessary, else by '*'.
-    for (var i = 0; i < markupList.length; i++) {
-      invariant(
-        markupList[i],
-        'dangerouslyRenderMarkup(...): Missing markup.'
-      );
-      nodeName = getNodeName(markupList[i]);
-      nodeName = getMarkupWrap(nodeName) ? nodeName : '*';
-      markupByNodeName[nodeName] = markupByNodeName[nodeName] || [];
-      markupByNodeName[nodeName][i] = markupList[i];
-    }
-    var resultList = [];
-    var resultListAssignmentCount = 0;
-    for (nodeName in markupByNodeName) {
-      if (!markupByNodeName.hasOwnProperty(nodeName)) {
-        continue;
-      }
-      var markupListByNodeName = markupByNodeName[nodeName];
-
-      // This for-in loop skips the holes of the sparse array. The order of
-      // iteration should follow the order of assignment, which happens to match
-      // numerical index order, but we don't rely on that.
-      var resultIndex;
-      for (resultIndex in markupListByNodeName) {
-        if (markupListByNodeName.hasOwnProperty(resultIndex)) {
-          var markup = markupListByNodeName[resultIndex];
-
-          // Push the requested markup with an additional RESULT_INDEX_ATTR
-          // attribute.  If the markup does not start with a < character, it
-          // will be discarded below (with an appropriate console.error).
-          markupListByNodeName[resultIndex] = markup.replace(
-            OPEN_TAG_NAME_EXP,
-            // This index will be parsed back out below.
-            '$1 ' + RESULT_INDEX_ATTR + '="' + resultIndex + '" '
-          );
-        }
-      }
-
-      // Render each group of markup with similar wrapping `nodeName`.
-      var renderNodes = createNodesFromMarkup(
-        markupListByNodeName.join(''),
-        emptyFunction // Do nothing special with <script> tags.
-      );
-
-      for (var j = 0; j < renderNodes.length; ++j) {
-        var renderNode = renderNodes[j];
-        if (renderNode.hasAttribute &&
-            renderNode.hasAttribute(RESULT_INDEX_ATTR)) {
-
-          resultIndex = +renderNode.getAttribute(RESULT_INDEX_ATTR);
-          renderNode.removeAttribute(RESULT_INDEX_ATTR);
-
-          invariant(
-            !resultList.hasOwnProperty(resultIndex),
-            'Danger: Assigning to an already-occupied result index.'
-          );
-
-          resultList[resultIndex] = renderNode;
-
-          // This should match resultList.length and markupList.length when
-          // we're done.
-          resultListAssignmentCount += 1;
-
-        } else if (__DEV__) {
-          console.error(
-            'Danger: Discarding unexpected node:',
-            renderNode
-          );
-        }
-      }
-    }
-
-    // Although resultList was populated out of order, it should now be a dense
-    // array.
-    invariant(
-      resultListAssignmentCount === resultList.length,
-      'Danger: Did not assign to every index of resultList.'
-    );
-
-    invariant(
-      resultList.length === markupList.length,
-      'Danger: Expected markup to render %s nodes, but rendered %s.',
-      markupList.length,
-      resultList.length
-    );
-
-    return resultList;
-  },
-
   /**
    * Replaces a node with a string of markup at its current position within its
    * parent. The markup must render into a single root node.
@@ -159,17 +31,17 @@ var Danger = {
     invariant(
       ExecutionEnvironment.canUseDOM,
       '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.'
+        'worker thread. Make sure `window` and `document` are available ' +
+        'globally before requiring React when unit testing or use ' +
+        'ReactDOMServer.renderToString() for server rendering.',
     );
     invariant(markup, 'dangerouslyReplaceNodeWithMarkup(...): Missing markup.');
     invariant(
       oldChild.nodeName !== 'HTML',
       '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().'
+        '<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().',
     );
 
     if (typeof markup === 'string') {
@@ -179,7 +51,6 @@ var Danger = {
       DOMLazyTree.replaceChildWithTree(oldChild, markup);
     }
   },
-
 };
 
 module.exports = Danger;
diff --git a/src/renderers/dom/shared/HTMLDOMPropertyConfig.js b/src/renderers/dom/shared/HTMLDOMPropertyConfig.js
index ce5e93cea6e1..1ec8124272ed 100644
--- a/src/renderers/dom/shared/HTMLDOMPropertyConfig.js
+++ b/src/renderers/dom/shared/HTMLDOMPropertyConfig.js
@@ -15,7 +15,6 @@ var DOMProperty = require('DOMProperty');
 
 var MUST_USE_PROPERTY = DOMProperty.injection.MUST_USE_PROPERTY;
 var HAS_BOOLEAN_VALUE = DOMProperty.injection.HAS_BOOLEAN_VALUE;
-var HAS_SIDE_EFFECTS = DOMProperty.injection.HAS_SIDE_EFFECTS;
 var HAS_NUMERIC_VALUE = DOMProperty.injection.HAS_NUMERIC_VALUE;
 var HAS_POSITIVE_NUMERIC_VALUE =
   DOMProperty.injection.HAS_POSITIVE_NUMERIC_VALUE;
@@ -24,7 +23,7 @@ var HAS_OVERLOADED_BOOLEAN_VALUE =
 
 var HTMLDOMPropertyConfig = {
   isCustomAttribute: RegExp.prototype.test.bind(
-    new RegExp('^(data|aria)-[' + DOMProperty.ATTRIBUTE_NAME_CHAR + ']*$')
+    new RegExp('^(data|aria)-[' + DOMProperty.ATTRIBUTE_NAME_CHAR + ']*$'),
   ),
   Properties: {
     /**
@@ -37,6 +36,8 @@ var HTMLDOMPropertyConfig = {
     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
@@ -117,11 +118,13 @@ var HTMLDOMPropertyConfig = {
     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,
@@ -153,7 +156,7 @@ var HTMLDOMPropertyConfig = {
     // Setting .type throws on non-<input> tags
     type: 0,
     useMap: 0,
-    value: MUST_USE_PROPERTY | HAS_SIDE_EFFECTS,
+    value: 0,
     width: 0,
     wmode: 0,
     wrap: 0,
@@ -207,7 +210,34 @@ var HTMLDOMPropertyConfig = {
     htmlFor: 'for',
     httpEquiv: 'http-equiv',
   },
-  DOMPropertyNames: {
+  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);
+      }
+    },
   },
 };
 
diff --git a/src/renderers/dom/shared/ReactComponentBrowserEnvironment.js b/src/renderers/dom/shared/ReactComponentBrowserEnvironment.js
index cf5df870d39d..13226723bce2 100644
--- a/src/renderers/dom/shared/ReactComponentBrowserEnvironment.js
+++ b/src/renderers/dom/shared/ReactComponentBrowserEnvironment.js
@@ -13,7 +13,6 @@
 
 var DOMChildrenOperations = require('DOMChildrenOperations');
 var ReactDOMIDOperations = require('ReactDOMIDOperations');
-var ReactPerf = require('ReactPerf');
 
 /**
  * Abstracts away all functionality of the reconciler that requires knowledge of
@@ -21,31 +20,10 @@ var ReactPerf = require('ReactPerf');
  * need for this injection.
  */
 var ReactComponentBrowserEnvironment = {
-
   processChildrenUpdates:
     ReactDOMIDOperations.dangerouslyProcessChildrenUpdates,
 
-  replaceNodeWithMarkup:
-    DOMChildrenOperations.dangerouslyReplaceNodeWithMarkup,
-
-  /**
-   * If a particular environment requires that some resources be cleaned up,
-   * specify this in the injected Mixin. In the DOM, we would likely want to
-   * purge any cached node ID lookups.
-   *
-   * @private
-   */
-  unmountIDFromEnvironment: function(rootNodeID) {
-  },
-
+  replaceNodeWithMarkup: DOMChildrenOperations.dangerouslyReplaceNodeWithMarkup,
 };
 
-ReactPerf.measureMethods(
-  ReactComponentBrowserEnvironment,
-  'ReactComponentBrowserEnvironment',
-  {
-    replaceNodeWithMarkup: 'replaceNodeWithMarkup',
-  }
-);
-
 module.exports = ReactComponentBrowserEnvironment;
diff --git a/src/renderers/dom/shared/ReactDOMComponent.js b/src/renderers/dom/shared/ReactDOMComponent.js
index 808706d62b8d..6c7a1ca8bd01 100644
--- a/src/renderers/dom/shared/ReactDOMComponent.js
+++ b/src/renderers/dom/shared/ReactDOMComponent.js
@@ -19,27 +19,25 @@ 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 ReactPerf = require('ReactPerf');
+var ReactServerRenderingTransaction = require('ReactServerRenderingTransaction');
 
+var emptyFunction = require('emptyFunction');
 var escapeTextContentForBrowser = require('escapeTextContentForBrowser');
 var invariant = require('invariant');
 var isEventSupported = require('isEventSupported');
-var keyOf = require('keyOf');
 var shallowEqual = require('shallowEqual');
+var inputValueTracking = require('inputValueTracking');
 var validateDOMNesting = require('validateDOMNesting');
 var warning = require('warning');
 
@@ -50,16 +48,18 @@ 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 CONTENT_TYPES = {string: true, number: true};
 
-var STYLE = keyOf({style: null});
-var HTML = keyOf({__html: null});
+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) {
@@ -82,9 +82,9 @@ function friendlyStringify(obj) {
       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);
+          var keyEscaped = /^[a-z$_][\w$_]*$/i.test(key)
+            ? key
+            : JSON.stringify(key);
           pairs.push(keyEscaped + ': ' + friendlyStringify(obj[key]));
         }
       }
@@ -128,12 +128,12 @@ function checkAndWarnForMutatedStyle(style1, style2, component) {
   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.',
+      '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)
+    friendlyStringify(style2),
   );
 }
 
@@ -149,75 +149,78 @@ function assertValidProps(component, props) {
   if (voidElementTags[component._tag]) {
     invariant(
       props.children == null && props.dangerouslySetInnerHTML == null,
-      '%s is a void element tag and must not have `children` or ' +
-      'use `props.dangerouslySetInnerHTML`.%s',
+      '%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() + '.' :
-        ''
+      component._currentElement._owner
+        ? ' Check the render method of ' +
+            component._currentElement._owner.getName() +
+            '.'
+        : '',
     );
   }
   if (props.dangerouslySetInnerHTML != null) {
     invariant(
       props.children == null,
-      'Can only set one of `children` or `props.dangerouslySetInnerHTML`.'
+      'Can only set one of `children` or `props.dangerouslySetInnerHTML`.',
     );
     invariant(
       typeof props.dangerouslySetInnerHTML === 'object' &&
-      HTML in props.dangerouslySetInnerHTML,
+        HTML in props.dangerouslySetInnerHTML,
       '`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. ' +
-      'Please visit https://fb.me/react-invariant-dangerously-set-inner-html ' +
-      'for more information.'
+        'Please visit https://fb.me/react-invariant-dangerously-set-inner-html ' +
+        'for more information.',
     );
   }
   if (__DEV__) {
     warning(
       props.innerHTML == null,
       'Directly setting property `innerHTML` is not permitted. ' +
-      'For more information, lookup documentation on `dangerouslySetInnerHTML`.'
+        'For more information, lookup documentation on `dangerouslySetInnerHTML`.',
     );
     warning(
       props.suppressContentEditableWarning ||
-      !props.contentEditable ||
-      props.children == null,
+        !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.'
+        'React. It is now your responsibility to guarantee that none of ' +
+        'those nodes are unexpectedly modified or duplicated. This is ' +
+        'probably not intentional.',
     );
     warning(
-      props.onFocusIn == null &&
-      props.onFocusOut == null,
+      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.'
+        'All React events are normalized to bubble, so onFocusIn and onFocusOut ' +
+        'are not needed/supported by React.',
     );
   }
   invariant(
     props.style == null || typeof props.style === 'object',
     '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)
+      "not a string. For example, style={{marginRight: spacing + 'em'}} when " +
+      'using JSX.%s',
+    getDeclarationErrorAddendum(component),
   );
 }
 
 function enqueuePutListener(inst, registrationName, listener, transaction) {
+  if (transaction instanceof ReactServerRenderingTransaction) {
+    return;
+  }
   if (__DEV__) {
     // IE8 has no API for event capturing and the `onScroll` event doesn't
     // bubble.
     warning(
       registrationName !== 'onScroll' || isEventSupported('scroll', true),
-      'This browser doesn\'t support the `onScroll` event'
+      "This browser doesn't support the `onScroll` event",
     );
   }
-  var containerInfo = inst._nativeContainerInfo;
-  var doc = containerInfo._ownerDocument;
-  if (!doc) {
-    // Server rendering.
-    return;
-  }
+  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,
@@ -231,10 +234,61 @@ function putListener() {
   EventPluginHub.putListener(
     listenerToPut.inst,
     listenerToPut.registrationName,
-    listenerToPut.listener
+    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 (__DEV__) {
+  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 = {
@@ -263,72 +317,56 @@ var mediaEvents = {
   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.
   invariant(inst._rootNodeID, 'Must be mounted to trap events');
   var node = getNode(inst);
-  invariant(
-    node,
-    'trapBubbledEvent(...): Requires node to be rendered.'
-  );
+  invariant(node, 'trapBubbledEvent(...): Requires node to be rendered.');
 
   switch (inst._tag) {
     case 'iframe':
     case 'object':
       inst._wrapperState.listeners = [
-        ReactBrowserEventEmitter.trapBubbledEvent(
-          EventConstants.topLevelTypes.topLoad,
-          'load',
-          node
-        ),
+        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(
-              EventConstants.topLevelTypes[event],
+              event,
               mediaEvents[event],
-              node
-            )
+              node,
+            ),
           );
         }
       }
-
+      break;
+    case 'source':
+      inst._wrapperState.listeners = [
+        ReactBrowserEventEmitter.trapBubbledEvent('topError', 'error', node),
+      ];
       break;
     case 'img':
       inst._wrapperState.listeners = [
-        ReactBrowserEventEmitter.trapBubbledEvent(
-          EventConstants.topLevelTypes.topError,
-          'error',
-          node
-        ),
-        ReactBrowserEventEmitter.trapBubbledEvent(
-          EventConstants.topLevelTypes.topLoad,
-          'load',
-          node
-        ),
+        ReactBrowserEventEmitter.trapBubbledEvent('topError', 'error', node),
+        ReactBrowserEventEmitter.trapBubbledEvent('topLoad', 'load', node),
       ];
       break;
     case 'form':
       inst._wrapperState.listeners = [
-        ReactBrowserEventEmitter.trapBubbledEvent(
-          EventConstants.topLevelTypes.topReset,
-          'reset',
-          node
-        ),
-        ReactBrowserEventEmitter.trapBubbledEvent(
-          EventConstants.topLevelTypes.topSubmit,
-          'submit',
-          node
-        ),
+        ReactBrowserEventEmitter.trapBubbledEvent('topReset', 'reset', node),
+        ReactBrowserEventEmitter.trapBubbledEvent('topSubmit', 'submit', node),
       ];
       break;
     case 'input':
@@ -336,9 +374,9 @@ function trapBubbledEventsLocal() {
     case 'textarea':
       inst._wrapperState.listeners = [
         ReactBrowserEventEmitter.trapBubbledEvent(
-          EventConstants.topLevelTypes.topInvalid,
+          'topInvalid',
           'invalid',
-          node
+          node,
         ),
       ];
       break;
@@ -353,36 +391,39 @@ function postUpdateSelectWrapper() {
 // 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,
+  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,
+  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 = Object.assign({
-  'menuitem': true,
-}, omittedCloseTags);
+var voidElementTags = Object.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.
@@ -428,79 +469,80 @@ function ReactDOMComponent(element) {
   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._hostNode = null;
+  this._hostParent = null;
+  this._rootNodeID = 0;
+  this._domID = 0;
+  this._hostContainerInfo = null;
   this._wrapperState = null;
   this._topLevelWrapper = null;
   this._flags = 0;
   if (__DEV__) {
     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 containing DOM component instance
-   * @param {?object} info about the native container
+   * @param {?ReactDOMComponent} the parent component instance
+   * @param {?object} info about the host container
    * @param {object} context
    * @return {string} The computed markup.
    */
   mountComponent: function(
     transaction,
-    nativeParent,
-    nativeContainerInfo,
-    context
+    hostParent,
+    hostContainerInfo,
+    context,
   ) {
     this._rootNodeID = globalIdCounter++;
-    this._domID = nativeContainerInfo._idCounter++;
-    this._nativeParent = nativeParent;
-    this._nativeContainerInfo = nativeContainerInfo;
+    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 'object':
       case 'img':
-      case 'form':
+      case 'link':
+      case 'object':
+      case 'source':
       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);
+        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, nativeParent);
-        props = ReactDOMOption.getNativeProps(this, props);
+        ReactDOMOption.mountWrapper(this, props, hostParent);
+        props = ReactDOMOption.getHostProps(this, props);
         break;
       case 'select':
-        ReactDOMSelect.mountWrapper(this, props, nativeParent);
-        props = ReactDOMSelect.getNativeProps(this, props);
+        ReactDOMSelect.mountWrapper(this, props, hostParent);
+        props = ReactDOMSelect.getHostProps(this, props);
         transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, this);
         break;
       case 'textarea':
-        ReactDOMTextarea.mountWrapper(this, props, nativeParent);
-        props = ReactDOMTextarea.getNativeProps(this, props);
+        ReactDOMTextarea.mountWrapper(this, props, hostParent);
+        props = ReactDOMTextarea.getHostProps(this, props);
+        transaction.getReactMountReady().enqueue(trackInputValue, this);
         transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, this);
         break;
     }
@@ -511,15 +553,17 @@ ReactDOMComponent.Mixin = {
     // 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 (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') {
+    if (
+      namespaceURI == null ||
+      (namespaceURI === DOMNamespaces.svg && parentTag === 'foreignobject')
+    ) {
       namespaceURI = DOMNamespaces.html;
     }
     if (namespaceURI === DOMNamespaces.html) {
@@ -533,23 +577,26 @@ ReactDOMComponent.Mixin = {
 
     if (__DEV__) {
       var parentInfo;
-      if (nativeParent != null) {
-        parentInfo = nativeParent._ancestorInfo;
-      } else if (nativeContainerInfo._tag) {
-        parentInfo = nativeContainerInfo._ancestorInfo;
+      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, this, parentInfo);
+        validateDOMNesting(this._tag, null, this, parentInfo);
       }
-      this._ancestorInfo =
-        validateDOMNesting.updatedAncestorInfo(parentInfo, this._tag, this);
+      this._ancestorInfo = validateDOMNesting.updatedAncestorInfo(
+        parentInfo,
+        this._tag,
+        this,
+      );
     }
 
     var mountImage;
     if (transaction.useCreateElement) {
-      var ownerDocument = nativeContainerInfo._ownerDocument;
+      var ownerDocument = hostContainerInfo._ownerDocument;
       var el;
       if (namespaceURI === DOMNamespaces.html) {
         if (this._tag === 'script') {
@@ -559,18 +606,23 @@ ReactDOMComponent.Mixin = {
           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
+          this._currentElement.type,
         );
       }
       ReactDOMComponentTree.precacheNode(this, el);
       this._flags |= Flags.hasCachedChildNodes;
-      if (!this._nativeParent) {
+      if (!this._hostParent) {
         DOMPropertyOperations.setAttributeForRoot(el);
       }
       this._updateDOMProperties(null, props, transaction);
@@ -578,7 +630,10 @@ ReactDOMComponent.Mixin = {
       this._createInitialChildren(transaction, props, context, lazyTree);
       mountImage = lazyTree;
     } else {
-      var tagOpen = this._createOpenTagMarkupAndPutListeners(transaction, props);
+      var tagOpen = this._createOpenTagMarkupAndPutListeners(
+        transaction,
+        props,
+      );
       var tagContent = this._createContentMarkup(transaction, props, context);
       if (!tagContent && omittedCloseTags[this._tag]) {
         mountImage = tagOpen + '/>';
@@ -589,17 +644,39 @@ ReactDOMComponent.Mixin = {
     }
 
     switch (this._tag) {
-      case 'button':
       case 'input':
-      case 'select':
+        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
-          );
+          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;
@@ -640,17 +717,29 @@ ReactDOMComponent.Mixin = {
               // See `_updateDOMProperties`. style block
               this._previousStyle = propValue;
             }
-            propValue = this._previousStyleCopy = Object.assign({}, props.style);
+            propValue = this._previousStyleCopy = Object.assign(
+              {},
+              props.style,
+            );
           }
-          propValue = CSSPropertyOperations.createMarkupForStyles(propValue, this);
+          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);
+            markup = DOMPropertyOperations.createMarkupForCustomAttribute(
+              propKey,
+              propValue,
+            );
           }
         } else {
-          markup = DOMPropertyOperations.createMarkupForProperty(propKey, propValue);
+          markup = DOMPropertyOperations.createMarkupForProperty(
+            propKey,
+            propValue,
+          );
         }
         if (markup) {
           ret += ' ' + markup;
@@ -664,7 +753,7 @@ ReactDOMComponent.Mixin = {
       return ret;
     }
 
-    if (!this._nativeParent) {
+    if (!this._hostParent) {
       ret += ' ' + DOMPropertyOperations.createMarkupForRoot();
     }
     ret += ' ' + DOMPropertyOperations.createMarkupForID(this._domID);
@@ -690,17 +779,21 @@ ReactDOMComponent.Mixin = {
         ret = innerHTML.__html;
       }
     } else {
-      var contentToUse =
-        CONTENT_TYPES[typeof props.children] ? props.children : null;
+      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 (__DEV__) {
+          setAndValidateContentChildDev.call(this, contentToUse);
+        }
       } else if (childrenToUse != null) {
         var mountImages = this.mountChildren(
           childrenToUse,
           transaction,
-          context
+          context,
         );
         ret = mountImages.join('');
       }
@@ -730,17 +823,27 @@ ReactDOMComponent.Mixin = {
         DOMLazyTree.queueHTML(lazyTree, innerHTML.__html);
       }
     } else {
-      var contentToUse =
-        CONTENT_TYPES[typeof props.children] ? props.children : null;
+      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) {
-        // TODO: Validate that text is allowed as a child of this node
-        DOMLazyTree.queueText(lazyTree, contentToUse);
+        // 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 (__DEV__) {
+            setAndValidateContentChildDev.call(this, contentToUse);
+          }
+          DOMLazyTree.queueText(lazyTree, contentToUse);
+        }
       } else if (childrenToUse != null) {
         var mountImages = this.mountChildren(
           childrenToUse,
           transaction,
-          context
+          context,
         );
         for (var i = 0; i < mountImages.length; i++) {
           DOMLazyTree.queueChild(lazyTree, mountImages[i]);
@@ -764,7 +867,7 @@ ReactDOMComponent.Mixin = {
   },
 
   /**
-   * Updates a native DOM component after it has already been allocated and
+   * 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
@@ -778,43 +881,43 @@ ReactDOMComponent.Mixin = {
     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);
+        lastProps = ReactDOMInput.getHostProps(this, lastProps);
+        nextProps = ReactDOMInput.getHostProps(this, nextProps);
         break;
       case 'option':
-        lastProps = ReactDOMOption.getNativeProps(this, lastProps);
-        nextProps = ReactDOMOption.getNativeProps(this, nextProps);
+        lastProps = ReactDOMOption.getHostProps(this, lastProps);
+        nextProps = ReactDOMOption.getHostProps(this, nextProps);
         break;
       case 'select':
-        lastProps = ReactDOMSelect.getNativeProps(this, lastProps);
-        nextProps = ReactDOMSelect.getNativeProps(this, nextProps);
+        lastProps = ReactDOMSelect.getHostProps(this, lastProps);
+        nextProps = ReactDOMSelect.getHostProps(this, nextProps);
         break;
       case 'textarea':
-        ReactDOMTextarea.updateWrapper(this);
-        lastProps = ReactDOMTextarea.getNativeProps(this, lastProps);
-        nextProps = ReactDOMTextarea.getNativeProps(this, nextProps);
+        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
-    );
+    this._updateDOMChildren(lastProps, nextProps, transaction, context);
 
-    if (this._tag === 'select') {
-      // <select> value update needs to occur after <option> children
-      // reconciliation
-      transaction.getReactMountReady().enqueue(postUpdateSelectWrapper, this);
+    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);
+        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;
     }
   },
 
@@ -839,9 +942,11 @@ ReactDOMComponent.Mixin = {
     var styleName;
     var styleUpdates;
     for (propKey in lastProps) {
-      if (nextProps.hasOwnProperty(propKey) ||
-         !lastProps.hasOwnProperty(propKey) ||
-         lastProps[propKey] == null) {
+      if (
+        nextProps.hasOwnProperty(propKey) ||
+        !lastProps.hasOwnProperty(propKey) ||
+        lastProps[propKey] == null
+      ) {
         continue;
       }
       if (propKey === STYLE) {
@@ -860,20 +965,27 @@ ReactDOMComponent.Mixin = {
           // 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)) {
+        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) {
+      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) {
@@ -882,7 +994,7 @@ ReactDOMComponent.Mixin = {
             checkAndWarnForMutatedStyle(
               this._previousStyleCopy,
               this._previousStyle,
-              this
+              this,
             );
             this._previousStyle = nextProp;
           }
@@ -893,16 +1005,20 @@ ReactDOMComponent.Mixin = {
         if (lastProp) {
           // Unset styles on `lastProp` but not on `nextProp`.
           for (styleName in lastProp) {
-            if (lastProp.hasOwnProperty(styleName) &&
-                (!nextProp || !nextProp.hasOwnProperty(styleName))) {
+            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]) {
+            if (
+              nextProp.hasOwnProperty(styleName) &&
+              lastProp[styleName] !== nextProp[styleName]
+            ) {
               styleUpdates = styleUpdates || {};
               styleUpdates[styleName] = nextProp[styleName];
             }
@@ -922,12 +1038,13 @@ ReactDOMComponent.Mixin = {
           DOMPropertyOperations.setValueForAttribute(
             getNode(this),
             propKey,
-            nextProp
+            nextProp,
           );
         }
       } else if (
-          DOMProperty.properties[propKey] ||
-          DOMProperty.isCustomAttribute(propKey)) {
+        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
@@ -943,7 +1060,7 @@ ReactDOMComponent.Mixin = {
       CSSPropertyOperations.setValueForStyles(
         getNode(this),
         styleUpdates,
-        this
+        this,
       );
     }
   },
@@ -958,10 +1075,12 @@ ReactDOMComponent.Mixin = {
    * @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 lastContent = CONTENT_TYPES[typeof lastProps.children]
+      ? lastProps.children
+      : null;
+    var nextContent = CONTENT_TYPES[typeof nextProps.children]
+      ? nextProps.children
+      : null;
 
     var lastHtml =
       lastProps.dangerouslySetInnerHTML &&
@@ -982,22 +1101,35 @@ ReactDOMComponent.Mixin = {
       this.updateChildren(null, transaction, context);
     } else if (lastHasContentOrHtml && !nextHasContentOrHtml) {
       this.updateTextContent('');
+      if (__DEV__) {
+        ReactInstrumentation.debugTool.onSetChildren(this._debugID, []);
+      }
     }
 
     if (nextContent != null) {
       if (lastContent !== nextContent) {
         this.updateTextContent('' + nextContent);
+        if (__DEV__) {
+          setAndValidateContentChildDev.call(this, nextContent);
+        }
       }
     } else if (nextHtml != null) {
       if (lastHtml !== nextHtml) {
         this.updateMarkup('' + nextHtml);
       }
+      if (__DEV__) {
+        ReactInstrumentation.debugTool.onSetChildren(this._debugID, []);
+      }
     } else if (nextChildren != null) {
+      if (__DEV__) {
+        setAndValidateContentChildDev.call(this, null);
+      }
+
       this.updateChildren(nextChildren, transaction, context);
     }
   },
 
-  getNativeNode: function() {
+  getHostNode: function() {
     return getNode(this);
   },
 
@@ -1009,12 +1141,14 @@ ReactDOMComponent.Mixin = {
    */
   unmountComponent: function(safely) {
     switch (this._tag) {
+      case 'audio':
+      case 'form':
       case 'iframe':
-      case 'object':
       case 'img':
-      case 'form':
+      case 'link':
+      case 'object':
+      case 'source':
       case 'video':
-      case 'audio':
         var listeners = this._wrapperState.listeners;
         if (listeners) {
           for (var i = 0; i < listeners.length; i++) {
@@ -1022,6 +1156,10 @@ ReactDOMComponent.Mixin = {
           }
         }
         break;
+      case 'input':
+      case 'textarea':
+        inputValueTracking.stopTracking(this);
+        break;
       case 'html':
       case 'head':
       case 'body':
@@ -1034,11 +1172,11 @@ ReactDOMComponent.Mixin = {
         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
+            '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,
         );
         break;
     }
@@ -1046,27 +1184,24 @@ ReactDOMComponent.Mixin = {
     this.unmountChildren(safely);
     ReactDOMComponentTree.uncacheNode(this);
     EventPluginHub.deleteAllListeners(this);
-    ReactComponentBrowserEnvironment.unmountIDFromEnvironment(this._rootNodeID);
-    this._rootNodeID = null;
-    this._domID = null;
+    this._rootNodeID = 0;
+    this._domID = 0;
     this._wrapperState = null;
+
+    if (__DEV__) {
+      setAndValidateContentChildDev.call(this, null);
+    }
   },
 
   getPublicInstance: function() {
     return getNode(this);
   },
-
 };
 
-ReactPerf.measureMethods(ReactDOMComponent.Mixin, 'ReactDOMComponent', {
-  mountComponent: 'mountComponent',
-  receiveComponent: 'receiveComponent',
-});
-
 Object.assign(
   ReactDOMComponent.prototype,
   ReactDOMComponent.Mixin,
-  ReactMultiChild.Mixin
+  ReactMultiChild.Mixin,
 );
 
 module.exports = ReactDOMComponent;
diff --git a/src/renderers/dom/shared/ReactDOMContainerInfo.js b/src/renderers/dom/shared/ReactDOMContainerInfo.js
index 75be5eae89a8..263c42c7645d 100644
--- a/src/renderers/dom/shared/ReactDOMContainerInfo.js
+++ b/src/renderers/dom/shared/ReactDOMContainerInfo.js
@@ -19,15 +19,17 @@ function ReactDOMContainerInfo(topLevelWrapper, node) {
   var info = {
     _topLevelWrapper: topLevelWrapper,
     _idCounter: 1,
-    _ownerDocument: node ?
-      node.nodeType === DOC_NODE_TYPE ? node : node.ownerDocument :
-      null,
+    _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 (__DEV__) {
-    info._ancestorInfo = node ?
-      validateDOMNesting.updatedAncestorInfo(null, info._tag, null) : null;
+    info._ancestorInfo = node
+      ? validateDOMNesting.updatedAncestorInfo(null, info._tag, null)
+      : null;
   }
   return info;
 }
diff --git a/src/renderers/dom/shared/ReactDOMDebugTool.js b/src/renderers/dom/shared/ReactDOMDebugTool.js
deleted file mode 100644
index 9fcc3763fadb..000000000000
--- a/src/renderers/dom/shared/ReactDOMDebugTool.js
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
- * 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 ReactDOMDebugTool
- */
-
-'use strict';
-
-var ReactDOMUnknownPropertyDevtool = require('ReactDOMUnknownPropertyDevtool');
-
-var warning = require('warning');
-
-var eventHandlers = [];
-var handlerDoesThrowForEvent = {};
-
-function emitEvent(handlerFunctionName, arg1, arg2, arg3, arg4, arg5) {
-  if (__DEV__) {
-    eventHandlers.forEach(function(handler) {
-      try {
-        if (handler[handlerFunctionName]) {
-          handler[handlerFunctionName](arg1, arg2, arg3, arg4, arg5);
-        }
-      } catch (e) {
-        warning(
-          !handlerDoesThrowForEvent[handlerFunctionName],
-          'exception thrown by devtool while handling %s: %s',
-          handlerFunctionName,
-          e.message
-        );
-        handlerDoesThrowForEvent[handlerFunctionName] = true;
-      }
-    });
-  }
-}
-
-var ReactDOMDebugTool = {
-  addDevtool(devtool) {
-    eventHandlers.push(devtool);
-  },
-  removeDevtool(devtool) {
-    for (var i = 0; i < eventHandlers.length; i++) {
-      if (eventHandlers[i] === devtool) {
-        eventHandlers.splice(i, 1);
-        i--;
-      }
-    }
-  },
-  onCreateMarkupForProperty(name, value) {
-    emitEvent('onCreateMarkupForProperty', name, value);
-  },
-  onSetValueForProperty(node, name, value) {
-    emitEvent('onSetValueForProperty', node, name, value);
-  },
-  onDeleteValueForProperty(node, name) {
-    emitEvent('onDeleteValueForProperty', node, name);
-  },
-};
-
-ReactDOMDebugTool.addDevtool(ReactDOMUnknownPropertyDevtool);
-
-module.exports = ReactDOMDebugTool;
diff --git a/src/renderers/dom/shared/ReactDOMEmptyComponent.js b/src/renderers/dom/shared/ReactDOMEmptyComponent.js
index 81f894091de5..bbc63163420c 100644
--- a/src/renderers/dom/shared/ReactDOMEmptyComponent.js
+++ b/src/renderers/dom/shared/ReactDOMEmptyComponent.js
@@ -14,31 +14,30 @@
 var DOMLazyTree = require('DOMLazyTree');
 var ReactDOMComponentTree = require('ReactDOMComponentTree');
 
-
 var ReactDOMEmptyComponent = function(instantiate) {
   // ReactCompositeComponent uses this:
   this._currentElement = null;
   // ReactDOMComponentTree uses these:
-  this._nativeNode = null;
-  this._nativeParent = null;
-  this._nativeContainerInfo = null;
-  this._domID = null;
+  this._hostNode = null;
+  this._hostParent = null;
+  this._hostContainerInfo = null;
+  this._domID = 0;
 };
 Object.assign(ReactDOMEmptyComponent.prototype, {
   mountComponent: function(
     transaction,
-    nativeParent,
-    nativeContainerInfo,
-    context
+    hostParent,
+    hostContainerInfo,
+    context,
   ) {
-    var domID = nativeContainerInfo._idCounter++;
+    var domID = hostContainerInfo._idCounter++;
     this._domID = domID;
-    this._nativeParent = nativeParent;
-    this._nativeContainerInfo = nativeContainerInfo;
+    this._hostParent = hostParent;
+    this._hostContainerInfo = hostContainerInfo;
 
     var nodeValue = ' react-empty: ' + this._domID + ' ';
     if (transaction.useCreateElement) {
-      var ownerDocument = nativeContainerInfo._ownerDocument;
+      var ownerDocument = hostContainerInfo._ownerDocument;
       var node = ownerDocument.createComment(nodeValue);
       ReactDOMComponentTree.precacheNode(this, node);
       return DOMLazyTree(node);
@@ -52,9 +51,8 @@ Object.assign(ReactDOMEmptyComponent.prototype, {
       return '<!--' + nodeValue + '-->';
     }
   },
-  receiveComponent: function() {
-  },
-  getNativeNode: function() {
+  receiveComponent: function() {},
+  getHostNode: function() {
     return ReactDOMComponentTree.getNodeFromInstance(this);
   },
   unmountComponent: function() {
diff --git a/src/renderers/dom/shared/ReactDOMFeatureFlags.js b/src/renderers/dom/shared/ReactDOMFeatureFlags.js
index f27e8541903c..5e9d93267cf9 100644
--- a/src/renderers/dom/shared/ReactDOMFeatureFlags.js
+++ b/src/renderers/dom/shared/ReactDOMFeatureFlags.js
@@ -13,6 +13,7 @@
 
 var ReactDOMFeatureFlags = {
   useCreateElement: true,
+  useFiber: false,
 };
 
 module.exports = ReactDOMFeatureFlags;
diff --git a/src/renderers/dom/shared/ReactDOMInstrumentation.js b/src/renderers/dom/shared/ReactDOMInstrumentation.js
deleted file mode 100644
index b290c6c553cf..000000000000
--- a/src/renderers/dom/shared/ReactDOMInstrumentation.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/**
- * 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 ReactDOMInstrumentation
- */
-
-'use strict';
-
-var ReactDOMDebugTool = require('ReactDOMDebugTool');
-
-module.exports = {debugTool: ReactDOMDebugTool};
diff --git a/src/renderers/dom/shared/ReactDOMTextComponent.js b/src/renderers/dom/shared/ReactDOMTextComponent.js
index 9a69c7f97762..c305207a9c17 100644
--- a/src/renderers/dom/shared/ReactDOMTextComponent.js
+++ b/src/renderers/dom/shared/ReactDOMTextComponent.js
@@ -14,7 +14,6 @@
 var DOMChildrenOperations = require('DOMChildrenOperations');
 var DOMLazyTree = require('DOMLazyTree');
 var ReactDOMComponentTree = require('ReactDOMComponentTree');
-var ReactPerf = require('ReactPerf');
 
 var escapeTextContentForBrowser = require('escapeTextContentForBrowser');
 var invariant = require('invariant');
@@ -40,18 +39,17 @@ var ReactDOMTextComponent = function(text) {
   this._currentElement = text;
   this._stringText = '' + text;
   // ReactDOMComponentTree uses these:
-  this._nativeNode = null;
-  this._nativeParent = null;
+  this._hostNode = null;
+  this._hostParent = null;
 
   // Properties
-  this._domID = null;
+  this._domID = 0;
   this._mountIndex = 0;
   this._closingComment = null;
   this._commentNodes = null;
 };
 
 Object.assign(ReactDOMTextComponent.prototype, {
-
   /**
    * Creates the markup for this text node. This node is not intended to have
    * any features besides containing text content.
@@ -62,31 +60,31 @@ Object.assign(ReactDOMTextComponent.prototype, {
    */
   mountComponent: function(
     transaction,
-    nativeParent,
-    nativeContainerInfo,
-    context
+    hostParent,
+    hostContainerInfo,
+    context,
   ) {
     if (__DEV__) {
       var parentInfo;
-      if (nativeParent != null) {
-        parentInfo = nativeParent._ancestorInfo;
-      } else if (nativeContainerInfo != null) {
-        parentInfo = nativeContainerInfo._ancestorInfo;
+      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('#text', this, parentInfo);
+        validateDOMNesting(null, this._stringText, this, parentInfo);
       }
     }
 
-    var domID = nativeContainerInfo._idCounter++;
+    var domID = hostContainerInfo._idCounter++;
     var openingValue = ' react-text: ' + domID + ' ';
     var closingValue = ' /react-text ';
     this._domID = domID;
-    this._nativeParent = nativeParent;
+    this._hostParent = hostParent;
     if (transaction.useCreateElement) {
-      var ownerDocument = nativeContainerInfo._ownerDocument;
+      var ownerDocument = hostContainerInfo._ownerDocument;
       var openingComment = ownerDocument.createComment(openingValue);
       var closingComment = ownerDocument.createComment(closingValue);
       var lazyTree = DOMLazyTree(ownerDocument.createDocumentFragment());
@@ -94,7 +92,7 @@ Object.assign(ReactDOMTextComponent.prototype, {
       if (this._stringText) {
         DOMLazyTree.queueChild(
           lazyTree,
-          DOMLazyTree(ownerDocument.createTextNode(this._stringText))
+          DOMLazyTree(ownerDocument.createTextNode(this._stringText)),
         );
       }
       DOMLazyTree.queueChild(lazyTree, DOMLazyTree(closingComment));
@@ -112,8 +110,13 @@ Object.assign(ReactDOMTextComponent.prototype, {
       }
 
       return (
-        '<!--' + openingValue + '-->' + escapedText +
-        '<!--' + closingValue + '-->'
+        '<!--' +
+        openingValue +
+        '-->' +
+        escapedText +
+        '<!--' +
+        closingValue +
+        '-->'
       );
     }
   },
@@ -134,20 +137,20 @@ Object.assign(ReactDOMTextComponent.prototype, {
         // and/or updateComponent to do the actual update for consistency with
         // other component types?
         this._stringText = nextStringText;
-        var commentNodes = this.getNativeNode();
+        var commentNodes = this.getHostNode();
         DOMChildrenOperations.replaceDelimitedText(
           commentNodes[0],
           commentNodes[1],
-          nextStringText
+          nextStringText,
         );
       }
     }
   },
 
-  getNativeNode: function() {
-    var nativeNode = this._commentNodes;
-    if (nativeNode) {
-      return nativeNode;
+  getHostNode: function() {
+    var hostNode = this._commentNodes;
+    if (hostNode) {
+      return hostNode;
     }
     if (!this._closingComment) {
       var openingComment = ReactDOMComponentTree.getNodeFromInstance(this);
@@ -156,7 +159,7 @@ Object.assign(ReactDOMTextComponent.prototype, {
         invariant(
           node != null,
           'Missing closing comment for text component %s',
-          this._domID
+          this._domID,
         );
         if (node.nodeType === 8 && node.nodeValue === ' /react-text ') {
           this._closingComment = node;
@@ -165,9 +168,9 @@ Object.assign(ReactDOMTextComponent.prototype, {
         node = node.nextSibling;
       }
     }
-    nativeNode = [this._nativeNode, this._closingComment];
-    this._commentNodes = nativeNode;
-    return nativeNode;
+    hostNode = [this._hostNode, this._closingComment];
+    this._commentNodes = hostNode;
+    return hostNode;
   },
 
   unmountComponent: function() {
@@ -175,16 +178,6 @@ Object.assign(ReactDOMTextComponent.prototype, {
     this._commentNodes = null;
     ReactDOMComponentTree.uncacheNode(this);
   },
-
 });
 
-ReactPerf.measureMethods(
-  ReactDOMTextComponent.prototype,
-  'ReactDOMTextComponent',
-  {
-    mountComponent: 'mountComponent',
-    receiveComponent: 'receiveComponent',
-  }
-);
-
 module.exports = ReactDOMTextComponent;
diff --git a/src/renderers/dom/shared/ReactDefaultInjection.js b/src/renderers/dom/shared/ReactDefaultInjection.js
index 09cbf25e485f..277052c25068 100644
--- a/src/renderers/dom/shared/ReactDefaultInjection.js
+++ b/src/renderers/dom/shared/ReactDefaultInjection.js
@@ -11,14 +11,13 @@
 
 'use strict';
 
+var ARIADOMPropertyConfig = require('ARIADOMPropertyConfig');
 var BeforeInputEventPlugin = require('BeforeInputEventPlugin');
 var ChangeEventPlugin = require('ChangeEventPlugin');
 var DefaultEventPluginOrder = require('DefaultEventPluginOrder');
 var EnterLeaveEventPlugin = require('EnterLeaveEventPlugin');
-var ExecutionEnvironment = require('ExecutionEnvironment');
 var HTMLDOMPropertyConfig = require('HTMLDOMPropertyConfig');
-var ReactComponentBrowserEnvironment =
-  require('ReactComponentBrowserEnvironment');
+var ReactComponentBrowserEnvironment = require('ReactComponentBrowserEnvironment');
 var ReactDOMComponent = require('ReactDOMComponent');
 var ReactDOMComponentTree = require('ReactDOMComponentTree');
 var ReactDOMEmptyComponent = require('ReactDOMEmptyComponent');
@@ -43,9 +42,7 @@ function inject() {
   }
   alreadyInjected = true;
 
-  ReactInjection.EventEmitter.injectReactEventListener(
-    ReactEventListener
-  );
+  ReactInjection.EventEmitter.injectReactEventListener(ReactEventListener);
 
   /**
    * Inject modules for resolving DOM hierarchy and plugin ordering.
@@ -66,39 +63,24 @@ function inject() {
     BeforeInputEventPlugin: BeforeInputEventPlugin,
   });
 
-  ReactInjection.NativeComponent.injectGenericComponentClass(
-    ReactDOMComponent
-  );
+  ReactInjection.HostComponent.injectGenericComponentClass(ReactDOMComponent);
 
-  ReactInjection.NativeComponent.injectTextComponentClass(
-    ReactDOMTextComponent
-  );
+  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.EmptyComponent.injectEmptyComponentFactory(function(
+    instantiate,
+  ) {
+    return new ReactDOMEmptyComponent(instantiate);
+  });
 
-  ReactInjection.Updates.injectReconcileTransaction(
-    ReactReconcileTransaction
-  );
-  ReactInjection.Updates.injectBatchingStrategy(
-    ReactDefaultBatchingStrategy
-  );
+  ReactInjection.Updates.injectReconcileTransaction(ReactReconcileTransaction);
+  ReactInjection.Updates.injectBatchingStrategy(ReactDefaultBatchingStrategy);
 
   ReactInjection.Component.injectEnvironment(ReactComponentBrowserEnvironment);
-
-  if (__DEV__) {
-    var url = (ExecutionEnvironment.canUseDOM && window.location.href) || '';
-    if ((/[?&]react_perf\b/).test(url)) {
-      var ReactDefaultPerf = require('ReactDefaultPerf');
-      ReactDefaultPerf.start();
-    }
-  }
 }
 
 module.exports = {
diff --git a/src/renderers/dom/shared/ReactInjection.js b/src/renderers/dom/shared/ReactInjection.js
index 26085eb2f73b..25ef6325b96b 100644
--- a/src/renderers/dom/shared/ReactInjection.js
+++ b/src/renderers/dom/shared/ReactInjection.js
@@ -15,23 +15,19 @@ var DOMProperty = require('DOMProperty');
 var EventPluginHub = require('EventPluginHub');
 var EventPluginUtils = require('EventPluginUtils');
 var ReactComponentEnvironment = require('ReactComponentEnvironment');
-var ReactClass = require('ReactClass');
 var ReactEmptyComponent = require('ReactEmptyComponent');
 var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
-var ReactNativeComponent = require('ReactNativeComponent');
-var ReactPerf = require('ReactPerf');
+var ReactHostComponent = require('ReactHostComponent');
 var ReactUpdates = require('ReactUpdates');
 
 var ReactInjection = {
   Component: ReactComponentEnvironment.injection,
-  Class: ReactClass.injection,
   DOMProperty: DOMProperty.injection,
   EmptyComponent: ReactEmptyComponent.injection,
   EventPluginHub: EventPluginHub.injection,
   EventPluginUtils: EventPluginUtils.injection,
   EventEmitter: ReactBrowserEventEmitter.injection,
-  NativeComponent: ReactNativeComponent.injection,
-  Perf: ReactPerf.injection,
+  HostComponent: ReactHostComponent.injection,
   Updates: ReactUpdates.injection,
 };
 
diff --git a/src/renderers/dom/shared/SVGDOMPropertyConfig.js b/src/renderers/dom/shared/SVGDOMPropertyConfig.js
index 0711446e9a0c..dbb9da3be1f9 100644
--- a/src/renderers/dom/shared/SVGDOMPropertyConfig.js
+++ b/src/renderers/dom/shared/SVGDOMPropertyConfig.js
@@ -263,6 +263,8 @@ var ATTRS = {
   xlinkTitle: 'xlink:title',
   xlinkType: 'xlink:type',
   xmlBase: 'xml:base',
+  xmlns: 0,
+  xmlnsXlink: 'xmlns:xlink',
   xmlLang: 'xml:lang',
   xmlSpace: 'xml:space',
   y: 0,
@@ -290,7 +292,7 @@ var SVGDOMPropertyConfig = {
   DOMAttributeNames: {},
 };
 
-Object.keys(ATTRS).map((key) => {
+Object.keys(ATTRS).forEach(key => {
   SVGDOMPropertyConfig.Properties[key] = 0;
   if (ATTRS[key]) {
     SVGDOMPropertyConfig.DOMAttributeNames[key] = ATTRS[key];
diff --git a/src/renderers/dom/shared/__tests__/CSSProperty-test.js b/src/renderers/dom/shared/__tests__/CSSProperty-test.js
index 26b8f09afbb5..711a9c3870e1 100644
--- a/src/renderers/dom/shared/__tests__/CSSProperty-test.js
+++ b/src/renderers/dom/shared/__tests__/CSSProperty-test.js
@@ -11,21 +11,26 @@
 
 'use strict';
 
-describe('CSSProperty', function() {
+describe('CSSProperty', () => {
   var CSSProperty;
 
-  beforeEach(function() {
+  beforeEach(() => {
     jest.resetModuleRegistry();
     CSSProperty = require('CSSProperty');
   });
 
-  it('should generate browser prefixes for its `isUnitlessNumber`', function() {
+  it('should generate browser prefixes for its `isUnitlessNumber`', () => {
     expect(CSSProperty.isUnitlessNumber.lineClamp).toBeTruthy();
     expect(CSSProperty.isUnitlessNumber.WebkitLineClamp).toBeTruthy();
     expect(CSSProperty.isUnitlessNumber.msFlexGrow).toBeTruthy();
     expect(CSSProperty.isUnitlessNumber.MozFlexGrow).toBeTruthy();
     expect(CSSProperty.isUnitlessNumber.msGridRow).toBeTruthy();
+    expect(CSSProperty.isUnitlessNumber.msGridRowEnd).toBeTruthy();
+    expect(CSSProperty.isUnitlessNumber.msGridRowSpan).toBeTruthy();
+    expect(CSSProperty.isUnitlessNumber.msGridRowStart).toBeTruthy();
     expect(CSSProperty.isUnitlessNumber.msGridColumn).toBeTruthy();
+    expect(CSSProperty.isUnitlessNumber.msGridColumnEnd).toBeTruthy();
+    expect(CSSProperty.isUnitlessNumber.msGridColumnSpan).toBeTruthy();
+    expect(CSSProperty.isUnitlessNumber.msGridColumnStart).toBeTruthy();
   });
-
 });
diff --git a/src/renderers/dom/shared/__tests__/CSSPropertyOperations-test.js b/src/renderers/dom/shared/__tests__/CSSPropertyOperations-test.js
index d33d2e6b1ef5..21029d00c3d3 100644
--- a/src/renderers/dom/shared/__tests__/CSSPropertyOperations-test.js
+++ b/src/renderers/dom/shared/__tests__/CSSPropertyOperations-test.js
@@ -15,78 +15,101 @@ var React = require('React');
 var ReactDOM = require('ReactDOM');
 var ReactDOMServer = require('ReactDOMServer');
 
-describe('CSSPropertyOperations', function() {
+describe('CSSPropertyOperations', () => {
   var CSSPropertyOperations;
 
-  beforeEach(function() {
+  beforeEach(() => {
     jest.resetModuleRegistry();
     CSSPropertyOperations = require('CSSPropertyOperations');
   });
 
-  it('should create markup for simple styles', function() {
-    expect(CSSPropertyOperations.createMarkupForStyles({
-      backgroundColor: '#3b5998',
-      display: 'none',
-    })).toBe('background-color:#3b5998;display:none;');
+  it('should create markup for simple styles', () => {
+    expect(
+      CSSPropertyOperations.createMarkupForStyles({
+        backgroundColor: '#3b5998',
+        display: 'none',
+      }),
+    ).toBe('background-color:#3b5998;display:none;');
   });
 
-  it('should ignore undefined styles', function() {
-    expect(CSSPropertyOperations.createMarkupForStyles({
-      backgroundColor: undefined,
-      display: 'none',
-    })).toBe('display:none;');
+  it('should ignore undefined styles', () => {
+    expect(
+      CSSPropertyOperations.createMarkupForStyles({
+        backgroundColor: undefined,
+        display: 'none',
+      }),
+    ).toBe('display:none;');
   });
 
-  it('should ignore null styles', function() {
-    expect(CSSPropertyOperations.createMarkupForStyles({
-      backgroundColor: null,
-      display: 'none',
-    })).toBe('display:none;');
+  it('should ignore null styles', () => {
+    expect(
+      CSSPropertyOperations.createMarkupForStyles({
+        backgroundColor: null,
+        display: 'none',
+      }),
+    ).toBe('display:none;');
   });
 
-  it('should return null for no styles', function() {
-    expect(CSSPropertyOperations.createMarkupForStyles({
-      backgroundColor: null,
-      display: null,
-    })).toBe(null);
+  it('should return null for no styles', () => {
+    expect(
+      CSSPropertyOperations.createMarkupForStyles({
+        backgroundColor: null,
+        display: null,
+      }),
+    ).toBe(null);
   });
 
-  it('should automatically append `px` to relevant styles', function() {
-    expect(CSSPropertyOperations.createMarkupForStyles({
-      left: 0,
-      margin: 16,
-      opacity: 0.5,
-      padding: '4px',
-    })).toBe('left:0;margin:16px;opacity:0.5;padding:4px;');
+  it('should automatically append `px` to relevant styles', () => {
+    expect(
+      CSSPropertyOperations.createMarkupForStyles({
+        left: 0,
+        margin: 16,
+        opacity: 0.5,
+        padding: '4px',
+      }),
+    ).toBe('left:0;margin:16px;opacity:0.5;padding:4px;');
   });
 
-  it('should trim values so `px` will be appended correctly', function() {
-    expect(CSSPropertyOperations.createMarkupForStyles({
-      margin: '16 ',
-      opacity: 0.5,
-      padding: ' 4 ',
-    })).toBe('margin:16px;opacity:0.5;padding:4px;');
+  it('should trim values so `px` will be appended correctly', () => {
+    expect(
+      CSSPropertyOperations.createMarkupForStyles({
+        margin: '16 ',
+        opacity: 0.5,
+        padding: ' 4 ',
+      }),
+    ).toBe('margin:16px;opacity:0.5;padding:4px;');
   });
 
-  it('should not append `px` to styles that might need a number', function() {
+  it('should not append `px` to styles that might need a number', () => {
     var CSSProperty = require('CSSProperty');
     var unitlessProperties = Object.keys(CSSProperty.isUnitlessNumber);
     unitlessProperties.forEach(function(property) {
       var styles = {};
       styles[property] = 1;
-      expect(CSSPropertyOperations.createMarkupForStyles(styles))
-        .toMatch(/:1;$/);
+      expect(CSSPropertyOperations.createMarkupForStyles(styles)).toMatch(
+        /:1;$/,
+      );
     });
   });
 
-  it('should create vendor-prefixed markup correctly', function() {
-    expect(CSSPropertyOperations.createMarkupForStyles({
-      msTransition: 'none',
-      MozTransition: 'none',
-    })).toBe('-ms-transition:none;-moz-transition:none;');
+  it('should create vendor-prefixed markup correctly', () => {
+    expect(
+      CSSPropertyOperations.createMarkupForStyles({
+        msTransition: 'none',
+        MozTransition: 'none',
+      }),
+    ).toBe('-ms-transition:none;-moz-transition:none;');
+  });
+
+  it('should create markup with unitless css custom property', () => {
+    expect(
+      CSSPropertyOperations.createMarkupForStyles({
+        '--foo': 5,
+      }),
+    ).toBe('--foo:5;');
   });
 
-  it('should set style attribute when styles exist', function() {
+  it('should set style attribute when styles exist', () => {
     var styles = {
       backgroundColor: '#000',
       display: 'none',
@@ -97,7 +120,7 @@ describe('CSSPropertyOperations', function() {
     expect(/style=".*"/.test(root.innerHTML)).toBe(true);
   });
 
-  it('should not set style attribute when no styles exist', function() {
+  it('should not set style attribute when no styles exist', () => {
     var styles = {
       backgroundColor: null,
       display: null,
@@ -107,30 +130,34 @@ describe('CSSPropertyOperations', function() {
     expect(/style=/.test(html)).toBe(false);
   });
 
-  it('should warn when using hyphenated style names', function() {
-    var Comp = React.createClass({
-      displayName: 'Comp',
-      render: function() {
-        return <div style={{ 'background-color': 'crimson' }}/>;
-      },
-    });
+  it('should warn when using hyphenated style names', () => {
+    class Comp extends React.Component {
+      static displayName = 'Comp';
+
+      render() {
+        return <div style={{'background-color': 'crimson'}} />;
+      }
+    }
+
     spyOn(console, 'error');
     var root = document.createElement('div');
     ReactDOM.render(<Comp />, root);
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toEqual(
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toEqual(
       'Warning: Unsupported style property background-color. Did you mean backgroundColor? ' +
-      'Check the render method of `Comp`.'
+        'Check the render method of `Comp`.',
     );
   });
 
-  it('should warn when updating hyphenated style names', function() {
-    var Comp = React.createClass({
-      displayName: 'Comp',
-      render: function() {
+  it('should warn when updating hyphenated style names', () => {
+    class Comp extends React.Component {
+      static displayName = 'Comp';
+
+      render() {
         return <div style={this.props.style} />;
-      },
-    });
+      }
+    }
+
     spyOn(console, 'error');
     var styles = {
       '-ms-transform': 'translate3d(0, 0, 0)',
@@ -140,84 +167,125 @@ describe('CSSPropertyOperations', function() {
     ReactDOM.render(<Comp />, root);
     ReactDOM.render(<Comp style={styles} />, root);
 
-    expect(console.error.argsForCall.length).toBe(2);
-    expect(console.error.argsForCall[0][0]).toEqual(
+    expect(console.error.calls.count()).toBe(2);
+    expect(console.error.calls.argsFor(0)[0]).toEqual(
       'Warning: Unsupported style property -ms-transform. Did you mean msTransform? ' +
-      'Check the render method of `Comp`.'
+        'Check the render method of `Comp`.',
     );
-    expect(console.error.argsForCall[1][0]).toEqual(
+    expect(console.error.calls.argsFor(1)[0]).toEqual(
       'Warning: Unsupported style property -webkit-transform. Did you mean WebkitTransform? ' +
-      'Check the render method of `Comp`.'
+        'Check the render method of `Comp`.',
     );
   });
 
-  it('warns when miscapitalizing vendored style names', function() {
-    var Comp = React.createClass({
-      displayName: 'Comp',
-      render: function() {
-        return (<div style={{
-          msTransform: 'translate3d(0, 0, 0)',
-          oTransform: 'translate3d(0, 0, 0)',
-          webkitTransform: 'translate3d(0, 0, 0)',
-        }} />);
-      },
-    });
+  it('warns when miscapitalizing vendored style names', () => {
+    class Comp extends React.Component {
+      static displayName = 'Comp';
+
+      render() {
+        return (
+          <div
+            style={{
+              msTransform: 'translate3d(0, 0, 0)',
+              oTransform: 'translate3d(0, 0, 0)',
+              webkitTransform: 'translate3d(0, 0, 0)',
+            }}
+          />
+        );
+      }
+    }
+
     spyOn(console, 'error');
     var root = document.createElement('div');
     ReactDOM.render(<Comp />, root);
     // msTransform is correct already and shouldn't warn
-    expect(console.error.argsForCall.length).toBe(2);
-    expect(console.error.argsForCall[0][0]).toEqual(
+    expect(console.error.calls.count()).toBe(2);
+    expect(console.error.calls.argsFor(0)[0]).toEqual(
       'Warning: Unsupported vendor-prefixed style property oTransform. ' +
-      'Did you mean OTransform? Check the render method of `Comp`.'
+        'Did you mean OTransform? Check the render method of `Comp`.',
     );
-    expect(console.error.argsForCall[1][0]).toEqual(
+    expect(console.error.calls.argsFor(1)[0]).toEqual(
       'Warning: Unsupported vendor-prefixed style property webkitTransform. ' +
-      'Did you mean WebkitTransform? Check the render method of `Comp`.'
+        'Did you mean WebkitTransform? Check the render method of `Comp`.',
     );
   });
 
-  it('should warn about style having a trailing semicolon', function() {
-    var Comp = React.createClass({
-      displayName: 'Comp',
-      render: function() {
-        return (<div style={{
-          fontFamily: 'Helvetica, arial',
-          backgroundImage: 'url(foo;bar)',
-          backgroundColor: 'blue;',
-          color: 'red;   ',
-        }} />);
-      },
-    });
+  it('should warn about style having a trailing semicolon', () => {
+    class Comp extends React.Component {
+      static displayName = 'Comp';
+
+      render() {
+        return (
+          <div
+            style={{
+              fontFamily: 'Helvetica, arial',
+              backgroundImage: 'url(foo;bar)',
+              backgroundColor: 'blue;',
+              color: 'red;   ',
+            }}
+          />
+        );
+      }
+    }
+
     spyOn(console, 'error');
     var root = document.createElement('div');
     ReactDOM.render(<Comp />, root);
-    expect(console.error.calls.length).toBe(2);
-    expect(console.error.argsForCall[0][0]).toEqual(
-      'Warning: Style property values shouldn\'t contain a semicolon. ' +
-      'Check the render method of `Comp`. Try "backgroundColor: blue" instead.',
+    expect(console.error.calls.count()).toBe(2);
+    expect(console.error.calls.argsFor(0)[0]).toEqual(
+      "Warning: Style property values shouldn't contain a semicolon. " +
+        'Check the render method of `Comp`. Try "backgroundColor: blue" instead.',
     );
-    expect(console.error.argsForCall[1][0]).toEqual(
-      'Warning: Style property values shouldn\'t contain a semicolon. ' +
-      'Check the render method of `Comp`. Try "color: red" instead.',
+    expect(console.error.calls.argsFor(1)[0]).toEqual(
+      "Warning: Style property values shouldn't contain a semicolon. " +
+        'Check the render method of `Comp`. Try "color: red" instead.',
     );
   });
 
-  it('should warn about style containing a NaN value', function() {
-    var Comp = React.createClass({
-      displayName: 'Comp',
-      render: function() {
-        return <div style={{ fontSize: NaN }}/>;
-      },
-    });
+  it('should warn about style containing a NaN value', () => {
+    class Comp extends React.Component {
+      static displayName = 'Comp';
+
+      render() {
+        return <div style={{fontSize: NaN}} />;
+      }
+    }
+
     spyOn(console, 'error');
     var root = document.createElement('div');
     ReactDOM.render(<Comp />, root);
 
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toEqual(
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toEqual(
       'Warning: `NaN` is an invalid value for the `fontSize` css style property. ' +
-      'Check the render method of `Comp`.'
+        'Check the render method of `Comp`.',
     );
   });
+
+  it('should not warn when setting CSS custom properties', () => {
+    class Comp extends React.Component {
+      render() {
+        return <div style={{'--foo-primary': 'red', backgroundColor: 'red'}} />;
+      }
+    }
+
+    spyOn(console, 'error');
+    var root = document.createElement('div');
+    ReactDOM.render(<Comp />, root);
+
+    expect(console.error.calls.count()).toBe(0);
+  });
+
+  it('should not add units to CSS custom properties', () => {
+    class Comp extends React.Component {
+      render() {
+        return <div style={{'--foo': 5}} />;
+      }
+    }
+
+    var root = document.createElement('div');
+    ReactDOM.render(<Comp />, root);
+
+    expect(root.children[0].style.Foo).toEqual('5');
+  });
 });
diff --git a/src/renderers/dom/shared/__tests__/DOMPropertyOperations-test.js b/src/renderers/dom/shared/__tests__/DOMPropertyOperations-test.js
index 14b72282ae26..9e440956e8b9 100644
--- a/src/renderers/dom/shared/__tests__/DOMPropertyOperations-test.js
+++ b/src/renderers/dom/shared/__tests__/DOMPropertyOperations-test.js
@@ -11,197 +11,179 @@
 
 'use strict';
 
-describe('DOMPropertyOperations', function() {
+describe('DOMPropertyOperations', () => {
   var DOMPropertyOperations;
   var DOMProperty;
+  var ReactDOMComponentTree;
 
-  beforeEach(function() {
+  beforeEach(() => {
     jest.resetModuleRegistry();
     var ReactDefaultInjection = require('ReactDefaultInjection');
     ReactDefaultInjection.inject();
 
     DOMPropertyOperations = require('DOMPropertyOperations');
     DOMProperty = require('DOMProperty');
+    ReactDOMComponentTree = require('ReactDOMComponentTree');
   });
 
-  describe('createMarkupForProperty', function() {
-
-    it('should create markup for simple properties', function() {
-      expect(DOMPropertyOperations.createMarkupForProperty(
-        'name',
-        'simple'
-      )).toBe('name="simple"');
+  describe('createMarkupForProperty', () => {
+    it('should create markup for simple properties', () => {
+      expect(
+        DOMPropertyOperations.createMarkupForProperty('name', 'simple'),
+      ).toBe('name="simple"');
 
-      expect(DOMPropertyOperations.createMarkupForProperty(
-        'name',
-        false
-      )).toBe('name="false"');
+      expect(DOMPropertyOperations.createMarkupForProperty('name', false)).toBe(
+        'name="false"',
+      );
 
-      expect(DOMPropertyOperations.createMarkupForProperty(
-        'name',
-        null
-      )).toBe('');
+      expect(DOMPropertyOperations.createMarkupForProperty('name', null)).toBe(
+        '',
+      );
     });
 
-    it('should work with the id attribute', function() {
-      expect(DOMPropertyOperations.createMarkupForProperty(
-        'id',
-        'simple'
-      )).toBe('id="simple"');
+    it('should work with the id attribute', () => {
+      expect(
+        DOMPropertyOperations.createMarkupForProperty('id', 'simple'),
+      ).toBe('id="simple"');
     });
 
-    it('should create markup for boolean properties', function() {
-      expect(DOMPropertyOperations.createMarkupForProperty(
-        'checked',
-        'simple'
-      )).toBe('checked=""');
-
-      expect(DOMPropertyOperations.createMarkupForProperty(
-        'checked',
-        true
-      )).toBe('checked=""');
-
-      expect(DOMPropertyOperations.createMarkupForProperty(
-        'checked',
-        false
-      )).toBe('');
-
-      expect(DOMPropertyOperations.createMarkupForProperty(
-        'scoped',
-        true
-      )).toBe('scoped=""');
-    });
+    it('should create markup for boolean properties', () => {
+      expect(
+        DOMPropertyOperations.createMarkupForProperty('checked', 'simple'),
+      ).toBe('checked=""');
+
+      expect(
+        DOMPropertyOperations.createMarkupForProperty('checked', true),
+      ).toBe('checked=""');
 
-    it('should create markup for booleanish properties', function() {
-      expect(DOMPropertyOperations.createMarkupForProperty(
-        'download',
-        'simple'
-      )).toBe('download="simple"');
-
-      expect(DOMPropertyOperations.createMarkupForProperty(
-        'download',
-        true
-      )).toBe('download=""');
-
-      expect(DOMPropertyOperations.createMarkupForProperty(
-        'download',
-        'true'
-      )).toBe('download="true"');
-
-      expect(DOMPropertyOperations.createMarkupForProperty(
-        'download',
-        false
-      )).toBe('');
-
-      expect(DOMPropertyOperations.createMarkupForProperty(
-        'download',
-        'false'
-      )).toBe('download="false"');
-
-      expect(DOMPropertyOperations.createMarkupForProperty(
-        'download',
-        undefined
-      )).toBe('');
-
-      expect(DOMPropertyOperations.createMarkupForProperty(
-        'download',
-        null
-      )).toBe('');
-
-      expect(DOMPropertyOperations.createMarkupForProperty(
-        'download',
-        0
-      )).toBe('download="0"');
+      expect(
+        DOMPropertyOperations.createMarkupForProperty('checked', false),
+      ).toBe('');
+
+      expect(
+        DOMPropertyOperations.createMarkupForProperty('scoped', true),
+      ).toBe('scoped=""');
     });
 
-    it('should create markup for custom attributes', function() {
-      expect(DOMPropertyOperations.createMarkupForProperty(
-        'aria-label',
-        'simple'
-      )).toBe('aria-label="simple"');
-
-      expect(DOMPropertyOperations.createMarkupForProperty(
-        'aria-label',
-        false
-      )).toBe('aria-label="false"');
-
-      expect(DOMPropertyOperations.createMarkupForProperty(
-        'aria-label',
-        null
-      )).toBe('');
+    it('should create markup for booleanish properties', () => {
+      expect(
+        DOMPropertyOperations.createMarkupForProperty('download', 'simple'),
+      ).toBe('download="simple"');
+
+      expect(
+        DOMPropertyOperations.createMarkupForProperty('download', true),
+      ).toBe('download=""');
+
+      expect(
+        DOMPropertyOperations.createMarkupForProperty('download', 'true'),
+      ).toBe('download="true"');
+
+      expect(
+        DOMPropertyOperations.createMarkupForProperty('download', false),
+      ).toBe('');
+
+      expect(
+        DOMPropertyOperations.createMarkupForProperty('download', 'false'),
+      ).toBe('download="false"');
+
+      expect(
+        DOMPropertyOperations.createMarkupForProperty('download', undefined),
+      ).toBe('');
+
+      expect(
+        DOMPropertyOperations.createMarkupForProperty('download', null),
+      ).toBe('');
+
+      expect(DOMPropertyOperations.createMarkupForProperty('download', 0)).toBe(
+        'download="0"',
+      );
     });
 
-    it('should create markup for numeric properties', function() {
-      expect(DOMPropertyOperations.createMarkupForProperty(
-        'start',
-        5
-      )).toBe('start="5"');
-
-      expect(DOMPropertyOperations.createMarkupForProperty(
-        'start',
-        0
-      )).toBe('start="0"');
-
-      expect(DOMPropertyOperations.createMarkupForProperty(
-        'size',
-        0
-      )).toBe('');
-
-      expect(DOMPropertyOperations.createMarkupForProperty(
-        'size',
-        1
-      )).toBe('size="1"');
+    it('should create markup for custom attributes', () => {
+      expect(
+        DOMPropertyOperations.createMarkupForProperty('aria-label', 'simple'),
+      ).toBe('aria-label="simple"');
+
+      expect(
+        DOMPropertyOperations.createMarkupForProperty('aria-label', false),
+      ).toBe('aria-label="false"');
+
+      expect(
+        DOMPropertyOperations.createMarkupForProperty('aria-label', null),
+      ).toBe('');
     });
 
-  });
+    it('should create markup for numeric properties', () => {
+      expect(DOMPropertyOperations.createMarkupForProperty('start', 5)).toBe(
+        'start="5"',
+      );
 
-  describe('createMarkupForProperty', function() {
+      expect(DOMPropertyOperations.createMarkupForProperty('start', 0)).toBe(
+        'start="0"',
+      );
 
-    it('should allow custom properties on web components', function() {
-      expect(DOMPropertyOperations.createMarkupForCustomAttribute(
-        'awesomeness',
-        5
-      )).toBe('awesomeness="5"');
+      expect(DOMPropertyOperations.createMarkupForProperty('size', 0)).toBe('');
 
-      expect(DOMPropertyOperations.createMarkupForCustomAttribute(
-        'dev',
-        'jim'
-      )).toBe('dev="jim"');
+      expect(DOMPropertyOperations.createMarkupForProperty('size', 1)).toBe(
+        'size="1"',
+      );
     });
   });
 
-  describe('setValueForProperty', function() {
+  describe('createMarkupForProperty', () => {
+    it('should allow custom properties on web components', () => {
+      expect(
+        DOMPropertyOperations.createMarkupForCustomAttribute('awesomeness', 5),
+      ).toBe('awesomeness="5"');
+
+      expect(
+        DOMPropertyOperations.createMarkupForCustomAttribute('dev', 'jim'),
+      ).toBe('dev="jim"');
+    });
+  });
+
+  describe('setValueForProperty', () => {
     var stubNode;
+    var stubInstance;
 
-    beforeEach(function() {
+    beforeEach(() => {
       stubNode = document.createElement('div');
+      stubInstance = {_debugID: 1};
+      ReactDOMComponentTree.precacheNode(stubInstance, stubNode);
     });
 
-    it('should set values as properties by default', function() {
+    it('should set values as properties by default', () => {
       DOMPropertyOperations.setValueForProperty(stubNode, 'title', 'Tip!');
       expect(stubNode.title).toBe('Tip!');
     });
 
-    it('should set values as attributes if necessary', function() {
+    it('should set values as attributes if necessary', () => {
       DOMPropertyOperations.setValueForProperty(stubNode, 'role', '#');
       expect(stubNode.getAttribute('role')).toBe('#');
       expect(stubNode.role).toBeUndefined();
     });
 
-    it('should set values as namespace attributes if necessary', function() {
+    it('should set values as namespace attributes if necessary', () => {
       spyOn(stubNode, 'setAttributeNS');
       DOMPropertyOperations.setValueForProperty(
         stubNode,
         'xlinkHref',
-        'about:blank'
+        'about:blank',
       );
-      expect(stubNode.setAttributeNS.argsForCall.length).toBe(1);
-      expect(stubNode.setAttributeNS.argsForCall[0])
-        .toEqual(['http://www.w3.org/1999/xlink', 'xlink:href', 'about:blank']);
+      expect(stubNode.setAttributeNS.calls.count()).toBe(1);
+      expect(stubNode.setAttributeNS.calls.argsFor(0)).toEqual([
+        'http://www.w3.org/1999/xlink',
+        'xlink:href',
+        'about:blank',
+      ]);
     });
 
-    it('should set values as boolean properties', function() {
-      DOMPropertyOperations.setValueForProperty(stubNode, 'disabled', 'disabled');
+    it('should set values as boolean properties', () => {
+      DOMPropertyOperations.setValueForProperty(
+        stubNode,
+        'disabled',
+        'disabled',
+      );
       expect(stubNode.getAttribute('disabled')).toBe('');
       DOMPropertyOperations.setValueForProperty(stubNode, 'disabled', true);
       expect(stubNode.getAttribute('disabled')).toBe('');
@@ -209,7 +191,7 @@ describe('DOMPropertyOperations', function() {
       expect(stubNode.getAttribute('disabled')).toBe(null);
     });
 
-    it('should convert attribute values to string first', function() {
+    it('should convert attribute values to string first', () => {
       // Browsers default to this behavior, but some test environments do not.
       // This ensures that we have consistent behavior.
       var obj = {
@@ -221,40 +203,34 @@ describe('DOMPropertyOperations', function() {
       expect(stubNode.getAttribute('role')).toBe('<html>');
     });
 
-    it('should not remove empty attributes for special properties', function() {
+    it('should not remove empty attributes for special properties', () => {
       stubNode = document.createElement('input');
+      ReactDOMComponentTree.precacheNode(stubInstance, stubNode);
+
       DOMPropertyOperations.setValueForProperty(stubNode, 'value', '');
       // JSDOM does not behave correctly for attributes/properties
       //expect(stubNode.getAttribute('value')).toBe('');
       expect(stubNode.value).toBe('');
     });
 
-    it('should remove for falsey boolean properties', function() {
+    it('should remove for falsey boolean properties', () => {
       DOMPropertyOperations.setValueForProperty(
         stubNode,
         'allowFullScreen',
-        false
+        false,
       );
       expect(stubNode.hasAttribute('allowFullScreen')).toBe(false);
     });
 
-    it('should remove when setting custom attr to null', function() {
-      DOMPropertyOperations.setValueForProperty(
-        stubNode,
-        'data-foo',
-        'bar'
-      );
+    it('should remove when setting custom attr to null', () => {
+      DOMPropertyOperations.setValueForProperty(stubNode, 'data-foo', 'bar');
       expect(stubNode.hasAttribute('data-foo')).toBe(true);
-      DOMPropertyOperations.setValueForProperty(
-        stubNode,
-        'data-foo',
-        null
-      );
+      DOMPropertyOperations.setValueForProperty(stubNode, 'data-foo', null);
       expect(stubNode.hasAttribute('data-foo')).toBe(false);
     });
 
-    it('should use mutation method where applicable', function() {
-      var foobarSetter = jest.genMockFn();
+    it('should use mutation method where applicable', () => {
+      var foobarSetter = jest.fn();
       // inject foobar DOM property
       DOMProperty.injection.injectDOMPropertyConfig({
         Properties: {foobar: null},
@@ -266,7 +242,7 @@ describe('DOMPropertyOperations', function() {
       DOMPropertyOperations.setValueForProperty(
         stubNode,
         'foobar',
-        'cows say moo'
+        'cows say moo',
       );
 
       expect(foobarSetter.mock.calls.length).toBe(1);
@@ -274,42 +250,30 @@ describe('DOMPropertyOperations', function() {
       expect(foobarSetter.mock.calls[0][1]).toBe('cows say moo');
     });
 
-    it('should set className to empty string instead of null', function() {
+    it('should set className to empty string instead of null', () => {
       DOMPropertyOperations.setValueForProperty(
         stubNode,
         'className',
-        'selected'
+        'selected',
       );
       expect(stubNode.className).toBe('selected');
 
-      DOMPropertyOperations.setValueForProperty(
-        stubNode,
-        'className',
-        null
-      );
+      DOMPropertyOperations.setValueForProperty(stubNode, 'className', null);
       // className should be '', not 'null' or null (which becomes 'null' in
       // some browsers)
       expect(stubNode.className).toBe('');
       expect(stubNode.getAttribute('class')).toBe(null);
     });
 
-    it('should remove property properly for boolean properties', function() {
-      DOMPropertyOperations.setValueForProperty(
-        stubNode,
-        'hidden',
-        true
-      );
+    it('should remove property properly for boolean properties', () => {
+      DOMPropertyOperations.setValueForProperty(stubNode, 'hidden', true);
       expect(stubNode.hasAttribute('hidden')).toBe(true);
 
-      DOMPropertyOperations.setValueForProperty(
-        stubNode,
-        'hidden',
-        false
-      );
+      DOMPropertyOperations.setValueForProperty(stubNode, 'hidden', false);
       expect(stubNode.hasAttribute('hidden')).toBe(false);
     });
 
-    it('should remove property properly even with different name', function() {
+    it('should remove property properly even with different name', () => {
       // Suppose 'foobar' is a property that corresponds to the underlying
       // 'className' property:
       DOMProperty.injection.injectDOMPropertyConfig({
@@ -322,33 +286,56 @@ describe('DOMPropertyOperations', function() {
         },
       });
 
-      DOMPropertyOperations.setValueForProperty(
-        stubNode,
-        'foobar',
-        'selected'
-      );
+      DOMPropertyOperations.setValueForProperty(stubNode, 'foobar', 'selected');
       expect(stubNode.className).toBe('selected');
 
-      DOMPropertyOperations.setValueForProperty(
-        stubNode,
-        'foobar',
-        null
-      );
+      DOMPropertyOperations.setValueForProperty(stubNode, 'foobar', null);
       // className should be '', not 'null' or null (which becomes 'null' in
       // some browsers)
       expect(stubNode.className).toBe('');
     });
+  });
+
+  describe('value mutation method', function() {
+    it('should update an empty attribute to zero', function() {
+      var stubNode = document.createElement('input');
+      var stubInstance = {_debugID: 1};
+      ReactDOMComponentTree.precacheNode(stubInstance, stubNode);
+
+      stubNode.setAttribute('type', 'radio');
+
+      DOMPropertyOperations.setValueForProperty(stubNode, 'value', '');
+      spyOn(stubNode, 'setAttribute');
+      DOMPropertyOperations.setValueForProperty(stubNode, 'value', 0);
+
+      expect(stubNode.setAttribute.calls.count()).toBe(1);
+    });
+
+    it('should always assign the value attribute for non-inputs', function() {
+      var stubNode = document.createElement('progress');
+      var stubInstance = {_debugID: 1};
+      ReactDOMComponentTree.precacheNode(stubInstance, stubNode);
+
+      spyOn(stubNode, 'setAttribute');
 
+      DOMPropertyOperations.setValueForProperty(stubNode, 'value', 30);
+      DOMPropertyOperations.setValueForProperty(stubNode, 'value', '30');
+
+      expect(stubNode.setAttribute.calls.count()).toBe(2);
+    });
   });
 
-  describe('deleteValueForProperty', function() {
+  describe('deleteValueForProperty', () => {
     var stubNode;
+    var stubInstance;
 
-    beforeEach(function() {
+    beforeEach(() => {
       stubNode = document.createElement('div');
+      stubInstance = {_debugID: 1};
+      ReactDOMComponentTree.precacheNode(stubInstance, stubNode);
     });
 
-    it('should remove attributes for normal properties', function() {
+    it('should remove attributes for normal properties', () => {
       DOMPropertyOperations.setValueForProperty(stubNode, 'title', 'foo');
       expect(stubNode.getAttribute('title')).toBe('foo');
       expect(stubNode.title).toBe('foo');
@@ -359,8 +346,10 @@ describe('DOMPropertyOperations', function() {
       //expect(stubNode.title).toBe('');
     });
 
-    it('should not remove attributes for special properties', function() {
+    it('should not remove attributes for special properties', () => {
       stubNode = document.createElement('input');
+      ReactDOMComponentTree.precacheNode(stubInstance, stubNode);
+
       stubNode.setAttribute('value', 'foo');
 
       DOMPropertyOperations.deleteValueForProperty(stubNode, 'value');
@@ -369,8 +358,10 @@ describe('DOMPropertyOperations', function() {
       expect(stubNode.value).toBe('');
     });
 
-    it('should not leave all options selected when deleting multiple', function() {
+    it('should not leave all options selected when deleting multiple', () => {
       stubNode = document.createElement('select');
+      ReactDOMComponentTree.precacheNode(stubInstance, stubNode);
+
       stubNode.multiple = true;
       stubNode.appendChild(document.createElement('option'));
       stubNode.appendChild(document.createElement('option'));
@@ -381,26 +372,23 @@ describe('DOMPropertyOperations', function() {
       expect(stubNode.getAttribute('multiple')).toBe(null);
       expect(stubNode.multiple).toBe(false);
 
-      expect(
-        stubNode.options[0].selected &&
-        stubNode.options[1].selected
-      ).toBe(false);
+      expect(stubNode.options[0].selected && stubNode.options[1].selected).toBe(
+        false,
+      );
     });
   });
 
-  describe('injectDOMPropertyConfig', function() {
-    it('should support custom attributes', function() {
+  describe('injectDOMPropertyConfig', () => {
+    it('should support custom attributes', () => {
       // foobar does not exist yet
-      expect(DOMPropertyOperations.createMarkupForProperty(
-        'foobar',
-        'simple'
-      )).toBe(null);
+      expect(
+        DOMPropertyOperations.createMarkupForProperty('foobar', 'simple'),
+      ).toBe(null);
 
       // foo-* does not exist yet
-      expect(DOMPropertyOperations.createMarkupForProperty(
-        'foo-xyz',
-        'simple'
-      )).toBe(null);
+      expect(
+        DOMPropertyOperations.createMarkupForProperty('foo-xyz', 'simple'),
+      ).toBe(null);
 
       // inject foobar DOM property
       DOMProperty.injection.injectDOMPropertyConfig({
@@ -411,32 +399,28 @@ describe('DOMPropertyOperations', function() {
       });
 
       // Ensure old attributes still work
-      expect(DOMPropertyOperations.createMarkupForProperty(
-        'name',
-        'simple'
-      )).toBe('name="simple"');
-      expect(DOMPropertyOperations.createMarkupForProperty(
-        'data-name',
-        'simple'
-      )).toBe('data-name="simple"');
+      expect(
+        DOMPropertyOperations.createMarkupForProperty('name', 'simple'),
+      ).toBe('name="simple"');
+      expect(
+        DOMPropertyOperations.createMarkupForProperty('data-name', 'simple'),
+      ).toBe('data-name="simple"');
 
       // foobar should work
-      expect(DOMPropertyOperations.createMarkupForProperty(
-        'foobar',
-        'simple'
-      )).toBe('foobar="simple"');
+      expect(
+        DOMPropertyOperations.createMarkupForProperty('foobar', 'simple'),
+      ).toBe('foobar="simple"');
 
       // foo-* should work
-      expect(DOMPropertyOperations.createMarkupForProperty(
-        'foo-xyz',
-        'simple'
-      )).toBe('foo-xyz="simple"');
+      expect(
+        DOMPropertyOperations.createMarkupForProperty('foo-xyz', 'simple'),
+      ).toBe('foo-xyz="simple"');
 
       // It should complain about double injections.
       expect(function() {
-        DOMProperty.injection.injectDOMPropertyConfig(
-          {Properties: {foobar: null}}
-        );
+        DOMProperty.injection.injectDOMPropertyConfig({
+          Properties: {foobar: null},
+        });
       }).toThrow();
     });
   });
diff --git a/src/renderers/dom/shared/__tests__/Danger-test.js b/src/renderers/dom/shared/__tests__/Danger-test.js
deleted file mode 100644
index 97149d1d1d65..000000000000
--- a/src/renderers/dom/shared/__tests__/Danger-test.js
+++ /dev/null
@@ -1,101 +0,0 @@
-/**
- * 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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-describe('Danger', function() {
-
-  describe('dangerouslyRenderMarkup', function() {
-    var Danger;
-
-    beforeEach(function() {
-      jest.resetModuleRegistry();
-      Danger = require('Danger');
-    });
-
-    it('should render markup', function() {
-      var markup = '<div data-reactid=".rX"></div>';
-      var output = Danger.dangerouslyRenderMarkup([markup])[0];
-
-      expect(output.nodeName).toBe('DIV');
-    });
-
-    it('should render markup with props', function() {
-      var markup = '<div class="foo" data-reactid=".rX"></div>';
-      var output = Danger.dangerouslyRenderMarkup([markup])[0];
-
-      expect(output.nodeName).toBe('DIV');
-      expect(output.className).toBe('foo');
-    });
-
-    it('should render wrapped markup', function() {
-      var markup = '<th data-reactid=".rX"></th>';
-      var output = Danger.dangerouslyRenderMarkup([markup])[0];
-
-      expect(output.nodeName).toBe('TH');
-    });
-
-    it('should render lists of markup with similar `nodeName`', function() {
-      var renderedMarkup = Danger.dangerouslyRenderMarkup(
-        ['<p id="A">1</p>', '<p id="B">2</p>', '<p id="C">3</p>']
-      );
-
-      expect(renderedMarkup.length).toBe(3);
-
-      expect(renderedMarkup[0].nodeName).toBe('P');
-      expect(renderedMarkup[1].nodeName).toBe('P');
-      expect(renderedMarkup[2].nodeName).toBe('P');
-
-      expect(renderedMarkup[0].innerHTML).toBe('1');
-      expect(renderedMarkup[1].innerHTML).toBe('2');
-      expect(renderedMarkup[2].innerHTML).toBe('3');
-    });
-
-    it('should render lists of markup with different `nodeName`', function() {
-      var renderedMarkup = Danger.dangerouslyRenderMarkup(
-        ['<p id="A">1</p>', '<td id="B">2</td>', '<p id="C">3</p>']
-      );
-
-      expect(renderedMarkup.length).toBe(3);
-
-      expect(renderedMarkup[0].nodeName).toBe('P');
-      expect(renderedMarkup[1].nodeName).toBe('TD');
-      expect(renderedMarkup[2].nodeName).toBe('P');
-
-      expect(renderedMarkup[0].innerHTML).toBe('1');
-      expect(renderedMarkup[1].innerHTML).toBe('2');
-      expect(renderedMarkup[2].innerHTML).toBe('3');
-    });
-
-    it('should throw when rendering invalid markup', function() {
-      expect(function() {
-        Danger.dangerouslyRenderMarkup(['']);
-      }).toThrow(
-        'dangerouslyRenderMarkup(...): Missing markup.'
-      );
-
-      spyOn(console, 'error');
-
-      var renderedMarkup = Danger.dangerouslyRenderMarkup(['<p></p><p></p>']);
-      var args = console.error.argsForCall[0];
-
-      expect(renderedMarkup.length).toBe(1);
-      expect(renderedMarkup[0].nodeName).toBe('P');
-
-      expect(console.error.argsForCall.length).toBe(1);
-
-      expect(args.length).toBe(2);
-      expect(args[0]).toBe('Danger: Discarding unexpected node:');
-      expect(args[1].nodeName).toBe('P');
-    });
-  });
-
-});
diff --git a/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js b/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js
index 7bc84cf5eba6..1cf818de21ed 100644
--- a/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js
+++ b/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js
@@ -11,29 +11,34 @@
 
 'use strict';
 
-
-describe('ReactDOMComponent', function() {
+describe('ReactDOMComponent', () => {
   var React;
   var ReactDOM;
   var ReactDOMFeatureFlags;
   var ReactDOMServer;
+  var inputValueTracking;
+
+  function normalizeCodeLocInfo(str) {
+    return str.replace(/\(at .+?:\d+\)/g, '(at **)');
+  }
 
-  beforeEach(function() {
+  beforeEach(() => {
     jest.resetModuleRegistry();
     React = require('React');
-    ReactDOMFeatureFlags = require('ReactDOMFeatureFlags')
     ReactDOM = require('ReactDOM');
+    ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
     ReactDOMServer = require('ReactDOMServer');
+    inputValueTracking = require('inputValueTracking');
   });
 
-  describe('updateDOM', function() {
+  describe('updateDOM', () => {
     var ReactTestUtils;
 
-    beforeEach(function() {
+    beforeEach(() => {
       ReactTestUtils = require('ReactTestUtils');
     });
 
-    it('should handle className', function() {
+    it('should handle className', () => {
       var container = document.createElement('div');
       ReactDOM.render(<div style={{}} />, container);
 
@@ -45,7 +50,7 @@ describe('ReactDOMComponent', function() {
       expect(container.firstChild.className).toEqual('');
     });
 
-    it('should gracefully handle various style value types', function() {
+    it('should gracefully handle various style value types', () => {
       var container = document.createElement('div');
       ReactDOM.render(<div style={{}} />, container);
       var stubStyle = container.firstChild.style;
@@ -67,7 +72,7 @@ describe('ReactDOMComponent', function() {
     });
 
     // TODO: (poshannessy) deprecate this pattern.
-    it('should update styles when mutating style object', function() {
+    it('should update styles when mutating style object', () => {
       // not actually used. Just to suppress the style mutation warning
       spyOn(console, 'error');
 
@@ -106,29 +111,29 @@ describe('ReactDOMComponent', function() {
       expect(stubStyle.lineHeight).toBe('');
     });
 
-    it('should warn when mutating style', function() {
+    it('should warn when mutating style', () => {
       spyOn(console, 'error');
 
       var style = {border: '1px solid black'};
-      var App = React.createClass({
-        getInitialState: function() {
-          return {style: style};
-        },
-        render: function() {
+
+      class App extends React.Component {
+        state = {style: style};
+
+        render() {
           return <div style={this.state.style}>asd</div>;
-        },
-      });
+        }
+      }
 
       var stub = ReactTestUtils.renderIntoDocument(<App />);
       style.position = 'absolute';
       stub.setState({style: style});
-      expect(console.error.argsForCall.length).toBe(1);
-      expect(console.error.argsForCall[0][0]).toEqual(
+      expect(console.error.calls.count()).toBe(1);
+      expect(console.error.calls.argsFor(0)[0]).toEqual(
         'Warning: `div` was passed a style object that has previously been ' +
-        'mutated. Mutating `style` is deprecated. Consider cloning it ' +
-        'beforehand. Check the `render` of `App`. Previous style: ' +
-        '{border: "1px solid black"}. Mutated style: ' +
-        '{border: "1px solid black", position: "absolute"}.'
+          'mutated. Mutating `style` is deprecated. Consider cloning it ' +
+          'beforehand. Check the `render` of `App`. Previous style: ' +
+          '{border: "1px solid black"}. Mutated style: ' +
+          '{border: "1px solid black", position: "absolute"}.',
       );
 
       style = {background: 'red'};
@@ -136,73 +141,114 @@ describe('ReactDOMComponent', function() {
       style.background = 'green';
       stub.setState({style: {background: 'green'}});
       // already warned once for the same component and owner
-      expect(console.error.argsForCall.length).toBe(1);
+      expect(console.error.calls.count()).toBe(1);
 
       style = {background: 'red'};
       var div = document.createElement('div');
-      ReactDOM.render(<span style={style}></span>, div);
+      ReactDOM.render(<span style={style} />, div);
       style.background = 'blue';
-      ReactDOM.render(<span style={style}></span>, div);
-      expect(console.error.argsForCall.length).toBe(2);
+      ReactDOM.render(<span style={style} />, div);
+      expect(console.error.calls.count()).toBe(2);
+    });
+
+    it('should warn for unknown prop', () => {
+      spyOn(console, 'error');
+      var container = document.createElement('div');
+      ReactDOM.render(<div foo="bar" />, container);
+      expect(console.error.calls.count(0)).toBe(1);
+      expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
+        'Warning: Unknown prop `foo` on <div> tag. Remove this prop from the element. ' +
+          'For details, see https://fb.me/react-unknown-prop\n    in div (at **)',
+      );
+    });
+
+    it('should group multiple unknown prop warnings together', () => {
+      spyOn(console, 'error');
+      var container = document.createElement('div');
+      ReactDOM.render(<div foo="bar" baz="qux" />, container);
+      expect(console.error.calls.count(0)).toBe(1);
+      expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
+        'Warning: Unknown props `foo`, `baz` on <div> tag. Remove these props from the element. ' +
+          'For details, see https://fb.me/react-unknown-prop\n    in div (at **)',
+      );
+    });
+
+    it('should warn for onDblClick prop', () => {
+      spyOn(console, 'error');
+      var container = document.createElement('div');
+      ReactDOM.render(<div onDblClick={() => {}} />, container);
+      expect(console.error.calls.count(0)).toBe(1);
+      expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
+        'Warning: Unknown event handler property onDblClick. Did you mean `onDoubleClick`?\n    in div (at **)',
+      );
     });
 
     it('should warn about styles with numeric string values for non-unitless properties', function() {
       spyOn(console, 'error');
 
       var div = document.createElement('div');
-      var One = React.createClass({
-        render: function() {
-          return this.props.inline ?
-            <span style={{fontSize: '1'}} /> :
-            <div style={{fontSize: '1'}} />;
-        },
-      });
-      var Two = React.createClass({
-        render: function() {
-          return <div style={{fontSize: '1'}} />;
-        },
-      });
+      function One(props) {
+        return props.inline
+          ? <span style={{fontSize: '1'}} />
+          : <div style={{fontSize: '1'}} />;
+      }
+      function Two() {
+        return <div style={{fontSize: '1'}} />;
+      }
       ReactDOM.render(<One inline={false} />, div);
-      expect(console.error.calls.length).toBe(1);
-      expect(console.error.argsForCall[0][0]).toBe(
+      expect(console.error.calls.count()).toBe(1);
+      expect(console.error.calls.argsFor(0)[0]).toBe(
         'Warning: a `div` tag (owner: `One`) was passed a numeric string value ' +
-        'for CSS property `fontSize` (value: `1`) which will be treated ' +
-        'as a unitless number in a future version of React.'
+          'for CSS property `fontSize` (value: `1`) which will be treated ' +
+          'as a unitless number in a future version of React.',
       );
 
       // Don't warn again for the same component
       ReactDOM.render(<One inline={true} />, div);
-      expect(console.error.calls.length).toBe(1);
+      expect(console.error.calls.count()).toBe(1);
 
       // Do warn for different components
       ReactDOM.render(<Two />, div);
-      expect(console.error.calls.length).toBe(2);
-      expect(console.error.argsForCall[1][0]).toBe(
+      expect(console.error.calls.count()).toBe(2);
+      expect(console.error.calls.argsFor(1)[0]).toBe(
         'Warning: a `div` tag (owner: `Two`) was passed a numeric string value ' +
-        'for CSS property `fontSize` (value: `1`) which will be treated ' +
-        'as a unitless number in a future version of React.'
+          'for CSS property `fontSize` (value: `1`) which will be treated ' +
+          'as a unitless number in a future version of React.',
       );
 
       // Really don't warn again for the same component
       ReactDOM.render(<One inline={true} />, div);
-      expect(console.error.calls.length).toBe(2);
+      expect(console.error.calls.count()).toBe(2);
     });
 
-    it('should warn nicely about NaN in style', function() {
+    it('should not warn for "0" as a unitless style value', () => {
+      spyOn(console, 'error');
+
+      class Component extends React.Component {
+        render() {
+          return <div style={{margin: '0'}} />;
+        }
+      }
+
+      ReactTestUtils.renderIntoDocument(<Component />);
+      expect(console.error.calls.count()).toBe(0);
+    });
+
+    it('should warn nicely about NaN in style', () => {
       spyOn(console, 'error');
 
       var style = {fontSize: NaN};
       var div = document.createElement('div');
-      ReactDOM.render(<span style={style}></span>, div);
-      ReactDOM.render(<span style={style}></span>, div);
+      ReactDOM.render(<span style={style} />, div);
+      ReactDOM.render(<span style={style} />, div);
 
-      expect(console.error.argsForCall.length).toBe(1);
-      expect(console.error.argsForCall[0][0]).toEqual(
+      expect(console.error.calls.count()).toBe(1);
+      expect(console.error.calls.argsFor(0)[0]).toEqual(
         'Warning: `NaN` is an invalid value for the `fontSize` css style property.',
       );
     });
 
-    it('should update styles if initially null', function() {
+    it('should update styles if initially null', () => {
       var styles = null;
       var container = document.createElement('div');
       ReactDOM.render(<div style={styles} />, container);
@@ -215,7 +261,7 @@ describe('ReactDOMComponent', function() {
       expect(stubStyle.display).toEqual('block');
     });
 
-    it('should update styles if updated to null multiple times', function() {
+    it('should update styles if updated to null multiple times', () => {
       var styles = null;
       var container = document.createElement('div');
       ReactDOM.render(<div style={styles} />, container);
@@ -236,7 +282,7 @@ describe('ReactDOMComponent', function() {
       expect(stubStyle.display).toEqual('');
     });
 
-    it('should skip reserved props on web components', function() {
+    it('should skip reserved props on web components', () => {
       var container = document.createElement('div');
 
       ReactDOM.render(
@@ -244,11 +290,11 @@ describe('ReactDOMComponent', function() {
           children={['foo']}
           suppressContentEditableWarning={true}
         />,
-        container
+        container,
       );
       expect(container.firstChild.hasAttribute('children')).toBe(false);
       expect(
-        container.firstChild.hasAttribute('suppressContentEditableWarning')
+        container.firstChild.hasAttribute('suppressContentEditableWarning'),
       ).toBe(false);
 
       ReactDOM.render(
@@ -256,35 +302,35 @@ describe('ReactDOMComponent', function() {
           children={['bar']}
           suppressContentEditableWarning={false}
         />,
-        container
+        container,
       );
       expect(container.firstChild.hasAttribute('children')).toBe(false);
       expect(
-        container.firstChild.hasAttribute('suppressContentEditableWarning')
+        container.firstChild.hasAttribute('suppressContentEditableWarning'),
       ).toBe(false);
     });
 
-    it('should skip dangerouslySetInnerHTML on web components', function() {
+    it('should skip dangerouslySetInnerHTML on web components', () => {
       var container = document.createElement('div');
 
       ReactDOM.render(
         <my-component dangerouslySetInnerHTML={{__html: 'hi'}} />,
-        container
+        container,
+      );
+      expect(container.firstChild.hasAttribute('dangerouslySetInnerHTML')).toBe(
+        false,
       );
-      expect(
-        container.firstChild.hasAttribute('dangerouslySetInnerHTML')
-      ).toBe(false);
 
       ReactDOM.render(
         <my-component dangerouslySetInnerHTML={{__html: 'bye'}} />,
-        container
+        container,
+      );
+      expect(container.firstChild.hasAttribute('dangerouslySetInnerHTML')).toBe(
+        false,
       );
-      expect(
-        container.firstChild.hasAttribute('dangerouslySetInnerHTML')
-      ).toBe(false);
     });
 
-    it('should remove attributes', function() {
+    it('should remove attributes', () => {
       var container = document.createElement('div');
       ReactDOM.render(<img height="17" />, container);
 
@@ -293,7 +339,7 @@ describe('ReactDOMComponent', function() {
       expect(container.firstChild.hasAttribute('height')).toBe(false);
     });
 
-    it('should remove properties', function() {
+    it('should remove properties', () => {
       var container = document.createElement('div');
       ReactDOM.render(<div className="monkey" />, container);
 
@@ -302,7 +348,16 @@ describe('ReactDOMComponent', function() {
       expect(container.firstChild.className).toEqual('');
     });
 
-    it('should clear a single style prop when changing `style`', function() {
+    it('should properly update custom attributes on custom elements', () => {
+      var container = document.createElement('div');
+      ReactDOM.render(<some-custom-element foo="bar" />, container);
+      ReactDOM.render(<some-custom-element bar="buzz" />, container);
+      var node = container.firstChild;
+      expect(node.hasAttribute('foo')).toBe(false);
+      expect(node.getAttribute('bar')).toBe('buzz');
+    });
+
+    it('should clear a single style prop when changing `style`', () => {
       var styles = {display: 'none', color: 'red'};
       var container = document.createElement('div');
       ReactDOM.render(<div style={styles} />, container);
@@ -315,24 +370,24 @@ describe('ReactDOMComponent', function() {
       expect(stubStyle.color).toEqual('green');
     });
 
-    it('should reject attribute key injection attack on markup', function() {
+    it('should reject attribute key injection attack on markup', () => {
       spyOn(console, 'error');
       for (var i = 0; i < 3; i++) {
         var container = document.createElement('div');
         var element = React.createElement(
           'x-foo-component',
           {'blah" onclick="beevil" noise="hi': 'selected'},
-          null
+          null,
         );
         ReactDOM.render(element, container);
       }
-      expect(console.error.argsForCall.length).toBe(1);
-      expect(console.error.argsForCall[0][0]).toEqual(
-        'Warning: Invalid attribute name: `blah" onclick="beevil" noise="hi`'
+      expect(console.error.calls.count()).toBe(1);
+      expect(console.error.calls.argsFor(0)[0]).toEqual(
+        'Warning: Invalid attribute name: `blah" onclick="beevil" noise="hi`',
       );
     });
 
-    it('should reject attribute key injection attack on update', function() {
+    it('should reject attribute key injection attack on update', () => {
       spyOn(console, 'error');
       for (var i = 0; i < 3; i++) {
         var container = document.createElement('div');
@@ -342,17 +397,17 @@ describe('ReactDOMComponent', function() {
         var afterUpdate = React.createElement(
           'x-foo-component',
           {'blah" onclick="beevil" noise="hi': 'selected'},
-          null
+          null,
         );
         ReactDOM.render(afterUpdate, container);
       }
-      expect(console.error.argsForCall.length).toBe(1);
-      expect(console.error.argsForCall[0][0]).toEqual(
-        'Warning: Invalid attribute name: `blah" onclick="beevil" noise="hi`'
+      expect(console.error.calls.count()).toBe(1);
+      expect(console.error.calls.argsFor(0)[0]).toEqual(
+        'Warning: Invalid attribute name: `blah" onclick="beevil" noise="hi`',
       );
     });
 
-    it('should update arbitrary attributes for tags containing dashes', function() {
+    it('should update arbitrary attributes for tags containing dashes', () => {
       var container = document.createElement('div');
 
       var beforeUpdate = React.createElement('x-foo-component', {}, null);
@@ -364,7 +419,7 @@ describe('ReactDOMComponent', function() {
       expect(container.childNodes[0].getAttribute('myattr')).toBe('myval');
     });
 
-    it('should clear all the styles when removing `style`', function() {
+    it('should clear all the styles when removing `style`', () => {
       var styles = {display: 'none', color: 'red'};
       var container = document.createElement('div');
       ReactDOM.render(<div style={styles} />, container);
@@ -376,7 +431,7 @@ describe('ReactDOMComponent', function() {
       expect(stubStyle.color).toEqual('');
     });
 
-    it('should update styles when `style` changes from null to object', function() {
+    it('should update styles when `style` changes from null to object', () => {
       var container = document.createElement('div');
       var styles = {color: 'red'};
       ReactDOM.render(<div style={styles} />, container);
@@ -387,32 +442,35 @@ describe('ReactDOMComponent', function() {
       expect(stubStyle.color).toEqual('red');
     });
 
-    it('should empty element when removing innerHTML', function() {
+    it('should empty element when removing innerHTML', () => {
       var container = document.createElement('div');
-      ReactDOM.render(<div dangerouslySetInnerHTML={{__html: ':)'}} />, container);
+      ReactDOM.render(
+        <div dangerouslySetInnerHTML={{__html: ':)'}} />,
+        container,
+      );
 
       expect(container.firstChild.innerHTML).toEqual(':)');
       ReactDOM.render(<div />, container);
       expect(container.firstChild.innerHTML).toEqual('');
     });
 
-    it('should transition from string content to innerHTML', function() {
+    it('should transition from string content to innerHTML', () => {
       var container = document.createElement('div');
       ReactDOM.render(<div>hello</div>, container);
 
       expect(container.firstChild.innerHTML).toEqual('hello');
       ReactDOM.render(
         <div dangerouslySetInnerHTML={{__html: 'goodbye'}} />,
-        container
+        container,
       );
       expect(container.firstChild.innerHTML).toEqual('goodbye');
     });
 
-    it('should transition from innerHTML to string content', function() {
+    it('should transition from innerHTML to string content', () => {
       var container = document.createElement('div');
       ReactDOM.render(
         <div dangerouslySetInnerHTML={{__html: 'bonjour'}} />,
-        container
+        container,
       );
 
       expect(container.firstChild.innerHTML).toEqual('bonjour');
@@ -420,11 +478,11 @@ describe('ReactDOMComponent', function() {
       expect(container.firstChild.innerHTML).toEqual('adieu');
     });
 
-    it('should transition from innerHTML to children in nested el', function() {
+    it('should transition from innerHTML to children in nested el', () => {
       var container = document.createElement('div');
       ReactDOM.render(
         <div><div dangerouslySetInnerHTML={{__html: 'bonjour'}} /></div>,
-        container
+        container,
       );
 
       expect(container.textContent).toEqual('bonjour');
@@ -432,30 +490,30 @@ describe('ReactDOMComponent', function() {
       expect(container.textContent).toEqual('adieu');
     });
 
-    it('should transition from children to innerHTML in nested el', function() {
+    it('should transition from children to innerHTML in nested el', () => {
       var container = document.createElement('div');
       ReactDOM.render(<div><div><span>adieu</span></div></div>, container);
 
       expect(container.textContent).toEqual('adieu');
       ReactDOM.render(
         <div><div dangerouslySetInnerHTML={{__html: 'bonjour'}} /></div>,
-        container
+        container,
       );
       expect(container.textContent).toEqual('bonjour');
     });
 
-    it('should not incur unnecessary DOM mutations for attributes', function() {
+    it('should not incur unnecessary DOM mutations for attributes', () => {
       var container = document.createElement('div');
       ReactDOM.render(<div id="" />, container);
 
       var node = container.firstChild;
       var nodeSetAttribute = node.setAttribute;
-      node.setAttribute = jest.genMockFn();
-      node.setAttribute.mockImpl(nodeSetAttribute);
+      node.setAttribute = jest.fn();
+      node.setAttribute.mockImplementation(nodeSetAttribute);
 
       var nodeRemoveAttribute = node.removeAttribute;
-      node.removeAttribute = jest.genMockFn();
-      node.removeAttribute.mockImpl(nodeRemoveAttribute);
+      node.removeAttribute = jest.fn();
+      node.removeAttribute.mockImplementation(nodeRemoveAttribute);
 
       ReactDOM.render(<div id="" />, container);
       expect(node.setAttribute.mock.calls.length).toBe(0);
@@ -482,60 +540,46 @@ describe('ReactDOMComponent', function() {
       expect(node.removeAttribute.mock.calls.length).toBe(2);
     });
 
-    it('should not incur unnecessary DOM mutations for string properties', function() {
+    it('should not incur unnecessary DOM mutations for string properties', () => {
       var container = document.createElement('div');
       ReactDOM.render(<div value="" />, container);
 
       var node = container.firstChild;
-      var nodeValue = ''; // node.value always returns undefined
+
       var nodeValueSetter = jest.genMockFn();
-      Object.defineProperty(node, 'value', {
-        get: function() {
-          return nodeValue;
-        },
-        set: nodeValueSetter.mockImplementation(function(newValue) {
-          nodeValue = newValue;
-        }),
-      });
 
-      function renderWithValueAndExpect(value, expected) {
-        ReactDOM.render(<div value={value} />, container);
-        expect(nodeValueSetter.mock.calls.length).toBe(expected);
-      }
+      var oldSetAttribute = node.setAttribute.bind(node);
+      node.setAttribute = function(key, value) {
+        oldSetAttribute(key, value);
+        nodeValueSetter(key, value);
+      };
 
-      if (ReactDOMFeatureFlags.useCreateElement) {
-        renderWithValueAndExpect(undefined, 0);
-        renderWithValueAndExpect('', 1);
-        renderWithValueAndExpect('foo', 2);
-        renderWithValueAndExpect('foo', 2);
-        renderWithValueAndExpect(undefined, 3);
-        renderWithValueAndExpect(null, 3);
-        renderWithValueAndExpect('', 4);
-        renderWithValueAndExpect(undefined, 4);
-      } else {
-        renderWithValueAndExpect(undefined, 0);
-        // This differs because we will have created a node with the value
-        // attribute set. This means it will hasAttribute, so we won't try to
-        // set the value.
-        renderWithValueAndExpect('', 0);
-        renderWithValueAndExpect('foo', 1);
-        renderWithValueAndExpect('foo', 1);
-        renderWithValueAndExpect(undefined, 2);
-        renderWithValueAndExpect(null, 2);
-        // Again, much like the initial update case, we will always have the
-        // attribute set so we won't set the value.
-        renderWithValueAndExpect('', 2);
-        renderWithValueAndExpect(undefined, 2);
-      }
+      ReactDOM.render(<div value="foo" />, container);
+      expect(nodeValueSetter.mock.calls.length).toBe(1);
+
+      ReactDOM.render(<div value="foo" />, container);
+      expect(nodeValueSetter.mock.calls.length).toBe(1);
+
+      ReactDOM.render(<div />, container);
+      expect(nodeValueSetter.mock.calls.length).toBe(1);
+
+      ReactDOM.render(<div value={null} />, container);
+      expect(nodeValueSetter.mock.calls.length).toBe(1);
+
+      ReactDOM.render(<div value="" />, container);
+      expect(nodeValueSetter.mock.calls.length).toBe(2);
+
+      ReactDOM.render(<div />, container);
+      expect(nodeValueSetter.mock.calls.length).toBe(2);
     });
 
-    it('should not incur unnecessary DOM mutations for boolean properties', function() {
+    it('should not incur unnecessary DOM mutations for boolean properties', () => {
       var container = document.createElement('div');
       ReactDOM.render(<div checked={true} />, container);
 
       var node = container.firstChild;
       var nodeValue = true;
-      var nodeValueSetter = jest.genMockFn();
+      var nodeValueSetter = jest.fn();
       Object.defineProperty(node, 'checked', {
         get: function() {
           return nodeValue;
@@ -558,17 +602,17 @@ describe('ReactDOMComponent', function() {
       expect(nodeValueSetter.mock.calls.length).toBe(3);
     });
 
-    it('should ignore attribute whitelist for elements with the "is: attribute', function() {
+    it('should ignore attribute whitelist for elements with the "is: attribute', () => {
       var container = document.createElement('div');
-      ReactDOM.render(<button is="test" cowabunga="chevynova"/>, container);
+      ReactDOM.render(<button is="test" cowabunga="chevynova" />, container);
       expect(container.firstChild.hasAttribute('cowabunga')).toBe(true);
     });
 
-    it('should not update when switching between null/undefined', function() {
+    it('should not update when switching between null/undefined', () => {
       var container = document.createElement('div');
       var node = ReactDOM.render(<div />, container);
 
-      var setter = jest.genMockFn();
+      var setter = jest.fn();
       node.setAttribute = setter;
 
       ReactDOM.render(<div dir={null} />, container);
@@ -579,7 +623,7 @@ describe('ReactDOMComponent', function() {
       expect(setter.mock.calls.length).toBe(1);
     });
 
-    it('handles multiple child updates without interference', function() {
+    it('handles multiple child updates without interference', () => {
       // This test might look like it's just testing ReactMultiChild but the
       // last bug in this was actually in DOMChildrenOperations so this test
       // needs to be in some DOM-specific test file.
@@ -595,7 +639,7 @@ describe('ReactDOMComponent', function() {
             <div key="C">C</div><div key="D">D</div>
           </div>
         </div>,
-        container
+        container,
       );
       // BADC
       ReactDOM.render(
@@ -607,21 +651,21 @@ describe('ReactDOMComponent', function() {
             <div key="D">D</div><div key="C">C</div>
           </div>
         </div>,
-        container
+        container,
       );
 
       expect(container.textContent).toBe('BADC');
     });
   });
 
-  describe('createOpenTagMarkup', function() {
+  describe('createOpenTagMarkup', () => {
     var genMarkup;
 
     function quoteRegexp(str) {
       return (str + '').replace(/([.?*+\^$\[\]\\(){}|-])/g, '\\$1');
     }
 
-    beforeEach(function() {
+    beforeEach(() => {
       var ReactDefaultInjection = require('ReactDefaultInjection');
       ReactDefaultInjection.inject();
 
@@ -630,221 +674,277 @@ describe('ReactDOMComponent', function() {
 
       var NodeStub = function(initialProps) {
         this._currentElement = {props: initialProps};
-        this._rootNodeID = 'test';
+        this._rootNodeID = 1;
       };
       Object.assign(NodeStub.prototype, ReactDOMComponent.Mixin);
 
       genMarkup = function(props) {
         var transaction = new ReactReconcileTransaction();
-        return (new NodeStub(props))._createOpenTagMarkupAndPutListeners(
+        return new NodeStub(props)._createOpenTagMarkupAndPutListeners(
           transaction,
-          props
+          props,
         );
       };
 
-      this.addMatchers({
-        toHaveAttribute: function(attr, value) {
-          var expected = '(?:^|\\s)' + attr + '=[\\\'"]';
-          if (typeof value !== 'undefined') {
-            expected += quoteRegexp(value) + '[\\\'"]';
-          }
-          return this.actual.match(new RegExp(expected));
+      jasmine.addMatchers({
+        toHaveAttribute() {
+          return {
+            compare(actual, expected) {
+              var [attr, value] = expected;
+              var re = '(?:^|\\s)' + attr + '=[\\\'"]';
+              if (typeof value !== 'undefined') {
+                re += quoteRegexp(value) + '[\\\'"]';
+              }
+              return {
+                pass: new RegExp(re).test(actual),
+              };
+            },
+          };
         },
       });
     });
 
-    it('should generate the correct markup with className', function() {
-      expect(genMarkup({className: 'a'})).toHaveAttribute('class', 'a');
-      expect(genMarkup({className: 'a b'})).toHaveAttribute('class', 'a b');
-      expect(genMarkup({className: ''})).toHaveAttribute('class', '');
+    it('should generate the correct markup with className', () => {
+      expect(genMarkup({className: 'a'})).toHaveAttribute(['class', 'a']);
+      expect(genMarkup({className: 'a b'})).toHaveAttribute(['class', 'a b']);
+      expect(genMarkup({className: ''})).toHaveAttribute(['class', '']);
     });
 
-    it('should escape style names and values', function() {
-      expect(genMarkup({
-        style: {'b&ckground': '<3'},
-      })).toHaveAttribute('style', 'b&amp;ckground:&lt;3;');
+    it('should escape style names and values', () => {
+      expect(
+        genMarkup({
+          style: {'b&ckground': '<3'},
+        }),
+      ).toHaveAttribute(['style', 'b&amp;ckground:&lt;3;']);
     });
   });
 
-  describe('createContentMarkup', function() {
+  describe('createContentMarkup', () => {
     var genMarkup;
 
     function quoteRegexp(str) {
       return (str + '').replace(/([.?*+\^$\[\]\\(){}|-])/g, '\\$1');
     }
 
-    beforeEach(function() {
+    beforeEach(() => {
       var ReactDOMComponent = require('ReactDOMComponent');
       var ReactReconcileTransaction = require('ReactReconcileTransaction');
 
       var NodeStub = function(initialProps) {
         this._currentElement = {props: initialProps};
-        this._rootNodeID = 'test';
+        this._rootNodeID = 1;
       };
       Object.assign(NodeStub.prototype, ReactDOMComponent.Mixin);
 
       genMarkup = function(props) {
         var transaction = new ReactReconcileTransaction();
-        return (new NodeStub(props))._createContentMarkup(
-          transaction,
-          props,
-          {}
-        );
+        return new NodeStub(props)._createContentMarkup(transaction, props, {});
       };
 
-      this.addMatchers({
-        toHaveInnerhtml: function(html) {
-          var expected = '^' + quoteRegexp(html) + '$';
-          return this.actual.match(new RegExp(expected));
+      jasmine.addMatchers({
+        toHaveInnerhtml() {
+          return {
+            compare(actual, expected) {
+              var re = '^' + quoteRegexp(expected) + '$';
+              return {
+                pass: new RegExp(re).test(actual),
+              };
+            },
+          };
         },
       });
     });
 
-    it('should handle dangerouslySetInnerHTML', function() {
+    it('should handle dangerouslySetInnerHTML', () => {
       var innerHTML = {__html: 'testContent'};
-      expect(
-        genMarkup({dangerouslySetInnerHTML: innerHTML})
-      ).toHaveInnerhtml('testContent');
+      expect(genMarkup({dangerouslySetInnerHTML: innerHTML})).toHaveInnerhtml(
+        'testContent',
+      );
     });
   });
 
-  describe('mountComponent', function() {
+  describe('mountComponent', () => {
     var mountComponent;
 
-    beforeEach(function() {
+    beforeEach(() => {
       mountComponent = function(props) {
         var container = document.createElement('div');
         ReactDOM.render(<div {...props} />, container);
       };
     });
 
-    it('should not duplicate uppercased selfclosing tags', function() {
-      var Container = React.createClass({
-        render: function() {
+    it('should work error event on <source> element', () => {
+      spyOn(console, 'error');
+      var container = document.createElement('div');
+      ReactDOM.render(
+        <video>
+          <source
+            src="http://example.org/video"
+            type="video/mp4"
+            onError={e => console.error('onError called')}
+          />
+        </video>,
+        container,
+      );
+
+      var errorEvent = document.createEvent('Event');
+      errorEvent.initEvent('error', false, false);
+      container.getElementsByTagName('source')[0].dispatchEvent(errorEvent);
+
+      expect(console.error.calls.count()).toBe(1);
+      expect(console.error.calls.argsFor(0)[0]).toContain('onError called');
+    });
+
+    it('should not duplicate uppercased selfclosing tags', () => {
+      class Container extends React.Component {
+        render() {
           return React.createElement('BR', null);
-        },
-      });
-      var returnedValue = ReactDOMServer.renderToString(<Container/>);
+        }
+      }
+
+      var returnedValue = ReactDOMServer.renderToString(<Container />);
       expect(returnedValue).not.toContain('</BR>');
     });
 
-    it('should warn against children for void elements', function() {
+    it('should warn against children for void elements', () => {
       var container = document.createElement('div');
 
       expect(function() {
         ReactDOM.render(<input>children</input>, container);
-      }).toThrow(
-        'input is a void element tag and must not have `children` or ' +
-        'use `props.dangerouslySetInnerHTML`.'
+      }).toThrowError(
+        'input is a void element tag and must neither have `children` nor ' +
+          'use `dangerouslySetInnerHTML`.',
       );
     });
 
-    it('should warn against dangerouslySetInnerHTML for void elements', function() {
+    it('should warn against dangerouslySetInnerHTML for void elements', () => {
       var container = document.createElement('div');
 
       expect(function() {
         ReactDOM.render(
           <input dangerouslySetInnerHTML={{__html: 'content'}} />,
-          container
+          container,
         );
-      }).toThrow(
-        'input is a void element tag and must not have `children` or use ' +
-        '`props.dangerouslySetInnerHTML`.'
+      }).toThrowError(
+        'input is a void element tag and must neither have `children` nor use ' +
+          '`dangerouslySetInnerHTML`.',
       );
     });
 
-    it('should treat menuitem as a void element but still create the closing tag', function() {
+    it('should treat menuitem as a void element but still create the closing tag', () => {
       var container = document.createElement('div');
 
-      var returnedValue = ReactDOMServer.renderToString(<menu><menuitem /></menu>);
+      var returnedValue = ReactDOMServer.renderToString(
+        <menu><menuitem /></menu>,
+      );
 
       expect(returnedValue).toContain('</menuitem>');
 
       expect(function() {
         ReactDOM.render(<menu><menuitem>children</menuitem></menu>, container);
-      }).toThrow(
-        'menuitem is a void element tag and must not have `children` or use ' +
-        '`props.dangerouslySetInnerHTML`.'
+      }).toThrowError(
+        'menuitem is a void element tag and must neither have `children` nor use ' +
+          '`dangerouslySetInnerHTML`.',
       );
-
     });
 
-    it('should validate against multiple children props', function() {
+    it('should validate against multiple children props', () => {
       expect(function() {
         mountComponent({children: '', dangerouslySetInnerHTML: ''});
-      }).toThrow(
-        'Can only set one of `children` or `props.dangerouslySetInnerHTML`.'
+      }).toThrowError(
+        'Can only set one of `children` or `props.dangerouslySetInnerHTML`.',
       );
     });
 
-    it('should validate against use of innerHTML', function() {
-
+    it('should validate against use of innerHTML', () => {
       spyOn(console, 'error');
       mountComponent({innerHTML: '<span>Hi Jim!</span>'});
-      expect(console.error.argsForCall.length).toBe(1);
-      expect(console.error.argsForCall[0][0]).toContain(
-        'Directly setting property `innerHTML` is not permitted. '
+      expect(console.error.calls.count()).toBe(1);
+      expect(console.error.calls.argsFor(0)[0]).toContain(
+        'Directly setting property `innerHTML` is not permitted. ',
       );
     });
 
-    it('should validate use of dangerouslySetInnerHTML', function() {
+    it('should validate use of dangerouslySetInnerHTML', () => {
       expect(function() {
         mountComponent({dangerouslySetInnerHTML: '<span>Hi Jim!</span>'});
-      }).toThrow(
+      }).toThrowError(
         '`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. ' +
-        'Please visit https://fb.me/react-invariant-dangerously-set-inner-html for more information.'
+          'Please visit https://fb.me/react-invariant-dangerously-set-inner-html for more information.',
       );
     });
 
-    it('should validate use of dangerouslySetInnerHTML', function() {
+    it('should validate use of dangerouslySetInnerHTML', () => {
       expect(function() {
-        mountComponent({dangerouslySetInnerHTML: {foo: 'bar'} });
-      }).toThrow(
+        mountComponent({dangerouslySetInnerHTML: {foo: 'bar'}});
+      }).toThrowError(
         '`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. ' +
-        'Please visit https://fb.me/react-invariant-dangerously-set-inner-html for more information.'
+          'Please visit https://fb.me/react-invariant-dangerously-set-inner-html for more information.',
       );
     });
 
-    it('should allow {__html: null}', function() {
+    it('should allow {__html: null}', () => {
       expect(function() {
-        mountComponent({dangerouslySetInnerHTML: {__html: null} });
+        mountComponent({dangerouslySetInnerHTML: {__html: null}});
       }).not.toThrow();
     });
 
-    it('should warn about contentEditable and children', function() {
+    it('should warn about contentEditable and children', () => {
       spyOn(console, 'error');
       mountComponent({contentEditable: true, children: ''});
-      expect(console.error.argsForCall.length).toBe(1);
-      expect(console.error.argsForCall[0][0]).toContain('contentEditable');
+      expect(console.error.calls.count()).toBe(1);
+      expect(console.error.calls.argsFor(0)[0]).toContain('contentEditable');
     });
 
-    it('should respect suppressContentEditableWarning', function() {
+    it('should respect suppressContentEditableWarning', () => {
       spyOn(console, 'error');
-      mountComponent({contentEditable: true, children: '', suppressContentEditableWarning: true});
-      expect(console.error.argsForCall.length).toBe(0);
+      mountComponent({
+        contentEditable: true,
+        children: '',
+        suppressContentEditableWarning: true,
+      });
+      expect(console.error.calls.count()).toBe(0);
     });
 
-    it('should validate against invalid styles', function() {
+    it('should validate against invalid styles', () => {
       expect(function() {
         mountComponent({style: 'display: none'});
-      }).toThrow(
+      }).toThrowError(
         'The `style` prop expects a mapping from style properties to values, ' +
-        'not a string. For example, style={{marginRight: spacing + \'em\'}} ' +
-        'when using JSX.'
+          "not a string. For example, style={{marginRight: spacing + 'em'}} " +
+          'when using JSX.',
+      );
+    });
+
+    it('should track input values', function() {
+      var container = document.createElement('div');
+      var inst = ReactDOM.render(
+        <input type="text" defaultValue="foo" />,
+        container,
       );
+
+      var tracker = inputValueTracking._getTrackerFromNode(inst);
+
+      expect(tracker.getValue()).toEqual('foo');
+    });
+
+    it('should track textarea values', function() {
+      var container = document.createElement('div');
+      var inst = ReactDOM.render(<textarea defaultValue="foo" />, container);
+
+      var tracker = inputValueTracking._getTrackerFromNode(inst);
+
+      expect(tracker.getValue()).toEqual('foo');
     });
 
     it('should execute custom event plugin listening behavior', function() {
       var SimpleEventPlugin = require('SimpleEventPlugin');
 
-      SimpleEventPlugin.didPutListener = jest.genMockFn();
-      SimpleEventPlugin.willDeleteListener = jest.genMockFn();
+      SimpleEventPlugin.didPutListener = jest.fn();
+      SimpleEventPlugin.willDeleteListener = jest.fn();
 
       var container = document.createElement('div');
-      ReactDOM.render(
-        <div onClick={() => true} />,
-        container
-      );
+      ReactDOM.render(<div onClick={() => true} />, container);
 
       expect(SimpleEventPlugin.didPutListener.mock.calls.length).toBe(1);
 
@@ -853,11 +953,11 @@ describe('ReactDOMComponent', function() {
       expect(SimpleEventPlugin.willDeleteListener.mock.calls.length).toBe(1);
     });
 
-    it('should handle null and missing properly with event hooks', function() {
+    it('should handle null and missing properly with event hooks', () => {
       var SimpleEventPlugin = require('SimpleEventPlugin');
 
-      SimpleEventPlugin.didPutListener = jest.genMockFn();
-      SimpleEventPlugin.willDeleteListener = jest.genMockFn();
+      SimpleEventPlugin.didPutListener = jest.fn();
+      SimpleEventPlugin.willDeleteListener = jest.fn();
       var container = document.createElement('div');
 
       ReactDOM.render(<div onClick={false} />, container);
@@ -889,126 +989,143 @@ describe('ReactDOMComponent', function() {
       expect(SimpleEventPlugin.willDeleteListener.mock.calls.length).toBe(1);
     });
 
-    it('should warn for children on void elements', function() {
-      var X = React.createClass({
-        render: function() {
+    it('should warn for children on void elements', () => {
+      class X extends React.Component {
+        render() {
           return <input>moo</input>;
-        },
-      });
+        }
+      }
 
       var container = document.createElement('div');
       expect(function() {
         ReactDOM.render(<X />, container);
-      }).toThrow(
-        'input is a void element tag and must not have `children` ' +
-        'or use `props.dangerouslySetInnerHTML`. Check the render method of X.'
+      }).toThrowError(
+        'input is a void element tag and must neither have `children` ' +
+          'nor use `dangerouslySetInnerHTML`. Check the render method of X.',
       );
     });
+
+    it('should support custom elements which extend native elements', () => {
+      if (ReactDOMFeatureFlags.useCreateElement) {
+        var container = document.createElement('div');
+        spyOn(document, 'createElement').and.callThrough();
+        ReactDOM.render(<div is="custom-div" />, container);
+        expect(document.createElement).toHaveBeenCalledWith(
+          'div',
+          'custom-div',
+        );
+      } else {
+        expect(
+          ReactDOMServer.renderToString(<div is="custom-div" />),
+        ).toContain('is="custom-div"');
+      }
+    });
   });
 
-  describe('updateComponent', function() {
+  describe('updateComponent', () => {
     var container;
 
-    beforeEach(function() {
+    beforeEach(() => {
       container = document.createElement('div');
     });
 
-    it('should warn against children for void elements', function() {
+    it('should warn against children for void elements', () => {
       ReactDOM.render(<input />, container);
 
       expect(function() {
         ReactDOM.render(<input>children</input>, container);
-      }).toThrow(
-        'input is a void element tag and must not have `children` or use ' +
-        '`props.dangerouslySetInnerHTML`.'
+      }).toThrowError(
+        'input is a void element tag and must neither have `children` nor use ' +
+          '`dangerouslySetInnerHTML`.',
       );
     });
 
-    it('should warn against dangerouslySetInnerHTML for void elements', function() {
+    it('should warn against dangerouslySetInnerHTML for void elements', () => {
       ReactDOM.render(<input />, container);
 
       expect(function() {
         ReactDOM.render(
           <input dangerouslySetInnerHTML={{__html: 'content'}} />,
-          container
+          container,
         );
-      }).toThrow(
-        'input is a void element tag and must not have `children` or use ' +
-        '`props.dangerouslySetInnerHTML`.'
+      }).toThrowError(
+        'input is a void element tag and must neither have `children` nor use ' +
+          '`dangerouslySetInnerHTML`.',
       );
     });
 
-    it('should validate against multiple children props', function() {
-      ReactDOM.render(<div></div>, container);
+    it('should validate against multiple children props', () => {
+      ReactDOM.render(<div />, container);
 
       expect(function() {
         ReactDOM.render(
-          <div children="" dangerouslySetInnerHTML={{__html: ''}}></div>,
-          container
+          <div children="" dangerouslySetInnerHTML={{__html: ''}} />,
+          container,
         );
-      }).toThrow(
-        'Can only set one of `children` or `props.dangerouslySetInnerHTML`.'
+      }).toThrowError(
+        'Can only set one of `children` or `props.dangerouslySetInnerHTML`.',
       );
     });
 
-    it('should warn about contentEditable and children', function() {
+    it('should warn about contentEditable and children', () => {
       spyOn(console, 'error');
-      ReactDOM.render(
-        <div contentEditable={true}><div /></div>,
-        container
-      );
-      expect(console.error.argsForCall.length).toBe(1);
-      expect(console.error.argsForCall[0][0]).toContain('contentEditable');
+      ReactDOM.render(<div contentEditable={true}><div /></div>, container);
+      expect(console.error.calls.count()).toBe(1);
+      expect(console.error.calls.argsFor(0)[0]).toContain('contentEditable');
     });
 
-    it('should validate against invalid styles', function() {
-      ReactDOM.render(<div></div>, container);
+    it('should validate against invalid styles', () => {
+      ReactDOM.render(<div />, container);
 
       expect(function() {
-        ReactDOM.render(<div style={1}></div>, container);
-      }).toThrow(
+        ReactDOM.render(<div style={1} />, container);
+      }).toThrowError(
         'The `style` prop expects a mapping from style properties to values, ' +
-        'not a string. For example, style={{marginRight: spacing + \'em\'}} ' +
-        'when using JSX.'
+          "not a string. For example, style={{marginRight: spacing + 'em'}} " +
+          'when using JSX.',
       );
     });
 
-    it('should report component containing invalid styles', function() {
-      var Animal = React.createClass({
-        render: function() {
-          return <div style={1}></div>;
-        },
-      });
+    it('should report component containing invalid styles', () => {
+      class Animal extends React.Component {
+        render() {
+          return <div style={1} />;
+        }
+      }
 
       expect(function() {
-        ReactDOM.render(<Animal/>, container);
-      }).toThrow(
+        ReactDOM.render(<Animal />, container);
+      }).toThrowError(
         'The `style` prop expects a mapping from style properties to values, ' +
-        'not a string. For example, style={{marginRight: spacing + \'em\'}} ' +
-        'when using JSX. This DOM node was rendered by `Animal`.'
+          "not a string. For example, style={{marginRight: spacing + 'em'}} " +
+          'when using JSX. This DOM node was rendered by `Animal`.',
       );
     });
 
-    it('should properly escape text content and attributes values', function() {
+    it('should properly escape text content and attributes values', () => {
       expect(
         ReactDOMServer.renderToStaticMarkup(
-          React.DOM.div({
-            title: '\'"<>&',
-            style: {
-              textAlign: '\'"<>&',
+          React.createElement(
+            'div',
+            {
+              title: '\'"<>&',
+              style: {
+                textAlign: '\'"<>&',
+              },
             },
-          }, '\'"<>&')
-        )
+            '\'"<>&',
+          ),
+        ),
       ).toBe(
         '<div title="&#x27;&quot;&lt;&gt;&amp;" style="text-align:&#x27;&quot;&lt;&gt;&amp;;">' +
           '&#x27;&quot;&lt;&gt;&amp;' +
-        '</div>'
+          '</div>',
       );
     });
   });
 
-  describe('unmountComponent', function() {
-    it('should clean up listeners', function() {
+  describe('unmountComponent', () => {
+    it('should clean up listeners', () => {
       var EventPluginHub = require('EventPluginHub');
       var ReactDOMComponentTree = require('ReactDOMComponentTree');
 
@@ -1021,28 +1138,52 @@ describe('ReactDOMComponent', function() {
 
       var rootNode = ReactDOM.findDOMNode(instance);
       var inst = ReactDOMComponentTree.getInstanceFromNode(rootNode);
-      expect(
-        EventPluginHub.getListener(inst, 'onClick')
-      ).toBe(callback);
+      expect(EventPluginHub.getListener(inst, 'onClick')).toBe(callback);
       expect(rootNode).toBe(ReactDOM.findDOMNode(instance));
 
       ReactDOM.unmountComponentAtNode(container);
 
-      expect(
-        EventPluginHub.getListener(inst, 'onClick')
-      ).toBe(undefined);
+      expect(EventPluginHub.getListener(inst, 'onClick')).toBe(undefined);
+    });
+
+    it('should clean up input value tracking', function() {
+      var container = document.createElement('div');
+      var node = ReactDOM.render(
+        <input type="text" defaultValue="foo" />,
+        container,
+      );
+      var tracker = inputValueTracking._getTrackerFromNode(node);
+
+      spyOn(tracker, 'stopTracking');
+
+      ReactDOM.unmountComponentAtNode(container);
+
+      expect(tracker.stopTracking.calls.count()).toBe(1);
+    });
+
+    it('should clean up input textarea tracking', function() {
+      var container = document.createElement('div');
+      var node = ReactDOM.render(<textarea defaultValue="foo" />, container);
+      var tracker = inputValueTracking._getTrackerFromNode(node);
+
+      spyOn(tracker, 'stopTracking');
+
+      ReactDOM.unmountComponentAtNode(container);
+
+      expect(tracker.stopTracking.calls.count()).toBe(1);
     });
 
     it('unmounts children before unsetting DOM node info', function() {
-      var Inner = React.createClass({
-        render: function() {
+      class Inner extends React.Component {
+        render() {
           return <span />;
-        },
-        componentWillUnmount: function() {
+        }
+
+        componentWillUnmount() {
           // Should not throw
           expect(ReactDOM.findDOMNode(this).nodeName).toBe('SPAN');
-        },
-      });
+        }
+      }
 
       var container = document.createElement('div');
       ReactDOM.render(<div><Inner /></div>, container);
@@ -1050,12 +1191,11 @@ describe('ReactDOMComponent', function() {
     });
   });
 
-  describe('onScroll warning', function() {
+  describe('onScroll warning', () => {
     it('should warn about the `onScroll` issue when unsupported (IE8)', () => {
       // Mock this here so we can mimic IE8 support. We require isEventSupported
       // before React so it's pre-mocked before React would require it.
-      jest.resetModuleRegistry()
-        .mock('isEventSupported');
+      jest.resetModuleRegistry().mock('isEventSupported');
       var isEventSupported = require('isEventSupported');
       isEventSupported.mockReturnValueOnce(false);
 
@@ -1063,39 +1203,41 @@ describe('ReactDOMComponent', function() {
 
       spyOn(console, 'error');
       ReactTestUtils.renderIntoDocument(<div onScroll={function() {}} />);
-      expect(console.error.calls.length).toBe(1);
-      expect(console.error.argsForCall[0][0]).toBe(
-        'Warning: This browser doesn\'t support the `onScroll` event'
+      expect(console.error.calls.count()).toBe(1);
+      expect(console.error.calls.argsFor(0)[0]).toBe(
+        "Warning: This browser doesn't support the `onScroll` event",
       );
     });
+
+    it('should not warn when server-side rendering `onScroll`', () => {
+      spyOn(console, 'error');
+      ReactDOMServer.renderToString(<div onScroll={() => {}} />);
+      expect(console.error).not.toHaveBeenCalled();
+    });
   });
 
-  describe('tag sanitization', function() {
+  describe('tag sanitization', () => {
     it('should throw when an invalid tag name is used', () => {
       var ReactTestUtils = require('ReactTestUtils');
       var hackzor = React.createElement('script tag');
-      expect(
-        () => ReactTestUtils.renderIntoDocument(hackzor)
-      ).toThrow(
-        'Invalid tag: script tag'
+      expect(() => ReactTestUtils.renderIntoDocument(hackzor)).toThrowError(
+        'Invalid tag: script tag',
       );
     });
 
     it('should throw when an attack vector is used', () => {
       var ReactTestUtils = require('ReactTestUtils');
       var hackzor = React.createElement('div><img /><div');
-      expect(
-        () => ReactTestUtils.renderIntoDocument(hackzor)
-      ).toThrow(
-        'Invalid tag: div><img /><div'
+      expect(() => ReactTestUtils.renderIntoDocument(hackzor)).toThrowError(
+        'Invalid tag: div><img /><div',
       );
     });
   });
 
-  describe('nesting validation', function() {
+  describe('nesting validation', () => {
     var ReactTestUtils;
 
-    beforeEach(function() {
+    beforeEach(() => {
       ReactTestUtils = require('ReactTestUtils');
     });
 
@@ -1103,10 +1245,10 @@ describe('ReactDOMComponent', function() {
       spyOn(console, 'error');
       ReactTestUtils.renderIntoDocument(<div><tr /><tr /></div>);
 
-      expect(console.error.calls.length).toBe(1);
-      expect(console.error.argsForCall[0][0]).toBe(
+      expect(console.error.calls.count()).toBe(1);
+      expect(console.error.calls.argsFor(0)[0]).toBe(
         'Warning: validateDOMNesting(...): <tr> cannot appear as a child of ' +
-        '<div>. See div > tr.'
+          '<div>. See div > tr.',
       );
     });
 
@@ -1115,145 +1257,315 @@ describe('ReactDOMComponent', function() {
       var p = document.createElement('p');
       ReactDOM.render(<span><p /></span>, p);
 
-      expect(console.error.calls.length).toBe(1);
-      expect(console.error.argsForCall[0][0]).toBe(
+      expect(console.error.calls.count()).toBe(1);
+      expect(console.error.calls.argsFor(0)[0]).toBe(
         'Warning: validateDOMNesting(...): <p> cannot appear as a descendant ' +
-        'of <p>. See p > ... > p.'
+          'of <p>. See p > ... > p.',
       );
     });
 
     it('warns nicely for table rows', () => {
       spyOn(console, 'error');
-      var Row = React.createClass({
-        render: function() {
-          return <tr />;
-        },
-      });
-      var Foo = React.createClass({
-        render: function() {
+
+      class Row extends React.Component {
+        render() {
+          return <tr>x</tr>;
+        }
+      }
+
+      class Foo extends React.Component {
+        render() {
           return <table><Row /> </table>;
-        },
-      });
+        }
+      }
+
       ReactTestUtils.renderIntoDocument(<Foo />);
 
-      expect(console.error.calls.length).toBe(2);
-      expect(console.error.argsForCall[0][0]).toBe(
+      expect(console.error.calls.count()).toBe(3);
+      expect(console.error.calls.argsFor(0)[0]).toBe(
         'Warning: validateDOMNesting(...): <tr> cannot appear as a child of ' +
-        '<table>. See Foo > table > Row > tr. Add a <tbody> to your code to ' +
-        'match the DOM tree generated by the browser.'
+          '<table>. See Foo > table > Row > tr. Add a <tbody> to your code to ' +
+          'match the DOM tree generated by the browser.',
       );
-      expect(console.error.argsForCall[1][0]).toBe(
-        'Warning: validateDOMNesting(...): #text cannot appear as a child ' +
-        'of <table>. See Foo > table > #text.'
+      expect(console.error.calls.argsFor(1)[0]).toBe(
+        'Warning: validateDOMNesting(...): Text nodes cannot appear as a ' +
+          'child of <tr>. See Row > tr > #text.',
+      );
+      expect(console.error.calls.argsFor(2)[0]).toBe(
+        'Warning: validateDOMNesting(...): Whitespace text nodes cannot ' +
+          "appear as a child of <table>. Make sure you don't have any extra " +
+          'whitespace between tags on each line of your source code. See Foo > ' +
+          'table > #text.',
       );
     });
 
     it('gives useful context in warnings', () => {
       spyOn(console, 'error');
-      var Row = React.createClass({
-        render: () => <tr />,
-      });
-      var FancyRow = React.createClass({
-        render: () => <Row />,
-      });
-      var Table = React.createClass({
-        render: function() {
+      function Row() {
+        return <tr />;
+      }
+      function FancyRow() {
+        return <Row />;
+      }
+
+      class Table extends React.Component {
+        render() {
           return <table>{this.props.children}</table>;
-        },
-      });
-      var FancyTable = React.createClass({
-        render: function() {
+        }
+      }
+
+      class FancyTable extends React.Component {
+        render() {
           return <Table>{this.props.children}</Table>;
-        },
-      });
+        }
+      }
 
-      var Viz1 = React.createClass({
-        render: () => <table><FancyRow /></table>,
-      });
-      var App1 = React.createClass({
-        render: () => <Viz1 />,
-      });
+      function Viz1() {
+        return <table><FancyRow /></table>;
+      }
+      function App1() {
+        return <Viz1 />;
+      }
       ReactTestUtils.renderIntoDocument(<App1 />);
-      expect(console.error.calls.length).toBe(1);
-      expect(console.error.argsForCall[0][0]).toContain(
-        'See Viz1 > table > FancyRow > Row > tr.'
+      expect(console.error.calls.count()).toBe(1);
+      expect(console.error.calls.argsFor(0)[0]).toContain(
+        'See Viz1 > table > FancyRow > Row > tr.',
       );
 
-      var Viz2 = React.createClass({
-        render: () => <FancyTable><FancyRow /></FancyTable>,
-      });
-      var App2 = React.createClass({
-        render: () => <Viz2 />,
-      });
+      function Viz2() {
+        return <FancyTable><FancyRow /></FancyTable>;
+      }
+      function App2() {
+        return <Viz2 />;
+      }
       ReactTestUtils.renderIntoDocument(<App2 />);
-      expect(console.error.calls.length).toBe(2);
-      expect(console.error.argsForCall[1][0]).toContain(
-        'See Viz2 > FancyTable > Table > table > FancyRow > Row > tr.'
+      expect(console.error.calls.count()).toBe(2);
+      expect(console.error.calls.argsFor(1)[0]).toContain(
+        'See Viz2 > FancyTable > Table > table > FancyRow > Row > tr.',
       );
 
       ReactTestUtils.renderIntoDocument(<FancyTable><FancyRow /></FancyTable>);
-      expect(console.error.calls.length).toBe(3);
-      expect(console.error.argsForCall[2][0]).toContain(
-        'See FancyTable > Table > table > FancyRow > Row > tr.'
+      expect(console.error.calls.count()).toBe(3);
+      expect(console.error.calls.argsFor(2)[0]).toContain(
+        'See FancyTable > Table > table > FancyRow > Row > tr.',
       );
 
       ReactTestUtils.renderIntoDocument(<table><FancyRow /></table>);
-      expect(console.error.calls.length).toBe(4);
-      expect(console.error.argsForCall[3][0]).toContain(
-        'See table > FancyRow > Row > tr.'
+      expect(console.error.calls.count()).toBe(4);
+      expect(console.error.calls.argsFor(3)[0]).toContain(
+        'See table > FancyRow > Row > tr.',
       );
 
       ReactTestUtils.renderIntoDocument(<FancyTable><tr /></FancyTable>);
-      expect(console.error.calls.length).toBe(5);
-      expect(console.error.argsForCall[4][0]).toContain(
-        'See FancyTable > Table > table > tr.'
+      expect(console.error.calls.count()).toBe(5);
+      expect(console.error.calls.argsFor(4)[0]).toContain(
+        'See FancyTable > Table > table > tr.',
       );
 
-      var Link = React.createClass({
-        render: function() {
+      class Link extends React.Component {
+        render() {
           return <a>{this.props.children}</a>;
-        },
-      });
+        }
+      }
+
       ReactTestUtils.renderIntoDocument(<Link><div><Link /></div></Link>);
-      expect(console.error.calls.length).toBe(6);
-      expect(console.error.argsForCall[5][0]).toContain(
-        'See Link > a > ... > Link > a.'
+      expect(console.error.calls.count()).toBe(6);
+      expect(console.error.calls.argsFor(5)[0]).toContain(
+        'See Link > a > ... > Link > a.',
+      );
+    });
+
+    it('should warn about incorrect casing on properties (ssr)', () => {
+      spyOn(console, 'error');
+      ReactDOMServer.renderToString(
+        React.createElement('input', {type: 'text', tabindex: '1'}),
+      );
+      expect(console.error.calls.count()).toBe(1);
+      expect(console.error.calls.argsFor(0)[0]).toContain('tabIndex');
+    });
+
+    it('should warn about incorrect casing on event handlers (ssr)', () => {
+      spyOn(console, 'error');
+      ReactDOMServer.renderToString(
+        React.createElement('input', {type: 'text', onclick: '1'}),
+      );
+      ReactDOMServer.renderToString(
+        React.createElement('input', {type: 'text', onKeydown: '1'}),
       );
+      expect(console.error.calls.count()).toBe(2);
+      expect(console.error.calls.argsFor(0)[0]).toContain('onClick');
+      expect(console.error.calls.argsFor(1)[0]).toContain('onKeyDown');
     });
 
-    it('should warn about incorrect casing on properties', function() {
+    it('should warn about incorrect casing on properties', () => {
       spyOn(console, 'error');
-      ReactDOMServer.renderToString(React.createElement('input', {type: 'text', tabindex: '1'}));
-      expect(console.error.argsForCall.length).toBe(1);
-      expect(console.error.argsForCall[0][0]).toContain('tabIndex');
+      ReactTestUtils.renderIntoDocument(
+        React.createElement('input', {type: 'text', tabindex: '1'}),
+      );
+      expect(console.error.calls.count()).toBe(1);
+      expect(console.error.calls.argsFor(0)[0]).toContain('tabIndex');
     });
 
-    it('should warn about incorrect casing on event handlers', function() {
+    it('should warn about incorrect casing on event handlers', () => {
       spyOn(console, 'error');
-      ReactDOMServer.renderToString(React.createElement('input', {type: 'text', onclick: '1'}));
-      ReactDOMServer.renderToString(React.createElement('input', {type: 'text', onKeydown: '1'}));
-      expect(console.error.argsForCall.length).toBe(2);
-      expect(console.error.argsForCall[0][0]).toContain('onClick');
-      expect(console.error.argsForCall[1][0]).toContain('onKeyDown');
+      ReactTestUtils.renderIntoDocument(
+        React.createElement('input', {type: 'text', onclick: '1'}),
+      );
+      ReactTestUtils.renderIntoDocument(
+        React.createElement('input', {type: 'text', onKeydown: '1'}),
+      );
+      expect(console.error.calls.count()).toBe(2);
+      expect(console.error.calls.argsFor(0)[0]).toContain('onClick');
+      expect(console.error.calls.argsFor(1)[0]).toContain('onKeyDown');
     });
 
-    it('should warn about class', function() {
+    it('should warn about class', () => {
       spyOn(console, 'error');
-      ReactDOMServer.renderToString(React.createElement('div', {class: 'muffins'}));
-      expect(console.error.argsForCall.length).toBe(1);
-      expect(console.error.argsForCall[0][0]).toContain('className');
+      ReactDOMServer.renderToString(
+        React.createElement('div', {class: 'muffins'}),
+      );
+      expect(console.error.calls.count()).toBe(1);
+      expect(console.error.calls.argsFor(0)[0]).toContain('className');
     });
 
-    it('should warn about props that are no longer supported', function() {
+    it('should warn about props that are no longer supported', () => {
       spyOn(console, 'error');
       ReactTestUtils.renderIntoDocument(<div />);
-      expect(console.error.argsForCall.length).toBe(0);
+      expect(console.error.calls.count()).toBe(0);
 
       ReactTestUtils.renderIntoDocument(<div onFocusIn={() => {}} />);
-      expect(console.error.argsForCall.length).toBe(1);
+      expect(console.error.calls.count()).toBe(1);
 
       ReactTestUtils.renderIntoDocument(<div onFocusOut={() => {}} />);
-      expect(console.error.argsForCall.length).toBe(2);
+      expect(console.error.calls.count()).toBe(2);
+    });
+
+    it('gives source code refs for unknown prop warning', () => {
+      spyOn(console, 'error');
+      ReactDOMServer.renderToString(<div class="paladin" />);
+      ReactDOMServer.renderToString(<input type="text" onclick="1" />);
+      expect(console.error.calls.count()).toBe(2);
+      expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
+        'Warning: Unknown DOM property class. Did you mean className?\n    in div (at **)',
+      );
+      expect(normalizeCodeLocInfo(console.error.calls.argsFor(1)[0])).toBe(
+        'Warning: Unknown event handler property onclick. Did you mean ' +
+          '`onClick`?\n    in input (at **)',
+      );
+    });
+
+    it('gives source code refs for unknown prop warning for update render', () => {
+      spyOn(console, 'error');
+      var container = document.createElement('div');
+
+      ReactDOMServer.renderToString(<div className="paladin" />, container);
+      expect(console.error.calls.count()).toBe(0);
+
+      ReactDOMServer.renderToString(<div class="paladin" />, container);
+      expect(console.error.calls.count()).toBe(1);
+      expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
+        'Warning: Unknown DOM property class. Did you mean className?\n    in div (at **)',
+      );
+    });
+
+    it('gives source code refs for unknown prop warning for exact elements ', () => {
+      spyOn(console, 'error');
+
+      ReactDOMServer.renderToString(
+        <div className="foo1">
+          <div class="foo2" />
+          <div onClick="foo3" />
+          <div onclick="foo4" />
+          <div className="foo5" />
+          <div className="foo6" />
+        </div>,
+      );
+
+      expect(console.error.calls.count()).toBe(2);
+
+      expect(console.error.calls.argsFor(0)[0]).toContain('className');
+      var matches = console.error.calls.argsFor(0)[0].match(/.*\(.*:(\d+)\).*/);
+      var previousLine = matches[1];
+
+      expect(console.error.calls.argsFor(1)[0]).toContain('onClick');
+      matches = console.error.calls.argsFor(1)[0].match(/.*\(.*:(\d+)\).*/);
+      var currentLine = matches[1];
+
+      //verify line number has a proper relative difference,
+      //since hard coding the line number would make test too brittle
+      expect(parseInt(previousLine, 10) + 2).toBe(parseInt(currentLine, 10));
+    });
+
+    it('gives source code refs for unknown prop warning for exact elements in composition ', () => {
+      spyOn(console, 'error');
+      var container = document.createElement('div');
+
+      class Parent extends React.Component {
+        render() {
+          return <div><Child1 /><Child2 /><Child3 /><Child4 /></div>;
+        }
+      }
+
+      class Child1 extends React.Component {
+        render() {
+          return <div class="paladin">Child1</div>;
+        }
+      }
+
+      class Child2 extends React.Component {
+        render() {
+          return <div>Child2</div>;
+        }
+      }
+
+      class Child3 extends React.Component {
+        render() {
+          return <div onclick="1">Child3</div>;
+        }
+      }
+
+      class Child4 extends React.Component {
+        render() {
+          return <div>Child4</div>;
+        }
+      }
+
+      ReactDOMServer.renderToString(<Parent />, container);
+
+      expect(console.error.calls.count()).toBe(2);
+
+      expect(console.error.calls.argsFor(0)[0]).toContain('className');
+      var matches = console.error.calls.argsFor(0)[0].match(/.*\(.*:(\d+)\).*/);
+      var previousLine = matches[1];
+
+      expect(console.error.calls.argsFor(1)[0]).toContain('onClick');
+      matches = console.error.calls.argsFor(1)[0].match(/.*\(.*:(\d+)\).*/);
+      var currentLine = matches[1];
+
+      //verify line number has a proper relative difference,
+      //since hard coding the line number would make test too brittle
+      expect(parseInt(previousLine, 10) + 12).toBe(parseInt(currentLine, 10));
+    });
+
+    it('should suggest property name if available', () => {
+      spyOn(console, 'error');
+
+      ReactTestUtils.renderIntoDocument(
+        React.createElement('label', {for: 'test'}),
+      );
+      ReactTestUtils.renderIntoDocument(
+        React.createElement('input', {type: 'text', autofocus: true}),
+      );
+
+      expect(console.error.calls.count()).toBe(2);
+
+      expect(console.error.calls.argsFor(0)[0]).toBe(
+        'Warning: Unknown DOM property for. Did you mean htmlFor?\n    in label',
+      );
+
+      expect(console.error.calls.argsFor(1)[0]).toBe(
+        'Warning: Unknown DOM property autofocus. Did you mean autoFocus?\n    in input',
+      );
     });
   });
 });
diff --git a/src/renderers/dom/shared/__tests__/ReactDOMInvalidARIAHook-test.js b/src/renderers/dom/shared/__tests__/ReactDOMInvalidARIAHook-test.js
new file mode 100644
index 000000000000..1fae95ffeef7
--- /dev/null
+++ b/src/renderers/dom/shared/__tests__/ReactDOMInvalidARIAHook-test.js
@@ -0,0 +1,67 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+describe('ReactDOMInvalidARIAHook', () => {
+  var React;
+  var ReactTestUtils;
+  var mountComponent;
+
+  beforeEach(() => {
+    jest.resetModuleRegistry();
+    React = require('React');
+    ReactTestUtils = require('ReactTestUtils');
+
+    mountComponent = function(props) {
+      ReactTestUtils.renderIntoDocument(<div {...props} />);
+    };
+  });
+
+  describe('aria-* props', () => {
+    it('should allow valid aria-* props', () => {
+      spyOn(console, 'error');
+      mountComponent({'aria-label': 'Bumble bees'});
+      expect(console.error.calls.count()).toBe(0);
+    });
+    it('should warn for one invalid aria-* prop', () => {
+      spyOn(console, 'error');
+      mountComponent({'aria-badprop': 'maybe'});
+      expect(console.error.calls.count()).toBe(1);
+      expect(console.error.calls.argsFor(0)[0]).toContain(
+        'Warning: Invalid aria prop `aria-badprop` on <div> tag. ' +
+          'For details, see https://fb.me/invalid-aria-prop',
+      );
+    });
+    it('should warn for many invalid aria-* props', () => {
+      spyOn(console, 'error');
+      mountComponent({
+        'aria-badprop': 'Very tall trees',
+        'aria-malprop': 'Turbulent seas',
+      });
+      expect(console.error.calls.count()).toBe(1);
+      expect(console.error.calls.argsFor(0)[0]).toContain(
+        'Warning: Invalid aria props `aria-badprop`, `aria-malprop` on <div> ' +
+          'tag. For details, see https://fb.me/invalid-aria-prop',
+      );
+    });
+    it('should warn for an improperly cased aria-* prop', () => {
+      spyOn(console, 'error');
+      // The valid attribute name is aria-haspopup.
+      mountComponent({'aria-hasPopup': 'true'});
+      expect(console.error.calls.count()).toBe(1);
+      expect(console.error.calls.argsFor(0)[0]).toContain(
+        'Warning: Unknown ARIA attribute aria-hasPopup. ' +
+          'Did you mean aria-haspopup?',
+      );
+    });
+  });
+});
diff --git a/src/renderers/dom/shared/__tests__/ReactDOMTextComponent-test.js b/src/renderers/dom/shared/__tests__/ReactDOMTextComponent-test.js
index 5c3e9a2e62dd..38c94772ced0 100644
--- a/src/renderers/dom/shared/__tests__/ReactDOMTextComponent-test.js
+++ b/src/renderers/dom/shared/__tests__/ReactDOMTextComponent-test.js
@@ -15,14 +15,14 @@ var React;
 var ReactDOM;
 var ReactDOMServer;
 
-describe('ReactDOMTextComponent', function() {
-  beforeEach(function() {
+describe('ReactDOMTextComponent', () => {
+  beforeEach(() => {
     React = require('React');
     ReactDOM = require('ReactDOM');
     ReactDOMServer = require('ReactDOMServer');
   });
 
-  it('updates a mounted text component in place', function() {
+  it('updates a mounted text component in place', () => {
     var el = document.createElement('div');
     var inst = ReactDOM.render(<div><span />{'foo'}{'bar'}</div>, el);
 
@@ -40,7 +40,7 @@ describe('ReactDOMTextComponent', function() {
     expect(bar.data).toBe('qux');
   });
 
-  it('can be toggled in and out of the markup', function() {
+  it('can be toggled in and out of the markup', () => {
     var el = document.createElement('div');
     var inst = ReactDOM.render(<div>{'foo'}<div />{'bar'}</div>, el);
 
@@ -63,7 +63,7 @@ describe('ReactDOMTextComponent', function() {
     expect(childNodes[5].data).toBe('bar');
   });
 
-  it('can reconcile text merged by Node.normalize()', function() {
+  it('can reconcile text merged by Node.normalize()', () => {
     var el = document.createElement('div');
     var inst = ReactDOM.render(<div>{'foo'}{'bar'}{'baz'}</div>, el);
 
@@ -75,7 +75,7 @@ describe('ReactDOMTextComponent', function() {
     expect(container.textContent).toBe('barbazqux');
   });
 
-  it('can reconcile text from pre-rendered markup', function() {
+  it('can reconcile text from pre-rendered markup', () => {
     var el = document.createElement('div');
     var reactEl = <div>{'foo'}{'bar'}{'baz'}</div>;
     el.innerHTML = ReactDOMServer.renderToString(reactEl);
@@ -90,7 +90,7 @@ describe('ReactDOMTextComponent', function() {
     expect(el.textContent).toBe('');
   });
 
-  it('can reconcile text arbitrarily split into multiple nodes', function() {
+  it('can reconcile text arbitrarily split into multiple nodes', () => {
     var el = document.createElement('div');
     var inst = ReactDOM.render(<div><span />{'foobarbaz'}</div>, el);
 
diff --git a/src/renderers/dom/shared/__tests__/escapeTextContentForBrowser-test.js b/src/renderers/dom/shared/__tests__/escapeTextContentForBrowser-test.js
index e2cb4461aaf4..8dc2b9792d73 100644
--- a/src/renderers/dom/shared/__tests__/escapeTextContentForBrowser-test.js
+++ b/src/renderers/dom/shared/__tests__/escapeTextContentForBrowser-test.js
@@ -11,16 +11,15 @@
 
 'use strict';
 
-describe('escapeTextContentForBrowser', function() {
-
+describe('escapeTextContentForBrowser', () => {
   var escapeTextContentForBrowser = require('escapeTextContentForBrowser');
 
-  it('should escape boolean to string', function() {
+  it('should escape boolean to string', () => {
     expect(escapeTextContentForBrowser(true)).toBe('true');
     expect(escapeTextContentForBrowser(false)).toBe('false');
   });
 
-  it('should escape object to string', function() {
+  it('should escape object to string', () => {
     var escaped = escapeTextContentForBrowser({
       toString: function() {
         return 'ponys';
@@ -30,19 +29,20 @@ describe('escapeTextContentForBrowser', function() {
     expect(escaped).toBe('ponys');
   });
 
-  it('should escape number to string', function() {
+  it('should escape number to string', () => {
     expect(escapeTextContentForBrowser(42)).toBe('42');
   });
 
-  it('should escape string', function() {
-    var escaped = escapeTextContentForBrowser('<script type=\'\' src=""></script>');
+  it('should escape string', () => {
+    var escaped = escapeTextContentForBrowser(
+      '<script type=\'\' src=""></script>',
+    );
     expect(escaped).not.toContain('<');
     expect(escaped).not.toContain('>');
-    expect(escaped).not.toContain('\'');
-    expect(escaped).not.toContain('\"');
+    expect(escaped).not.toContain("'");
+    expect(escaped).not.toContain('"');
 
     escaped = escapeTextContentForBrowser('&');
     expect(escaped).toBe('&amp;');
   });
-
 });
diff --git a/src/renderers/dom/shared/__tests__/quoteAttributeValueForBrowser-test.js b/src/renderers/dom/shared/__tests__/quoteAttributeValueForBrowser-test.js
index 5d7bc86016ae..884fc322c555 100644
--- a/src/renderers/dom/shared/__tests__/quoteAttributeValueForBrowser-test.js
+++ b/src/renderers/dom/shared/__tests__/quoteAttributeValueForBrowser-test.js
@@ -11,16 +11,15 @@
 
 'use strict';
 
-describe('quoteAttributeValueForBrowser', function() {
-
+describe('quoteAttributeValueForBrowser', () => {
   var quoteAttributeValueForBrowser = require('quoteAttributeValueForBrowser');
 
-  it('should escape boolean to string', function() {
+  it('should escape boolean to string', () => {
     expect(quoteAttributeValueForBrowser(true)).toBe('"true"');
     expect(quoteAttributeValueForBrowser(false)).toBe('"false"');
   });
 
-  it('should escape object to string', function() {
+  it('should escape object to string', () => {
     var escaped = quoteAttributeValueForBrowser({
       toString: function() {
         return 'ponys';
@@ -30,19 +29,20 @@ describe('quoteAttributeValueForBrowser', function() {
     expect(escaped).toBe('"ponys"');
   });
 
-  it('should escape number to string', function() {
+  it('should escape number to string', () => {
     expect(quoteAttributeValueForBrowser(42)).toBe('"42"');
   });
 
-  it('should escape string', function() {
-    var escaped = quoteAttributeValueForBrowser('<script type=\'\' src=""></script>');
+  it('should escape string', () => {
+    var escaped = quoteAttributeValueForBrowser(
+      '<script type=\'\' src=""></script>',
+    );
     expect(escaped).not.toContain('<');
     expect(escaped).not.toContain('>');
-    expect(escaped).not.toContain('\'');
-    expect(escaped.substr(1, -1)).not.toContain('\"');
+    expect(escaped).not.toContain("'");
+    expect(escaped.substr(1, -1)).not.toContain('"');
 
     escaped = quoteAttributeValueForBrowser('&');
     expect(escaped).toBe('"&amp;"');
   });
-
 });
diff --git a/src/renderers/dom/shared/dangerousStyleValue.js b/src/renderers/dom/shared/dangerousStyleValue.js
index 8aa2e49607fa..74e130ddafaf 100644
--- a/src/renderers/dom/shared/dangerousStyleValue.js
+++ b/src/renderers/dom/shared/dangerousStyleValue.js
@@ -27,7 +27,7 @@ var styleWarnings = {};
  * @param {ReactDOMComponent} component
  * @return {string} Normalized style value with dimensions applied.
  */
-function dangerousStyleValue(name, value, component) {
+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
@@ -44,14 +44,20 @@ function dangerousStyleValue(name, value, component) {
   }
 
   var isNonNumeric = isNaN(value);
-  if (isNonNumeric || value === 0 ||
-      isUnitlessNumber.hasOwnProperty(name) && isUnitlessNumber[name]) {
+  if (
+    isCustomProperty ||
+    isNonNumeric ||
+    value === 0 ||
+    (isUnitlessNumber.hasOwnProperty(name) && isUnitlessNumber[name])
+  ) {
     return '' + value; // cast to string
   }
 
   if (typeof value === 'string') {
     if (__DEV__) {
-      if (component) {
+      // 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]) {
@@ -69,12 +75,12 @@ function dangerousStyleValue(name, value, component) {
           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.',
+              '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
+            value,
           );
         }
       }
diff --git a/src/renderers/dom/shared/devtools/ReactDOMUnknownPropertyDevtool.js b/src/renderers/dom/shared/devtools/ReactDOMUnknownPropertyDevtool.js
deleted file mode 100644
index 5adc359063e1..000000000000
--- a/src/renderers/dom/shared/devtools/ReactDOMUnknownPropertyDevtool.js
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * 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 ReactDOMUnknownPropertyDevtool
- */
-
-'use strict';
-
-var DOMProperty = require('DOMProperty');
-var EventPluginRegistry = require('EventPluginRegistry');
-
-var warning = require('warning');
-
-if (__DEV__) {
-  var reactProps = {
-    children: true,
-    dangerouslySetInnerHTML: true,
-    key: true,
-    ref: true,
-  };
-  var warnedProperties = {};
-
-  var warnUnknownProperty = function(name) {
-    if (DOMProperty.properties.hasOwnProperty(name) || DOMProperty.isCustomAttribute(name)) {
-      return;
-    }
-    if (reactProps.hasOwnProperty(name) && reactProps[name] ||
-        warnedProperties.hasOwnProperty(name) && warnedProperties[name]) {
-      return;
-    }
-
-    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
-    );
-
-    // For now, only warn when we have a suggested correction. This prevents
-    // logging too much when using transferPropsTo.
-    warning(
-      standardName == null,
-      'Unknown DOM property %s. Did you mean %s?',
-      name,
-      standardName
-    );
-
-    var registrationName = (
-      EventPluginRegistry.possibleRegistrationNames.hasOwnProperty(
-        lowerCasedName
-      ) ?
-      EventPluginRegistry.possibleRegistrationNames[lowerCasedName] :
-      null
-    );
-
-    warning(
-      registrationName == null,
-      'Unknown event handler property %s. Did you mean `%s`?',
-      name,
-      registrationName
-    );
-  };
-}
-
-var ReactDOMUnknownPropertyDevtool = {
-  onCreateMarkupForProperty(name, value) {
-    warnUnknownProperty(name);
-  },
-  onSetValueForProperty(node, name, value) {
-    warnUnknownProperty(name);
-  },
-  onDeleteValueForProperty(node, name) {
-    warnUnknownProperty(name);
-  },
-};
-
-module.exports = ReactDOMUnknownPropertyDevtool;
diff --git a/src/renderers/dom/shared/escapeTextContentForBrowser.js b/src/renderers/dom/shared/escapeTextContentForBrowser.js
index 897daf43ca02..9a7a2f10dbf6 100644
--- a/src/renderers/dom/shared/escapeTextContentForBrowser.js
+++ b/src/renderers/dom/shared/escapeTextContentForBrowser.js
@@ -1,29 +1,102 @@
 /**
- * Copyright 2013-present, Facebook, Inc.
+ * Copyright 2016-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.
  *
+ * 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.
+ *
  * @providesModule escapeTextContentForBrowser
  */
 
 'use strict';
 
-var ESCAPE_LOOKUP = {
-  '&': '&amp;',
-  '>': '&gt;',
-  '<': '&lt;',
-  '"': '&quot;',
-  '\'': '&#x27;',
-};
+// 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);
+    }
 
-var ESCAPE_REGEX = /[&><"']/g;
+    lastIndex = index + 1;
+    html += escape;
+  }
 
-function escaper(match) {
-  return ESCAPE_LOOKUP[match];
+  return lastIndex !== index ? html + str.substring(lastIndex, index) : html;
 }
+// end code copied and modified from escape-html
 
 /**
  * Escapes text to prevent scripting attacks.
@@ -32,7 +105,13 @@ function escaper(match) {
  * @return {string} An escaped string.
  */
 function escapeTextContentForBrowser(text) {
-  return ('' + text).replace(ESCAPE_REGEX, escaper);
+  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;
diff --git a/src/renderers/dom/shared/hooks/ReactDOMInvalidARIAHook.js b/src/renderers/dom/shared/hooks/ReactDOMInvalidARIAHook.js
new file mode 100644
index 000000000000..9f06f149f8c1
--- /dev/null
+++ b/src/renderers/dom/shared/hooks/ReactDOMInvalidARIAHook.js
@@ -0,0 +1,117 @@
+/**
+ * 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 ReactDOMInvalidARIAHook
+ */
+
+'use strict';
+
+var DOMProperty = require('DOMProperty');
+var ReactComponentTreeHook = require('ReactComponentTreeHook');
+
+var warning = require('warning');
+
+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) {
+      warning(
+        false,
+        'Unknown ARIA attribute %s. Did you mean %s?%s',
+        name,
+        standardName,
+        ReactComponentTreeHook.getStackAddendumByID(debugID),
+      );
+      warnedProperties[name] = true;
+      return true;
+    }
+  }
+
+  return true;
+}
+
+function warnInvalidARIAProps(debugID, element) {
+  const invalidProps = [];
+
+  for (var key in element.props) {
+    var isValid = validateProperty(element.type, key, debugID);
+    if (!isValid) {
+      invalidProps.push(key);
+    }
+  }
+
+  const unknownPropString = invalidProps
+    .map(prop => '`' + prop + '`')
+    .join(', ');
+
+  if (invalidProps.length === 1) {
+    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),
+    );
+  } else if (invalidProps.length > 1) {
+    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),
+    );
+  }
+}
+
+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(debugID, element) {
+    if (__DEV__) {
+      handleElement(debugID, element);
+    }
+  },
+  onBeforeUpdateComponent(debugID, element) {
+    if (__DEV__) {
+      handleElement(debugID, element);
+    }
+  },
+};
+
+module.exports = ReactDOMInvalidARIAHook;
diff --git a/src/renderers/dom/shared/hooks/ReactDOMNullInputValuePropHook.js b/src/renderers/dom/shared/hooks/ReactDOMNullInputValuePropHook.js
new file mode 100644
index 000000000000..21cbae338427
--- /dev/null
+++ b/src/renderers/dom/shared/hooks/ReactDOMNullInputValuePropHook.js
@@ -0,0 +1,58 @@
+/**
+ * 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 ReactDOMNullInputValuePropHook
+ */
+
+'use strict';
+
+var ReactComponentTreeHook = require('ReactComponentTreeHook');
+
+var warning = require('warning');
+
+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
+  ) {
+    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),
+    );
+
+    didWarnValueNull = true;
+  }
+}
+
+var ReactDOMNullInputValuePropHook = {
+  onBeforeMountComponent(debugID, element) {
+    handleElement(debugID, element);
+  },
+  onBeforeUpdateComponent(debugID, element) {
+    handleElement(debugID, element);
+  },
+};
+
+module.exports = ReactDOMNullInputValuePropHook;
diff --git a/src/renderers/dom/shared/hooks/ReactDOMUnknownPropertyHook.js b/src/renderers/dom/shared/hooks/ReactDOMUnknownPropertyHook.js
new file mode 100644
index 000000000000..6720bc7f0399
--- /dev/null
+++ b/src/renderers/dom/shared/hooks/ReactDOMUnknownPropertyHook.js
@@ -0,0 +1,150 @@
+/**
+ * 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 ReactDOMUnknownPropertyHook
+ */
+
+'use strict';
+
+var DOMProperty = require('DOMProperty');
+var EventPluginRegistry = require('EventPluginRegistry');
+var ReactComponentTreeHook = require('ReactComponentTreeHook');
+
+var warning = require('warning');
+
+if (__DEV__) {
+  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) {
+      warning(
+        false,
+        'Unknown DOM property %s. Did you mean %s?%s',
+        name,
+        standardName,
+        ReactComponentTreeHook.getStackAddendumByID(debugID),
+      );
+      return true;
+    } else if (registrationName != null) {
+      warning(
+        false,
+        'Unknown event handler property %s. Did you mean `%s`?%s',
+        name,
+        registrationName,
+        ReactComponentTreeHook.getStackAddendumByID(debugID),
+      );
+      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(prop => '`' + prop + '`').join(', ');
+
+  if (unknownProps.length === 1) {
+    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),
+    );
+  } else if (unknownProps.length > 1) {
+    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),
+    );
+  }
+};
+
+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(debugID, element) {
+    handleElement(debugID, element);
+  },
+  onBeforeUpdateComponent(debugID, element) {
+    handleElement(debugID, element);
+  },
+};
+
+module.exports = ReactDOMUnknownPropertyHook;
diff --git a/src/renderers/native/NativeMethodsMixin.js b/src/renderers/native/NativeMethodsMixin.js
new file mode 100644
index 000000000000..1ad5dc00b3a5
--- /dev/null
+++ b/src/renderers/native/NativeMethodsMixin.js
@@ -0,0 +1,232 @@
+/**
+ * Copyright (c) 2015-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 NativeMethodsMixin
+ * @flow
+ */
+'use strict';
+
+var ReactNativeAttributePayload = require('ReactNativeAttributePayload');
+var TextInputState = require('TextInputState');
+var UIManager = require('UIManager');
+
+var findNodeHandle = require('findNodeHandle');
+var invariant = require('invariant');
+
+type MeasureOnSuccessCallback = (
+  x: number,
+  y: number,
+  width: number,
+  height: number,
+  pageX: number,
+  pageY: number,
+) => void;
+
+type MeasureInWindowOnSuccessCallback = (
+  x: number,
+  y: number,
+  width: number,
+  height: number,
+) => void;
+
+type MeasureLayoutOnSuccessCallback = (
+  left: number,
+  top: number,
+  width: number,
+  height: number,
+) => void;
+
+function warnForStyleProps(props, validAttributes) {
+  for (var key in validAttributes.style) {
+    if (!(validAttributes[key] || props[key] === undefined)) {
+      console.error(
+        'You are setting the style `{ ' +
+          key +
+          ': ... }` as a prop. You ' +
+          'should nest it in a style object. ' +
+          'E.g. `{ style: { ' +
+          key +
+          ': ... } }`',
+      );
+    }
+  }
+}
+
+/**
+ * `NativeMethodsMixin` provides methods to access the underlying native
+ * component directly. This can be useful in cases when you want to focus
+ * a view or measure its on-screen dimensions, for example.
+ *
+ * The methods described here are available on most of the default components
+ * provided by React Native. Note, however, that they are *not* available on
+ * composite components that aren't directly backed by a native view. This will
+ * generally include most components that you define in your own app. For more
+ * information, see [Direct
+ * Manipulation](docs/direct-manipulation.html).
+ */
+var NativeMethodsMixin = {
+  /**
+   * Determines the location on screen, width, and height of the given view and
+   * returns the values via an async callback. If successful, the callback will
+   * be called with the following arguments:
+   *
+   *  - x
+   *  - y
+   *  - width
+   *  - height
+   *  - pageX
+   *  - pageY
+   *
+   * Note that these measurements are not available until after the rendering
+   * has been completed in native. If you need the measurements as soon as
+   * possible, consider using the [`onLayout`
+   * prop](docs/view.html#onlayout) instead.
+   */
+  measure: function(callback: MeasureOnSuccessCallback) {
+    UIManager.measure(findNodeHandle(this), mountSafeCallback(this, callback));
+  },
+
+  /**
+   * Determines the location of the given view in the window and returns the
+   * values via an async callback. If the React root view is embedded in
+   * another native view, this will give you the absolute coordinates. If
+   * successful, the callback will be called with the following
+   * arguments:
+   *
+   *  - x
+   *  - y
+   *  - width
+   *  - height
+   *
+   * Note that these measurements are not available until after the rendering
+   * has been completed in native.
+   */
+  measureInWindow: function(callback: MeasureInWindowOnSuccessCallback) {
+    UIManager.measureInWindow(
+      findNodeHandle(this),
+      mountSafeCallback(this, callback),
+    );
+  },
+
+  /**
+   * Like [`measure()`](#measure), but measures the view relative an ancestor,
+   * specified as `relativeToNativeNode`. This means that the returned x, y
+   * are relative to the origin x, y of the ancestor view.
+   *
+   * As always, to obtain a native node handle for a component, you can use
+   * `React.findNodeHandle(component)`.
+   */
+  measureLayout: function(
+    relativeToNativeNode: number,
+    onSuccess: MeasureLayoutOnSuccessCallback,
+    onFail: () => void /* currently unused */,
+  ) {
+    UIManager.measureLayout(
+      findNodeHandle(this),
+      relativeToNativeNode,
+      mountSafeCallback(this, onFail),
+      mountSafeCallback(this, onSuccess),
+    );
+  },
+
+  /**
+   * This function sends props straight to native. They will not participate in
+   * future diff process - this means that if you do not include them in the
+   * next render, they will remain active (see [Direct
+   * Manipulation](docs/direct-manipulation.html)).
+   */
+  setNativeProps: function(nativeProps: Object) {
+    if (__DEV__) {
+      warnForStyleProps(nativeProps, this.viewConfig.validAttributes);
+    }
+
+    var updatePayload = ReactNativeAttributePayload.create(
+      nativeProps,
+      this.viewConfig.validAttributes,
+    );
+
+    UIManager.updateView(
+      findNodeHandle(this),
+      this.viewConfig.uiViewClassName,
+      updatePayload,
+    );
+  },
+
+  /**
+   * Requests focus for the given input or view. The exact behavior triggered
+   * will depend on the platform and type of view.
+   */
+  focus: function() {
+    TextInputState.focusTextInput(findNodeHandle(this));
+  },
+
+  /**
+   * Removes focus from an input or view. This is the opposite of `focus()`.
+   */
+  blur: function() {
+    TextInputState.blurTextInput(findNodeHandle(this));
+  },
+};
+
+function throwOnStylesProp(component, props) {
+  if (props.styles !== undefined) {
+    var owner = component._owner || null;
+    var name = component.constructor.displayName;
+    var msg =
+      '`styles` is not a supported property of `' +
+      name +
+      '`, did ' +
+      'you mean `style` (singular)?';
+    if (owner && owner.constructor && owner.constructor.displayName) {
+      msg +=
+        '\n\nCheck the `' +
+        owner.constructor.displayName +
+        '` parent ' +
+        ' component.';
+    }
+    throw new Error(msg);
+  }
+}
+if (__DEV__) {
+  // hide this from Flow since we can't define these properties outside of
+  // __DEV__ without actually implementing them (setting them to undefined
+  // isn't allowed by ReactClass)
+  var NativeMethodsMixin_DEV = (NativeMethodsMixin: any);
+  invariant(
+    !NativeMethodsMixin_DEV.componentWillMount &&
+      !NativeMethodsMixin_DEV.componentWillReceiveProps,
+    'Do not override existing functions.',
+  );
+  NativeMethodsMixin_DEV.componentWillMount = function() {
+    throwOnStylesProp(this, this.props);
+  };
+  NativeMethodsMixin_DEV.componentWillReceiveProps = function(newProps) {
+    throwOnStylesProp(this, newProps);
+  };
+}
+
+/**
+ * In the future, we should cleanup callbacks by cancelling them instead of
+ * using this.
+ */
+function mountSafeCallback(
+  context: ReactComponent<any, any, any>,
+  callback: ?Function,
+): any {
+  return function() {
+    if (
+      !callback ||
+      (typeof context.isMounted === 'function' && !context.isMounted())
+    ) {
+      return undefined;
+    }
+    return callback.apply(context, arguments);
+  };
+}
+
+module.exports = NativeMethodsMixin;
diff --git a/src/renderers/native/ReactNative.js b/src/renderers/native/ReactNative.js
new file mode 100644
index 000000000000..218defb7fc54
--- /dev/null
+++ b/src/renderers/native/ReactNative.js
@@ -0,0 +1,77 @@
+/**
+ * Copyright (c) 2015-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 ReactNative
+ * @flow
+ */
+'use strict';
+
+// Require ReactNativeDefaultInjection first for its side effects of setting up
+// the JS environment
+var ReactNativeComponentTree = require('ReactNativeComponentTree');
+var ReactNativeDefaultInjection = require('ReactNativeDefaultInjection');
+
+var ReactNativeMount = require('ReactNativeMount');
+var ReactUpdates = require('ReactUpdates');
+
+var findNodeHandle = require('findNodeHandle');
+
+ReactNativeDefaultInjection.inject();
+
+var render = function(
+  element: ReactElement<any>,
+  mountInto: number,
+  callback?: ?() => void,
+): ?ReactComponent<any, any, any> {
+  return ReactNativeMount.renderComponent(element, mountInto, callback);
+};
+
+var ReactNative = {
+  hasReactNativeInitialized: false,
+  findNodeHandle: findNodeHandle,
+  render: render,
+  unmountComponentAtNode: ReactNativeMount.unmountComponentAtNode,
+
+  /* eslint-disable camelcase */
+  unstable_batchedUpdates: ReactUpdates.batchedUpdates,
+  /* eslint-enable camelcase */
+
+  unmountComponentAtNodeAndRemoveContainer:
+    ReactNativeMount.unmountComponentAtNodeAndRemoveContainer,
+};
+
+// Inject the runtime into a devtools global hook regardless of browser.
+// Allows for debugging when the hook is injected on the page.
+/* globals __REACT_DEVTOOLS_GLOBAL_HOOK__ */
+if (
+  typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' &&
+  typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.inject === 'function'
+) {
+  __REACT_DEVTOOLS_GLOBAL_HOOK__.inject({
+    ComponentTree: {
+      getClosestInstanceFromNode: function(node) {
+        return ReactNativeComponentTree.getClosestInstanceFromNode(node);
+      },
+      getNodeFromInstance: function(inst) {
+        // inst is an internal instance (but could be a composite)
+        while (inst._renderedComponent) {
+          inst = inst._renderedComponent;
+        }
+        if (inst) {
+          return ReactNativeComponentTree.getNodeFromInstance(inst);
+        } else {
+          return null;
+        }
+      },
+    },
+    Mount: ReactNativeMount,
+    Reconciler: require('ReactReconciler'),
+  });
+}
+
+module.exports = ReactNative;
diff --git a/src/renderers/native/ReactNative/__mocks__/View.js b/src/renderers/native/ReactNative/__mocks__/View.js
new file mode 100644
index 000000000000..71856da1673f
--- /dev/null
+++ b/src/renderers/native/ReactNative/__mocks__/View.js
@@ -0,0 +1,19 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+'use strict';
+
+var createReactNativeComponentClass = require('createReactNativeComponentClass');
+
+var View = createReactNativeComponentClass({
+  validAttributes: {},
+  uiViewClassName: 'View',
+});
+
+module.exports = View;
diff --git a/src/renderers/native/ReactNativeAttributePayload.js b/src/renderers/native/ReactNativeAttributePayload.js
new file mode 100644
index 000000000000..13a0aa52f3cf
--- /dev/null
+++ b/src/renderers/native/ReactNativeAttributePayload.js
@@ -0,0 +1,516 @@
+/**
+ * Copyright (c) 2015-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 ReactNativeAttributePayload
+ * @flow
+ */
+'use strict';
+
+var ReactNativePropRegistry = require('ReactNativePropRegistry');
+
+var deepDiffer = require('deepDiffer');
+var flattenStyle = require('flattenStyle');
+
+var emptyObject = {};
+
+/**
+ * Create a payload that contains all the updates between two sets of props.
+ *
+ * These helpers are all encapsulated into a single module, because they use
+ * mutation as a performance optimization which leads to subtle shared
+ * dependencies between the code paths. To avoid this mutable state leaking
+ * across modules, I've kept them isolated to this module.
+ */
+
+type AttributeDiffer = (prevProp: mixed, nextProp: mixed) => boolean;
+type AttributePreprocessor = (nextProp: mixed) => mixed;
+
+type CustomAttributeConfiguration =
+  | {diff: AttributeDiffer, process: AttributePreprocessor}
+  | {diff: AttributeDiffer}
+  | {process: AttributePreprocessor};
+
+type AttributeConfiguration = {
+  [key: string]:
+    | CustomAttributeConfiguration
+    | AttributeConfiguration /*| boolean*/,
+};
+
+type NestedNode = Array<NestedNode> | Object | number;
+
+// Tracks removed keys
+var removedKeys = null;
+var removedKeyCount = 0;
+
+function defaultDiffer(prevProp: mixed, nextProp: mixed): boolean {
+  if (typeof nextProp !== 'object' || nextProp === null) {
+    // Scalars have already been checked for equality
+    return true;
+  } else {
+    // For objects and arrays, the default diffing algorithm is a deep compare
+    return deepDiffer(prevProp, nextProp);
+  }
+}
+
+function resolveObject(idOrObject: number | Object): Object {
+  if (typeof idOrObject === 'number') {
+    return ReactNativePropRegistry.getByID(idOrObject);
+  }
+  return idOrObject;
+}
+
+function restoreDeletedValuesInNestedArray(
+  updatePayload: Object,
+  node: NestedNode,
+  validAttributes: AttributeConfiguration,
+) {
+  if (Array.isArray(node)) {
+    var i = node.length;
+    while (i-- && removedKeyCount > 0) {
+      restoreDeletedValuesInNestedArray(
+        updatePayload,
+        node[i],
+        validAttributes,
+      );
+    }
+  } else if (node && removedKeyCount > 0) {
+    var obj = resolveObject(node);
+    for (var propKey in removedKeys) {
+      if (!removedKeys[propKey]) {
+        continue;
+      }
+      var nextProp = obj[propKey];
+      if (nextProp === undefined) {
+        continue;
+      }
+
+      var attributeConfig = validAttributes[propKey];
+      if (!attributeConfig) {
+        continue; // not a valid native prop
+      }
+
+      if (typeof nextProp === 'function') {
+        nextProp = true;
+      }
+      if (typeof nextProp === 'undefined') {
+        nextProp = null;
+      }
+
+      if (typeof attributeConfig !== 'object') {
+        // case: !Object is the default case
+        updatePayload[propKey] = nextProp;
+      } else if (
+        typeof attributeConfig.diff === 'function' ||
+        typeof attributeConfig.process === 'function'
+      ) {
+        // case: CustomAttributeConfiguration
+        var nextValue = typeof attributeConfig.process === 'function'
+          ? attributeConfig.process(nextProp)
+          : nextProp;
+        updatePayload[propKey] = nextValue;
+      }
+      removedKeys[propKey] = false;
+      removedKeyCount--;
+    }
+  }
+}
+
+function diffNestedArrayProperty(
+  updatePayload: ?Object,
+  prevArray: Array<NestedNode>,
+  nextArray: Array<NestedNode>,
+  validAttributes: AttributeConfiguration,
+): ?Object {
+  var minLength = prevArray.length < nextArray.length
+    ? prevArray.length
+    : nextArray.length;
+  var i;
+  for (i = 0; i < minLength; i++) {
+    // Diff any items in the array in the forward direction. Repeated keys
+    // will be overwritten by later values.
+    updatePayload = diffNestedProperty(
+      updatePayload,
+      prevArray[i],
+      nextArray[i],
+      validAttributes,
+    );
+  }
+  for (; i < prevArray.length; i++) {
+    // Clear out all remaining properties.
+    updatePayload = clearNestedProperty(
+      updatePayload,
+      prevArray[i],
+      validAttributes,
+    );
+  }
+  for (; i < nextArray.length; i++) {
+    // Add all remaining properties.
+    updatePayload = addNestedProperty(
+      updatePayload,
+      nextArray[i],
+      validAttributes,
+    );
+  }
+  return updatePayload;
+}
+
+function diffNestedProperty(
+  updatePayload: ?Object,
+  prevProp: NestedNode,
+  nextProp: NestedNode,
+  validAttributes: AttributeConfiguration,
+): ?Object {
+  if (!updatePayload && prevProp === nextProp) {
+    // If no properties have been added, then we can bail out quickly on object
+    // equality.
+    return updatePayload;
+  }
+
+  if (!prevProp || !nextProp) {
+    if (nextProp) {
+      return addNestedProperty(updatePayload, nextProp, validAttributes);
+    }
+    if (prevProp) {
+      return clearNestedProperty(updatePayload, prevProp, validAttributes);
+    }
+    return updatePayload;
+  }
+
+  if (!Array.isArray(prevProp) && !Array.isArray(nextProp)) {
+    // Both are leaves, we can diff the leaves.
+    return diffProperties(
+      updatePayload,
+      resolveObject(prevProp),
+      resolveObject(nextProp),
+      validAttributes,
+    );
+  }
+
+  if (Array.isArray(prevProp) && Array.isArray(nextProp)) {
+    // Both are arrays, we can diff the arrays.
+    return diffNestedArrayProperty(
+      updatePayload,
+      prevProp,
+      nextProp,
+      validAttributes,
+    );
+  }
+
+  if (Array.isArray(prevProp)) {
+    return diffProperties(
+      updatePayload,
+      // $FlowFixMe - We know that this is always an object when the input is.
+      flattenStyle(prevProp),
+      // $FlowFixMe - We know that this isn't an array because of above flow.
+      resolveObject(nextProp),
+      validAttributes,
+    );
+  }
+
+  return diffProperties(
+    updatePayload,
+    resolveObject(prevProp),
+    // $FlowFixMe - We know that this is always an object when the input is.
+    flattenStyle(nextProp),
+    validAttributes,
+  );
+}
+
+/**
+ * addNestedProperty takes a single set of props and valid attribute
+ * attribute configurations. It processes each prop and adds it to the
+ * updatePayload.
+ */
+function addNestedProperty(
+  updatePayload: ?Object,
+  nextProp: NestedNode,
+  validAttributes: AttributeConfiguration,
+) {
+  if (!nextProp) {
+    return updatePayload;
+  }
+
+  if (!Array.isArray(nextProp)) {
+    // Add each property of the leaf.
+    return addProperties(
+      updatePayload,
+      resolveObject(nextProp),
+      validAttributes,
+    );
+  }
+
+  for (var i = 0; i < nextProp.length; i++) {
+    // Add all the properties of the array.
+    updatePayload = addNestedProperty(
+      updatePayload,
+      nextProp[i],
+      validAttributes,
+    );
+  }
+
+  return updatePayload;
+}
+
+/**
+ * clearNestedProperty takes a single set of props and valid attributes. It
+ * adds a null sentinel to the updatePayload, for each prop key.
+ */
+function clearNestedProperty(
+  updatePayload: ?Object,
+  prevProp: NestedNode,
+  validAttributes: AttributeConfiguration,
+): ?Object {
+  if (!prevProp) {
+    return updatePayload;
+  }
+
+  if (!Array.isArray(prevProp)) {
+    // Add each property of the leaf.
+    return clearProperties(
+      updatePayload,
+      resolveObject(prevProp),
+      validAttributes,
+    );
+  }
+
+  for (var i = 0; i < prevProp.length; i++) {
+    // Add all the properties of the array.
+    updatePayload = clearNestedProperty(
+      updatePayload,
+      prevProp[i],
+      validAttributes,
+    );
+  }
+  return updatePayload;
+}
+
+/**
+ * diffProperties takes two sets of props and a set of valid attributes
+ * and write to updatePayload the values that changed or were deleted.
+ * If no updatePayload is provided, a new one is created and returned if
+ * anything changed.
+ */
+function diffProperties(
+  updatePayload: ?Object,
+  prevProps: Object,
+  nextProps: Object,
+  validAttributes: AttributeConfiguration,
+): ?Object {
+  var attributeConfig: ?(CustomAttributeConfiguration | AttributeConfiguration);
+  var nextProp;
+  var prevProp;
+
+  for (var propKey in nextProps) {
+    attributeConfig = validAttributes[propKey];
+    if (!attributeConfig) {
+      continue; // not a valid native prop
+    }
+
+    prevProp = prevProps[propKey];
+    nextProp = nextProps[propKey];
+
+    // functions are converted to booleans as markers that the associated
+    // events should be sent from native.
+    if (typeof nextProp === 'function') {
+      nextProp = (true: any);
+      // If nextProp is not a function, then don't bother changing prevProp
+      // since nextProp will win and go into the updatePayload regardless.
+      if (typeof prevProp === 'function') {
+        prevProp = (true: any);
+      }
+    }
+
+    // An explicit value of undefined is treated as a null because it overrides
+    // any other preceeding value.
+    if (typeof nextProp === 'undefined') {
+      nextProp = (null: any);
+      if (typeof prevProp === 'undefined') {
+        prevProp = (null: any);
+      }
+    }
+
+    if (removedKeys) {
+      removedKeys[propKey] = false;
+    }
+
+    if (updatePayload && updatePayload[propKey] !== undefined) {
+      // Something else already triggered an update to this key because another
+      // value diffed. Since we're now later in the nested arrays our value is
+      // more important so we need to calculate it and override the existing
+      // value. It doesn't matter if nothing changed, we'll set it anyway.
+
+      // Pattern match on: attributeConfig
+      if (typeof attributeConfig !== 'object') {
+        // case: !Object is the default case
+        updatePayload[propKey] = nextProp;
+      } else if (
+        typeof attributeConfig.diff === 'function' ||
+        typeof attributeConfig.process === 'function'
+      ) {
+        // case: CustomAttributeConfiguration
+        var nextValue = typeof attributeConfig.process === 'function'
+          ? attributeConfig.process(nextProp)
+          : nextProp;
+        updatePayload[propKey] = nextValue;
+      }
+      continue;
+    }
+
+    if (prevProp === nextProp) {
+      continue; // nothing changed
+    }
+
+    // Pattern match on: attributeConfig
+    if (typeof attributeConfig !== 'object') {
+      // case: !Object is the default case
+      if (defaultDiffer(prevProp, nextProp)) {
+        // a normal leaf has changed
+        (updatePayload || (updatePayload = {}))[propKey] = nextProp;
+      }
+    } else if (
+      typeof attributeConfig.diff === 'function' ||
+      typeof attributeConfig.process === 'function'
+    ) {
+      // case: CustomAttributeConfiguration
+      var shouldUpdate =
+        prevProp === undefined ||
+        (typeof attributeConfig.diff === 'function'
+          ? attributeConfig.diff(prevProp, nextProp)
+          : defaultDiffer(prevProp, nextProp));
+      if (shouldUpdate) {
+        nextValue = typeof attributeConfig.process === 'function'
+          ? attributeConfig.process(nextProp)
+          : nextProp;
+        (updatePayload || (updatePayload = {}))[propKey] = nextValue;
+      }
+    } else {
+      // default: fallthrough case when nested properties are defined
+      removedKeys = null;
+      removedKeyCount = 0;
+      // We think that attributeConfig is not CustomAttributeConfiguration at
+      // this point so we assume it must be AttributeConfiguration.
+      updatePayload = diffNestedProperty(
+        updatePayload,
+        prevProp,
+        nextProp,
+        ((attributeConfig: any): AttributeConfiguration),
+      );
+      if (removedKeyCount > 0 && updatePayload) {
+        restoreDeletedValuesInNestedArray(
+          updatePayload,
+          nextProp,
+          ((attributeConfig: any): AttributeConfiguration),
+        );
+        removedKeys = null;
+      }
+    }
+  }
+
+  // Also iterate through all the previous props to catch any that have been
+  // removed and make sure native gets the signal so it can reset them to the
+  // default.
+  for (propKey in prevProps) {
+    if (nextProps[propKey] !== undefined) {
+      continue; // we've already covered this key in the previous pass
+    }
+    attributeConfig = validAttributes[propKey];
+    if (!attributeConfig) {
+      continue; // not a valid native prop
+    }
+
+    if (updatePayload && updatePayload[propKey] !== undefined) {
+      // This was already updated to a diff result earlier.
+      continue;
+    }
+
+    prevProp = prevProps[propKey];
+    if (prevProp === undefined) {
+      continue; // was already empty anyway
+    }
+    // Pattern match on: attributeConfig
+    if (
+      typeof attributeConfig !== 'object' ||
+      typeof attributeConfig.diff === 'function' ||
+      typeof attributeConfig.process === 'function'
+    ) {
+      // case: CustomAttributeConfiguration | !Object
+      // Flag the leaf property for removal by sending a sentinel.
+      (updatePayload || (updatePayload = {}))[propKey] = null;
+      if (!removedKeys) {
+        removedKeys = {};
+      }
+      if (!removedKeys[propKey]) {
+        removedKeys[propKey] = true;
+        removedKeyCount++;
+      }
+    } else {
+      // default:
+      // This is a nested attribute configuration where all the properties
+      // were removed so we need to go through and clear out all of them.
+      updatePayload = clearNestedProperty(
+        updatePayload,
+        prevProp,
+        ((attributeConfig: any): AttributeConfiguration),
+      );
+    }
+  }
+  return updatePayload;
+}
+
+/**
+ * addProperties adds all the valid props to the payload after being processed.
+ */
+function addProperties(
+  updatePayload: ?Object,
+  props: Object,
+  validAttributes: AttributeConfiguration,
+): ?Object {
+  // TODO: Fast path
+  return diffProperties(updatePayload, emptyObject, props, validAttributes);
+}
+
+/**
+ * clearProperties clears all the previous props by adding a null sentinel
+ * to the payload for each valid key.
+ */
+function clearProperties(
+  updatePayload: ?Object,
+  prevProps: Object,
+  validAttributes: AttributeConfiguration,
+): ?Object {
+  // TODO: Fast path
+  return diffProperties(updatePayload, prevProps, emptyObject, validAttributes);
+}
+
+var ReactNativeAttributePayload = {
+  create: function(
+    props: Object,
+    validAttributes: AttributeConfiguration,
+  ): ?Object {
+    return addProperties(
+      null, // updatePayload
+      props,
+      validAttributes,
+    );
+  },
+
+  diff: function(
+    prevProps: Object,
+    nextProps: Object,
+    validAttributes: AttributeConfiguration,
+  ): ?Object {
+    return diffProperties(
+      null, // updatePayload
+      prevProps,
+      nextProps,
+      validAttributes,
+    );
+  },
+};
+
+module.exports = ReactNativeAttributePayload;
diff --git a/src/renderers/native/ReactNativeBaseComponent.js b/src/renderers/native/ReactNativeBaseComponent.js
new file mode 100644
index 000000000000..37de967708b9
--- /dev/null
+++ b/src/renderers/native/ReactNativeBaseComponent.js
@@ -0,0 +1,233 @@
+/**
+ * Copyright (c) 2015-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 ReactNativeBaseComponent
+ * @flow
+ */
+'use strict';
+
+var NativeMethodsMixin = require('NativeMethodsMixin');
+var ReactNativeAttributePayload = require('ReactNativeAttributePayload');
+var ReactNativeComponentTree = require('ReactNativeComponentTree');
+var ReactNativeEventEmitter = require('ReactNativeEventEmitter');
+var ReactNativeTagHandles = require('ReactNativeTagHandles');
+var ReactMultiChild = require('ReactMultiChild');
+var UIManager = require('UIManager');
+
+var deepFreezeAndThrowOnMutationInDev = require('deepFreezeAndThrowOnMutationInDev');
+
+var registrationNames = ReactNativeEventEmitter.registrationNames;
+var putListener = ReactNativeEventEmitter.putListener;
+var deleteListener = ReactNativeEventEmitter.deleteListener;
+var deleteAllListeners = ReactNativeEventEmitter.deleteAllListeners;
+
+type ReactNativeBaseComponentViewConfig = {
+  validAttributes: Object,
+  uiViewClassName: string,
+};
+
+// require('UIManagerStatTracker').install(); // uncomment to enable
+
+/**
+ * @constructor ReactNativeBaseComponent
+ * @extends ReactComponent
+ * @extends ReactMultiChild
+ * @param {!object} UIKit View Configuration.
+ */
+var ReactNativeBaseComponent = function(
+  viewConfig: ReactNativeBaseComponentViewConfig,
+) {
+  this.viewConfig = viewConfig;
+};
+
+/**
+ * Mixin for containers that contain UIViews. NOTE: markup is rendered markup
+ * which is a `viewID` ... see the return value for `mountComponent` !
+ */
+ReactNativeBaseComponent.Mixin = {
+  getPublicInstance: function() {
+    // TODO: This should probably use a composite wrapper
+    return this;
+  },
+
+  unmountComponent: function() {
+    ReactNativeComponentTree.uncacheNode(this);
+    deleteAllListeners(this);
+    this.unmountChildren();
+    this._rootNodeID = 0;
+  },
+
+  /**
+   * Every native component is responsible for allocating its own `tag`, and
+   * issuing the native `createView` command. But it is not responsible for
+   * recording the fact that its own `rootNodeID` is associated with a
+   * `nodeHandle`. Only the code that actually adds its `nodeHandle` (`tag`) as
+   * a child of a container can confidently record that in
+   * `ReactNativeTagHandles`.
+   */
+  initializeChildren: function(children, containerTag, transaction, context) {
+    var mountImages = this.mountChildren(children, transaction, context);
+    // In a well balanced tree, half of the nodes are in the bottom row and have
+    // no children - let's avoid calling out to the native bridge for a large
+    // portion of the children.
+    if (mountImages.length) {
+      // TODO: Pool these per platform view class. Reusing the `mountImages`
+      // array would likely be a jit deopt.
+      var createdTags = [];
+      for (var i = 0, l = mountImages.length; i < l; i++) {
+        var mountImage = mountImages[i];
+        var childTag = mountImage;
+        createdTags[i] = childTag;
+      }
+      UIManager.setChildren(containerTag, createdTags);
+    }
+  },
+
+  /**
+   * Updates the component's currently mounted representation.
+   *
+   * @param {object} nextElement
+   * @param {ReactReconcileTransaction} transaction
+   * @param {object} context
+   * @internal
+   */
+  receiveComponent: function(nextElement, transaction, context) {
+    var prevElement = this._currentElement;
+    this._currentElement = nextElement;
+
+    if (__DEV__) {
+      for (var key in this.viewConfig.validAttributes) {
+        if (nextElement.props.hasOwnProperty(key)) {
+          deepFreezeAndThrowOnMutationInDev(nextElement.props[key]);
+        }
+      }
+    }
+
+    var updatePayload = ReactNativeAttributePayload.diff(
+      prevElement.props,
+      nextElement.props,
+      this.viewConfig.validAttributes,
+    );
+
+    if (updatePayload) {
+      UIManager.updateView(
+        this._rootNodeID,
+        this.viewConfig.uiViewClassName,
+        updatePayload,
+      );
+    }
+
+    this._reconcileListenersUponUpdate(prevElement.props, nextElement.props);
+    this.updateChildren(nextElement.props.children, transaction, context);
+  },
+
+  /**
+   * @param {object} initialProps Native component props.
+   */
+  _registerListenersUponCreation: function(initialProps) {
+    for (var key in initialProps) {
+      // NOTE: The check for `!props[key]`, is only possible because this method
+      // registers listeners the *first* time a component is created.
+      if (registrationNames[key] && initialProps[key]) {
+        var listener = initialProps[key];
+        putListener(this, key, listener);
+      }
+    }
+  },
+
+  /**
+   * Reconciles event listeners, adding or removing if necessary.
+   * @param {object} prevProps Native component props including events.
+   * @param {object} nextProps Next native component props including events.
+   */
+  _reconcileListenersUponUpdate: function(prevProps, nextProps) {
+    for (var key in nextProps) {
+      if (registrationNames[key] && nextProps[key] !== prevProps[key]) {
+        if (nextProps[key]) {
+          putListener(this, key, nextProps[key]);
+        } else {
+          deleteListener(this, key);
+        }
+      }
+    }
+  },
+
+  /**
+   * Currently this still uses IDs for reconciliation so this can return null.
+   *
+   * @return {null} Null.
+   */
+  getHostNode: function() {
+    return this._rootNodeID;
+  },
+
+  /**
+   * @param {ReactNativeReconcileTransaction} transaction
+   * @param {?ReactNativeBaseComponent} the parent component instance
+   * @param {?object} info about the host container
+   * @param {object} context
+   * @return {string} Unique iOS view tag.
+   */
+  mountComponent: function(
+    transaction,
+    hostParent,
+    hostContainerInfo,
+    context,
+  ) {
+    var tag = ReactNativeTagHandles.allocateTag();
+
+    this._rootNodeID = tag;
+    this._hostParent = hostParent;
+    this._hostContainerInfo = hostContainerInfo;
+
+    if (__DEV__) {
+      for (var key in this.viewConfig.validAttributes) {
+        if (this._currentElement.props.hasOwnProperty(key)) {
+          deepFreezeAndThrowOnMutationInDev(this._currentElement.props[key]);
+        }
+      }
+    }
+
+    var updatePayload = ReactNativeAttributePayload.create(
+      this._currentElement.props,
+      this.viewConfig.validAttributes,
+    );
+
+    var nativeTopRootTag = hostContainerInfo._tag;
+    UIManager.createView(
+      tag,
+      this.viewConfig.uiViewClassName,
+      nativeTopRootTag,
+      updatePayload,
+    );
+
+    ReactNativeComponentTree.precacheNode(this, tag);
+
+    this._registerListenersUponCreation(this._currentElement.props);
+    this.initializeChildren(
+      this._currentElement.props.children,
+      tag,
+      transaction,
+      context,
+    );
+    return tag;
+  },
+};
+
+/**
+ * Order of mixins is important. ReactNativeBaseComponent overrides methods in
+ * ReactMultiChild.
+ */
+Object.assign(
+  ReactNativeBaseComponent.prototype,
+  ReactMultiChild.Mixin,
+  ReactNativeBaseComponent.Mixin,
+  NativeMethodsMixin,
+);
+
+module.exports = ReactNativeBaseComponent;
diff --git a/src/renderers/native/ReactNativeBridgeEventPlugin.js b/src/renderers/native/ReactNativeBridgeEventPlugin.js
new file mode 100644
index 000000000000..35c2dad39705
--- /dev/null
+++ b/src/renderers/native/ReactNativeBridgeEventPlugin.js
@@ -0,0 +1,70 @@
+/**
+ * Copyright (c) 2015-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 ReactNativeBridgeEventPlugin
+ * @flow
+ */
+'use strict';
+
+var EventPropagators = require('EventPropagators');
+var SyntheticEvent = require('SyntheticEvent');
+var UIManager = require('UIManager');
+
+var warning = require('warning');
+
+var customBubblingEventTypes = UIManager.customBubblingEventTypes;
+var customDirectEventTypes = UIManager.customDirectEventTypes;
+
+var allTypesByEventName = {};
+
+for (var bubblingTypeName in customBubblingEventTypes) {
+  allTypesByEventName[bubblingTypeName] =
+    customBubblingEventTypes[bubblingTypeName];
+}
+
+for (var directTypeName in customDirectEventTypes) {
+  warning(
+    !customBubblingEventTypes[directTypeName],
+    'Event cannot be both direct and bubbling: %s',
+    directTypeName,
+  );
+  allTypesByEventName[directTypeName] = customDirectEventTypes[directTypeName];
+}
+
+var ReactNativeBridgeEventPlugin = {
+  eventTypes: {...customBubblingEventTypes, ...customDirectEventTypes},
+
+  /**
+   * @see {EventPluginHub.extractEvents}
+   */
+  extractEvents: function(
+    topLevelType: string,
+    targetInst: Object,
+    nativeEvent: Event,
+    nativeEventTarget: Object,
+  ): ?Object {
+    var bubbleDispatchConfig = customBubblingEventTypes[topLevelType];
+    var directDispatchConfig = customDirectEventTypes[topLevelType];
+    var event = SyntheticEvent.getPooled(
+      bubbleDispatchConfig || directDispatchConfig,
+      targetInst,
+      nativeEvent,
+      nativeEventTarget,
+    );
+    if (bubbleDispatchConfig) {
+      EventPropagators.accumulateTwoPhaseDispatches(event);
+    } else if (directDispatchConfig) {
+      EventPropagators.accumulateDirectDispatches(event);
+    } else {
+      return null;
+    }
+    return event;
+  },
+};
+
+module.exports = ReactNativeBridgeEventPlugin;
diff --git a/src/renderers/native/ReactNativeComponentEnvironment.js b/src/renderers/native/ReactNativeComponentEnvironment.js
new file mode 100644
index 000000000000..041b7bac5c6e
--- /dev/null
+++ b/src/renderers/native/ReactNativeComponentEnvironment.js
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2015-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 ReactNativeComponentEnvironment
+ * @flow
+ */
+'use strict';
+
+var ReactNativeDOMIDOperations = require('ReactNativeDOMIDOperations');
+var ReactNativeReconcileTransaction = require('ReactNativeReconcileTransaction');
+
+var ReactNativeComponentEnvironment = {
+  processChildrenUpdates:
+    ReactNativeDOMIDOperations.dangerouslyProcessChildrenUpdates,
+
+  replaceNodeWithMarkup:
+    ReactNativeDOMIDOperations.dangerouslyReplaceNodeWithMarkupByID,
+
+  /**
+   * @param {DOMElement} Element to clear.
+   */
+  clearNode: function(/*containerView*/) {},
+
+  ReactReconcileTransaction: ReactNativeReconcileTransaction,
+};
+
+module.exports = ReactNativeComponentEnvironment;
diff --git a/src/renderers/native/ReactNativeComponentTree.js b/src/renderers/native/ReactNativeComponentTree.js
new file mode 100644
index 000000000000..7b16b8512a17
--- /dev/null
+++ b/src/renderers/native/ReactNativeComponentTree.js
@@ -0,0 +1,66 @@
+/**
+ * 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 ReactNativeComponentTree
+ */
+
+'use strict';
+
+var invariant = require('invariant');
+
+var instanceCache = {};
+
+/**
+ * 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, tag) {
+  var nativeInst = getRenderedHostOrTextFromComponent(inst);
+  instanceCache[tag] = nativeInst;
+}
+
+function uncacheNode(inst) {
+  var tag = inst._rootNodeID;
+  if (tag) {
+    delete instanceCache[tag];
+  }
+}
+
+function getInstanceFromTag(tag) {
+  return instanceCache[tag] || null;
+}
+
+function getTagFromInstance(inst) {
+  invariant(inst._rootNodeID, 'All native instances should have a tag.');
+  return inst._rootNodeID;
+}
+
+var ReactNativeComponentTree = {
+  getClosestInstanceFromNode: getInstanceFromTag,
+  getInstanceFromNode: getInstanceFromTag,
+  getNodeFromInstance: getTagFromInstance,
+  precacheNode: precacheNode,
+  uncacheNode: uncacheNode,
+};
+
+module.exports = ReactNativeComponentTree;
diff --git a/src/renderers/native/ReactNativeContainerInfo.js b/src/renderers/native/ReactNativeContainerInfo.js
new file mode 100644
index 000000000000..6d24f4c75156
--- /dev/null
+++ b/src/renderers/native/ReactNativeContainerInfo.js
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) 2015-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 ReactNativeContainerInfo
+ * @flow
+ */
+'use strict';
+
+function ReactNativeContainerInfo(tag: number) {
+  var info = {
+    _tag: tag,
+  };
+  return info;
+}
+
+module.exports = ReactNativeContainerInfo;
diff --git a/src/renderers/native/ReactNativeDOMIDOperations.js b/src/renderers/native/ReactNativeDOMIDOperations.js
new file mode 100644
index 000000000000..c008373f66c0
--- /dev/null
+++ b/src/renderers/native/ReactNativeDOMIDOperations.js
@@ -0,0 +1,85 @@
+/**
+ * Copyright (c) 2015-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 ReactNativeDOMIDOperations
+ */
+'use strict';
+
+var ReactNativeComponentTree = require('ReactNativeComponentTree');
+var UIManager = require('UIManager');
+
+/**
+ * Updates a component's children by processing a series of updates.
+ * For each of the update/create commands, the `fromIndex` refers to the index
+ * that the item existed at *before* any of the updates are applied, and the
+ * `toIndex` refers to the index after *all* of the updates are applied
+ * (including deletes/moves). TODO: refactor so this can be shared with
+ * DOMChildrenOperations.
+ *
+ * @param {ReactNativeBaseComponent} updates List of update configurations.
+ * @param {array<string>} markup List of markup strings - in the case of React
+ * IOS, the ids of new components assumed to be already created.
+ */
+var dangerouslyProcessChildrenUpdates = function(inst, childrenUpdates) {
+  if (!childrenUpdates.length) {
+    return;
+  }
+
+  var containerTag = ReactNativeComponentTree.getNodeFromInstance(inst);
+
+  var moveFromIndices;
+  var moveToIndices;
+  var addChildTags;
+  var addAtIndices;
+  var removeAtIndices;
+
+  for (var i = 0; i < childrenUpdates.length; i++) {
+    var update = childrenUpdates[i];
+    if (update.type === 'MOVE_EXISTING') {
+      (moveFromIndices || (moveFromIndices = [])).push(update.fromIndex);
+      (moveToIndices || (moveToIndices = [])).push(update.toIndex);
+    } else if (update.type === 'REMOVE_NODE') {
+      (removeAtIndices || (removeAtIndices = [])).push(update.fromIndex);
+    } else if (update.type === 'INSERT_MARKUP') {
+      var mountImage = update.content;
+      var tag = mountImage;
+      (addAtIndices || (addAtIndices = [])).push(update.toIndex);
+      (addChildTags || (addChildTags = [])).push(tag);
+    }
+  }
+
+  UIManager.manageChildren(
+    containerTag,
+    moveFromIndices,
+    moveToIndices,
+    addChildTags,
+    addAtIndices,
+    removeAtIndices,
+  );
+};
+
+/**
+ * Operations used to process updates to DOM nodes. This is made injectable via
+ * `ReactComponent.DOMIDOperations`.
+ */
+var ReactNativeDOMIDOperations = {
+  dangerouslyProcessChildrenUpdates,
+
+  /**
+   * Replaces a view that exists in the document with markup.
+   *
+   * @param {string} id ID of child to be replaced.
+   * @param {string} markup Mount image to replace child with id.
+   */
+  dangerouslyReplaceNodeWithMarkupByID: function(id, mountImage) {
+    var oldTag = id;
+    UIManager.replaceExistingNonRootView(oldTag, mountImage);
+  },
+};
+
+module.exports = ReactNativeDOMIDOperations;
diff --git a/src/renderers/native/ReactNativeDefaultInjection.js b/src/renderers/native/ReactNativeDefaultInjection.js
new file mode 100644
index 000000000000..3deef3b0e0e7
--- /dev/null
+++ b/src/renderers/native/ReactNativeDefaultInjection.js
@@ -0,0 +1,109 @@
+/**
+ * Copyright (c) 2015-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 ReactNativeDefaultInjection
+ * @flow
+ */
+'use strict';
+
+/**
+ * Make sure essential globals are available and are patched correctly. Please don't remove this
+ * line. Bundles created by react-packager `require` it before executing any application code. This
+ * ensures it exists in the dependency graph and can be `require`d.
+ * TODO: require this in packager, not in React #10932517
+ */
+require('InitializeJavaScriptAppEngine');
+
+var EventPluginHub = require('EventPluginHub');
+var EventPluginUtils = require('EventPluginUtils');
+var RCTEventEmitter = require('RCTEventEmitter');
+var React = require('React');
+var ReactComponentEnvironment = require('ReactComponentEnvironment');
+var ReactDefaultBatchingStrategy = require('ReactDefaultBatchingStrategy');
+var ReactEmptyComponent = require('ReactEmptyComponent');
+var ReactNativeBridgeEventPlugin = require('ReactNativeBridgeEventPlugin');
+var ReactHostComponent = require('ReactHostComponent');
+var ReactNativeComponentEnvironment = require('ReactNativeComponentEnvironment');
+var ReactNativeComponentTree = require('ReactNativeComponentTree');
+var ReactNativeEventEmitter = require('ReactNativeEventEmitter');
+var ReactNativeEventPluginOrder = require('ReactNativeEventPluginOrder');
+var ReactNativeGlobalResponderHandler = require('ReactNativeGlobalResponderHandler');
+var ReactNativeTextComponent = require('ReactNativeTextComponent');
+var ReactNativeTreeTraversal = require('ReactNativeTreeTraversal');
+var ReactSimpleEmptyComponent = require('ReactSimpleEmptyComponent');
+var ReactUpdates = require('ReactUpdates');
+var ResponderEventPlugin = require('ResponderEventPlugin');
+
+var invariant = require('invariant');
+
+function inject() {
+  /**
+   * Register the event emitter with the native bridge
+   */
+  RCTEventEmitter.register(ReactNativeEventEmitter);
+
+  /**
+   * Inject module for resolving DOM hierarchy and plugin ordering.
+   */
+  EventPluginHub.injection.injectEventPluginOrder(ReactNativeEventPluginOrder);
+  EventPluginUtils.injection.injectComponentTree(ReactNativeComponentTree);
+  EventPluginUtils.injection.injectTreeTraversal(ReactNativeTreeTraversal);
+
+  ResponderEventPlugin.injection.injectGlobalResponderHandler(
+    ReactNativeGlobalResponderHandler,
+  );
+
+  /**
+   * Some important event plugins included by default (without having to require
+   * them).
+   */
+  EventPluginHub.injection.injectEventPluginsByName({
+    ResponderEventPlugin: ResponderEventPlugin,
+    ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin,
+  });
+
+  ReactUpdates.injection.injectReconcileTransaction(
+    ReactNativeComponentEnvironment.ReactReconcileTransaction,
+  );
+
+  ReactUpdates.injection.injectBatchingStrategy(ReactDefaultBatchingStrategy);
+
+  ReactComponentEnvironment.injection.injectEnvironment(
+    ReactNativeComponentEnvironment,
+  );
+
+  var EmptyComponent = instantiate => {
+    // Can't import View at the top because it depends on React to make its composite
+    var View = require('View');
+    return new ReactSimpleEmptyComponent(
+      React.createElement(View, {
+        collapsable: true,
+        style: {position: 'absolute'},
+      }),
+      instantiate,
+    );
+  };
+
+  ReactEmptyComponent.injection.injectEmptyComponentFactory(EmptyComponent);
+
+  ReactHostComponent.injection.injectTextComponentClass(
+    ReactNativeTextComponent,
+  );
+  ReactHostComponent.injection.injectGenericComponentClass(function(tag) {
+    // Show a nicer error message for non-function tags
+    var info = '';
+    if (typeof tag === 'string' && /^[a-z]/.test(tag)) {
+      info += ' Each component name should start with an uppercase letter.';
+    }
+    invariant(false, 'Expected a component class, got %s.%s', tag, info);
+  });
+}
+
+module.exports = {
+  inject: inject,
+};
diff --git a/src/renderers/native/ReactNativeEventEmitter.js b/src/renderers/native/ReactNativeEventEmitter.js
new file mode 100644
index 000000000000..95011989c0f0
--- /dev/null
+++ b/src/renderers/native/ReactNativeEventEmitter.js
@@ -0,0 +1,219 @@
+/**
+ * Copyright (c) 2015-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 ReactNativeEventEmitter
+ * @flow
+ */
+'use strict';
+
+var EventPluginHub = require('EventPluginHub');
+var EventPluginRegistry = require('EventPluginRegistry');
+var ReactEventEmitterMixin = require('ReactEventEmitterMixin');
+var ReactNativeComponentTree = require('ReactNativeComponentTree');
+var ReactNativeTagHandles = require('ReactNativeTagHandles');
+var ReactUpdates = require('ReactUpdates');
+
+var warning = require('warning');
+
+/**
+ * Version of `ReactBrowserEventEmitter` that works on the receiving side of a
+ * serialized worker boundary.
+ */
+
+// Shared default empty native event - conserve memory.
+var EMPTY_NATIVE_EVENT = {};
+
+/**
+ * Selects a subsequence of `Touch`es, without destroying `touches`.
+ *
+ * @param {Array<Touch>} touches Deserialized touch objects.
+ * @param {Array<number>} indices Indices by which to pull subsequence.
+ * @return {Array<Touch>} Subsequence of touch objects.
+ */
+var touchSubsequence = function(touches, indices) {
+  var ret = [];
+  for (var i = 0; i < indices.length; i++) {
+    ret.push(touches[indices[i]]);
+  }
+  return ret;
+};
+
+/**
+ * TODO: Pool all of this.
+ *
+ * Destroys `touches` by removing touch objects at indices `indices`. This is
+ * to maintain compatibility with W3C touch "end" events, where the active
+ * touches don't include the set that has just been "ended".
+ *
+ * @param {Array<Touch>} touches Deserialized touch objects.
+ * @param {Array<number>} indices Indices to remove from `touches`.
+ * @return {Array<Touch>} Subsequence of removed touch objects.
+ */
+var removeTouchesAtIndices = function(
+  touches: Array<Object>,
+  indices: Array<number>,
+): Array<Object> {
+  var rippedOut = [];
+  // use an unsafe downcast to alias to nullable elements,
+  // so we can delete and then compact.
+  var temp: Array<?Object> = (touches: Array<any>);
+  for (var i = 0; i < indices.length; i++) {
+    var index = indices[i];
+    rippedOut.push(touches[index]);
+    temp[index] = null;
+  }
+  var fillAt = 0;
+  for (var j = 0; j < temp.length; j++) {
+    var cur = temp[j];
+    if (cur !== null) {
+      temp[fillAt++] = cur;
+    }
+  }
+  temp.length = fillAt;
+  return rippedOut;
+};
+
+/**
+ * `ReactNativeEventEmitter` is used to attach top-level event listeners. For example:
+ *
+ *   ReactNativeEventEmitter.putListener('myID', 'onClick', myFunction);
+ *
+ * This would allocate a "registration" of `('onClick', myFunction)` on 'myID'.
+ *
+ * @internal
+ */
+var ReactNativeEventEmitter = {
+  ...ReactEventEmitterMixin,
+
+  registrationNames: EventPluginRegistry.registrationNameModules,
+
+  putListener: EventPluginHub.putListener,
+
+  getListener: EventPluginHub.getListener,
+
+  deleteListener: EventPluginHub.deleteListener,
+
+  deleteAllListeners: EventPluginHub.deleteAllListeners,
+
+  /**
+   * Internal version of `receiveEvent` in terms of normalized (non-tag)
+   * `rootNodeID`.
+   *
+   * @see receiveEvent.
+   *
+   * @param {rootNodeID} rootNodeID React root node ID that event occurred on.
+   * @param {TopLevelType} topLevelType Top level type of event.
+   * @param {object} nativeEventParam Object passed from native.
+   */
+  _receiveRootNodeIDEvent: function(
+    rootNodeID: number,
+    topLevelType: string,
+    nativeEventParam: Object,
+  ) {
+    var nativeEvent = nativeEventParam || EMPTY_NATIVE_EVENT;
+    var inst = ReactNativeComponentTree.getInstanceFromNode(rootNodeID);
+    if (!inst) {
+      // If the original instance is already gone, we don't have to dispatch
+      // any events.
+      return;
+    }
+    ReactUpdates.batchedUpdates(function() {
+      ReactNativeEventEmitter.handleTopLevel(
+        topLevelType,
+        inst,
+        nativeEvent,
+        nativeEvent.target,
+      );
+    });
+  },
+
+  /**
+   * Publicly exposed method on module for native objc to invoke when a top
+   * level event is extracted.
+   * @param {rootNodeID} rootNodeID React root node ID that event occurred on.
+   * @param {TopLevelType} topLevelType Top level type of event.
+   * @param {object} nativeEventParam Object passed from native.
+   */
+  receiveEvent: function(
+    tag: number,
+    topLevelType: string,
+    nativeEventParam: Object,
+  ) {
+    var rootNodeID = tag;
+    ReactNativeEventEmitter._receiveRootNodeIDEvent(
+      rootNodeID,
+      topLevelType,
+      nativeEventParam,
+    );
+  },
+
+  /**
+   * Simple multi-wrapper around `receiveEvent` that is intended to receive an
+   * efficient representation of `Touch` objects, and other information that
+   * can be used to construct W3C compliant `Event` and `Touch` lists.
+   *
+   * This may create dispatch behavior that differs than web touch handling. We
+   * loop through each of the changed touches and receive it as a single event.
+   * So two `touchStart`/`touchMove`s that occur simultaneously are received as
+   * two separate touch event dispatches - when they arguably should be one.
+   *
+   * This implementation reuses the `Touch` objects themselves as the `Event`s
+   * since we dispatch an event for each touch (though that might not be spec
+   * compliant). The main purpose of reusing them is to save allocations.
+   *
+   * TODO: Dispatch multiple changed touches in one event. The bubble path
+   * could be the first common ancestor of all the `changedTouches`.
+   *
+   * One difference between this behavior and W3C spec: cancelled touches will
+   * not appear in `.touches`, or in any future `.touches`, though they may
+   * still be "actively touching the surface".
+   *
+   * Web desktop polyfills only need to construct a fake touch event with
+   * identifier 0, also abandoning traditional click handlers.
+   */
+  receiveTouches: function(
+    eventTopLevelType: string,
+    touches: Array<Object>,
+    changedIndices: Array<number>,
+  ) {
+    var changedTouches = eventTopLevelType === 'topTouchEnd' ||
+      eventTopLevelType === 'topTouchCancel'
+      ? removeTouchesAtIndices(touches, changedIndices)
+      : touchSubsequence(touches, changedIndices);
+
+    for (var jj = 0; jj < changedTouches.length; jj++) {
+      var touch = changedTouches[jj];
+      // Touch objects can fulfill the role of `DOM` `Event` objects if we set
+      // the `changedTouches`/`touches`. This saves allocations.
+      touch.changedTouches = changedTouches;
+      touch.touches = touches;
+      var nativeEvent = touch;
+      var rootNodeID = null;
+      var target = nativeEvent.target;
+      if (target !== null && target !== undefined) {
+        if (target < ReactNativeTagHandles.tagsStartAt) {
+          if (__DEV__) {
+            warning(
+              false,
+              'A view is reporting that a touch occured on tag zero.',
+            );
+          }
+        } else {
+          rootNodeID = target;
+        }
+      }
+      ReactNativeEventEmitter._receiveRootNodeIDEvent(
+        rootNodeID,
+        eventTopLevelType,
+        nativeEvent,
+      );
+    }
+  },
+};
+
+module.exports = ReactNativeEventEmitter;
diff --git a/src/renderers/native/ReactNativeEventPluginOrder.js b/src/renderers/native/ReactNativeEventPluginOrder.js
new file mode 100644
index 000000000000..b1b5f66d1108
--- /dev/null
+++ b/src/renderers/native/ReactNativeEventPluginOrder.js
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2015-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 ReactNativeEventPluginOrder
+ * @flow
+ */
+'use strict';
+
+var ReactNativeEventPluginOrder = [
+  'ResponderEventPlugin',
+  'ReactNativeBridgeEventPlugin',
+];
+
+module.exports = ReactNativeEventPluginOrder;
diff --git a/src/renderers/native/ReactNativeGlobalResponderHandler.js b/src/renderers/native/ReactNativeGlobalResponderHandler.js
new file mode 100644
index 000000000000..26bf46d87d43
--- /dev/null
+++ b/src/renderers/native/ReactNativeGlobalResponderHandler.js
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 2015-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 ReactNativeGlobalResponderHandler
+ */
+'use strict';
+
+var UIManager = require('UIManager');
+
+var ReactNativeGlobalResponderHandler = {
+  onChange: function(from, to, blockNativeResponder) {
+    if (to !== null) {
+      UIManager.setJSResponder(to._rootNodeID, blockNativeResponder);
+    } else {
+      UIManager.clearJSResponder();
+    }
+  },
+};
+
+module.exports = ReactNativeGlobalResponderHandler;
diff --git a/src/renderers/native/ReactNativeMount.js b/src/renderers/native/ReactNativeMount.js
new file mode 100644
index 000000000000..8654fbcec904
--- /dev/null
+++ b/src/renderers/native/ReactNativeMount.js
@@ -0,0 +1,221 @@
+/**
+ * Copyright (c) 2015-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 ReactNativeMount
+ * @flow
+ */
+'use strict';
+
+var React = require('React');
+var ReactInstrumentation = require('ReactInstrumentation');
+var ReactNativeContainerInfo = require('ReactNativeContainerInfo');
+var ReactNativeTagHandles = require('ReactNativeTagHandles');
+var ReactReconciler = require('ReactReconciler');
+var ReactUpdateQueue = require('ReactUpdateQueue');
+var ReactUpdates = require('ReactUpdates');
+var UIManager = require('UIManager');
+
+var emptyObject = require('emptyObject');
+var instantiateReactComponent = require('instantiateReactComponent');
+var shouldUpdateReactComponent = require('shouldUpdateReactComponent');
+
+/**
+ * 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 TopLevelWrapper = function() {};
+TopLevelWrapper.prototype.isReactComponent = {};
+if (__DEV__) {
+  TopLevelWrapper.displayName = 'TopLevelWrapper';
+}
+TopLevelWrapper.prototype.render = function() {
+  return this.props.child;
+};
+TopLevelWrapper.isReactTopLevelWrapper = true;
+
+/**
+ * Mounts this component and inserts it into the DOM.
+ *
+ * @param {ReactComponent} componentInstance The instance to mount.
+ * @param {number} rootID ID of the root node.
+ * @param {number} containerTag container element to mount into.
+ * @param {ReactReconcileTransaction} transaction
+ */
+function mountComponentIntoNode(componentInstance, containerTag, transaction) {
+  var markup = ReactReconciler.mountComponent(
+    componentInstance,
+    transaction,
+    null,
+    ReactNativeContainerInfo(containerTag),
+    emptyObject,
+    0 /* parentDebugID */,
+  );
+  componentInstance._renderedComponent._topLevelWrapper = componentInstance;
+  ReactNativeMount._mountImageIntoNode(markup, containerTag);
+}
+
+/**
+ * Batched mount.
+ *
+ * @param {ReactComponent} componentInstance The instance to mount.
+ * @param {number} rootID ID of the root node.
+ * @param {number} containerTag container element to mount into.
+ */
+function batchedMountComponentIntoNode(componentInstance, containerTag) {
+  var transaction = ReactUpdates.ReactReconcileTransaction.getPooled();
+  transaction.perform(
+    mountComponentIntoNode,
+    null,
+    componentInstance,
+    containerTag,
+    transaction,
+  );
+  ReactUpdates.ReactReconcileTransaction.release(transaction);
+}
+
+/**
+ * As soon as `ReactMount` is refactored to not rely on the DOM, we can share
+ * code between the two. For now, we'll hard code the ID logic.
+ */
+var ReactNativeMount = {
+  _instancesByContainerID: {},
+
+  // these two functions are needed by React Devtools
+  findNodeHandle: require('findNodeHandle'),
+
+  /**
+   * @param {ReactComponent} instance Instance to render.
+   * @param {containerTag} containerView Handle to native view tag
+   */
+  renderComponent: function(
+    nextElement: ReactElement<*>,
+    containerTag: number,
+    callback?: ?() => void,
+  ): ?ReactComponent<any, any, any> {
+    var nextWrappedElement = React.createElement(TopLevelWrapper, {
+      child: nextElement,
+    });
+
+    var topRootNodeID = containerTag;
+    var prevComponent = ReactNativeMount._instancesByContainerID[topRootNodeID];
+    if (prevComponent) {
+      var prevWrappedElement = prevComponent._currentElement;
+      var prevElement = prevWrappedElement.props.child;
+      if (shouldUpdateReactComponent(prevElement, nextElement)) {
+        ReactUpdateQueue.enqueueElementInternal(
+          prevComponent,
+          nextWrappedElement,
+          emptyObject,
+        );
+        if (callback) {
+          ReactUpdateQueue.enqueueCallbackInternal(prevComponent, callback);
+        }
+        return prevComponent;
+      } else {
+        ReactNativeMount.unmountComponentAtNode(containerTag);
+      }
+    }
+
+    if (!ReactNativeTagHandles.reactTagIsNativeTopRootID(containerTag)) {
+      console.error('You cannot render into anything but a top root');
+      return null;
+    }
+
+    ReactNativeTagHandles.assertRootTag(containerTag);
+
+    var instance = instantiateReactComponent(nextWrappedElement, false);
+    ReactNativeMount._instancesByContainerID[containerTag] = instance;
+
+    // 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,
+      instance,
+      containerTag,
+    );
+    var component = instance.getPublicInstance();
+    if (callback) {
+      callback.call(component);
+    }
+    return component;
+  },
+
+  /**
+   * @param {View} view View tree image.
+   * @param {number} containerViewID View to insert sub-view into.
+   */
+  _mountImageIntoNode: function(mountImage: number, containerID: number) {
+    // Since we now know that the `mountImage` has been mounted, we can
+    // mark it as such.
+    var childTag = mountImage;
+    UIManager.setChildren(containerID, [childTag]);
+  },
+
+  /**
+   * Standard unmounting of the component that is rendered into `containerID`,
+   * but will also execute a command to remove the actual container view
+   * itself. This is useful when a client is cleaning up a React tree, and also
+   * knows that the container will no longer be needed. When executing
+   * asynchronously, it's easier to just have this method be the one that calls
+   * for removal of the view.
+   */
+  unmountComponentAtNodeAndRemoveContainer: function(containerTag: number) {
+    ReactNativeMount.unmountComponentAtNode(containerTag);
+    // call back into native to remove all of the subviews from this container
+    UIManager.removeRootView(containerTag);
+  },
+
+  /**
+   * Unmount component at container ID by iterating through each child component
+   * that has been rendered and unmounting it. There should just be one child
+   * component at this time.
+   */
+  unmountComponentAtNode: function(containerTag: number): boolean {
+    if (!ReactNativeTagHandles.reactTagIsNativeTopRootID(containerTag)) {
+      console.error('You cannot render into anything but a top root');
+      return false;
+    }
+
+    var instance = ReactNativeMount._instancesByContainerID[containerTag];
+    if (!instance) {
+      return false;
+    }
+    if (__DEV__) {
+      ReactInstrumentation.debugTool.onBeginFlush();
+    }
+    ReactNativeMount.unmountComponentFromNode(instance, containerTag);
+    delete ReactNativeMount._instancesByContainerID[containerTag];
+    if (__DEV__) {
+      ReactInstrumentation.debugTool.onEndFlush();
+    }
+    return true;
+  },
+
+  /**
+   * Unmounts a component and sends messages back to iOS to remove its subviews.
+   *
+   * @param {ReactComponent} instance React component instance.
+   * @param {string} containerID ID of container we're removing from.
+   * @final
+   * @internal
+   * @see {ReactNativeMount.unmountComponentAtNode}
+   */
+  unmountComponentFromNode: function(
+    instance: ReactComponent<any, any, any>,
+    containerID: number,
+  ) {
+    // Call back into native to remove all of the subviews from this container
+    ReactReconciler.unmountComponent(instance);
+    UIManager.removeSubviewsFromContainerWithID(containerID);
+  },
+};
+
+module.exports = ReactNativeMount;
diff --git a/src/renderers/native/ReactNativePropRegistry.js b/src/renderers/native/ReactNativePropRegistry.js
new file mode 100644
index 000000000000..3cffb9acf3b9
--- /dev/null
+++ b/src/renderers/native/ReactNativePropRegistry.js
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2015-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 ReactNativePropRegistry
+ * @flow
+ */
+'use strict';
+
+var objects = {};
+var uniqueID = 1;
+var emptyObject = {};
+
+class ReactNativePropRegistry {
+  static register(object: Object): number {
+    var id = ++uniqueID;
+    if (__DEV__) {
+      Object.freeze(object);
+    }
+    objects[id] = object;
+    return id;
+  }
+
+  static getByID(id: number): Object {
+    if (!id) {
+      // Used in the style={[condition && id]} pattern,
+      // we want it to be a no-op when the value is false or null
+      return emptyObject;
+    }
+
+    var object = objects[id];
+    if (!object) {
+      console.warn('Invalid style with id `' + id + '`. Skipping ...');
+      return emptyObject;
+    }
+    return object;
+  }
+}
+
+module.exports = ReactNativePropRegistry;
diff --git a/src/renderers/native/ReactNativeReconcileTransaction.js b/src/renderers/native/ReactNativeReconcileTransaction.js
new file mode 100644
index 000000000000..9ee4fc9815ac
--- /dev/null
+++ b/src/renderers/native/ReactNativeReconcileTransaction.js
@@ -0,0 +1,132 @@
+/**
+ * Copyright (c) 2015-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 ReactNativeReconcileTransaction
+ * @flow
+ */
+'use strict';
+
+var CallbackQueue = require('CallbackQueue');
+var PooledClass = require('PooledClass');
+var Transaction = require('Transaction');
+var ReactInstrumentation = require('ReactInstrumentation');
+var ReactUpdateQueue = require('ReactUpdateQueue');
+
+/**
+ * Provides a `CallbackQueue` queue for collecting `onDOMReady` callbacks during
+ * the performing of 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 = [ON_DOM_READY_QUEUEING];
+
+if (__DEV__) {
+  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 ReactNativeReconcileTransaction
+ */
+function ReactNativeReconcileTransaction() {
+  this.reinitializeTransaction();
+  this.reactMountReady = CallbackQueue.getPooled(null);
+}
+
+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.
+   *   TODO: convert to ReactMountReady
+   */
+  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;
+  },
+};
+
+Object.assign(
+  ReactNativeReconcileTransaction.prototype,
+  Transaction,
+  ReactNativeReconcileTransaction,
+  Mixin,
+);
+
+PooledClass.addPoolingTo(ReactNativeReconcileTransaction);
+
+module.exports = ReactNativeReconcileTransaction;
diff --git a/src/renderers/native/ReactNativeTagHandles.js b/src/renderers/native/ReactNativeTagHandles.js
new file mode 100644
index 000000000000..6b878dbdbdad
--- /dev/null
+++ b/src/renderers/native/ReactNativeTagHandles.js
@@ -0,0 +1,58 @@
+/**
+ * Copyright (c) 2015-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 ReactNativeTagHandles
+ * @flow
+ */
+'use strict';
+
+var invariant = require('invariant');
+
+/**
+ * Keeps track of allocating and associating native "tags" which are numeric,
+ * unique view IDs. All the native tags are negative numbers, to avoid
+ * collisions, but in the JS we keep track of them as positive integers to store
+ * them effectively in Arrays. So we must refer to them as "inverses" of the
+ * native tags (that are * normally negative).
+ *
+ * It *must* be the case that every `rootNodeID` always maps to the exact same
+ * `tag` forever. The easiest way to accomplish this is to never delete
+ * anything from this table.
+ * Why: Because `dangerouslyReplaceNodeWithMarkupByID` relies on being able to
+ * unmount a component with a `rootNodeID`, then mount a new one in its place,
+ */
+var INITIAL_TAG_COUNT = 1;
+var ReactNativeTagHandles = {
+  tagsStartAt: INITIAL_TAG_COUNT,
+  tagCount: INITIAL_TAG_COUNT,
+
+  allocateTag: function(): number {
+    // Skip over root IDs as those are reserved for native
+    while (this.reactTagIsNativeTopRootID(ReactNativeTagHandles.tagCount)) {
+      ReactNativeTagHandles.tagCount++;
+    }
+    var tag = ReactNativeTagHandles.tagCount;
+    ReactNativeTagHandles.tagCount++;
+    return tag;
+  },
+
+  assertRootTag: function(tag: number): void {
+    invariant(
+      this.reactTagIsNativeTopRootID(tag),
+      'Expect a native root tag, instead got %s',
+      tag,
+    );
+  },
+
+  reactTagIsNativeTopRootID: function(reactTag: number): boolean {
+    // We reserve all tags that are 1 mod 10 for native root views
+    return reactTag % 10 === 1;
+  },
+};
+
+module.exports = ReactNativeTagHandles;
diff --git a/src/renderers/native/ReactNativeTextComponent.js b/src/renderers/native/ReactNativeTextComponent.js
new file mode 100644
index 000000000000..bc98cabf2779
--- /dev/null
+++ b/src/renderers/native/ReactNativeTextComponent.js
@@ -0,0 +1,79 @@
+/**
+ * Copyright (c) 2015-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 ReactNativeTextComponent
+ */
+
+'use strict';
+
+var ReactNativeComponentTree = require('ReactNativeComponentTree');
+var ReactNativeTagHandles = require('ReactNativeTagHandles');
+var UIManager = require('UIManager');
+
+var invariant = require('invariant');
+
+var ReactNativeTextComponent = function(text) {
+  // This is really a ReactText (ReactNode), not a ReactElement
+  this._currentElement = text;
+  this._stringText = '' + text;
+  this._hostParent = null;
+  this._rootNodeID = 0;
+};
+
+Object.assign(ReactNativeTextComponent.prototype, {
+  mountComponent: function(
+    transaction,
+    hostParent,
+    hostContainerInfo,
+    context,
+  ) {
+    // TODO: hostParent should have this context already. Stop abusing context.
+    invariant(
+      context.isInAParentText,
+      'RawText "%s" must be wrapped in an explicit <Text> component.',
+      this._stringText,
+    );
+    this._hostParent = hostParent;
+    var tag = ReactNativeTagHandles.allocateTag();
+    this._rootNodeID = tag;
+    var nativeTopRootTag = hostContainerInfo._tag;
+    UIManager.createView(tag, 'RCTRawText', nativeTopRootTag, {
+      text: this._stringText,
+    });
+
+    ReactNativeComponentTree.precacheNode(this, tag);
+
+    return tag;
+  },
+
+  getHostNode: function() {
+    return this._rootNodeID;
+  },
+
+  receiveComponent: function(nextText, transaction, context) {
+    if (nextText !== this._currentElement) {
+      this._currentElement = nextText;
+      var nextStringText = '' + nextText;
+      if (nextStringText !== this._stringText) {
+        this._stringText = nextStringText;
+        UIManager.updateView(this._rootNodeID, 'RCTRawText', {
+          text: this._stringText,
+        });
+      }
+    }
+  },
+
+  unmountComponent: function() {
+    ReactNativeComponentTree.uncacheNode(this);
+    this._currentElement = null;
+    this._stringText = null;
+    this._rootNodeID = 0;
+  },
+});
+
+module.exports = ReactNativeTextComponent;
diff --git a/src/renderers/native/ReactNativeTreeTraversal.js b/src/renderers/native/ReactNativeTreeTraversal.js
new file mode 100644
index 000000000000..80c6f5ddf15e
--- /dev/null
+++ b/src/renderers/native/ReactNativeTreeTraversal.js
@@ -0,0 +1,126 @@
+/**
+ * Copyright 2015-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 ReactNativeTreeTraversal
+ */
+
+'use strict';
+
+// Same as ReactDOMTreeTraversal without the invariants.
+
+/**
+ * Return the lowest common ancestor of A and B, or null if they are in
+ * different trees.
+ */
+function getLowestCommonAncestor(instA, instB) {
+  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) {
+  while (instB) {
+    if (instB === instA) {
+      return true;
+    }
+    instB = instB._hostParent;
+  }
+  return false;
+}
+
+/**
+ * Return the parent instance of the passed-in instance.
+ */
+function getParentInstance(inst) {
+  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,
+};
diff --git a/src/renderers/native/__mocks__/InitializeJavaScriptAppEngine.js b/src/renderers/native/__mocks__/InitializeJavaScriptAppEngine.js
new file mode 100644
index 000000000000..9df419b050e7
--- /dev/null
+++ b/src/renderers/native/__mocks__/InitializeJavaScriptAppEngine.js
@@ -0,0 +1,15 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+'use strict';
+
+// Noop
+
+// TODO #10932517: Move all initialization callers back into react-native
+
diff --git a/src/renderers/native/__mocks__/RCTEventEmitter.js b/src/renderers/native/__mocks__/RCTEventEmitter.js
new file mode 100644
index 000000000000..d6e66ad500fc
--- /dev/null
+++ b/src/renderers/native/__mocks__/RCTEventEmitter.js
@@ -0,0 +1,16 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+'use strict';
+
+var RCTEventEmitter = {
+  register: jest.fn(),
+};
+
+module.exports = RCTEventEmitter;
diff --git a/src/renderers/native/__mocks__/TextInputState.js b/src/renderers/native/__mocks__/TextInputState.js
new file mode 100644
index 000000000000..a0b4e576d77b
--- /dev/null
+++ b/src/renderers/native/__mocks__/TextInputState.js
@@ -0,0 +1,17 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+'use strict';
+
+// Mock of the Native Hooks
+// TODO: Should this move into the components themselves? E.g. focusable
+
+var TextInputState = {};
+
+module.exports = TextInputState;
diff --git a/src/renderers/native/__mocks__/UIManager.js b/src/renderers/native/__mocks__/UIManager.js
new file mode 100644
index 000000000000..dffb8fd9f639
--- /dev/null
+++ b/src/renderers/native/__mocks__/UIManager.js
@@ -0,0 +1,69 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+'use strict';
+
+// Mock of the Native Hooks
+
+var RCTUIManager = {
+  createView: jest.fn(),
+  setChildren: jest.fn(),
+  manageChildren: jest.fn(),
+  updateView: jest.fn(),
+  removeSubviewsFromContainerWithID: jest.fn(),
+  replaceExistingNonRootView: jest.fn(),
+  customBubblingEventTypes: {
+    topBlur: {
+      phasedRegistrationNames: {
+        bubbled: 'onBlur',
+        captured: 'onBlurCapture',
+      },
+    },
+    topFocus: {
+      phasedRegistrationNames: {
+        bubbled: 'onFocus',
+        captured: 'onFocusCapture',
+      },
+    },
+    topTouchCancel: {
+      phasedRegistrationNames: {
+        bubbled: 'onTouchCancel',
+        captured: 'onTouchCancelCapture',
+      },
+    },
+    topTouchEnd: {
+      phasedRegistrationNames: {
+        bubbled: 'onTouchEnd',
+        captured: 'onTouchEndCapture',
+      },
+    },
+    topTouchMove: {
+      phasedRegistrationNames: {
+        bubbled: 'onTouchMove',
+        captured: 'onTouchMoveCapture',
+      },
+    },
+    topTouchStart: {
+      phasedRegistrationNames: {
+        bubbled: 'onTouchStart',
+        captured: 'onTouchStartCapture',
+      },
+    },
+  },
+  customDirectEventTypes: {
+    topAccessibilityTap: {
+      registrationName: 'onAccessibilityTap',
+    },
+    topTextLayout: {
+      registrationName: 'onTextLayout',
+    },
+  },
+};
+
+module.exports = RCTUIManager;
diff --git a/src/renderers/native/__mocks__/deepDiffer.js b/src/renderers/native/__mocks__/deepDiffer.js
new file mode 100644
index 000000000000..313565af45db
--- /dev/null
+++ b/src/renderers/native/__mocks__/deepDiffer.js
@@ -0,0 +1,63 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+'use strict';
+
+// TODO: Move deepDiffer into react
+
+var deepDiffer = function(one: any, two: any): boolean {
+  if (one === two) {
+    // Short circuit on identical object references instead of traversing them.
+    return false;
+  }
+  if (typeof one === 'function' && typeof two === 'function') {
+    // We consider all functions equal
+    return false;
+  }
+  if (typeof one !== 'object' || one === null) {
+    // Primitives can be directly compared
+    return one !== two;
+  }
+  if (typeof two !== 'object' || two === null) {
+    // We know they are different because the previous case would have triggered
+    // otherwise.
+    return true;
+  }
+  if (one.constructor !== two.constructor) {
+    return true;
+  }
+  if (Array.isArray(one)) {
+    // We know two is also an array because the constructors are equal
+    var len = one.length;
+    if (two.length !== len) {
+      return true;
+    }
+    for (var ii = 0; ii < len; ii++) {
+      if (deepDiffer(one[ii], two[ii])) {
+        return true;
+      }
+    }
+  } else {
+    for (var key in one) {
+      if (deepDiffer(one[key], two[key])) {
+        return true;
+      }
+    }
+    for (var twoKey in two) {
+      // The only case we haven't checked yet is keys that are in two but aren't
+      // in one, which means they are different.
+      if (one[twoKey] === undefined && two[twoKey] !== undefined) {
+        return true;
+      }
+    }
+  }
+  return false;
+};
+
+module.exports = deepDiffer;
diff --git a/src/renderers/native/__mocks__/deepFreezeAndThrowOnMutationInDev.js b/src/renderers/native/__mocks__/deepFreezeAndThrowOnMutationInDev.js
new file mode 100644
index 000000000000..8d8ceb8593bd
--- /dev/null
+++ b/src/renderers/native/__mocks__/deepFreezeAndThrowOnMutationInDev.js
@@ -0,0 +1,16 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+'use strict';
+
+// TODO: move into react or fbjs
+
+var deepFreezeAndThrowOnMutationInDev = function() {};
+
+module.exports = deepFreezeAndThrowOnMutationInDev;
diff --git a/src/renderers/native/__mocks__/flattenStyle.js b/src/renderers/native/__mocks__/flattenStyle.js
new file mode 100644
index 000000000000..d9b46a98a2c4
--- /dev/null
+++ b/src/renderers/native/__mocks__/flattenStyle.js
@@ -0,0 +1,16 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+'use strict';
+
+// TODO: Move flattenStyle into react
+
+var flattenStyle = function() {};
+
+module.exports = flattenStyle;
diff --git a/src/renderers/native/__tests__/ReactNativeAttributePayload-test.js b/src/renderers/native/__tests__/ReactNativeAttributePayload-test.js
new file mode 100644
index 000000000000..77c8ae799ccd
--- /dev/null
+++ b/src/renderers/native/__tests__/ReactNativeAttributePayload-test.js
@@ -0,0 +1,236 @@
+/**
+ * Copyright (c) 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.
+ *
+ */
+'use strict';
+
+var ReactNativeAttributePayload = require('ReactNativeAttributePayload');
+var ReactNativePropRegistry = require('ReactNativePropRegistry');
+
+var diff = ReactNativeAttributePayload.diff;
+
+describe('ReactNativeAttributePayload', () => {
+  it('should work with simple example', () => {
+    expect(diff({a: 1, c: 3}, {b: 2, c: 3}, {a: true, b: true})).toEqual({
+      a: null,
+      b: 2,
+    });
+  });
+
+  it('should skip fields that are equal', () => {
+    expect(
+      diff(
+        {a: 1, b: 'two', c: true, d: false, e: undefined, f: 0},
+        {a: 1, b: 'two', c: true, d: false, e: undefined, f: 0},
+        {a: true, b: true, c: true, d: true, e: true, f: true},
+      ),
+    ).toEqual(null);
+  });
+
+  it('should remove fields', () => {
+    expect(diff({a: 1}, {}, {a: true})).toEqual({a: null});
+  });
+
+  it('should remove fields that are set to undefined', () => {
+    expect(diff({a: 1}, {a: undefined}, {a: true})).toEqual({a: null});
+  });
+
+  it('should ignore invalid fields', () => {
+    expect(diff({a: 1}, {b: 2}, {})).toEqual(null);
+  });
+
+  it('should use the diff attribute', () => {
+    var diffA = jest.fn((a, b) => true);
+    var diffB = jest.fn((a, b) => false);
+    expect(
+      diff(
+        {a: [1], b: [3]},
+        {a: [2], b: [4]},
+        {a: {diff: diffA}, b: {diff: diffB}},
+      ),
+    ).toEqual({a: [2]});
+    expect(diffA).toBeCalledWith([1], [2]);
+    expect(diffB).toBeCalledWith([3], [4]);
+  });
+
+  it('should not use the diff attribute on addition/removal', () => {
+    var diffA = jest.fn();
+    var diffB = jest.fn();
+    expect(
+      diff({a: [1]}, {b: [2]}, {a: {diff: diffA}, b: {diff: diffB}}),
+    ).toEqual({a: null, b: [2]});
+    expect(diffA).not.toBeCalled();
+    expect(diffB).not.toBeCalled();
+  });
+
+  it('should do deep diffs of Objects by default', () => {
+    expect(
+      diff(
+        {a: [1], b: {k: [3, 4]}, c: {k: [4, 4]}},
+        {a: [2], b: {k: [3, 4]}, c: {k: [4, 5]}},
+        {a: true, b: true, c: true},
+      ),
+    ).toEqual({a: [2], c: {k: [4, 5]}});
+  });
+
+  it('should work with undefined styles', () => {
+    expect(
+      diff(
+        {style: {a: '#ffffff', b: 1}},
+        {style: undefined},
+        {style: {b: true}},
+      ),
+    ).toEqual({b: null});
+    expect(
+      diff(
+        {style: undefined},
+        {style: {a: '#ffffff', b: 1}},
+        {style: {b: true}},
+      ),
+    ).toEqual({b: 1});
+    expect(
+      diff({style: undefined}, {style: undefined}, {style: {b: true}}),
+    ).toEqual(null);
+  });
+
+  it('should work with empty styles', () => {
+    expect(diff({a: 1, c: 3}, {}, {a: true, b: true})).toEqual({a: null});
+    expect(diff({}, {a: 1, c: 3}, {a: true, b: true})).toEqual({a: 1});
+    expect(diff({}, {}, {a: true, b: true})).toEqual(null);
+  });
+
+  it('should flatten nested styles and predefined styles', () => {
+    var validStyleAttribute = {someStyle: {foo: true, bar: true}};
+
+    expect(
+      diff({}, {someStyle: [{foo: 1}, {bar: 2}]}, validStyleAttribute),
+    ).toEqual({foo: 1, bar: 2});
+
+    expect(
+      diff({someStyle: [{foo: 1}, {bar: 2}]}, {}, validStyleAttribute),
+    ).toEqual({foo: null, bar: null});
+
+    var barStyle = ReactNativePropRegistry.register({
+      bar: 3,
+    });
+
+    expect(
+      diff(
+        {},
+        {someStyle: [[{foo: 1}, {foo: 2}], barStyle]},
+        validStyleAttribute,
+      ),
+    ).toEqual({foo: 2, bar: 3});
+  });
+
+  it('should reset a value to a previous if it is removed', () => {
+    var validStyleAttribute = {someStyle: {foo: true, bar: true}};
+
+    expect(
+      diff(
+        {someStyle: [{foo: 1}, {foo: 3}]},
+        {someStyle: [{foo: 1}, {bar: 2}]},
+        validStyleAttribute,
+      ),
+    ).toEqual({foo: 1, bar: 2});
+  });
+
+  it('should not clear removed props if they are still in another slot', () => {
+    var validStyleAttribute = {someStyle: {foo: true, bar: true}};
+
+    expect(
+      diff(
+        {someStyle: [{}, {foo: 3, bar: 2}]},
+        {someStyle: [{foo: 3}, {bar: 2}]},
+        validStyleAttribute,
+      ),
+    ).toEqual({foo: 3}); // this should ideally be null. heuristic tradeoff.
+
+    expect(
+      diff(
+        {someStyle: [{}, {foo: 3, bar: 2}]},
+        {someStyle: [{foo: 1, bar: 1}, {bar: 2}]},
+        validStyleAttribute,
+      ),
+    ).toEqual({bar: 2, foo: 1});
+  });
+
+  it('should clear a prop if a later style is explicit null/undefined', () => {
+    var validStyleAttribute = {someStyle: {foo: true, bar: true}};
+    expect(
+      diff(
+        {someStyle: [{}, {foo: 3, bar: 2}]},
+        {someStyle: [{foo: 1}, {bar: 2, foo: null}]},
+        validStyleAttribute,
+      ),
+    ).toEqual({foo: null});
+
+    expect(
+      diff(
+        {someStyle: [{foo: 3}, {foo: null, bar: 2}]},
+        {someStyle: [{foo: null}, {bar: 2}]},
+        validStyleAttribute,
+      ),
+    ).toEqual({foo: null});
+
+    expect(
+      diff(
+        {someStyle: [{foo: 1}, {foo: null}]},
+        {someStyle: [{foo: 2}, {foo: null}]},
+        validStyleAttribute,
+      ),
+    ).toEqual({foo: null}); // this should ideally be null. heuristic.
+
+    // Test the same case with object equality because an early bailout doesn't
+    // work in this case.
+    var fooObj = {foo: 3};
+    expect(
+      diff(
+        {someStyle: [{foo: 1}, fooObj]},
+        {someStyle: [{foo: 2}, fooObj]},
+        validStyleAttribute,
+      ),
+    ).toEqual({foo: 3}); // this should ideally be null. heuristic.
+
+    expect(
+      diff(
+        {someStyle: [{foo: 1}, {foo: 3}]},
+        {someStyle: [{foo: 2}, {foo: undefined}]},
+        validStyleAttribute,
+      ),
+    ).toEqual({foo: null}); // this should ideally be null. heuristic.
+  });
+
+  // Function properties are just markers to native that events should be sent.
+  it('should convert functions to booleans', () => {
+    // Note that if the property changes from one function to another, we don't
+    // need to send an update.
+    expect(
+      diff(
+        {
+          a: function() {
+            return 1;
+          },
+          b: function() {
+            return 2;
+          },
+          c: 3,
+        },
+        {
+          b: function() {
+            return 9;
+          },
+          c: function() {
+            return 3;
+          },
+        },
+        {a: true, b: true, c: true},
+      ),
+    ).toEqual({a: null, c: true});
+  });
+});
diff --git a/src/renderers/native/__tests__/ReactNativeEvents-test.js b/src/renderers/native/__tests__/ReactNativeEvents-test.js
new file mode 100644
index 000000000000..40543e92fe2d
--- /dev/null
+++ b/src/renderers/native/__tests__/ReactNativeEvents-test.js
@@ -0,0 +1,88 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var RCTEventEmitter;
+var React;
+var ReactErrorUtils;
+var ReactNative;
+var UIManager;
+var createReactNativeComponentClass;
+
+beforeEach(() => {
+  jest.resetModuleRegistry();
+
+  RCTEventEmitter = require('RCTEventEmitter');
+  React = require('React');
+  ReactErrorUtils = require('ReactErrorUtils');
+  ReactNative = require('ReactNative');
+  UIManager = require('UIManager');
+  createReactNativeComponentClass = require('createReactNativeComponentClass');
+
+  // Ensure errors from event callbacks are properly surfaced (otherwise,
+  // jest/jsdom swallows them when we do the .dispatchEvent call)
+  ReactErrorUtils.invokeGuardedCallback =
+    ReactErrorUtils.invokeGuardedCallbackWithCatch;
+});
+
+it('handles events', () => {
+  expect(RCTEventEmitter.register.mock.calls.length).toBe(1);
+  var EventEmitter = RCTEventEmitter.register.mock.calls[0][0];
+  var View = createReactNativeComponentClass({
+    validAttributes: {foo: true},
+    uiViewClassName: 'View',
+  });
+
+  var log = [];
+  ReactNative.render(
+    <View
+      foo="outer"
+      onTouchEnd={() => log.push('outer touchend')}
+      onTouchEndCapture={() => log.push('outer touchend capture')}
+      onTouchStart={() => log.push('outer touchstart')}
+      onTouchStartCapture={() => log.push('outer touchstart capture')}>
+      <View
+        foo="inner"
+        onTouchEndCapture={() => log.push('inner touchend capture')}
+        onTouchEnd={() => log.push('inner touchend')}
+        onTouchStartCapture={() => log.push('inner touchstart capture')}
+        onTouchStart={() => log.push('inner touchstart')}
+      />
+    </View>,
+    1,
+  );
+
+  expect(UIManager.createView.mock.calls.length).toBe(2);
+  var innerTag = UIManager.createView.mock.calls[1][0];
+
+  EventEmitter.receiveTouches(
+    'topTouchStart',
+    [{target: innerTag, identifier: 17}],
+    [0],
+  );
+  EventEmitter.receiveTouches(
+    'topTouchEnd',
+    [{target: innerTag, identifier: 17}],
+    [0],
+  );
+
+  expect(log).toEqual([
+    'outer touchstart capture',
+    'inner touchstart capture',
+    'inner touchstart',
+    'outer touchstart',
+    'outer touchend capture',
+    'inner touchend capture',
+    'inner touchend',
+    'outer touchend',
+  ]);
+});
diff --git a/src/renderers/native/__tests__/ReactNativeMount-test.js b/src/renderers/native/__tests__/ReactNativeMount-test.js
new file mode 100644
index 000000000000..bf479384ac70
--- /dev/null
+++ b/src/renderers/native/__tests__/ReactNativeMount-test.js
@@ -0,0 +1,60 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var React;
+var ReactNative;
+var createReactNativeComponentClass;
+var UIManager;
+
+describe('ReactNative', () => {
+  beforeEach(() => {
+    React = require('React');
+    ReactNative = require('ReactNative');
+    UIManager = require('UIManager');
+    createReactNativeComponentClass = require('createReactNativeComponentClass');
+  });
+
+  it('should be able to create and render a native component', () => {
+    var View = createReactNativeComponentClass({
+      validAttributes: {foo: true},
+      uiViewClassName: 'View',
+    });
+
+    ReactNative.render(<View foo="test" />, 1);
+    expect(UIManager.createView).toBeCalled();
+    expect(UIManager.setChildren).toBeCalled();
+    expect(UIManager.manageChildren).not.toBeCalled();
+    expect(UIManager.updateView).not.toBeCalled();
+  });
+
+  it('should be able to create and update a native component', () => {
+    var View = createReactNativeComponentClass({
+      validAttributes: {foo: true},
+      uiViewClassName: 'View',
+    });
+
+    ReactNative.render(<View foo="foo" />, 11);
+
+    expect(UIManager.createView.mock.calls.length).toBe(2);
+    expect(UIManager.setChildren.mock.calls.length).toBe(2);
+    expect(UIManager.manageChildren).not.toBeCalled();
+    expect(UIManager.updateView).not.toBeCalled();
+
+    ReactNative.render(<View foo="bar" />, 11);
+
+    expect(UIManager.createView.mock.calls.length).toBe(2);
+    expect(UIManager.setChildren.mock.calls.length).toBe(2);
+    expect(UIManager.manageChildren).not.toBeCalled();
+    expect(UIManager.updateView).toBeCalledWith(3, 'View', {foo: 'bar'});
+  });
+});
diff --git a/src/renderers/native/createReactNativeComponentClass.js b/src/renderers/native/createReactNativeComponentClass.js
new file mode 100644
index 000000000000..4d4e0d03f402
--- /dev/null
+++ b/src/renderers/native/createReactNativeComponentClass.js
@@ -0,0 +1,48 @@
+/**
+ * Copyright (c) 2015-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 createReactNativeComponentClass
+ * @flow
+ */
+
+'use strict';
+
+var ReactNativeBaseComponent = require('ReactNativeBaseComponent');
+
+// See also ReactNativeBaseComponent
+type ReactNativeBaseComponentViewConfig = {
+  validAttributes: Object,
+  uiViewClassName: string,
+  propTypes?: Object,
+};
+
+/**
+ * @param {string} config iOS View configuration.
+ * @private
+ */
+var createReactNativeComponentClass = function(
+  viewConfig: ReactNativeBaseComponentViewConfig,
+): ReactClass<any> {
+  var Constructor = function(element) {
+    this._currentElement = element;
+    this._topLevelWrapper = null;
+    this._hostParent = null;
+    this._hostContainerInfo = null;
+    this._rootNodeID = 0;
+    this._renderedChildren = null;
+  };
+  Constructor.displayName = viewConfig.uiViewClassName;
+  Constructor.viewConfig = viewConfig;
+  Constructor.propTypes = viewConfig.propTypes;
+  Constructor.prototype = new ReactNativeBaseComponent(viewConfig);
+  Constructor.prototype.constructor = Constructor;
+
+  return ((Constructor: any): ReactClass<any>);
+};
+
+module.exports = createReactNativeComponentClass;
diff --git a/src/renderers/native/findNodeHandle.js b/src/renderers/native/findNodeHandle.js
new file mode 100644
index 000000000000..3226c2e93086
--- /dev/null
+++ b/src/renderers/native/findNodeHandle.js
@@ -0,0 +1,106 @@
+/**
+ * Copyright (c) 2015-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 findNodeHandle
+ * @flow
+ */
+
+'use strict';
+
+var ReactCurrentOwner = require('ReactCurrentOwner');
+var ReactInstanceMap = require('ReactInstanceMap');
+
+var invariant = require('invariant');
+var warning = require('warning');
+
+/**
+ * ReactNative vs ReactWeb
+ * -----------------------
+ * React treats some pieces of data opaquely. This means that the information
+ * is first class (it can be passed around), but cannot be inspected. This
+ * allows us to build infrastructure that reasons about resources, without
+ * making assumptions about the nature of those resources, and this allows that
+ * infra to be shared across multiple platforms, where the resources are very
+ * different. General infra (such as `ReactMultiChild`) reasons opaquely about
+ * the data, but platform specific code (such as `ReactNativeBaseComponent`) can
+ * make assumptions about the data.
+ *
+ *
+ * `rootNodeID`, uniquely identifies a position in the generated native view
+ * tree. Many layers of composite components (created with `React.createClass`)
+ * can all share the same `rootNodeID`.
+ *
+ * `nodeHandle`: A sufficiently unambiguous way to refer to a lower level
+ * resource (dom node, native view etc). The `rootNodeID` is sufficient for web
+ * `nodeHandle`s, because the position in a tree is always enough to uniquely
+ * identify a DOM node (we never have nodes in some bank outside of the
+ * document). The same would be true for `ReactNative`, but we must maintain a
+ * mapping that we can send efficiently serializable
+ * strings across native boundaries.
+ *
+ * Opaque name      TodaysWebReact   FutureWebWorkerReact   ReactNative
+ * ----------------------------------------------------------------------------
+ * nodeHandle       N/A              rootNodeID             tag
+ */
+
+function findNodeHandle(componentOrHandle: any): ?number {
+  if (__DEV__) {
+    var owner = ReactCurrentOwner.current;
+    if (owner !== null) {
+      warning(
+        owner._warnedAboutRefsInRender,
+        '%s is accessing findNodeHandle 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',
+      );
+      owner._warnedAboutRefsInRender = true;
+    }
+  }
+  if (componentOrHandle == null) {
+    return null;
+  }
+  if (typeof componentOrHandle === 'number') {
+    // Already a node handle
+    return componentOrHandle;
+  }
+
+  var component = componentOrHandle;
+
+  // TODO (balpert): Wrap iOS native components in a composite wrapper, then
+  // ReactInstanceMap.get here will always succeed for mounted components
+  var internalInstance = ReactInstanceMap.get(component);
+  if (internalInstance) {
+    return internalInstance.getHostNode();
+  } else {
+    var rootNodeID = component._rootNodeID;
+    if (rootNodeID) {
+      return rootNodeID;
+    } else {
+      invariant(
+        // Native
+        (typeof component === 'object' && '_rootNodeID' in component) ||
+          // Composite
+          (component.render != null && typeof component.render === 'function'),
+        'findNodeHandle(...): Argument is not a component ' +
+          '(type: %s, keys: %s)',
+        typeof component,
+        Object.keys(component),
+      );
+      invariant(
+        false,
+        'findNodeHandle(...): Unable to find node handle for unmounted ' +
+          'component.',
+      );
+    }
+  }
+}
+
+module.exports = findNodeHandle;
diff --git a/src/renderers/noop/ReactNoop.js b/src/renderers/noop/ReactNoop.js
new file mode 100644
index 000000000000..3f420e9f0b30
--- /dev/null
+++ b/src/renderers/noop/ReactNoop.js
@@ -0,0 +1,261 @@
+/**
+ * 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 ReactNoop
+ * @flow
+ */
+
+/**
+ * This is a renderer of React that doesn't have a render target output.
+ * It is useful to demonstrate the internals of the reconciler in isolation
+ * and for testing semantics of reconciliation separate from the host
+ * environment.
+ */
+
+'use strict';
+
+import type {Fiber} from 'ReactFiber';
+import type {UpdateQueue} from 'ReactFiberUpdateQueue';
+import type {HostChildren} from 'ReactFiberReconciler';
+
+var ReactFiberReconciler = require('ReactFiberReconciler');
+var {AnimationPriority} = require('ReactPriorityLevel');
+
+var scheduledAnimationCallback = null;
+var scheduledDeferredCallback = null;
+
+const TERMINAL_TAG = 99;
+
+type Container = {rootID: number, children: Array<Instance>};
+type Props = {prop: any};
+type Instance = {
+  tag: 99,
+  type: string,
+  id: number,
+  children: Array<Instance>,
+  prop: any,
+};
+
+var instanceCounter = 0;
+
+function recursivelyAppendChildren(
+  flatArray: Array<Instance>,
+  child: HostChildren<Instance>,
+) {
+  if (!child) {
+    return;
+  }
+  if (child.tag === TERMINAL_TAG) {
+    flatArray.push(child);
+  } else {
+    let node = child;
+    do {
+      recursivelyAppendChildren(flatArray, node.output);
+    } while ((node = node.sibling));
+  }
+}
+
+function flattenChildren(children: HostChildren<Instance>) {
+  const flatArray = [];
+  recursivelyAppendChildren(flatArray, children);
+  return flatArray;
+}
+
+var NoopRenderer = ReactFiberReconciler({
+  updateContainer(
+    containerInfo: Container,
+    children: HostChildren<Instance>,
+  ): void {
+    containerInfo.children = flattenChildren(children);
+  },
+
+  createInstance(
+    type: string,
+    props: Props,
+    children: HostChildren<Instance>,
+  ): Instance {
+    const inst = {
+      tag: TERMINAL_TAG,
+      id: instanceCounter++,
+      type: type,
+      children: flattenChildren(children),
+      prop: props.prop,
+    };
+    // Hide from unit tests
+    Object.defineProperty(inst, 'tag', {value: inst.tag, enumerable: false});
+    Object.defineProperty(inst, 'id', {value: inst.id, enumerable: false});
+    return inst;
+  },
+
+  prepareUpdate(
+    instance: Instance,
+    oldProps: Props,
+    newProps: Props,
+    children: HostChildren<Instance>,
+  ): boolean {
+    return true;
+  },
+
+  commitUpdate(
+    instance: Instance,
+    oldProps: Props,
+    newProps: Props,
+    children: HostChildren<Instance>,
+  ): void {
+    instance.children = flattenChildren(children);
+    instance.prop = newProps.prop;
+  },
+
+  deleteInstance(instance: Instance): void {},
+
+  scheduleAnimationCallback(callback) {
+    scheduledAnimationCallback = callback;
+  },
+
+  scheduleDeferredCallback(callback) {
+    scheduledDeferredCallback = callback;
+  },
+});
+
+var rootContainer = {rootID: 0, children: []};
+
+var root = null;
+
+var ReactNoop = {
+  root: rootContainer,
+
+  render(element: ReactElement<any>) {
+    if (!root) {
+      root = NoopRenderer.mountContainer(element, rootContainer);
+    } else {
+      NoopRenderer.updateContainer(element, root);
+    }
+  },
+
+  flushAnimationPri() {
+    var cb = scheduledAnimationCallback;
+    if (cb === null) {
+      return;
+    }
+    scheduledAnimationCallback = null;
+    cb();
+  },
+
+  flushDeferredPri(timeout: number = Infinity) {
+    var cb = scheduledDeferredCallback;
+    if (cb === null) {
+      return;
+    }
+    scheduledDeferredCallback = null;
+    var timeRemaining = timeout;
+    cb({
+      timeRemaining() {
+        // Simulate a fix amount of time progressing between each call.
+        timeRemaining -= 5;
+        if (timeRemaining < 0) {
+          timeRemaining = 0;
+        }
+        return timeRemaining;
+      },
+    });
+  },
+
+  flush() {
+    ReactNoop.flushAnimationPri();
+    ReactNoop.flushDeferredPri();
+  },
+
+  performAnimationWork(fn: Function) {
+    NoopRenderer.performWithPriority(AnimationPriority, fn);
+  },
+
+  // Logs the current state of the tree.
+  dumpTree() {
+    if (!root) {
+      console.log('Nothing rendered yet.');
+      return;
+    }
+
+    var bufferedLog = [];
+    function log(...args) {
+      bufferedLog.push(...args, '\n');
+    }
+
+    function logHostInstances(children: Array<Instance>, depth) {
+      for (var i = 0; i < children.length; i++) {
+        var child = children[i];
+        log('  '.repeat(depth) + '- ' + child.type + '#' + child.id);
+        logHostInstances(child.children, depth + 1);
+      }
+    }
+    function logContainer(container: Container, depth) {
+      log('  '.repeat(depth) + '- [root#' + container.rootID + ']');
+      logHostInstances(container.children, depth + 1);
+    }
+
+    function logUpdateQueue(updateQueue: UpdateQueue, depth) {
+      log(
+        '  '.repeat(depth + 1) + 'QUEUED UPDATES',
+        updateQueue.isReplace ? 'is replace' : '',
+        updateQueue.isForced ? 'is forced' : '',
+      );
+      log(
+        '  '.repeat(depth + 1) + '~',
+        updateQueue.partialState,
+        updateQueue.callback ? 'with callback' : '',
+      );
+      var next;
+      while ((next = updateQueue.next)) {
+        log(
+          '  '.repeat(depth + 1) + '~',
+          next.partialState,
+          next.callback ? 'with callback' : '',
+        );
+      }
+    }
+
+    function logFiber(fiber: Fiber, depth) {
+      log(
+        '  '.repeat(depth) +
+          '- ' +
+          (fiber.type ? fiber.type.name || fiber.type : '[root]'),
+        '[' + fiber.pendingWorkPriority + (fiber.pendingProps ? '*' : '') + ']',
+      );
+      if (fiber.updateQueue) {
+        logUpdateQueue(fiber.updateQueue, depth);
+      }
+      const childInProgress = fiber.progressedChild;
+      if (childInProgress && childInProgress !== fiber.child) {
+        log(
+          '  '.repeat(depth + 1) + 'IN PROGRESS: ' + fiber.progressedPriority,
+        );
+        logFiber(childInProgress, depth + 1);
+        if (fiber.child) {
+          log('  '.repeat(depth + 1) + 'CURRENT');
+        }
+      } else if (fiber.child && fiber.updateQueue) {
+        log('  '.repeat(depth + 1) + 'CHILDREN');
+      }
+      if (fiber.child) {
+        logFiber(fiber.child, depth + 1);
+      }
+      if (fiber.sibling) {
+        logFiber(fiber.sibling, depth);
+      }
+    }
+
+    log('HOST INSTANCES:');
+    logContainer(rootContainer, 0);
+    log('FIBERS:');
+    logFiber((root.stateNode: any).current, 0);
+
+    console.log(...bufferedLog);
+  },
+};
+
+module.exports = ReactNoop;
diff --git a/src/renderers/shared/ReactDebugTool.js b/src/renderers/shared/ReactDebugTool.js
new file mode 100644
index 000000000000..a83432a1ac63
--- /dev/null
+++ b/src/renderers/shared/ReactDebugTool.js
@@ -0,0 +1,438 @@
+/**
+ * Copyright 2016-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 ReactDebugTool
+ * @flow
+ */
+
+'use strict';
+
+var ReactInvalidSetStateWarningHook = require('ReactInvalidSetStateWarningHook');
+var ReactHostOperationHistoryHook = require('ReactHostOperationHistoryHook');
+var ReactComponentTreeHook = require('ReactComponentTreeHook');
+var ExecutionEnvironment = require('ExecutionEnvironment');
+
+var performanceNow = require('performanceNow');
+var warning = require('warning');
+
+import type {ReactElement} from 'ReactElementType';
+import type {DebugID} from 'ReactInstanceType';
+import type {Operation} from 'ReactHostOperationHistoryHook';
+
+type Hook = any;
+
+type TimerType =
+  | 'ctor'
+  | 'render'
+  | 'componentWillMount'
+  | 'componentWillUnmount'
+  | 'componentWillReceiveProps'
+  | 'shouldComponentUpdate'
+  | 'componentWillUpdate'
+  | 'componentDidUpdate'
+  | 'componentDidMount';
+
+type Measurement = {
+  timerType: TimerType,
+  instanceID: DebugID,
+  duration: number,
+};
+
+type TreeSnapshot = {
+  [key: DebugID]: {
+    displayName: string,
+    text: string,
+    updateCount: number,
+    childIDs: Array<DebugID>,
+    ownerID: DebugID,
+    parentID: DebugID,
+  },
+};
+
+type HistoryItem = {
+  duration: number,
+  measurements: Array<Measurement>,
+  operations: Array<Operation>,
+  treeSnapshot: TreeSnapshot,
+};
+
+export type FlushHistory = Array<HistoryItem>;
+
+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) {
+    warning(
+      didHookThrowForEvent[event],
+      'Exception thrown by hook while handling %s: %s',
+      event,
+      e + '\n' + e.stack,
+    );
+    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((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,
+    };
+    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, allowRoot = false) {
+  if (allowRoot && debugID === 0) {
+    return;
+  }
+  if (!debugID) {
+    warning(false, 'ReactDebugTool: debugID may not be empty.');
+  }
+}
+
+function beginLifeCycleTimer(debugID, timerType) {
+  if (currentFlushNesting === 0) {
+    return;
+  }
+  if (currentTimerType && !lifeCycleTimerHasWarned) {
+    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',
+    );
+    lifeCycleTimerHasWarned = true;
+  }
+  currentTimerStartTime = performanceNow();
+  currentTimerNestedFlushDuration = 0;
+  currentTimerDebugID = debugID;
+  currentTimerType = timerType;
+}
+
+function endLifeCycleTimer(debugID, timerType) {
+  if (currentFlushNesting === 0) {
+    return;
+  }
+  if (currentTimerType !== timerType && !lifeCycleTimerHasWarned) {
+    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',
+    );
+    lifeCycleTimerHasWarned = true;
+  }
+  if (isProfiling) {
+    currentFlushMeasurements.push({
+      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 {
+    startTime,
+    nestedFlushStartTime,
+    debugID,
+    timerType,
+  } = lifeCycleTimerStack.pop();
+  var nestedFlushDuration = performanceNow() - nestedFlushStartTime;
+  currentTimerStartTime = startTime;
+  currentTimerNestedFlushDuration += nestedFlushDuration;
+  currentTimerDebugID = debugID;
+  currentTimerType = timerType;
+}
+
+var lastMarkTimeStamp = 0;
+var canUsePerformanceMeasure: boolean =
+  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(hook: Hook): void {
+    hooks.push(hook);
+  },
+  removeHook(hook: Hook): void {
+    for (var i = 0; i < hooks.length; i++) {
+      if (hooks[i] === hook) {
+        hooks.splice(i, 1);
+        i--;
+      }
+    }
+  },
+  isProfiling(): boolean {
+    return isProfiling;
+  },
+  beginProfiling(): void {
+    if (isProfiling) {
+      return;
+    }
+
+    isProfiling = true;
+    flushHistory.length = 0;
+    resetMeasurements();
+    ReactDebugTool.addHook(ReactHostOperationHistoryHook);
+  },
+  endProfiling(): void {
+    if (!isProfiling) {
+      return;
+    }
+
+    isProfiling = false;
+    resetMeasurements();
+    ReactDebugTool.removeHook(ReactHostOperationHistoryHook);
+  },
+  getFlushHistory(): FlushHistory {
+    return flushHistory;
+  },
+  onBeginFlush(): void {
+    currentFlushNesting++;
+    resetMeasurements();
+    pauseCurrentLifeCycleTimer();
+    emitEvent('onBeginFlush');
+  },
+  onEndFlush(): void {
+    resetMeasurements();
+    currentFlushNesting--;
+    resumeCurrentLifeCycleTimer();
+    emitEvent('onEndFlush');
+  },
+  onBeginLifeCycleTimer(debugID: DebugID, timerType: TimerType): void {
+    checkDebugID(debugID);
+    emitEvent('onBeginLifeCycleTimer', debugID, timerType);
+    markBegin(debugID, timerType);
+    beginLifeCycleTimer(debugID, timerType);
+  },
+  onEndLifeCycleTimer(debugID: DebugID, timerType: TimerType): void {
+    checkDebugID(debugID);
+    endLifeCycleTimer(debugID, timerType);
+    markEnd(debugID, timerType);
+    emitEvent('onEndLifeCycleTimer', debugID, timerType);
+  },
+  onBeginProcessingChildContext(): void {
+    emitEvent('onBeginProcessingChildContext');
+  },
+  onEndProcessingChildContext(): void {
+    emitEvent('onEndProcessingChildContext');
+  },
+  onHostOperation(operation: Operation) {
+    checkDebugID(operation.instanceID);
+    emitEvent('onHostOperation', operation);
+  },
+  onSetState(): void {
+    emitEvent('onSetState');
+  },
+  onSetChildren(debugID: DebugID, childDebugIDs: Array<DebugID>) {
+    checkDebugID(debugID);
+    childDebugIDs.forEach(checkDebugID);
+    emitEvent('onSetChildren', debugID, childDebugIDs);
+  },
+  onBeforeMountComponent(
+    debugID: DebugID,
+    element: ReactElement,
+    parentDebugID: DebugID,
+  ): void {
+    checkDebugID(debugID);
+    checkDebugID(parentDebugID, true);
+    emitEvent('onBeforeMountComponent', debugID, element, parentDebugID);
+    markBegin(debugID, 'mount');
+  },
+  onMountComponent(debugID: DebugID): void {
+    checkDebugID(debugID);
+    markEnd(debugID, 'mount');
+    emitEvent('onMountComponent', debugID);
+  },
+  onBeforeUpdateComponent(debugID: DebugID, element: ReactElement): void {
+    checkDebugID(debugID);
+    emitEvent('onBeforeUpdateComponent', debugID, element);
+    markBegin(debugID, 'update');
+  },
+  onUpdateComponent(debugID: DebugID): void {
+    checkDebugID(debugID);
+    markEnd(debugID, 'update');
+    emitEvent('onUpdateComponent', debugID);
+  },
+  onBeforeUnmountComponent(debugID: DebugID): void {
+    checkDebugID(debugID);
+    emitEvent('onBeforeUnmountComponent', debugID);
+    markBegin(debugID, 'unmount');
+  },
+  onUnmountComponent(debugID: DebugID): void {
+    checkDebugID(debugID);
+    markEnd(debugID, 'unmount');
+    emitEvent('onUnmountComponent', debugID);
+  },
+  onTestEvent(): void {
+    emitEvent('onTestEvent');
+  },
+};
+
+// TODO remove these when RN/www gets updated
+(ReactDebugTool: any).addDevtool = ReactDebugTool.addHook;
+(ReactDebugTool: any).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;
diff --git a/src/renderers/shared/ReactInstrumentation.js b/src/renderers/shared/ReactInstrumentation.js
new file mode 100644
index 000000000000..a5de36d00ef6
--- /dev/null
+++ b/src/renderers/shared/ReactInstrumentation.js
@@ -0,0 +1,23 @@
+/**
+ * Copyright 2016-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 ReactInstrumentation
+ * @flow
+ */
+
+'use strict';
+
+// Trust the developer to only use ReactInstrumentation with a __DEV__ check
+var debugTool = ((null: any): typeof ReactDebugTool);
+
+if (__DEV__) {
+  var ReactDebugTool = require('ReactDebugTool');
+  debugTool = ReactDebugTool;
+}
+
+module.exports = {debugTool};
diff --git a/src/renderers/shared/ReactPerf.js b/src/renderers/shared/ReactPerf.js
new file mode 100644
index 000000000000..17abb58095e7
--- /dev/null
+++ b/src/renderers/shared/ReactPerf.js
@@ -0,0 +1,458 @@
+/**
+ * Copyright 2016-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 ReactPerf
+ * @flow
+ */
+
+'use strict';
+
+var ReactDebugTool = require('ReactDebugTool');
+var lowPriorityWarning = require('lowPriorityWarning');
+var alreadyWarned = false;
+
+import type {FlushHistory} from 'ReactDebugTool';
+
+function roundFloat(val, base = 2) {
+  var n = Math.pow(10, base);
+  return Math.floor(val * n) / n;
+}
+
+// Flow type definition of console.table is too strict right now, see
+// https://github.com/facebook/flow/pull/2353 for updates
+function consoleTable(table: Array<{[key: string]: any}>): void {
+  console.table((table: any));
+}
+
+function warnInProduction() {
+  if (alreadyWarned) {
+    return;
+  }
+  alreadyWarned = true;
+  if (typeof console !== 'undefined') {
+    console.error(
+      'ReactPerf is not supported in the production builds of React. ' +
+        'To collect measurements, please use the development build of React instead.',
+    );
+  }
+}
+
+function getLastMeasurements() {
+  if (!__DEV__) {
+    warnInProduction();
+    return [];
+  }
+
+  return ReactDebugTool.getFlushHistory();
+}
+
+function getExclusive(flushHistory = getLastMeasurements()) {
+  if (!__DEV__) {
+    warnInProduction();
+    return [];
+  }
+
+  var aggregatedStats = {};
+  var affectedIDs = {};
+
+  function updateAggregatedStats(
+    treeSnapshot,
+    instanceID,
+    timerType,
+    applyUpdate,
+  ) {
+    var {displayName} = treeSnapshot[instanceID];
+    var key = displayName;
+    var stats = aggregatedStats[key];
+    if (!stats) {
+      affectedIDs[key] = {};
+      stats = aggregatedStats[key] = {
+        key,
+        instanceCount: 0,
+        counts: {},
+        durations: {},
+        totalDuration: 0,
+      };
+    }
+    if (!stats.durations[timerType]) {
+      stats.durations[timerType] = 0;
+    }
+    if (!stats.counts[timerType]) {
+      stats.counts[timerType] = 0;
+    }
+    affectedIDs[key][instanceID] = true;
+    applyUpdate(stats);
+  }
+
+  flushHistory.forEach(flush => {
+    var {measurements, treeSnapshot} = flush;
+    measurements.forEach(measurement => {
+      var {duration, instanceID, timerType} = measurement;
+      updateAggregatedStats(treeSnapshot, instanceID, timerType, stats => {
+        stats.totalDuration += duration;
+        stats.durations[timerType] += duration;
+        stats.counts[timerType]++;
+      });
+    });
+  });
+
+  return Object.keys(aggregatedStats)
+    .map(key => ({
+      ...aggregatedStats[key],
+      instanceCount: Object.keys(affectedIDs[key]).length,
+    }))
+    .sort((a, b) => b.totalDuration - a.totalDuration);
+}
+
+function getInclusive(flushHistory = getLastMeasurements()) {
+  if (!__DEV__) {
+    warnInProduction();
+    return [];
+  }
+
+  var aggregatedStats = {};
+  var affectedIDs = {};
+
+  function updateAggregatedStats(treeSnapshot, instanceID, applyUpdate) {
+    var {displayName, ownerID} = treeSnapshot[instanceID];
+    var owner = treeSnapshot[ownerID];
+    var key = (owner ? owner.displayName + ' > ' : '') + displayName;
+    var stats = aggregatedStats[key];
+    if (!stats) {
+      affectedIDs[key] = {};
+      stats = aggregatedStats[key] = {
+        key,
+        instanceCount: 0,
+        inclusiveRenderDuration: 0,
+        renderCount: 0,
+      };
+    }
+    affectedIDs[key][instanceID] = true;
+    applyUpdate(stats);
+  }
+
+  var isCompositeByID = {};
+  flushHistory.forEach(flush => {
+    var {measurements} = flush;
+    measurements.forEach(measurement => {
+      var {instanceID, timerType} = measurement;
+      if (timerType !== 'render') {
+        return;
+      }
+      isCompositeByID[instanceID] = true;
+    });
+  });
+
+  flushHistory.forEach(flush => {
+    var {measurements, treeSnapshot} = flush;
+    measurements.forEach(measurement => {
+      var {duration, instanceID, timerType} = measurement;
+      if (timerType !== 'render') {
+        return;
+      }
+      updateAggregatedStats(treeSnapshot, instanceID, stats => {
+        stats.renderCount++;
+      });
+      var nextParentID = instanceID;
+      while (nextParentID) {
+        // As we traverse parents, only count inclusive time towards composites.
+        // We know something is a composite if its render() was called.
+        if (isCompositeByID[nextParentID]) {
+          updateAggregatedStats(treeSnapshot, nextParentID, stats => {
+            stats.inclusiveRenderDuration += duration;
+          });
+        }
+        nextParentID = treeSnapshot[nextParentID].parentID;
+      }
+    });
+  });
+
+  return Object.keys(aggregatedStats)
+    .map(key => ({
+      ...aggregatedStats[key],
+      instanceCount: Object.keys(affectedIDs[key]).length,
+    }))
+    .sort((a, b) => b.inclusiveRenderDuration - a.inclusiveRenderDuration);
+}
+
+function getWasted(flushHistory = getLastMeasurements()) {
+  if (!__DEV__) {
+    warnInProduction();
+    return [];
+  }
+
+  var aggregatedStats = {};
+  var affectedIDs = {};
+
+  function updateAggregatedStats(treeSnapshot, instanceID, applyUpdate) {
+    var {displayName, ownerID} = treeSnapshot[instanceID];
+    var owner = treeSnapshot[ownerID];
+    var key = (owner ? owner.displayName + ' > ' : '') + displayName;
+    var stats = aggregatedStats[key];
+    if (!stats) {
+      affectedIDs[key] = {};
+      stats = aggregatedStats[key] = {
+        key,
+        instanceCount: 0,
+        inclusiveRenderDuration: 0,
+        renderCount: 0,
+      };
+    }
+    affectedIDs[key][instanceID] = true;
+    applyUpdate(stats);
+  }
+
+  flushHistory.forEach(flush => {
+    var {measurements, treeSnapshot, operations} = flush;
+    var isDefinitelyNotWastedByID = {};
+
+    // Find host components associated with an operation in this batch.
+    // Mark all components in their parent tree as definitely not wasted.
+    operations.forEach(operation => {
+      var {instanceID} = operation;
+      var nextParentID = instanceID;
+      while (nextParentID) {
+        isDefinitelyNotWastedByID[nextParentID] = true;
+        nextParentID = treeSnapshot[nextParentID].parentID;
+      }
+    });
+
+    // Find composite components that rendered in this batch.
+    // These are potential candidates for being wasted renders.
+    var renderedCompositeIDs = {};
+    measurements.forEach(measurement => {
+      var {instanceID, timerType} = measurement;
+      if (timerType !== 'render') {
+        return;
+      }
+      renderedCompositeIDs[instanceID] = true;
+    });
+
+    measurements.forEach(measurement => {
+      var {duration, instanceID, timerType} = measurement;
+      if (timerType !== 'render') {
+        return;
+      }
+
+      // If there was a DOM update below this component, or it has just been
+      // mounted, its render() is not considered wasted.
+      var {updateCount} = treeSnapshot[instanceID];
+      if (isDefinitelyNotWastedByID[instanceID] || updateCount === 0) {
+        return;
+      }
+
+      // We consider this render() wasted.
+      updateAggregatedStats(treeSnapshot, instanceID, stats => {
+        stats.renderCount++;
+      });
+
+      var nextParentID = instanceID;
+      while (nextParentID) {
+        // Any parents rendered during this batch are considered wasted
+        // unless we previously marked them as dirty.
+        var isWasted =
+          renderedCompositeIDs[nextParentID] &&
+          !isDefinitelyNotWastedByID[nextParentID];
+        if (isWasted) {
+          updateAggregatedStats(treeSnapshot, nextParentID, stats => {
+            stats.inclusiveRenderDuration += duration;
+          });
+        }
+        nextParentID = treeSnapshot[nextParentID].parentID;
+      }
+    });
+  });
+
+  return Object.keys(aggregatedStats)
+    .map(key => ({
+      ...aggregatedStats[key],
+      instanceCount: Object.keys(affectedIDs[key]).length,
+    }))
+    .sort((a, b) => b.inclusiveRenderDuration - a.inclusiveRenderDuration);
+}
+
+function getOperations(flushHistory = getLastMeasurements()) {
+  if (!__DEV__) {
+    warnInProduction();
+    return [];
+  }
+
+  var stats = [];
+  flushHistory.forEach((flush, flushIndex) => {
+    var {operations, treeSnapshot} = flush;
+    operations.forEach(operation => {
+      var {instanceID, type, payload} = operation;
+      var {displayName, ownerID} = treeSnapshot[instanceID];
+      var owner = treeSnapshot[ownerID];
+      var key = (owner ? owner.displayName + ' > ' : '') + displayName;
+
+      stats.push({
+        flushIndex,
+        instanceID,
+        key,
+        type,
+        ownerID,
+        payload,
+      });
+    });
+  });
+  return stats;
+}
+
+function printExclusive(flushHistory?: FlushHistory) {
+  if (!__DEV__) {
+    warnInProduction();
+    return;
+  }
+
+  var stats = getExclusive(flushHistory);
+  var table = stats.map(item => {
+    var {key, instanceCount, totalDuration} = item;
+    var renderCount = item.counts.render || 0;
+    var renderDuration = item.durations.render || 0;
+    return {
+      Component: key,
+      'Total time (ms)': roundFloat(totalDuration),
+      'Instance count': instanceCount,
+      'Total render time (ms)': roundFloat(renderDuration),
+      'Average render time (ms)': renderCount
+        ? roundFloat(renderDuration / renderCount)
+        : undefined,
+      'Render count': renderCount,
+      'Total lifecycle time (ms)': roundFloat(totalDuration - renderDuration),
+    };
+  });
+  consoleTable(table);
+}
+
+function printInclusive(flushHistory?: FlushHistory) {
+  if (!__DEV__) {
+    warnInProduction();
+    return;
+  }
+
+  var stats = getInclusive(flushHistory);
+  var table = stats.map(item => {
+    var {key, instanceCount, inclusiveRenderDuration, renderCount} = item;
+    return {
+      'Owner > Component': key,
+      'Inclusive render time (ms)': roundFloat(inclusiveRenderDuration),
+      'Instance count': instanceCount,
+      'Render count': renderCount,
+    };
+  });
+  consoleTable(table);
+}
+
+function printWasted(flushHistory?: FlushHistory) {
+  if (!__DEV__) {
+    warnInProduction();
+    return;
+  }
+
+  var stats = getWasted(flushHistory);
+  var table = stats.map(item => {
+    var {key, instanceCount, inclusiveRenderDuration, renderCount} = item;
+    return {
+      'Owner > Component': key,
+      'Inclusive wasted time (ms)': roundFloat(inclusiveRenderDuration),
+      'Instance count': instanceCount,
+      'Render count': renderCount,
+    };
+  });
+  consoleTable(table);
+}
+
+function printOperations(flushHistory?: FlushHistory) {
+  if (!__DEV__) {
+    warnInProduction();
+    return;
+  }
+
+  var stats = getOperations(flushHistory);
+  var table = stats.map(stat => ({
+    'Owner > Node': stat.key,
+    Operation: stat.type,
+    Payload: typeof stat.payload === 'object'
+      ? JSON.stringify(stat.payload)
+      : stat.payload,
+    'Flush index': stat.flushIndex,
+    'Owner Component ID': stat.ownerID,
+    'DOM Component ID': stat.instanceID,
+  }));
+  consoleTable(table);
+}
+
+var warnedAboutPrintDOM = false;
+function printDOM(measurements: FlushHistory) {
+  lowPriorityWarning(
+    warnedAboutPrintDOM,
+    '`ReactPerf.printDOM(...)` is deprecated. Use ' +
+      '`ReactPerf.printOperations(...)` instead.',
+  );
+  warnedAboutPrintDOM = true;
+  return printOperations(measurements);
+}
+
+var warnedAboutGetMeasurementsSummaryMap = false;
+function getMeasurementsSummaryMap(measurements: FlushHistory) {
+  lowPriorityWarning(
+    warnedAboutGetMeasurementsSummaryMap,
+    '`ReactPerf.getMeasurementsSummaryMap(...)` is deprecated. Use ' +
+      '`ReactPerf.getWasted(...)` instead.',
+  );
+  warnedAboutGetMeasurementsSummaryMap = true;
+  return getWasted(measurements);
+}
+
+function start() {
+  if (!__DEV__) {
+    warnInProduction();
+    return;
+  }
+
+  ReactDebugTool.beginProfiling();
+}
+
+function stop() {
+  if (!__DEV__) {
+    warnInProduction();
+    return;
+  }
+
+  ReactDebugTool.endProfiling();
+}
+
+function isRunning() {
+  if (!__DEV__) {
+    warnInProduction();
+    return false;
+  }
+
+  return ReactDebugTool.isProfiling();
+}
+
+var ReactPerfAnalysis = {
+  getLastMeasurements,
+  getExclusive,
+  getInclusive,
+  getWasted,
+  getOperations,
+  printExclusive,
+  printInclusive,
+  printWasted,
+  printOperations,
+  start,
+  stop,
+  isRunning,
+  // Deprecated:
+  printDOM,
+  getMeasurementsSummaryMap,
+};
+
+module.exports = ReactPerfAnalysis;
diff --git a/src/renderers/shared/__tests__/ReactDebugTool-test.js b/src/renderers/shared/__tests__/ReactDebugTool-test.js
new file mode 100644
index 000000000000..ab702ce347f0
--- /dev/null
+++ b/src/renderers/shared/__tests__/ReactDebugTool-test.js
@@ -0,0 +1,84 @@
+/**
+ * Copyright 2016-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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+describe('ReactDebugTool', () => {
+  var ReactDebugTool;
+
+  beforeEach(() => {
+    jest.resetModuleRegistry();
+    ReactDebugTool = require('ReactDebugTool');
+  });
+
+  it('should add and remove hooks', () => {
+    var handler1 = jasmine.createSpy('spy');
+    var handler2 = jasmine.createSpy('spy');
+    var hook1 = {onTestEvent: handler1};
+    var hook2 = {onTestEvent: handler2};
+
+    ReactDebugTool.addHook(hook1);
+    ReactDebugTool.onTestEvent();
+    expect(handler1.calls.count()).toBe(1);
+    expect(handler2.calls.count()).toBe(0);
+
+    ReactDebugTool.onTestEvent();
+    expect(handler1.calls.count()).toBe(2);
+    expect(handler2.calls.count()).toBe(0);
+
+    ReactDebugTool.addHook(hook2);
+    ReactDebugTool.onTestEvent();
+    expect(handler1.calls.count()).toBe(3);
+    expect(handler2.calls.count()).toBe(1);
+
+    ReactDebugTool.onTestEvent();
+    expect(handler1.calls.count()).toBe(4);
+    expect(handler2.calls.count()).toBe(2);
+
+    ReactDebugTool.removeHook(hook1);
+    ReactDebugTool.onTestEvent();
+    expect(handler1.calls.count()).toBe(4);
+    expect(handler2.calls.count()).toBe(3);
+
+    ReactDebugTool.removeHook(hook2);
+    ReactDebugTool.onTestEvent();
+    expect(handler1.calls.count()).toBe(4);
+    expect(handler2.calls.count()).toBe(3);
+  });
+
+  it('warns once when an error is thrown in hook', () => {
+    spyOn(console, 'error');
+    ReactDebugTool.addHook({
+      onTestEvent() {
+        throw new Error('Hi.');
+      },
+    });
+
+    ReactDebugTool.onTestEvent();
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'Exception thrown by hook while handling ' + 'onTestEvent: Error: Hi.',
+    );
+
+    ReactDebugTool.onTestEvent();
+    expect(console.error.calls.count()).toBe(1);
+  });
+
+  it('returns isProfiling state', () => {
+    expect(ReactDebugTool.isProfiling()).toBe(false);
+
+    ReactDebugTool.beginProfiling();
+    expect(ReactDebugTool.isProfiling()).toBe(true);
+
+    ReactDebugTool.endProfiling();
+    expect(ReactDebugTool.isProfiling()).toBe(false);
+  });
+});
diff --git a/src/renderers/shared/__tests__/ReactPerf-test.js b/src/renderers/shared/__tests__/ReactPerf-test.js
new file mode 100644
index 000000000000..3c5f3d58e63d
--- /dev/null
+++ b/src/renderers/shared/__tests__/ReactPerf-test.js
@@ -0,0 +1,741 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+describe('ReactPerf', () => {
+  var React;
+  var ReactDOM;
+  var ReactPerf;
+  var ReactTestUtils;
+  var emptyFunction;
+
+  var App;
+  var Box;
+  var Div;
+  var LifeCycle;
+
+  beforeEach(() => {
+    var now = 0;
+    jest.setMock('fbjs/lib/performanceNow', function() {
+      return now++;
+    });
+
+    if (typeof console.table !== 'function') {
+      console.table = () => {};
+      console.table.isFake = true;
+    }
+
+    React = require('React');
+    ReactDOM = require('ReactDOM');
+    ReactPerf = require('ReactPerf');
+    ReactTestUtils = require('ReactTestUtils');
+    emptyFunction = require('emptyFunction');
+
+    App = class extends React.Component {
+      render() {
+        return <div><Box /><Box flip={this.props.flipSecond} /></div>;
+      }
+    };
+
+    Box = class extends React.Component {
+      render() {
+        return <div key={!!this.props.flip}><input /></div>;
+      }
+    };
+
+    // ReactPerf only measures composites, so we put everything in one.
+    Div = class extends React.Component {
+      render() {
+        return <div {...this.props} />;
+      }
+    };
+
+    LifeCycle = class extends React.Component {
+      shouldComponentUpdate = emptyFunction.thatReturnsTrue;
+      componentWillMount = emptyFunction;
+      componentDidMount = emptyFunction;
+      componentWillReceiveProps = emptyFunction;
+      componentWillUpdate = emptyFunction;
+      componentDidUpdate = emptyFunction;
+      componentWillUnmount = emptyFunction;
+      render = emptyFunction.thatReturnsNull;
+    };
+  });
+
+  afterEach(() => {
+    if (console.table.isFake) {
+      delete console.table;
+    }
+  });
+
+  function measure(fn) {
+    ReactPerf.start();
+    fn();
+    ReactPerf.stop();
+
+    // Make sure none of the methods crash.
+    ReactPerf.getWasted();
+    ReactPerf.getInclusive();
+    ReactPerf.getExclusive();
+    ReactPerf.getOperations();
+
+    return ReactPerf.getLastMeasurements();
+  }
+
+  it('should count no-op update as waste', () => {
+    var container = document.createElement('div');
+    ReactDOM.render(<App />, container);
+    var measurements = measure(() => {
+      ReactDOM.render(<App />, container);
+    });
+
+    var summary = ReactPerf.getWasted(measurements);
+    expect(summary).toEqual([
+      {
+        key: 'App',
+        instanceCount: 1,
+        inclusiveRenderDuration: 3,
+        renderCount: 1,
+      },
+      {
+        key: 'App > Box',
+        instanceCount: 2,
+        inclusiveRenderDuration: 2,
+        renderCount: 2,
+      },
+    ]);
+  });
+
+  it('should count no-op update in child as waste', () => {
+    var container = document.createElement('div');
+    ReactDOM.render(<App />, container);
+
+    // Here, we add a Box -- two of the <Box /> updates are wasted time (but the
+    // addition of the third is not)
+    var measurements = measure(() => {
+      ReactDOM.render(<App flipSecond={true} />, container);
+    });
+
+    var summary = ReactPerf.getWasted(measurements);
+    expect(summary).toEqual([
+      {
+        key: 'App > Box',
+        instanceCount: 1,
+        inclusiveRenderDuration: 1,
+        renderCount: 1,
+      },
+    ]);
+  });
+
+  function expectNoWaste(fn) {
+    var measurements = measure(fn);
+    var summary = ReactPerf.getWasted(measurements);
+    expect(summary).toEqual([]);
+  }
+
+  it('should not count initial render as waste', () => {
+    expectNoWaste(() => {
+      ReactTestUtils.renderIntoDocument(<App />);
+    });
+  });
+
+  it('should not count unmount as waste', () => {
+    var container = document.createElement('div');
+    ReactDOM.render(<Div>hello</Div>, container);
+    expectNoWaste(() => {
+      ReactDOM.unmountComponentAtNode(container);
+    });
+  });
+
+  it('should not count content update as waste', () => {
+    var container = document.createElement('div');
+    ReactDOM.render(<Div>hello</Div>, container);
+    expectNoWaste(() => {
+      ReactDOM.render(<Div>hello world</Div>, container);
+    });
+  });
+
+  it('should not count child addition as waste', () => {
+    var container = document.createElement('div');
+    ReactDOM.render(<Div><span /></Div>, container);
+    expectNoWaste(() => {
+      ReactDOM.render(<Div><span /><span /></Div>, container);
+    });
+  });
+
+  it('should not count child removal as waste', () => {
+    var container = document.createElement('div');
+    ReactDOM.render(<Div><span /><span /></Div>, container);
+    expectNoWaste(() => {
+      ReactDOM.render(<Div><span /></Div>, container);
+    });
+  });
+
+  it('should not count property update as waste', () => {
+    var container = document.createElement('div');
+    ReactDOM.render(<Div className="yellow">hey</Div>, container);
+    expectNoWaste(() => {
+      ReactDOM.render(<Div className="blue">hey</Div>, container);
+    });
+  });
+
+  it('should not count style update as waste', () => {
+    var container = document.createElement('div');
+    ReactDOM.render(<Div style={{color: 'yellow'}}>hey</Div>, container);
+    expectNoWaste(() => {
+      ReactDOM.render(<Div style={{color: 'blue'}}>hey</Div>, container);
+    });
+  });
+
+  it('should not count property removal as waste', () => {
+    var container = document.createElement('div');
+    ReactDOM.render(<Div className="yellow">hey</Div>, container);
+    expectNoWaste(() => {
+      ReactDOM.render(<Div>hey</Div>, container);
+    });
+  });
+
+  it('should not count raw HTML update as waste', () => {
+    var container = document.createElement('div');
+    ReactDOM.render(
+      <Div dangerouslySetInnerHTML={{__html: 'me'}} />,
+      container,
+    );
+    expectNoWaste(() => {
+      ReactDOM.render(
+        <Div dangerouslySetInnerHTML={{__html: 'you'}} />,
+        container,
+      );
+    });
+  });
+
+  it('should not count child reordering as waste', () => {
+    var container = document.createElement('div');
+    ReactDOM.render(<Div><div key="A" /><div key="B" /></Div>, container);
+    expectNoWaste(() => {
+      ReactDOM.render(<Div><div key="B" /><div key="A" /></Div>, container);
+    });
+  });
+
+  it('should not count text update as waste', () => {
+    var container = document.createElement('div');
+    ReactDOM.render(<Div>{'hello'}{'world'}</Div>, container);
+    expectNoWaste(() => {
+      ReactDOM.render(<Div>{'hello'}{'friend'}</Div>, container);
+    });
+  });
+
+  it('should not count replacing null with a host as waste', () => {
+    var element = null;
+    function Foo() {
+      return element;
+    }
+    var container = document.createElement('div');
+    ReactDOM.render(<Foo />, container);
+    expectNoWaste(() => {
+      element = <div />;
+      ReactDOM.render(<Foo />, container);
+    });
+  });
+
+  it('should not count replacing a host with null as waste', () => {
+    var element = <div />;
+    function Foo() {
+      return element;
+    }
+    var container = document.createElement('div');
+    ReactDOM.render(<Foo />, container);
+    expectNoWaste(() => {
+      element = null;
+      ReactDOM.render(<Foo />, container);
+    });
+  });
+
+  it('should include stats for components unmounted during measurement', () => {
+    var container = document.createElement('div');
+    var measurements = measure(() => {
+      ReactDOM.render(<Div><Div key="a" /></Div>, container);
+      ReactDOM.render(<Div><Div key="b" /></Div>, container);
+    });
+    expect(ReactPerf.getExclusive(measurements)).toEqual([
+      {
+        key: 'Div',
+        instanceCount: 3,
+        counts: {ctor: 3, render: 4},
+        durations: {ctor: 3, render: 4},
+        totalDuration: 7,
+      },
+    ]);
+  });
+
+  it('should include lifecycle methods in measurements', () => {
+    var container = document.createElement('div');
+    var measurements = measure(() => {
+      var instance = ReactDOM.render(<LifeCycle />, container);
+      ReactDOM.render(<LifeCycle />, container);
+      instance.setState({});
+      ReactDOM.unmountComponentAtNode(container);
+    });
+    expect(ReactPerf.getExclusive(measurements)).toEqual([
+      {
+        key: 'LifeCycle',
+        instanceCount: 1,
+        totalDuration: 14,
+        counts: {
+          ctor: 1,
+          shouldComponentUpdate: 2,
+          componentWillMount: 1,
+          componentDidMount: 1,
+          componentWillReceiveProps: 1,
+          componentWillUpdate: 2,
+          componentDidUpdate: 2,
+          componentWillUnmount: 1,
+          render: 3,
+        },
+        durations: {
+          ctor: 1,
+          shouldComponentUpdate: 2,
+          componentWillMount: 1,
+          componentDidMount: 1,
+          componentWillReceiveProps: 1,
+          componentWillUpdate: 2,
+          componentDidUpdate: 2,
+          componentWillUnmount: 1,
+          render: 3,
+        },
+      },
+    ]);
+  });
+
+  it('should include render time of functional components', () => {
+    function Foo() {
+      return null;
+    }
+
+    var container = document.createElement('div');
+    var measurements = measure(() => {
+      ReactDOM.render(<Foo />, container);
+    });
+    expect(ReactPerf.getExclusive(measurements)).toEqual([
+      {
+        key: 'Foo',
+        instanceCount: 1,
+        totalDuration: 1,
+        counts: {
+          render: 1,
+        },
+        durations: {
+          render: 1,
+        },
+      },
+    ]);
+  });
+
+  it('should not count time in a portal towards lifecycle method', () => {
+    function Foo() {
+      return null;
+    }
+
+    var portalContainer = document.createElement('div');
+    class Portal extends React.Component {
+      componentDidMount() {
+        ReactDOM.render(<Foo />, portalContainer);
+      }
+      render() {
+        return null;
+      }
+    }
+
+    var container = document.createElement('div');
+    var measurements = measure(() => {
+      ReactDOM.render(<Portal />, container);
+    });
+
+    expect(ReactPerf.getExclusive(measurements)).toEqual([
+      {
+        key: 'Portal',
+        instanceCount: 1,
+        totalDuration: 6,
+        counts: {
+          ctor: 1,
+          componentDidMount: 1,
+          render: 1,
+        },
+        durations: {
+          ctor: 1,
+          // We want to exclude nested imperative ReactDOM.render() from lifecycle hook's own time.
+          // Otherwise it would artificially float to the top even though its exclusive time is small.
+          // This is how we get 4 as a number with the performanceNow() mock:
+          // - we capture the time we enter componentDidMount (n = 0)
+          // - we capture the time when we enter a nested flush (n = 1)
+          // - in the nested flush, we call it twice: before and after <Foo /> rendering. (n = 3)
+          // - we capture the time when we exit a nested flush (n = 4)
+          // - we capture the time we exit componentDidMount (n = 5)
+          // Time spent in componentDidMount = (5 - 0 - (4 - 3)) = 4.
+          componentDidMount: 4,
+          render: 1,
+        },
+      },
+      {
+        key: 'Foo',
+        instanceCount: 1,
+        totalDuration: 1,
+        counts: {
+          render: 1,
+        },
+        durations: {
+          render: 1,
+        },
+      },
+    ]);
+  });
+
+  it('warns once when using getMeasurementsSummaryMap', () => {
+    var measurements = measure(() => {});
+    spyOn(console, 'warn');
+    ReactPerf.getMeasurementsSummaryMap(measurements);
+    expect(console.warn.calls.count()).toBe(1);
+    expect(console.warn.calls.argsFor(0)[0]).toContain(
+      '`ReactPerf.getMeasurementsSummaryMap(...)` is deprecated. Use ' +
+        '`ReactPerf.getWasted(...)` instead.',
+    );
+
+    ReactPerf.getMeasurementsSummaryMap(measurements);
+    expect(console.warn.calls.count()).toBe(1);
+  });
+
+  it('warns once when using printDOM', () => {
+    var measurements = measure(() => {});
+    spyOn(console, 'warn');
+    ReactPerf.printDOM(measurements);
+    expect(console.warn.calls.count()).toBe(1);
+    expect(console.warn.calls.argsFor(0)[0]).toContain(
+      '`ReactPerf.printDOM(...)` is deprecated. Use ' +
+        '`ReactPerf.printOperations(...)` instead.',
+    );
+
+    ReactPerf.printDOM(measurements);
+    expect(console.warn.calls.count()).toBe(1);
+  });
+
+  it('returns isRunning state', () => {
+    expect(ReactPerf.isRunning()).toBe(false);
+
+    ReactPerf.start();
+    expect(ReactPerf.isRunning()).toBe(true);
+
+    ReactPerf.stop();
+    expect(ReactPerf.isRunning()).toBe(false);
+  });
+
+  it('start has no effect when already running', () => {
+    expect(ReactPerf.isRunning()).toBe(false);
+
+    ReactPerf.start();
+    expect(ReactPerf.isRunning()).toBe(true);
+
+    ReactPerf.start();
+    expect(ReactPerf.isRunning()).toBe(true);
+
+    ReactPerf.stop();
+    expect(ReactPerf.isRunning()).toBe(false);
+  });
+
+  it('stop has no effect when already stopped', () => {
+    expect(ReactPerf.isRunning()).toBe(false);
+
+    ReactPerf.stop();
+    expect(ReactPerf.isRunning()).toBe(false);
+
+    ReactPerf.stop();
+    expect(ReactPerf.isRunning()).toBe(false);
+  });
+
+  it('should print console error only once', () => {
+    __DEV__ = false;
+
+    spyOn(console, 'error');
+
+    expect(ReactPerf.getLastMeasurements()).toEqual([]);
+    expect(ReactPerf.getExclusive()).toEqual([]);
+    expect(ReactPerf.getInclusive()).toEqual([]);
+    expect(ReactPerf.getWasted()).toEqual([]);
+    expect(ReactPerf.getOperations()).toEqual([]);
+    expect(ReactPerf.printExclusive()).toEqual(undefined);
+    expect(ReactPerf.printInclusive()).toEqual(undefined);
+    expect(ReactPerf.printWasted()).toEqual(undefined);
+    expect(ReactPerf.printOperations()).toEqual(undefined);
+    expect(ReactPerf.start()).toBe(undefined);
+    expect(ReactPerf.stop()).toBe(undefined);
+    expect(ReactPerf.isRunning()).toBe(false);
+
+    expect(console.error.calls.count()).toBe(1);
+
+    __DEV__ = true;
+  });
+
+  it('should work when measurement starts during reconciliation', () => {
+    // https://github.com/facebook/react/issues/6949#issuecomment-230371009
+    class Measurer extends React.Component {
+      componentWillMount() {
+        ReactPerf.start();
+      }
+
+      componentDidMount() {
+        ReactPerf.stop();
+      }
+
+      componentWillUpdate() {
+        ReactPerf.start();
+      }
+
+      componentDidUpdate() {
+        ReactPerf.stop();
+      }
+
+      render() {
+        // Force reconciliation despite constant element
+        return React.cloneElement(this.props.children);
+      }
+    }
+
+    var container = document.createElement('div');
+    ReactDOM.render(<Measurer><App /></Measurer>, container);
+    expect(ReactPerf.getWasted()).toEqual([]);
+
+    ReactDOM.render(<Measurer><App /></Measurer>, container);
+    expect(ReactPerf.getWasted()).toEqual([
+      {
+        key: 'Measurer',
+        instanceCount: 1,
+        inclusiveRenderDuration: 4,
+        renderCount: 1,
+      },
+      {
+        key: 'App',
+        instanceCount: 1,
+        inclusiveRenderDuration: 3,
+        renderCount: 1,
+      },
+      {
+        key: 'App > Box',
+        instanceCount: 2,
+        inclusiveRenderDuration: 2,
+        renderCount: 2,
+      },
+    ]);
+  });
+
+  it('should not print errant warnings if render() throws', () => {
+    var container = document.createElement('div');
+    var thrownErr = new Error('Muhaha!');
+
+    class Evil extends React.Component {
+      render() {
+        throw thrownErr;
+      }
+    }
+
+    ReactPerf.start();
+    try {
+      ReactDOM.render(
+        <div>
+          <LifeCycle />
+          <Evil />
+        </div>,
+        container,
+      );
+    } catch (err) {
+      if (err !== thrownErr) {
+        throw err;
+      }
+    }
+    ReactPerf.stop();
+  });
+
+  it('should not print errant warnings if componentWillMount() throws', () => {
+    var container = document.createElement('div');
+    var thrownErr = new Error('Muhaha!');
+
+    class Evil extends React.Component {
+      componentWillMount() {
+        throw thrownErr;
+      }
+      render() {
+        return <div />;
+      }
+    }
+
+    ReactPerf.start();
+    try {
+      ReactDOM.render(
+        <div>
+          <LifeCycle />
+          <Evil />
+        </div>,
+        container,
+      );
+    } catch (err) {
+      if (err !== thrownErr) {
+        throw err;
+      }
+    }
+    ReactPerf.stop();
+  });
+
+  it('should not print errant warnings if componentDidMount() throws', () => {
+    var container = document.createElement('div');
+    var thrownErr = new Error('Muhaha!');
+
+    class Evil extends React.Component {
+      componentDidMount() {
+        throw thrownErr;
+      }
+      render() {
+        return <div />;
+      }
+    }
+
+    ReactPerf.start();
+    try {
+      ReactDOM.render(
+        <div>
+          <LifeCycle />
+          <Evil />
+        </div>,
+        container,
+      );
+    } catch (err) {
+      if (err !== thrownErr) {
+        throw err;
+      }
+    }
+    ReactPerf.stop();
+  });
+
+  it('should not print errant warnings if portal throws in render()', () => {
+    var container = document.createElement('div');
+    var thrownErr = new Error('Muhaha!');
+
+    class Evil extends React.Component {
+      render() {
+        throw thrownErr;
+      }
+    }
+    class EvilPortal extends React.Component {
+      componentWillMount() {
+        var portalContainer = document.createElement('div');
+        ReactDOM.render(<Evil />, portalContainer);
+      }
+      render() {
+        return <div />;
+      }
+    }
+
+    ReactPerf.start();
+    try {
+      ReactDOM.render(
+        <div>
+          <LifeCycle />
+          <EvilPortal />
+        </div>,
+        container,
+      );
+    } catch (err) {
+      if (err !== thrownErr) {
+        throw err;
+      }
+    }
+    ReactDOM.unmountComponentAtNode(container);
+    ReactPerf.stop();
+  });
+
+  it('should not print errant warnings if portal throws in componentWillMount()', () => {
+    var container = document.createElement('div');
+    var thrownErr = new Error('Muhaha!');
+
+    class Evil extends React.Component {
+      componentWillMount() {
+        throw thrownErr;
+      }
+      render() {
+        return <div />;
+      }
+    }
+    class EvilPortal extends React.Component {
+      componentWillMount() {
+        var portalContainer = document.createElement('div');
+        ReactDOM.render(<Evil />, portalContainer);
+      }
+      render() {
+        return <div />;
+      }
+    }
+
+    ReactPerf.start();
+    try {
+      ReactDOM.render(
+        <div>
+          <LifeCycle />
+          <EvilPortal />
+        </div>,
+        container,
+      );
+    } catch (err) {
+      if (err !== thrownErr) {
+        throw err;
+      }
+    }
+    ReactDOM.unmountComponentAtNode(container);
+    ReactPerf.stop();
+  });
+
+  it('should not print errant warnings if portal throws in componentDidMount()', () => {
+    var container = document.createElement('div');
+    var thrownErr = new Error('Muhaha!');
+
+    class Evil extends React.Component {
+      componentDidMount() {
+        throw thrownErr;
+      }
+      render() {
+        return <div />;
+      }
+    }
+    class EvilPortal extends React.Component {
+      componentWillMount() {
+        var portalContainer = document.createElement('div');
+        ReactDOM.render(<Evil />, portalContainer);
+      }
+      render() {
+        return <div />;
+      }
+    }
+
+    ReactPerf.start();
+    try {
+      ReactDOM.render(
+        <div>
+          <LifeCycle />
+          <EvilPortal />
+        </div>,
+        container,
+      );
+    } catch (err) {
+      if (err !== thrownErr) {
+        throw err;
+      }
+    }
+    ReactDOM.unmountComponentAtNode(container);
+    ReactPerf.stop();
+  });
+});
diff --git a/src/renderers/shared/event/EventPluginRegistry.js b/src/renderers/shared/event/EventPluginRegistry.js
deleted file mode 100644
index f6830e58869d..000000000000
--- a/src/renderers/shared/event/EventPluginRegistry.js
+++ /dev/null
@@ -1,295 +0,0 @@
-/**
- * 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 EventPluginRegistry
- */
-
-'use strict';
-
-var invariant = require('invariant');
-
-/**
- * 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);
-    invariant(
-      pluginIndex > -1,
-      'EventPluginRegistry: Cannot inject event plugins that do not exist in ' +
-      'the plugin ordering, `%s`.',
-      pluginName
-    );
-    if (EventPluginRegistry.plugins[pluginIndex]) {
-      continue;
-    }
-    invariant(
-      PluginModule.extractEvents,
-      'EventPluginRegistry: Event plugins must implement an `extractEvents` ' +
-      'method, but `%s` does not.',
-      pluginName
-    );
-    EventPluginRegistry.plugins[pluginIndex] = PluginModule;
-    var publishedEvents = PluginModule.eventTypes;
-    for (var eventName in publishedEvents) {
-      invariant(
-        publishEventForPlugin(
-          publishedEvents[eventName],
-          PluginModule,
-          eventName
-        ),
-        'EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.',
-        eventName,
-        pluginName
-      );
-    }
-  }
-}
-
-/**
- * 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) {
-  invariant(
-    !EventPluginRegistry.eventNameDispatchConfigs.hasOwnProperty(eventName),
-    'EventPluginHub: More than one plugin attempted to publish the same ' +
-    'event name, `%s`.',
-    eventName
-  );
-  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) {
-  invariant(
-    !EventPluginRegistry.registrationNameModules[registrationName],
-    'EventPluginHub: More than one plugin attempted to publish the same ' +
-    'registration name, `%s`.',
-    registrationName
-  );
-  EventPluginRegistry.registrationNameModules[registrationName] = PluginModule;
-  EventPluginRegistry.registrationNameDependencies[registrationName] =
-    PluginModule.eventTypes[eventName].dependencies;
-
-  if (__DEV__) {
-    var lowerCasedName = registrationName.toLowerCase();
-    EventPluginRegistry.possibleRegistrationNames[lowerCasedName] =
-      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: __DEV__ ? {} : null,
-
-  /**
-   * 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) {
-    invariant(
-      !EventPluginOrder,
-      'EventPluginRegistry: Cannot inject event plugin ordering more than ' +
-      'once. You are likely trying to load more than one copy of React.'
-    );
-    // 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) {
-        invariant(
-          !namesToPlugins[pluginName],
-          'EventPluginRegistry: Cannot inject two different event plugins ' +
-          'using the same name, `%s`.',
-          pluginName
-        );
-        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;
-    }
-    for (var phase in dispatchConfig.phasedRegistrationNames) {
-      if (!dispatchConfig.phasedRegistrationNames.hasOwnProperty(phase)) {
-        continue;
-      }
-      var PluginModule = EventPluginRegistry.registrationNameModules[
-        dispatchConfig.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 (__DEV__) {
-      var possibleRegistrationNames =
-        EventPluginRegistry.possibleRegistrationNames;
-      for (var lowerCasedName in possibleRegistrationNames) {
-        if (possibleRegistrationNames.hasOwnProperty(lowerCasedName)) {
-          delete possibleRegistrationNames[lowerCasedName];
-        }
-      }
-    }
-  },
-
-};
-
-module.exports = EventPluginRegistry;
diff --git a/src/renderers/shared/event/eventPlugins/ResponderTouchHistoryStore.js b/src/renderers/shared/event/eventPlugins/ResponderTouchHistoryStore.js
deleted file mode 100644
index 128494333d00..000000000000
--- a/src/renderers/shared/event/eventPlugins/ResponderTouchHistoryStore.js
+++ /dev/null
@@ -1,185 +0,0 @@
-/**
- * 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 ResponderTouchHistoryStore
- */
-
-'use strict';
-
-var EventPluginUtils = require('EventPluginUtils');
-
-var invariant = require('invariant');
-
-var isMoveish = EventPluginUtils.isMoveish;
-var isStartish = EventPluginUtils.isStartish;
-var isEndish = EventPluginUtils.isEndish;
-
-var MAX_TOUCH_BANK = 20;
-
-/**
- * Touch position/time tracking information by touchID. Typically, we'll only
- * see IDs with a range of 1-20 (they are recycled when touches end and then
- * start again). This data is commonly needed by many different interaction
- * logic modules so precomputing it is very helpful to do once.
- * Each touch object in `touchBank` is of the following form:
- * { touchActive: boolean,
- *   startTimeStamp: number,
- *   startPageX: number,
- *   startPageY: number,
- *   currentPageX: number,
- *   currentPageY: number,
- *   currentTimeStamp: number
- * }
- */
-var touchHistory = {
-  touchBank: [],
-  numberActiveTouches: 0,
-  // If there is only one active touch, we remember its location. This prevents
-  // us having to loop through all of the touches all the time in the most
-  // common case.
-  indexOfSingleActiveTouch: -1,
-  mostRecentTimeStamp: 0,
-};
-
-var timestampForTouch = function(touch) {
-  // The legacy internal implementation provides "timeStamp", which has been
-  // renamed to "timestamp". Let both work for now while we iron it out
-  // TODO (evv): rename timeStamp to timestamp in internal code
-  return touch.timeStamp || touch.timestamp;
-};
-
-/**
- * TODO: Instead of making gestures recompute filtered velocity, we could
- * include a built in velocity computation that can be reused globally.
- * @param {Touch} touch Native touch object.
- */
-var initializeTouchData = function(touch) {
-  return {
-    touchActive: true,
-    startTimeStamp: timestampForTouch(touch),
-    startPageX: touch.pageX,
-    startPageY: touch.pageY,
-    currentPageX: touch.pageX,
-    currentPageY: touch.pageY,
-    currentTimeStamp: timestampForTouch(touch),
-    previousPageX: touch.pageX,
-    previousPageY: touch.pageY,
-    previousTimeStamp: timestampForTouch(touch),
-  };
-};
-
-var reinitializeTouchTrack = function(touchTrack, touch) {
-  touchTrack.touchActive = true;
-  touchTrack.startTimeStamp = timestampForTouch(touch);
-  touchTrack.startPageX = touch.pageX;
-  touchTrack.startPageY = touch.pageY;
-  touchTrack.currentPageX = touch.pageX;
-  touchTrack.currentPageY = touch.pageY;
-  touchTrack.currentTimeStamp = timestampForTouch(touch);
-  touchTrack.previousPageX = touch.pageX;
-  touchTrack.previousPageY = touch.pageY;
-  touchTrack.previousTimeStamp = timestampForTouch(touch);
-};
-
-var validateTouch = function(touch) {
-  var identifier = touch.identifier;
-  invariant(identifier != null, 'Touch object is missing identifier');
-  if (identifier > MAX_TOUCH_BANK) {
-    console.warn(
-      'Touch identifier ' + identifier + ' is greater than maximum ' +
-      'supported ' + MAX_TOUCH_BANK + ' which causes performance issues ' +
-      'backfilling array locations for all of the indices.'
-    );
-  }
-};
-
-var recordStartTouchData = function(touch) {
-  var touchBank = touchHistory.touchBank;
-  var identifier = touch.identifier;
-  var touchTrack = touchBank[identifier];
-  if (__DEV__) {
-    validateTouch(touch);
-  }
-  if (touchTrack) {
-    reinitializeTouchTrack(touchTrack, touch);
-  } else {
-    touchBank[touch.identifier] = initializeTouchData(touch);
-  }
-  touchHistory.mostRecentTimeStamp = timestampForTouch(touch);
-};
-
-var recordMoveTouchData = function(touch) {
-  var touchBank = touchHistory.touchBank;
-  var touchTrack = touchBank[touch.identifier];
-  if (__DEV__) {
-    validateTouch(touch);
-    invariant(touchTrack, 'Touch data should have been recorded on start');
-  }
-  touchTrack.touchActive = true;
-  touchTrack.previousPageX = touchTrack.currentPageX;
-  touchTrack.previousPageY = touchTrack.currentPageY;
-  touchTrack.previousTimeStamp = touchTrack.currentTimeStamp;
-  touchTrack.currentPageX = touch.pageX;
-  touchTrack.currentPageY = touch.pageY;
-  touchTrack.currentTimeStamp = timestampForTouch(touch);
-  touchHistory.mostRecentTimeStamp = timestampForTouch(touch);
-};
-
-var recordEndTouchData = function(touch) {
-  var touchBank = touchHistory.touchBank;
-  var touchTrack = touchBank[touch.identifier];
-  if (__DEV__) {
-    validateTouch(touch);
-    invariant(touchTrack, 'Touch data should have been recorded on start');
-  }
-  touchTrack.previousPageX = touchTrack.currentPageX;
-  touchTrack.previousPageY = touchTrack.currentPageY;
-  touchTrack.previousTimeStamp = touchTrack.currentTimeStamp;
-  touchTrack.currentPageX = touch.pageX;
-  touchTrack.currentPageY = touch.pageY;
-  touchTrack.currentTimeStamp = timestampForTouch(touch);
-  touchTrack.touchActive = false;
-  touchHistory.mostRecentTimeStamp = timestampForTouch(touch);
-};
-
-var ResponderTouchHistoryStore = {
-  recordTouchTrack: function(topLevelType, nativeEvent) {
-    var touchBank = touchHistory.touchBank;
-    if (isMoveish(topLevelType)) {
-      nativeEvent.changedTouches.forEach(recordMoveTouchData);
-    } else if (isStartish(topLevelType)) {
-      nativeEvent.changedTouches.forEach(recordStartTouchData);
-      touchHistory.numberActiveTouches = nativeEvent.touches.length;
-      if (touchHistory.numberActiveTouches === 1) {
-        touchHistory.indexOfSingleActiveTouch = nativeEvent.touches[0].identifier;
-      }
-    } else if (isEndish(topLevelType)) {
-      nativeEvent.changedTouches.forEach(recordEndTouchData);
-      touchHistory.numberActiveTouches = nativeEvent.touches.length;
-      if (touchHistory.numberActiveTouches === 1) {
-        for (var i = 0; i < touchBank.length; i++) {
-          var touchTrackToCheck = touchBank[i];
-          if (touchTrackToCheck != null && touchTrackToCheck.touchActive) {
-            touchHistory.indexOfSingleActiveTouch = i;
-            break;
-          }
-        }
-        if (__DEV__) {
-          var activeTouchData = touchBank[touchHistory.indexOfSingleActiveTouch];
-          var foundActive = activeTouchData != null && !!activeTouchData.touchActive;
-          invariant(foundActive, 'Cannot find single active touch');
-        }
-      }
-    }
-  },
-
-  touchHistory: touchHistory,
-};
-
-
-module.exports = ResponderTouchHistoryStore;
diff --git a/src/renderers/shared/event/eventPlugins/__tests__/ResponderEventPlugin-test.js b/src/renderers/shared/event/eventPlugins/__tests__/ResponderEventPlugin-test.js
deleted file mode 100644
index 35e797d2fd9f..000000000000
--- a/src/renderers/shared/event/eventPlugins/__tests__/ResponderEventPlugin-test.js
+++ /dev/null
@@ -1,1008 +0,0 @@
-/**
- * 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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-var EventPluginHub;
-var EventConstants;
-var ReactInstanceHandles;
-var ResponderEventPlugin;
-var EventPluginUtils;
-
-var topLevelTypes;
-
-var touch = function(nodeHandle, i) {
-  return {target: nodeHandle, identifier: i};
-};
-
-/**
- * @param {NodeHandle} nodeHandle @see NodeHandle. Handle of target.
- * @param {Array<Touch>} touches All active touches.
- * @param {Array<Touch>} changedTouches Only the touches that have changed.
- * @return {TouchEvent} Model of a touch event that is compliant with responder
- * system plugin.
- */
-var touchEvent = function(nodeHandle, touches, changedTouches) {
-  return {
-    target: nodeHandle,
-    changedTouches: changedTouches,
-    touches: touches,
-  };
-};
-
-var subsequence = function(arr, indices) {
-  var ret = [];
-  for (var i = 0; i < indices.length; i++) {
-    var index = indices[i];
-    ret.push(arr[index]);
-  }
-  return ret;
-};
-
-var antiSubsequence = function(arr, indices) {
-  var ret = [];
-  for (var i = 0; i < arr.length; i++) {
-    if (indices.indexOf(i) === -1) {
-      ret.push(arr[i]);
-    }
-  }
-  return ret;
-};
-
-/**
- * Helper for creating touch test config data.
- * @param allTouchHandles
- */
-var _touchConfig = function(
-  topType,
-  targetNodeHandle,
-  allTouchHandles,
-  changedIndices,
-  eventTarget
-) {
-  var allTouchObjects = allTouchHandles.map(touch);
-  var changedTouchObjects = subsequence(allTouchObjects, changedIndices);
-  var activeTouchObjects =
-    topType === 'topTouchStart' ? allTouchObjects :
-    topType === 'topTouchMove' ? allTouchObjects :
-    topType === 'topTouchEnd' ? antiSubsequence(allTouchObjects, changedIndices) :
-    topType === 'topTouchCancel' ? antiSubsequence(allTouchObjects, changedIndices) :
-    null;
-
-  return {
-    nativeEvent: touchEvent(
-      targetNodeHandle,
-      activeTouchObjects,
-      changedTouchObjects
-    ),
-    topLevelType: topType,
-    targetInst: idToInstance[targetNodeHandle],
-  };
-};
-
-/**
- * Creates test data for touch events using environment agnostic "node
- * handles".
- *
- * @param {NodeHandle} nodeHandle Environment agnostic handle to DOM node.
- * @param {Array<NodeHandle>} allTouchHandles Encoding of all "touches" in the
- * form of a mapping from integer (touch `identifier`) to touch target. This is
- * encoded in array form. Because of this, it is possible for two separate
- * touches (meaning two separate indices) to have the same touch target ID -
- * this corresponds to real world cases where two separate unique touches have
- * the same target. These touches don't just represent all active touches,
- * rather it also includes any touches that are not active, but are in the
- * process of being removed.
- * @param {Array<NodeHandle>} changedIndices Indices of `allTouchHandles` that
- * have changed.
- * @return {object} Config data used by test cases for extracting responder
- * events.
- */
-var startConfig = function(nodeHandle, allTouchHandles, changedIndices) {
-  return _touchConfig(
-    topLevelTypes.topTouchStart,
-    nodeHandle,
-    allTouchHandles,
-    changedIndices,
-    nodeHandle
-  );
-};
-
-/**
- * @see `startConfig`
- */
-var moveConfig = function(nodeHandle, allTouchHandles, changedIndices) {
-  return _touchConfig(
-    topLevelTypes.topTouchMove,
-    nodeHandle,
-    allTouchHandles,
-    changedIndices,
-    nodeHandle
-  );
-};
-
-/**
- * @see `startConfig`
- */
-var endConfig = function(nodeHandle, allTouchHandles, changedIndices) {
-  return _touchConfig(
-    topLevelTypes.topTouchEnd,
-    nodeHandle,
-    allTouchHandles,
-    changedIndices,
-    nodeHandle
-  );
-};
-
-/**
- * Test config for events that aren't negotiation related, but rather result of
- * a negotiation.
- *
- * Returns object of the form:
- *
- *     {
- *       responderReject: {
- *         // Whatever "readableIDToID" was passed in.
- *         grandParent: {order: NA, assertEvent: null, returnVal: blah},
- *         ...
- *         child: {order: NA, assertEvent: null, returnVal: blah},
- *       }
- *       responderGrant: {
- *         grandParent: {order: NA, assertEvent: null, returnVal: blah},
- *         ...
- *         child: {order: NA, assertEvent: null, returnVal: blah}
- *       }
- *       ...
- *     }
- *
- * After this is created, a test case would configure specific event orderings
- * and optional assertions. Anything left with an `order` of `NA` will be
- * required to never be invoked (the test runner will make sure it throws if
- * ever invoked).
- *
- */
-var NA = -1;
-var oneEventLoopTestConfig = function(readableIDToID) {
-  var ret = {
-    // Negotiation
-    scrollShouldSetResponder: {bubbled:  {}, captured: {}},
-    startShouldSetResponder: {bubbled:  {}, captured: {}},
-    moveShouldSetResponder: {bubbled:  {}, captured: {}},
-    responderTerminationRequest: {},
-
-    // Non-negotiation
-    responderReject:    {}, // These do not bubble capture.
-    responderGrant:     {},
-    responderStart:     {},
-    responderMove:      {},
-    responderTerminate: {},
-    responderEnd:       {},
-    responderRelease:   {},
-  };
-  for (var eventName in ret) {
-    for (var readableNodeName in readableIDToID) {
-      if (ret[eventName].bubbled) {
-        // Two phase
-        ret[eventName].bubbled[readableNodeName] =
-          {order: NA, assertEvent: null, returnVal: undefined};
-        ret[eventName].captured[readableNodeName] =
-          {order: NA, assertEvent: null, returnVal: undefined};
-      } else {
-        ret[eventName][readableNodeName] =
-          {order: NA, assertEvent: null, returnVal: undefined};
-      }
-    }
-  }
-  return ret;
-};
-
-/**
- * @param {object} eventTestConfig
- * @param {object} readableIDToID
- */
-var registerTestHandlers = function(eventTestConfig, readableIDToID) {
-  var runs = {dispatchCount: 0};
-  var neverFire = function(readableID, registrationName) {
-    runs.dispatchCount++;
-    expect('').toBe(
-      'Event type: ' + registrationName +
-      '\nShould never occur on:' + readableID +
-      '\nFor event test config:\n' + JSON.stringify(eventTestConfig) + '\n'
-    );
-  };
-
-  var registerOneEventType = function(registrationName, eventTypeTestConfig) {
-    for (var readableID in eventTypeTestConfig) {
-      var nodeConfig = eventTypeTestConfig[readableID];
-      var id = readableIDToID[readableID];
-      var handler = nodeConfig.order === NA ? neverFire.bind(null, readableID, registrationName) :
-        // We partially apply readableID and nodeConfig, as they change in the
-        // parent closure across iterations.
-        function(rID, config, e) {
-          expect(
-            rID + '->' + registrationName + ' index:' + runs.dispatchCount++
-          ).toBe(
-            rID + '->' + registrationName + ' index:' + config.order
-          );
-          if (config.assertEvent) {
-            config.assertEvent(e);
-          }
-          return config.returnVal;
-        }.bind(null, readableID, nodeConfig);
-      EventPluginHub.putListener(idToInstance[id], registrationName, handler);
-    }
-  };
-  for (var eventName in eventTestConfig) {
-    var oneEventTypeTestConfig = eventTestConfig[eventName];
-    var hasTwoPhase = !!oneEventTypeTestConfig.bubbled;
-    if (hasTwoPhase) {
-      registerOneEventType(
-        ResponderEventPlugin.eventTypes[eventName].phasedRegistrationNames.bubbled,
-        oneEventTypeTestConfig.bubbled
-      );
-      registerOneEventType(
-        ResponderEventPlugin.eventTypes[eventName].phasedRegistrationNames.captured,
-        oneEventTypeTestConfig.captured
-      );
-    } else {
-      registerOneEventType(
-        ResponderEventPlugin.eventTypes[eventName].registrationName,
-        oneEventTypeTestConfig
-      );
-    }
-  }
-  return runs;
-};
-
-
-
-
-var run = function(config, hierarchyConfig, nativeEventConfig) {
-  var max = NA;
-  var searchForMax = function(nodeConfig) {
-    for (var readableID in nodeConfig) {
-      var order = nodeConfig[readableID].order;
-      max = order > max ? order : max;
-    }
-  };
-  for (var eventName in config) {
-    var eventConfig = config[eventName];
-    if (eventConfig.bubbled) {
-      searchForMax(eventConfig.bubbled);
-      searchForMax(eventConfig.captured);
-    } else {
-      searchForMax(eventConfig);
-    }
-  }
-
-  // Register the handlers
-  var runData = registerTestHandlers(config, hierarchyConfig);
-
-  // Trigger the event
-  var extractedEvents = ResponderEventPlugin.extractEvents(
-    nativeEventConfig.topLevelType,
-    nativeEventConfig.targetInst,
-    nativeEventConfig.nativeEvent,
-    nativeEventConfig.target
-  );
-
-  // At this point the negotiation events have been dispatched as part of the
-  // extraction process, but not the side effectful events. Below, we dispatch
-  // side effectful events.
-  EventPluginHub.enqueueEvents(extractedEvents);
-  EventPluginHub.processEventQueue(true);
-
-  // Ensure that every event that declared an `order`, was actually dispatched.
-  expect(
-    'number of events dispatched:' + runData.dispatchCount
-  ).toBe(
-    'number of events dispatched:' + (max + 1)
-  ); // +1 for extra ++
-};
-
-var GRANDPARENT_ID = '.0';
-var PARENT_ID = '.0.0';
-var CHILD_ID = '.0.0.0';
-var CHILD_ID2 = '.0.0.1';
-
-var idToInstance = {};
-[GRANDPARENT_ID, PARENT_ID, CHILD_ID, CHILD_ID2].forEach(function(id) {
-  idToInstance[id] = {_rootNodeID: id};
-});
-
-var three = {
-  grandParent: GRANDPARENT_ID,
-  parent: PARENT_ID,
-  child: CHILD_ID,
-};
-
-var siblings = {
-  parent: PARENT_ID,
-  childOne: CHILD_ID,
-  childTwo: CHILD_ID2,
-};
-
-describe('ResponderEventPlugin', function() {
-  beforeEach(function() {
-    jest.resetModuleRegistry();
-
-    EventConstants = require('EventConstants');
-    EventPluginHub = require('EventPluginHub');
-    EventPluginUtils = require('EventPluginUtils');
-    ReactInstanceHandles = require('ReactInstanceHandles');
-    ResponderEventPlugin = require('ResponderEventPlugin');
-
-    EventPluginUtils.injection.injectComponentTree({
-      getInstanceFromNode: function(id) {
-        return idToInstance[id];
-      },
-      getNodeFromInstance: function(inst) {
-        return inst._rootNodeID;
-      },
-    });
-
-    EventPluginUtils.injection.injectTreeTraversal({
-      isAncestor: function(a, b) {
-        return ReactInstanceHandles.isAncestorIDOf(
-          a._rootNodeID,
-          b._rootNodeID
-        );
-      },
-      getLowestCommonAncestor: function(a, b) {
-        if (!a || !b) {
-          return null;
-        }
-        var commonID = ReactInstanceHandles.getFirstCommonAncestorID(
-          a._rootNodeID,
-          b._rootNodeID
-        );
-        return idToInstance[commonID] || null;
-      },
-      getParentInstance: function(inst) {
-        var id = inst._rootNodeID;
-        var parentID = id.substr(0, id.lastIndexOf('.'));
-        return idToInstance[parentID] || null;
-      },
-      traverseTwoPhase: function(target, fn, arg) {
-        ReactInstanceHandles.traverseTwoPhase(
-          target._rootNodeID,
-          function(id, upwards) {
-            fn(idToInstance[id], upwards, arg);
-          }
-        );
-      },
-    });
-
-    topLevelTypes = EventConstants.topLevelTypes;
-  });
-
-  it('should do nothing when no one wants to respond', function() {
-    var config = oneEventLoopTestConfig(three);
-    config.startShouldSetResponder.captured.grandParent = {order: 0, returnVal: false};
-    config.startShouldSetResponder.captured.parent = {order: 1, returnVal: false};
-    config.startShouldSetResponder.captured.child = {order: 2, returnVal: false};
-    config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: false};
-    config.startShouldSetResponder.bubbled.parent = {order: 4, returnVal: false};
-    config.startShouldSetResponder.bubbled.grandParent = {order: 5, returnVal: false};
-    run(config, three, startConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(null);
-
-    // Now no handlers should be called on `touchEnd`.
-    config = oneEventLoopTestConfig(three);
-    run(config, three, endConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(null);
-  });
-
-
-  /**
-   * Simple Start Granting
-   * --------------------
-   */
-
-
-  it('should grant responder grandParent while capturing', () => {
-    var config = oneEventLoopTestConfig(three);
-    config.startShouldSetResponder.captured.grandParent = {order: 0, returnVal: true};
-    config.responderGrant.grandParent = {order: 1};
-    config.responderStart.grandParent = {order: 2};
-    run(config, three, startConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(three.grandParent);
-
-    config = oneEventLoopTestConfig(three);
-    config.responderEnd.grandParent = {order: 0};
-    config.responderRelease.grandParent = {order: 1};
-    run(config, three, endConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(null);
-  });
-
-  it('should grant responder parent while capturing', () => {
-    var config = oneEventLoopTestConfig(three);
-    config.startShouldSetResponder.captured.grandParent = {order: 0, returnVal: false};
-    config.startShouldSetResponder.captured.parent = {order: 1, returnVal: true};
-    config.responderGrant.parent = {order: 2};
-    config.responderStart.parent = {order: 3};
-    run(config, three, startConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(three.parent);
-
-    config = oneEventLoopTestConfig(three);
-    config.responderEnd.parent = {order: 0};
-    config.responderRelease.parent = {order: 1};
-    run(config, three, endConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(null);
-  });
-
-  it('should grant responder child while capturing', () => {
-    var config = oneEventLoopTestConfig(three);
-    config.startShouldSetResponder.captured.grandParent = {order: 0, returnVal: false};
-    config.startShouldSetResponder.captured.parent = {order: 1, returnVal: false};
-    config.startShouldSetResponder.captured.child = {order: 2, returnVal: true};
-    config.responderGrant.child = {order: 3};
-    config.responderStart.child = {order: 4};
-    run(config, three, startConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
-
-    config = oneEventLoopTestConfig(three);
-    config.responderEnd.child = {order: 0};
-    config.responderRelease.child = {order: 1};
-    run(config, three, endConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(null);
-  });
-
-  it('should grant responder child while bubbling', () => {
-    var config = oneEventLoopTestConfig(three);
-    config.startShouldSetResponder.captured.grandParent = {order: 0, returnVal: false};
-    config.startShouldSetResponder.captured.parent = {order: 1, returnVal: false};
-    config.startShouldSetResponder.captured.child = {order: 2, returnVal: false};
-    config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: true};
-    config.responderGrant.child = {order: 4};
-    config.responderStart.child = {order: 5};
-    run(config, three, startConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
-
-    config = oneEventLoopTestConfig(three);
-    config.responderEnd.child = {order: 0};
-    config.responderRelease.child = {order: 1};
-    run(config, three, endConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(null);
-  });
-
-  it('should grant responder parent while bubbling', () => {
-    var config = oneEventLoopTestConfig(three);
-    config.startShouldSetResponder.captured.grandParent = {order: 0, returnVal: false};
-    config.startShouldSetResponder.captured.parent = {order: 1, returnVal: false};
-    config.startShouldSetResponder.captured.child = {order: 2, returnVal: false};
-    config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: false};
-    config.startShouldSetResponder.bubbled.parent = {order: 4, returnVal: true};
-    config.responderGrant.parent = {order: 5};
-    config.responderStart.parent = {order: 6};
-    run(config, three, startConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(three.parent);
-
-    config = oneEventLoopTestConfig(three);
-    config.responderEnd.parent = {order: 0};
-    config.responderRelease.parent = {order: 1};
-    run(config, three, endConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(null);
-  });
-
-  it('should grant responder grandParent while bubbling', () => {
-    var config = oneEventLoopTestConfig(three);
-    config.startShouldSetResponder.captured.grandParent = {order: 0, returnVal: false};
-    config.startShouldSetResponder.captured.parent = {order: 1, returnVal: false};
-    config.startShouldSetResponder.captured.child = {order: 2, returnVal: false};
-    config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: false};
-    config.startShouldSetResponder.bubbled.parent = {order: 4, returnVal: false};
-    config.startShouldSetResponder.bubbled.grandParent = {order: 5, returnVal: true};
-    config.responderGrant.grandParent = {order: 6};
-    config.responderStart.grandParent = {order: 7};
-    run(config, three, startConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(three.grandParent);
-
-    config = oneEventLoopTestConfig(three);
-    config.responderEnd.grandParent = {order: 0};
-    config.responderRelease.grandParent = {order: 1};
-    run(config, three, endConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(null);
-  });
-
-
-
-  /**
-   * Simple Move Granting
-   * --------------------
-   */
-
-  it('should grant responder grandParent while capturing move', () => {
-    var config = oneEventLoopTestConfig(three);
-
-    config.startShouldSetResponder.captured.grandParent = {order: 0};
-    config.startShouldSetResponder.captured.parent = {order: 1};
-    config.startShouldSetResponder.captured.child = {order: 2};
-    config.startShouldSetResponder.bubbled.child = {order: 3};
-    config.startShouldSetResponder.bubbled.parent = {order: 4};
-    config.startShouldSetResponder.bubbled.grandParent = {order: 5};
-    run(config, three, startConfig(three.child, [three.child], [0]));
-
-    config = oneEventLoopTestConfig(three);
-    config.moveShouldSetResponder.captured.grandParent = {order: 0, returnVal: true};
-    config.responderGrant.grandParent = {order: 1};
-    config.responderMove.grandParent = {order: 2};
-    run(config, three, moveConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(three.grandParent);
-
-    config = oneEventLoopTestConfig(three);
-    config.responderEnd.grandParent = {order: 0};
-    config.responderRelease.grandParent = {order: 1};
-    run(config, three, endConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(null);
-  });
-
-  it('should grant responder parent while capturing move', () => {
-    var config = oneEventLoopTestConfig(three);
-
-    config.startShouldSetResponder.captured.grandParent = {order: 0};
-    config.startShouldSetResponder.captured.parent = {order: 1};
-    config.startShouldSetResponder.captured.child = {order: 2};
-    config.startShouldSetResponder.bubbled.child = {order: 3};
-    config.startShouldSetResponder.bubbled.parent = {order: 4};
-    config.startShouldSetResponder.bubbled.grandParent = {order: 5};
-    run(config, three, startConfig(three.child, [three.child], [0]));
-
-    config = oneEventLoopTestConfig(three);
-    config.moveShouldSetResponder.captured.grandParent = {order: 0, returnVal: false};
-    config.moveShouldSetResponder.captured.parent = {order: 1, returnVal: true};
-    config.responderGrant.parent = {order: 2};
-    config.responderMove.parent = {order: 3};
-    run(config, three, moveConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(three.parent);
-
-    config = oneEventLoopTestConfig(three);
-    config.responderEnd.parent = {order: 0};
-    config.responderRelease.parent = {order: 1};
-    run(config, three, endConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(null);
-  });
-
-  it('should grant responder child while capturing move', () => {
-    var config = oneEventLoopTestConfig(three);
-
-    config.startShouldSetResponder.captured.grandParent = {order: 0};
-    config.startShouldSetResponder.captured.parent = {order: 1};
-    config.startShouldSetResponder.captured.child = {order: 2};
-    config.startShouldSetResponder.bubbled.child = {order: 3};
-    config.startShouldSetResponder.bubbled.parent = {order: 4};
-    config.startShouldSetResponder.bubbled.grandParent = {order: 5};
-    run(config, three, startConfig(three.child, [three.child], [0]));
-
-    config = oneEventLoopTestConfig(three);
-    config.moveShouldSetResponder.captured.grandParent = {order: 0, returnVal: false};
-    config.moveShouldSetResponder.captured.parent = {order: 1, returnVal: false};
-    config.moveShouldSetResponder.captured.child = {order: 2, returnVal: true};
-    config.responderGrant.child = {order: 3};
-    config.responderMove.child = {order: 4};
-    run(config, three, moveConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
-
-    config = oneEventLoopTestConfig(three);
-    config.responderEnd.child = {order: 0};
-    config.responderRelease.child = {order: 1};
-    run(config, three, endConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(null);
-  });
-
-  it('should grant responder child while bubbling move', () => {
-    var config = oneEventLoopTestConfig(three);
-
-    config.startShouldSetResponder.captured.grandParent = {order: 0};
-    config.startShouldSetResponder.captured.parent = {order: 1};
-    config.startShouldSetResponder.captured.child = {order: 2};
-    config.startShouldSetResponder.bubbled.child = {order: 3};
-    config.startShouldSetResponder.bubbled.parent = {order: 4};
-    config.startShouldSetResponder.bubbled.grandParent = {order: 5};
-    run(config, three, startConfig(three.child, [three.child], [0]));
-
-    config = oneEventLoopTestConfig(three);
-    config.moveShouldSetResponder.captured.grandParent = {order: 0, returnVal: false};
-    config.moveShouldSetResponder.captured.parent = {order: 1, returnVal: false};
-    config.moveShouldSetResponder.captured.child = {order: 2, returnVal: false};
-    config.moveShouldSetResponder.bubbled.child = {order: 3, returnVal: true};
-    config.responderGrant.child = {order: 4};
-    config.responderMove.child = {order: 5};
-    run(config, three, moveConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
-
-    config = oneEventLoopTestConfig(three);
-    config.responderEnd.child = {order: 0};
-    config.responderRelease.child = {order: 1};
-    run(config, three, endConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(null);
-  });
-
-  it('should grant responder parent while bubbling move', () => {
-    var config = oneEventLoopTestConfig(three);
-
-    config.startShouldSetResponder.captured.grandParent = {order: 0};
-    config.startShouldSetResponder.captured.parent = {order: 1};
-    config.startShouldSetResponder.captured.child = {order: 2};
-    config.startShouldSetResponder.bubbled.child = {order: 3};
-    config.startShouldSetResponder.bubbled.parent = {order: 4};
-    config.startShouldSetResponder.bubbled.grandParent = {order: 5};
-    run(config, three, startConfig(three.child, [three.child], [0]));
-
-    config = oneEventLoopTestConfig(three);
-    config.moveShouldSetResponder.captured.grandParent = {order: 0, returnVal: false};
-    config.moveShouldSetResponder.captured.parent = {order: 1, returnVal: false};
-    config.moveShouldSetResponder.captured.child = {order: 2, returnVal: false};
-    config.moveShouldSetResponder.bubbled.child = {order: 3, returnVal: false};
-    config.moveShouldSetResponder.bubbled.parent = {order: 4, returnVal: true};
-    config.responderGrant.parent = {order: 5};
-    config.responderMove.parent = {order: 6};
-    run(config, three, moveConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(three.parent);
-
-    config = oneEventLoopTestConfig(three);
-    config.responderEnd.parent = {order: 0};
-    config.responderRelease.parent = {order: 1};
-    run(config, three, endConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(null);
-  });
-
-  it('should grant responder grandParent while bubbling move', () => {
-    var config = oneEventLoopTestConfig(three);
-
-    config.startShouldSetResponder.captured.grandParent = {order: 0};
-    config.startShouldSetResponder.captured.parent = {order: 1};
-    config.startShouldSetResponder.captured.child = {order: 2};
-    config.startShouldSetResponder.bubbled.child = {order: 3};
-    config.startShouldSetResponder.bubbled.parent = {order: 4};
-    config.startShouldSetResponder.bubbled.grandParent = {order: 5};
-    run(config, three, startConfig(three.child, [three.child], [0]));
-
-    config = oneEventLoopTestConfig(three);
-    config.moveShouldSetResponder.captured.grandParent = {order: 0, returnVal: false};
-    config.moveShouldSetResponder.captured.parent = {order: 1, returnVal: false};
-    config.moveShouldSetResponder.captured.child = {order: 2, returnVal: false};
-    config.moveShouldSetResponder.bubbled.child = {order: 3, returnVal: false};
-    config.moveShouldSetResponder.bubbled.parent = {order: 4, returnVal: false};
-    config.moveShouldSetResponder.bubbled.grandParent = {order: 5, returnVal: true};
-    config.responderGrant.grandParent = {order: 6};
-    config.responderMove.grandParent = {order: 7};
-    run(config, three, moveConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(three.grandParent);
-
-    config = oneEventLoopTestConfig(three);
-    config.responderEnd.grandParent = {order: 0};
-    config.responderRelease.grandParent = {order: 1};
-    run(config, three, endConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(null);
-  });
-
-
-  /**
-   * Common ancestor tests
-   * ---------------------
-   */
-
-  it('should bubble negotiation to first common ancestor of responder', () => {
-    var config = oneEventLoopTestConfig(three);
-    config.startShouldSetResponder.captured.grandParent = {order: 0, returnVal: false};
-    config.startShouldSetResponder.captured.parent = {order: 1, returnVal: true};
-    config.responderGrant.parent = {order: 2};
-    config.responderStart.parent = {order: 3};
-    run(config, three, startConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(three.parent);
-
-    // While `parent` is still responder, we create new handlers that verify
-    // the ordering of propagation, restarting the count at `0`.
-    config = oneEventLoopTestConfig(three);
-    config.startShouldSetResponder.captured.grandParent = {order: 0, returnVal: false};
-
-    config.startShouldSetResponder.bubbled.grandParent = {order: 1, returnVal: false};
-    config.responderStart.parent = {order: 2};
-    run(config, three, startConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(three.parent);
-
-    config = oneEventLoopTestConfig(three);
-    config.responderEnd.parent = {order: 0};
-    config.responderRelease.parent = {order: 1};
-    run(config, three, endConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(null);
-  });
-
-  it('should bubble negotiation to first common ancestor of responder then transfer', () => {
-    var config = oneEventLoopTestConfig(three);
-    config.startShouldSetResponder.captured.grandParent = {order: 0, returnVal: false};
-    config.startShouldSetResponder.captured.parent = {order: 1, returnVal: true};
-    config.responderGrant.parent = {order: 2};
-    config.responderStart.parent = {order: 3};
-    run(config, three, startConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(three.parent);
-
-    config = oneEventLoopTestConfig(three);
-
-    // Parent is responder, and responder is transferred by a second touch start
-    config.startShouldSetResponder.captured.grandParent = {order: 0, returnVal: true};
-    config.responderGrant.grandParent = {order: 1};
-    config.responderTerminationRequest.parent = {order: 2, returnVal: true};
-    config.responderTerminate.parent = {order: 3};
-    config.responderStart.grandParent = {order: 4};
-    run(config, three, startConfig(three.child, [three.child, three.child], [1]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(three.grandParent);
-
-    config = oneEventLoopTestConfig(three);
-    config.responderEnd.grandParent = {order: 0};
-                                      // one remains\ /one ended \
-    run(config, three, endConfig(three.child, [three.child, three.child], [1]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(three.grandParent);
-
-    config = oneEventLoopTestConfig(three);
-    config.responderEnd.grandParent = {order: 0};
-    config.responderRelease.grandParent = {order: 1};
-    run(config, three, endConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(null);
-  });
-
-  /**
-   * If nothing is responder, then the negotiation should propagate directly to
-   * the deepest target in the second touch.
-   */
-  it('should negotiate with deepest target on second touch if nothing is responder', () => {
-    // Initially nothing wants to become the responder
-    var config = oneEventLoopTestConfig(three);
-    config.startShouldSetResponder.captured.grandParent = {order: 0, returnVal: false};
-    config.startShouldSetResponder.captured.parent = {order: 1, returnVal: false};
-    config.startShouldSetResponder.bubbled.parent = {order: 2, returnVal: false};
-    config.startShouldSetResponder.bubbled.grandParent = {order: 3, returnVal: false};
-
-    run(config, three, startConfig(three.parent, [three.parent], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(null);
-
-    config = oneEventLoopTestConfig(three);
-
-    // Now child wants to become responder. Negotiation should bubble as deep
-    // as the target is because we don't find first common ancestor (with
-    // current responder) because there is no current responder.
-    // (Even if this is the second active touch).
-    config.startShouldSetResponder.captured.grandParent = {order: 0, returnVal: false};
-    config.startShouldSetResponder.captured.parent = {order: 1, returnVal: false};
-    config.startShouldSetResponder.captured.child = {order: 2, returnVal: false};
-    config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: true};
-    config.responderGrant.child = {order: 4};
-    config.responderStart.child = {order: 5};
-    //                                     /  Two active touches  \  /one of them new\
-    run(config, three, startConfig(three.child, [three.parent, three.child], [1]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
-
-
-    // Now we remove the original first touch, keeping the second touch that
-    // started within the current responder (child). Nothing changes because
-    // there's still touches that started inside of the current responder.
-    config = oneEventLoopTestConfig(three);
-    config.responderEnd.child = {order: 0};
-    //                                      / one ended\  /one remains \
-    run(config, three, endConfig(three.child, [three.parent, three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
-
-    // Okay, now let's add back that first touch (nothing should change) and
-    // then we'll try peeling back the touches in the opposite order to make
-    // sure that first removing the second touch instantly causes responder to
-    // be released.
-    config = oneEventLoopTestConfig(three);
-    config.startShouldSetResponder.captured.grandParent = {order: 0, returnVal: false};
-    config.startShouldSetResponder.captured.parent = {order: 1, returnVal: false};
-    config.startShouldSetResponder.bubbled.parent = {order: 2, returnVal: false};
-    config.startShouldSetResponder.bubbled.grandParent = {order: 3, returnVal: false};
-    // Interesting: child still gets moves even though touch target is parent!
-    // Current responder gets a `responderStart` for any touch while responder.
-    config.responderStart.child = {order: 4};
-    //                                           /  Two active touches  \  /one of them new\
-    run(config, three, startConfig(three.parent, [three.child, three.parent], [1]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
-
-
-    // Now, move that new touch that had no effect, and did not start within
-    // the current responder.
-    config = oneEventLoopTestConfig(three);
-    config.moveShouldSetResponder.captured.grandParent = {order: 0, returnVal: false};
-    config.moveShouldSetResponder.captured.parent = {order: 1, returnVal: false};
-    config.moveShouldSetResponder.bubbled.parent = {order: 2, returnVal: false};
-    config.moveShouldSetResponder.bubbled.grandParent = {order: 3, returnVal: false};
-    // Interesting: child still gets moves even though touch target is parent!
-    // Current responder gets a `responderMove` for any touch while responder.
-    config.responderMove.child = {order: 4};
-    //                                     /  Two active touches  \  /one of them moved\
-    run(config, three, moveConfig(three.parent, [three.child, three.parent], [1]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
-
-
-    config = oneEventLoopTestConfig(three);
-    config.responderEnd.child = {order: 0};
-    config.responderRelease.child = {order: 1};
-    //                                        /child end \ /parent remain\
-    run(config, three, endConfig(three.child, [three.child, three.parent], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(null);
-  });
-
-
-  /**
-   * If nothing is responder, then the negotiation should propagate directly to
-   * the deepest target in the second touch.
-   */
-  it('should negotiate until first common ancestor when there are siblings', () => {
-    // Initially nothing wants to become the responder
-    var config = oneEventLoopTestConfig(siblings);
-    config.startShouldSetResponder.captured.parent = {order: 0, returnVal: false};
-    config.startShouldSetResponder.captured.childOne = {order: 1, returnVal: false};
-    config.startShouldSetResponder.bubbled.childOne = {order: 2, returnVal: true};
-    config.responderGrant.childOne = {order: 3};
-    config.responderStart.childOne = {order: 4};
-
-    run(config, siblings, startConfig(siblings.childOne, [siblings.childOne], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(siblings.childOne);
-
-    // If the touch target is the sibling item, the negotiation should only
-    // propagate to first common ancestor of current responder and sibling (so
-    // the parent).
-    config = oneEventLoopTestConfig(siblings);
-    config.startShouldSetResponder.captured.parent = {order: 0, returnVal: false};
-    config.startShouldSetResponder.bubbled.parent = {order: 1, returnVal: false};
-    config.responderStart.childOne = {order: 2};
-
-    var touchConfig =
-      startConfig(siblings.childTwo, [siblings.childOne, siblings.childTwo], [1]);
-    run(config, siblings, touchConfig);
-    expect(ResponderEventPlugin._getResponderID()).toBe(siblings.childOne);
-
-
-    // move childOne
-    config = oneEventLoopTestConfig(siblings);
-    config.moveShouldSetResponder.captured.parent = {order: 0, returnVal: false};
-    config.moveShouldSetResponder.bubbled.parent = {order: 1, returnVal: false};
-    config.responderMove.childOne = {order: 2};
-    run(config, siblings, moveConfig(siblings.childOne, [siblings.childOne, siblings.childTwo], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(siblings.childOne);
-
-    // move childTwo: Only negotiates to `parent`.
-    config = oneEventLoopTestConfig(siblings);
-    config.moveShouldSetResponder.captured.parent = {order: 0, returnVal: false};
-    config.moveShouldSetResponder.bubbled.parent = {order: 1, returnVal: false};
-    config.responderMove.childOne = {order: 2};
-    run(config, siblings, moveConfig(siblings.childTwo, [siblings.childOne, siblings.childTwo], [1]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(siblings.childOne);
-
-  });
-
-
-  it('should notify of being rejected. responderStart/Move happens on current responder', () => {
-    // Initially nothing wants to become the responder
-    var config = oneEventLoopTestConfig(three);
-    config.startShouldSetResponder.captured.grandParent = {order: 0, returnVal: false};
-    config.startShouldSetResponder.captured.parent = {order: 1, returnVal: false};
-    config.startShouldSetResponder.captured.child = {order: 2, returnVal: false};
-    config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: true};
-    config.responderGrant.child = {order: 4};
-    config.responderStart.child = {order: 5};
-
-    run(config, three, startConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
-
-    // Suppose parent wants to become responder on move, and is rejected
-    config = oneEventLoopTestConfig(three);
-    config.moveShouldSetResponder.captured.grandParent = {order: 0, returnVal: false};
-    config.moveShouldSetResponder.captured.parent = {order: 1, returnVal: false};
-    config.moveShouldSetResponder.bubbled.parent = {order: 2, returnVal: true};
-    config.responderGrant.parent = {order: 3};
-    config.responderTerminationRequest.child = {order: 4, returnVal: false};
-    config.responderReject.parent = {order: 5};
-    // The start/move should occur on the original responder if new one is rejected
-    config.responderMove.child = {order: 6};
-
-    var touchConfig =
-      moveConfig(three.child, [three.child], [0]);
-    run(config, three, touchConfig);
-    expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
-
-    config = oneEventLoopTestConfig(three);
-    config.startShouldSetResponder.captured.grandParent = {order: 0, returnVal: false};
-    config.startShouldSetResponder.captured.parent = {order: 1, returnVal: false};
-    config.startShouldSetResponder.bubbled.parent = {order: 2, returnVal: true};
-    config.responderGrant.parent = {order: 3};
-    config.responderTerminationRequest.child = {order: 4, returnVal: false};
-    config.responderReject.parent = {order: 5};
-    // The start/move should occur on the original responder if new one is rejected
-    config.responderStart.child = {order: 6};
-
-    touchConfig =
-      startConfig(three.child, [three.child, three.child], [1]);
-    run(config, three, touchConfig);
-    expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
-
-  });
-
-
-  it('should negotiate scroll', () => {
-    // Initially nothing wants to become the responder
-    var config = oneEventLoopTestConfig(three);
-    config.startShouldSetResponder.captured.grandParent = {order: 0, returnVal: false};
-    config.startShouldSetResponder.captured.parent = {order: 1, returnVal: false};
-    config.startShouldSetResponder.captured.child = {order: 2, returnVal: false};
-    config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: true};
-    config.responderGrant.child = {order: 4};
-    config.responderStart.child = {order: 5};
-
-    run(config, three, startConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
-
-    // If the touch target is the sibling item, the negotiation should only
-    // propagate to first common ancestor of current responder and sibling (so
-    // the parent).
-    config = oneEventLoopTestConfig(three);
-    config.scrollShouldSetResponder.captured.grandParent = {order: 0, returnVal: false};
-    config.scrollShouldSetResponder.captured.parent = {order: 1, returnVal: false};
-    config.scrollShouldSetResponder.bubbled.parent = {order: 2, returnVal: true};
-    config.responderGrant.parent = {order: 3};
-    config.responderTerminationRequest.child = {order: 4, returnVal: false};
-    config.responderReject.parent = {order: 5};
-
-    run(config, three, {
-      topLevelType: topLevelTypes.topScroll,
-      targetInst: idToInstance[three.parent],
-      nativeEvent: {},
-    });
-    expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
-
-
-    // Now lets let the scroll take control this time.
-    config = oneEventLoopTestConfig(three);
-    config.scrollShouldSetResponder.captured.grandParent = {order: 0, returnVal: false};
-    config.scrollShouldSetResponder.captured.parent = {order: 1, returnVal: false};
-    config.scrollShouldSetResponder.bubbled.parent = {order: 2, returnVal: true};
-    config.responderGrant.parent = {order: 3};
-    config.responderTerminationRequest.child = {order: 4, returnVal: true};
-    config.responderTerminate.child = {order: 5};
-
-    run(config, three, {
-      topLevelType: topLevelTypes.topScroll,
-      targetInst: idToInstance[three.parent],
-      nativeEvent: {},
-    });
-    expect(ResponderEventPlugin._getResponderID()).toBe(three.parent);
-
-
-  });
-
-  it('should cancel correctly', () => {
-    // Initially our child becomes responder
-    var config = oneEventLoopTestConfig(three);
-    config.startShouldSetResponder.captured.grandParent = {order: 0, returnVal: false};
-    config.startShouldSetResponder.captured.parent = {order: 1, returnVal: false};
-    config.startShouldSetResponder.captured.child = {order: 2, returnVal: false};
-    config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: true};
-    config.responderGrant.child = {order: 4};
-    config.responderStart.child = {order: 5};
-
-    run(config, three, startConfig(three.child, [three.child], [0]));
-    expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
-
-    config = oneEventLoopTestConfig(three);
-    config.responderEnd.child = {order: 0};
-    config.responderTerminate.child = {order: 1};
-
-    var nativeEvent = _touchConfig(
-      topLevelTypes.topTouchCancel,
-      three.child,
-      [three.child],
-      [0]
-    );
-    run(config, three, nativeEvent);
-    expect(ResponderEventPlugin._getResponderID()).toBe(null);
-  });
-});
diff --git a/src/renderers/shared/fiber/ReactChildFiber.js b/src/renderers/shared/fiber/ReactChildFiber.js
new file mode 100644
index 000000000000..31d186022c1e
--- /dev/null
+++ b/src/renderers/shared/fiber/ReactChildFiber.js
@@ -0,0 +1,294 @@
+/**
+ * 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 ReactChildFiber
+ * @flow
+ */
+
+'use strict';
+
+import type {ReactCoroutine, ReactYield} from 'ReactCoroutine';
+import type {Fiber} from 'ReactFiber';
+import type {PriorityLevel} from 'ReactPriorityLevel';
+
+import type {ReactNodeList} from 'ReactTypes';
+
+var REACT_ELEMENT_TYPE = require('ReactElementSymbol');
+var {REACT_COROUTINE_TYPE, REACT_YIELD_TYPE} = require('ReactCoroutine');
+
+var ReactFiber = require('ReactFiber');
+var ReactReifiedYield = require('ReactReifiedYield');
+
+const {
+  cloneFiber,
+  createFiberFromElement,
+  createFiberFromCoroutine,
+  createFiberFromYield,
+} = ReactFiber;
+
+const {createReifiedYield} = ReactReifiedYield;
+
+const isArray = Array.isArray;
+
+function ChildReconciler(shouldClone) {
+  function createSubsequentChild(
+    returnFiber: Fiber,
+    existingChild: ?Fiber,
+    previousSibling: Fiber,
+    newChildren,
+    priority: PriorityLevel,
+  ): Fiber {
+    if (typeof newChildren !== 'object' || newChildren === null) {
+      return previousSibling;
+    }
+
+    switch (newChildren.$$typeof) {
+      case REACT_ELEMENT_TYPE: {
+        const element = (newChildren: ReactElement<any>);
+        if (
+          existingChild &&
+          element.type === existingChild.type &&
+          element.key === existingChild.key
+        ) {
+          // TODO: This is not sufficient since previous siblings could be new.
+          // Will fix reconciliation properly later.
+          const clone = shouldClone
+            ? cloneFiber(existingChild, priority)
+            : existingChild;
+          if (!shouldClone) {
+            // TODO: This might be lowering the priority of nested unfinished work.
+            clone.pendingWorkPriority = priority;
+          }
+          clone.pendingProps = element.props;
+          clone.sibling = null;
+          clone.return = returnFiber;
+          previousSibling.sibling = clone;
+          return clone;
+        }
+        const child = createFiberFromElement(element, priority);
+        previousSibling.sibling = child;
+        child.return = returnFiber;
+        return child;
+      }
+
+      case REACT_COROUTINE_TYPE: {
+        const coroutine = (newChildren: ReactCoroutine);
+        const child = createFiberFromCoroutine(coroutine, priority);
+        previousSibling.sibling = child;
+        child.return = returnFiber;
+        return child;
+      }
+
+      case REACT_YIELD_TYPE: {
+        const yieldNode = (newChildren: ReactYield);
+        const reifiedYield = createReifiedYield(yieldNode);
+        const child = createFiberFromYield(yieldNode, priority);
+        child.output = reifiedYield;
+        previousSibling.sibling = child;
+        child.return = returnFiber;
+        return child;
+      }
+    }
+
+    if (isArray(newChildren)) {
+      let prev: Fiber = previousSibling;
+      let existing: ?Fiber = existingChild;
+      for (var i = 0; i < newChildren.length; i++) {
+        var nextExisting = existing && existing.sibling;
+        prev = createSubsequentChild(
+          returnFiber,
+          existing,
+          prev,
+          newChildren[i],
+          priority,
+        );
+        if (prev && existing) {
+          // TODO: This is not correct because there could've been more
+          // than one sibling consumed but I don't want to return a tuple.
+          existing = nextExisting;
+        }
+      }
+      return prev;
+    } else {
+      // TODO: Throw for unknown children.
+      return previousSibling;
+    }
+  }
+
+  function createFirstChild(returnFiber, existingChild, newChildren, priority) {
+    if (typeof newChildren !== 'object' || newChildren === null) {
+      return null;
+    }
+
+    switch (newChildren.$$typeof) {
+      case REACT_ELEMENT_TYPE: {
+        /* $FlowFixMe(>=0.31.0): This is an unsafe cast. Consider adding a type
+         *                       annotation to the `newChildren` param of this
+         *                       function.
+         */
+        const element = (newChildren: ReactElement<any>);
+        if (
+          existingChild &&
+          element.type === existingChild.type &&
+          element.key === existingChild.key
+        ) {
+          // Get the clone of the existing fiber.
+          const clone = shouldClone
+            ? cloneFiber(existingChild, priority)
+            : existingChild;
+          if (!shouldClone) {
+            // TODO: This might be lowering the priority of nested unfinished work.
+            clone.pendingWorkPriority = priority;
+          }
+          clone.pendingProps = element.props;
+          clone.sibling = null;
+          clone.return = returnFiber;
+          return clone;
+        }
+        const child = createFiberFromElement(element, priority);
+        child.return = returnFiber;
+        return child;
+      }
+
+      case REACT_COROUTINE_TYPE: {
+        /* $FlowFixMe(>=0.31.0): No 'handler' property found in object type
+         */
+        const coroutine = (newChildren: ReactCoroutine);
+        const child = createFiberFromCoroutine(coroutine, priority);
+        child.return = returnFiber;
+        return child;
+      }
+
+      case REACT_YIELD_TYPE: {
+        // A yield results in a fragment fiber whose output is the continuation.
+        // TODO: When there is only a single child, we can optimize this to avoid
+        // the fragment.
+        /* $FlowFixMe(>=0.31.0): No 'continuation' property found in object
+         * type
+         */
+        const yieldNode = (newChildren: ReactYield);
+        const reifiedYield = createReifiedYield(yieldNode);
+        const child = createFiberFromYield(yieldNode, priority);
+        child.output = reifiedYield;
+        child.return = returnFiber;
+        return child;
+      }
+    }
+
+    if (isArray(newChildren)) {
+      var first: ?Fiber = null;
+      var prev: ?Fiber = null;
+      var existing: ?Fiber = existingChild;
+      /* $FlowIssue(>=0.31.0) #12747709
+       *
+       * `Array.isArray` is matched syntactically for now until predicate
+       * support is complete.
+       */
+      for (var i = 0; i < newChildren.length; i++) {
+        var nextExisting = existing && existing.sibling;
+        if (prev == null) {
+          prev = createFirstChild(
+            returnFiber,
+            existing,
+            newChildren[i],
+            priority,
+          );
+          first = prev;
+        } else {
+          prev = createSubsequentChild(
+            returnFiber,
+            existing,
+            prev,
+            newChildren[i],
+            priority,
+          );
+        }
+        if (prev && existing) {
+          // TODO: This is not correct because there could've been more
+          // than one sibling consumed but I don't want to return a tuple.
+          existing = nextExisting;
+        }
+      }
+      return first;
+    } else {
+      // TODO: Throw for unknown children.
+      return null;
+    }
+  }
+
+  // TODO: This API won't work because we'll need to transfer the side-effects of
+  // unmounting children to the returnFiber.
+  function reconcileChildFibers(
+    returnFiber: Fiber,
+    currentFirstChild: ?Fiber,
+    newChildren: ReactNodeList,
+    priority: PriorityLevel,
+  ): ?Fiber {
+    return createFirstChild(
+      returnFiber,
+      currentFirstChild,
+      newChildren,
+      priority,
+    );
+  }
+
+  return reconcileChildFibers;
+}
+
+exports.reconcileChildFibers = ChildReconciler(true);
+
+exports.reconcileChildFibersInPlace = ChildReconciler(false);
+
+function cloneSiblings(
+  current: Fiber,
+  workInProgress: Fiber,
+  returnFiber: Fiber,
+) {
+  workInProgress.return = returnFiber;
+  while (current.sibling) {
+    current = current.sibling;
+    workInProgress = workInProgress.sibling = cloneFiber(
+      current,
+      current.pendingWorkPriority,
+    );
+    workInProgress.return = returnFiber;
+  }
+  workInProgress.sibling = null;
+}
+
+exports.cloneChildFibers = function(current: ?Fiber, workInProgress: Fiber) {
+  if (!workInProgress.child) {
+    return;
+  }
+  if (current && workInProgress.child === current.child) {
+    // We use workInProgress.child since that lets Flow know that it can't be
+    // null since we validated that already. However, as the line above suggests
+    // they're actually the same thing.
+    const currentChild = workInProgress.child;
+    // TODO: This used to reset the pending priority. Not sure if that is needed.
+    // workInProgress.pendingWorkPriority = current.pendingWorkPriority;
+    // TODO: The below priority used to be set to NoWork which would've
+    // dropped work. This is currently unobservable but will become
+    // observable when the first sibling has lower priority work remaining
+    // than the next sibling. At that point we should add tests that catches
+    // this.
+    const newChild = cloneFiber(currentChild, currentChild.pendingWorkPriority);
+    workInProgress.child = newChild;
+    cloneSiblings(currentChild, newChild, workInProgress);
+  }
+
+  // If there is no alternate, then we don't need to clone the children.
+  // If the children of the alternate fiber is a different set, then we don't
+  // need to clone. We need to reset the return fiber though since we'll
+  // traverse down into them.
+  let child = workInProgress.child;
+  while (child) {
+    child.return = workInProgress;
+    child = child.sibling;
+  }
+};
diff --git a/src/renderers/shared/fiber/ReactFiber.js b/src/renderers/shared/fiber/ReactFiber.js
new file mode 100644
index 000000000000..6bd8c0e9a661
--- /dev/null
+++ b/src/renderers/shared/fiber/ReactFiber.js
@@ -0,0 +1,285 @@
+/**
+ * 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 ReactFiber
+ * @flow
+ */
+
+'use strict';
+
+import type {ReactCoroutine, ReactYield} from 'ReactCoroutine';
+import type {TypeOfWork} from 'ReactTypeOfWork';
+import type {PriorityLevel} from 'ReactPriorityLevel';
+import type {UpdateQueue} from 'ReactFiberUpdateQueue';
+
+var ReactTypeOfWork = require('ReactTypeOfWork');
+var {
+  IndeterminateComponent,
+  ClassComponent,
+  HostContainer,
+  HostComponent,
+  CoroutineComponent,
+  YieldComponent,
+} = ReactTypeOfWork;
+
+var {NoWork} = require('ReactPriorityLevel');
+
+// An Instance is shared between all versions of a component. We can easily
+// break this out into a separate object to avoid copying so much to the
+// alternate versions of the tree. We put this on a single object for now to
+// minimize the number of objects created during the initial render.
+type Instance = {
+  // Tag identifying the type of fiber.
+  tag: TypeOfWork,
+
+  // Unique identifier of this child.
+  key: null | string,
+
+  // The function/class/module associated with this fiber.
+  type: any,
+
+  // The local state associated with this fiber.
+  stateNode: any,
+
+  // Conceptual aliases
+  // parent : Instance -> return The parent happens to be the same as the
+  // return fiber since we've merged the fiber and instance.
+};
+
+// A Fiber is work on a Component that needs to be done or was done. There can
+// be more than one per component.
+export type Fiber = Instance & {
+  // The Fiber to return to after finishing processing this one.
+  // This is effectively the parent, but there can be multiple parents (two)
+  // so this is only the parent of the thing we're currently processing.
+  // It is conceptually the same as the return address of a stack frame.
+  return: ?Fiber,
+
+  // Singly Linked List Tree Structure.
+  child: ?Fiber,
+  sibling: ?Fiber,
+
+  // The ref last used to attach this node.
+  // I'll avoid adding an owner field for prod and model that as functions.
+  ref: null | ((handle: ?Object) => void),
+
+  // Input is the data coming into process this fiber. Arguments. Props.
+  pendingProps: any, // This type will be more specific once we overload the tag.
+  // TODO: I think that there is a way to merge pendingProps and memoizedProps.
+  memoizedProps: any, // The props used to create the output.
+  // A queue of local state updates.
+  updateQueue: ?UpdateQueue,
+  // The state used to create the output. This is a full state object.
+  memoizedState: any,
+  // Linked list of callbacks to call after updates are committed.
+  callbackList: ?UpdateQueue,
+  // Output is the return value of this fiber, or a linked list of return values
+  // if this returns multiple values. Such as a fragment.
+  output: any, // This type will be more specific once we overload the tag.
+
+  // Singly linked list fast path to the next fiber with side-effects.
+  nextEffect: ?Fiber,
+
+  // The first and last fiber with side-effect within this subtree. This allows
+  // us to reuse a slice of the linked list when we reuse the work done within
+  // this fiber.
+  firstEffect: ?Fiber,
+  lastEffect: ?Fiber,
+
+  // This will be used to quickly determine if a subtree has no pending changes.
+  pendingWorkPriority: PriorityLevel,
+
+  // This value represents the priority level that was last used to process this
+  // component. This indicates whether it is better to continue from the
+  // progressed work or if it is better to continue from the current state.
+  progressedPriority: PriorityLevel,
+
+  // If work bails out on a Fiber that already had some work started at a lower
+  // priority, then we need to store the progressed work somewhere. This holds
+  // the started child set until we need to get back to working on it. It may
+  // or may not be the same as the "current" child.
+  progressedChild: ?Fiber,
+
+  // This is a pooled version of a Fiber. Every fiber that gets updated will
+  // eventually have a pair. There are cases when we can clean up pairs to save
+  // memory if we need to.
+  alternate: ?Fiber,
+
+  // Conceptual aliases
+  // workInProgress : Fiber ->  alternate The alternate used for reuse happens
+  // to be the same as work in progress.
+};
+
+// This is a constructor of a POJO instead of a constructor function for a few
+// reasons:
+// 1) Nobody should add any instance methods on this. Instance methods can be
+//    more difficult to predict when they get optimized and they are almost
+//    never inlined properly in static compilers.
+// 2) Nobody should rely on `instanceof Fiber` for type testing. We should
+//    always know when it is a fiber.
+// 3) We can easily go from a createFiber call to calling a constructor if that
+//    is faster. The opposite is not true.
+// 4) We might want to experiment with using numeric keys since they are easier
+//    to optimize in a non-JIT environment.
+// 5) It should be easy to port this to a C struct and keep a C implementation
+//    compatible.
+var createFiber = function(tag: TypeOfWork, key: null | string): Fiber {
+  return {
+    // Instance
+
+    tag: tag,
+
+    key: key,
+
+    type: null,
+
+    stateNode: null,
+
+    // Fiber
+
+    return: null,
+
+    child: null,
+    sibling: null,
+
+    ref: null,
+
+    pendingProps: null,
+    memoizedProps: null,
+    updateQueue: null,
+    memoizedState: null,
+    callbackList: null,
+    output: null,
+
+    nextEffect: null,
+    firstEffect: null,
+    lastEffect: null,
+
+    pendingWorkPriority: NoWork,
+    progressedPriority: NoWork,
+    progressedChild: null,
+
+    alternate: null,
+  };
+};
+
+function shouldConstruct(Component) {
+  return !!(Component.prototype && Component.prototype.isReactComponent);
+}
+
+// This is used to create an alternate fiber to do work on.
+// TODO: Rename to createWorkInProgressFiber or something like that.
+exports.cloneFiber = function(
+  fiber: Fiber,
+  priorityLevel: PriorityLevel,
+): Fiber {
+  // We clone to get a work in progress. That means that this fiber is the
+  // current. To make it safe to reuse that fiber later on as work in progress
+  // we need to reset its work in progress flag now. We don't have an
+  // opportunity to do this earlier since we don't traverse the tree when
+  // the work in progress tree becomes the current tree.
+  // fiber.progressedPriority = NoWork;
+  // fiber.progressedChild = null;
+
+  // We use a double buffering pooling technique because we know that we'll only
+  // ever need at most two versions of a tree. We pool the "other" unused node
+  // that we're free to reuse. This is lazily created to avoid allocating extra
+  // objects for things that are never updated. It also allow us to reclaim the
+  // extra memory if needed.
+  let alt = fiber.alternate;
+  if (alt) {
+    // Whenever we clone, we do so to get a new work in progress.
+    // This ensures that we've reset these in the new tree.
+    alt.nextEffect = null;
+    alt.firstEffect = null;
+    alt.lastEffect = null;
+  } else {
+    // This should not have an alternate already
+    alt = createFiber(fiber.tag, fiber.key);
+    alt.type = fiber.type;
+
+    alt.progressedChild = fiber.progressedChild;
+    alt.progressedPriority = fiber.progressedPriority;
+
+    alt.alternate = fiber;
+    fiber.alternate = alt;
+  }
+
+  alt.stateNode = fiber.stateNode;
+  alt.child = fiber.child;
+  alt.sibling = fiber.sibling; // This should always be overridden. TODO: null
+  alt.ref = fiber.ref;
+  // pendingProps is here for symmetry but is unnecessary in practice for now.
+  // TODO: Pass in the new pendingProps as an argument maybe?
+  alt.pendingProps = fiber.pendingProps;
+  alt.updateQueue = fiber.updateQueue;
+  alt.callbackList = fiber.callbackList;
+  alt.pendingWorkPriority = priorityLevel;
+
+  alt.memoizedProps = fiber.memoizedProps;
+  alt.output = fiber.output;
+
+  return alt;
+};
+
+exports.createHostContainerFiber = function() {
+  const fiber = createFiber(HostContainer, null);
+  return fiber;
+};
+
+exports.createFiberFromElement = function(
+  element: ReactElement<*>,
+  priorityLevel: PriorityLevel,
+) {
+  // $FlowFixMe: ReactElement.key is currently defined as ?string but should be defined as null | string in Flow.
+  const fiber = createFiberFromElementType(element.type, element.key);
+  fiber.pendingProps = element.props;
+  fiber.pendingWorkPriority = priorityLevel;
+  return fiber;
+};
+
+function createFiberFromElementType(type: mixed, key: null | string) {
+  let fiber;
+  if (typeof type === 'function') {
+    fiber = shouldConstruct(type)
+      ? createFiber(ClassComponent, key)
+      : createFiber(IndeterminateComponent, key);
+    fiber.type = type;
+  } else if (typeof type === 'string') {
+    fiber = createFiber(HostComponent, key);
+    fiber.type = type;
+  } else if (typeof type === 'object' && type !== null) {
+    // Currently assumed to be a continuation and therefore is a fiber already.
+    fiber = ((type: any): Fiber);
+  } else {
+    throw new Error('Unknown component type: ' + typeof type);
+  }
+  return fiber;
+}
+
+exports.createFiberFromElementType = createFiberFromElementType;
+
+exports.createFiberFromCoroutine = function(
+  coroutine: ReactCoroutine,
+  priorityLevel: PriorityLevel,
+) {
+  const fiber = createFiber(CoroutineComponent, coroutine.key);
+  fiber.type = coroutine.handler;
+  fiber.pendingProps = coroutine;
+  fiber.pendingWorkPriority = priorityLevel;
+  return fiber;
+};
+
+exports.createFiberFromYield = function(
+  yieldNode: ReactYield,
+  priorityLevel: PriorityLevel,
+) {
+  const fiber = createFiber(YieldComponent, yieldNode.key);
+  fiber.pendingProps = {};
+  return fiber;
+};
diff --git a/src/renderers/shared/fiber/ReactFiberBeginWork.js b/src/renderers/shared/fiber/ReactFiberBeginWork.js
new file mode 100644
index 000000000000..107c3fce7ccc
--- /dev/null
+++ b/src/renderers/shared/fiber/ReactFiberBeginWork.js
@@ -0,0 +1,466 @@
+/**
+ * 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 ReactFiberBeginWork
+ * @flow
+ */
+
+'use strict';
+
+import type {ReactCoroutine} from 'ReactCoroutine';
+import type {Fiber} from 'ReactFiber';
+import type {FiberRoot} from 'ReactFiberRoot';
+import type {HostConfig} from 'ReactFiberReconciler';
+import type {Scheduler} from 'ReactFiberScheduler';
+import type {PriorityLevel} from 'ReactPriorityLevel';
+import type {UpdateQueue} from 'ReactFiberUpdateQueue';
+
+var {
+  reconcileChildFibers,
+  reconcileChildFibersInPlace,
+  cloneChildFibers,
+} = require('ReactChildFiber');
+var {LowPriority} = require('ReactPriorityLevel');
+var ReactTypeOfWork = require('ReactTypeOfWork');
+var {
+  IndeterminateComponent,
+  FunctionalComponent,
+  ClassComponent,
+  HostContainer,
+  HostComponent,
+  CoroutineComponent,
+  CoroutineHandlerPhase,
+  YieldComponent,
+} = ReactTypeOfWork;
+var {NoWork, OffscreenPriority} = require('ReactPriorityLevel');
+var {
+  createUpdateQueue,
+  addToQueue,
+  addCallbackToQueue,
+  mergeUpdateQueue,
+} = require('ReactFiberUpdateQueue');
+var ReactInstanceMap = require('ReactInstanceMap');
+
+module.exports = function<T, P, I, C>(
+  config: HostConfig<T, P, I, C>,
+  getScheduler: () => Scheduler,
+) {
+  function markChildAsProgressed(current, workInProgress, priorityLevel) {
+    // We now have clones. Let's store them as the currently progressed work.
+    workInProgress.progressedChild = workInProgress.child;
+    workInProgress.progressedPriority = priorityLevel;
+    if (current) {
+      // We also store it on the current. When the alternate swaps in we can
+      // continue from this point.
+      current.progressedChild = workInProgress.progressedChild;
+      current.progressedPriority = workInProgress.progressedPriority;
+    }
+  }
+
+  function reconcileChildren(current, workInProgress, nextChildren) {
+    const priorityLevel = workInProgress.pendingWorkPriority;
+    reconcileChildrenAtPriority(
+      current,
+      workInProgress,
+      nextChildren,
+      priorityLevel,
+    );
+  }
+
+  function reconcileChildrenAtPriority(
+    current,
+    workInProgress,
+    nextChildren,
+    priorityLevel,
+  ) {
+    // At this point any memoization is no longer valid since we'll have changed
+    // the children.
+    workInProgress.memoizedProps = null;
+    if (current && current.child === workInProgress.child) {
+      // If the current child is the same as the work in progress, it means that
+      // we haven't yet started any work on these children. Therefore, we use
+      // the clone algorithm to create a copy of all the current children.
+      workInProgress.child = reconcileChildFibers(
+        workInProgress,
+        workInProgress.child,
+        nextChildren,
+        priorityLevel,
+      );
+    } else {
+      // If, on the other hand, we don't have a current fiber or if it is
+      // already using a clone, that means we've already begun some work on this
+      // tree and we can continue where we left off by reconciling against the
+      // existing children.
+      workInProgress.child = reconcileChildFibersInPlace(
+        workInProgress,
+        workInProgress.child,
+        nextChildren,
+        priorityLevel,
+      );
+    }
+    markChildAsProgressed(current, workInProgress, priorityLevel);
+  }
+
+  function updateFunctionalComponent(current, workInProgress) {
+    var fn = workInProgress.type;
+    var props = workInProgress.pendingProps;
+
+    // TODO: Disable this before release, since it is not part of the public API
+    // I use this for testing to compare the relative overhead of classes.
+    if (typeof fn.shouldComponentUpdate === 'function') {
+      if (workInProgress.memoizedProps !== null) {
+        if (!fn.shouldComponentUpdate(workInProgress.memoizedProps, props)) {
+          return bailoutOnAlreadyFinishedWork(current, workInProgress);
+        }
+      }
+    }
+
+    var nextChildren = fn(props);
+    reconcileChildren(current, workInProgress, nextChildren);
+    return workInProgress.child;
+  }
+
+  function scheduleUpdate(
+    fiber: Fiber,
+    updateQueue: UpdateQueue,
+    priorityLevel: PriorityLevel,
+  ): void {
+    const {scheduleDeferredWork} = getScheduler();
+    fiber.updateQueue = updateQueue;
+    // Schedule update on the alternate as well, since we don't know which tree
+    // is current.
+    if (fiber.alternate) {
+      fiber.alternate.updateQueue = updateQueue;
+    }
+    while (true) {
+      if (
+        fiber.pendingWorkPriority === NoWork ||
+        fiber.pendingWorkPriority >= priorityLevel
+      ) {
+        fiber.pendingWorkPriority = priorityLevel;
+      }
+      if (fiber.alternate) {
+        if (
+          fiber.alternate.pendingWorkPriority === NoWork ||
+          fiber.alternate.pendingWorkPriority >= priorityLevel
+        ) {
+          fiber.alternate.pendingWorkPriority = priorityLevel;
+        }
+      }
+      // Duck type root
+      if (fiber.stateNode && fiber.stateNode.containerInfo) {
+        const root: FiberRoot = (fiber.stateNode: any);
+        scheduleDeferredWork(root, priorityLevel);
+        return;
+      }
+      if (!fiber.return) {
+        throw new Error('No root!');
+      }
+      fiber = fiber.return;
+    }
+  }
+
+  // Class component state updater
+  const updater = {
+    enqueueSetState(instance, partialState) {
+      const fiber = ReactInstanceMap.get(instance);
+      const updateQueue = fiber.updateQueue
+        ? addToQueue(fiber.updateQueue, partialState)
+        : createUpdateQueue(partialState);
+      scheduleUpdate(fiber, updateQueue, LowPriority);
+    },
+    enqueueReplaceState(instance, state) {
+      const fiber = ReactInstanceMap.get(instance);
+      const updateQueue = createUpdateQueue(state);
+      updateQueue.isReplace = true;
+      scheduleUpdate(fiber, updateQueue, LowPriority);
+    },
+    enqueueForceUpdate(instance) {
+      const fiber = ReactInstanceMap.get(instance);
+      const updateQueue = fiber.updateQueue || createUpdateQueue(null);
+      updateQueue.isForced = true;
+      scheduleUpdate(fiber, updateQueue, LowPriority);
+    },
+    enqueueCallback(instance, callback) {
+      const fiber = ReactInstanceMap.get(instance);
+      let updateQueue = fiber.updateQueue
+        ? fiber.updateQueue
+        : createUpdateQueue(null);
+      addCallbackToQueue(updateQueue, callback);
+      fiber.updateQueue = updateQueue;
+      if (fiber.alternate) {
+        fiber.alternate.updateQueue = updateQueue;
+      }
+    },
+  };
+
+  function updateClassComponent(current: ?Fiber, workInProgress: Fiber) {
+    // A class component update is the result of either new props or new state.
+    // Account for the possibly of missing pending props by falling back to the
+    // memoized props.
+    var props = workInProgress.pendingProps;
+    if (!props && current) {
+      props = current.memoizedProps;
+    }
+    // Compute the state using the memoized state and the update queue.
+    var updateQueue = workInProgress.updateQueue;
+    var previousState = current ? current.memoizedState : null;
+    var state = updateQueue
+      ? mergeUpdateQueue(updateQueue, previousState, props)
+      : previousState;
+
+    var instance = workInProgress.stateNode;
+    if (!instance) {
+      var ctor = workInProgress.type;
+      workInProgress.stateNode = instance = new ctor(props);
+      state = instance.state || null;
+      // The initial state must be added to the update queue in case
+      // setState is called before the initial render.
+      if (state !== null) {
+        workInProgress.updateQueue = createUpdateQueue(state);
+      }
+      // The instance needs access to the fiber so that it can schedule updates
+      ReactInstanceMap.set(instance, workInProgress);
+      instance.updater = updater;
+    } else if (
+      typeof instance.shouldComponentUpdate === 'function' &&
+      !(updateQueue && updateQueue.isForced)
+    ) {
+      if (workInProgress.memoizedProps !== null) {
+        // Reset the props, in case this is a ping-pong case rather than a
+        // completed update case. For the completed update case, the instance
+        // props will already be the memoizedProps.
+        instance.props = workInProgress.memoizedProps;
+        instance.state = workInProgress.memoizedState;
+        if (!instance.shouldComponentUpdate(props, state)) {
+          return bailoutOnAlreadyFinishedWork(current, workInProgress);
+        }
+      }
+    }
+
+    instance.props = props;
+    instance.state = state;
+    var nextChildren = instance.render();
+    reconcileChildren(current, workInProgress, nextChildren);
+
+    return workInProgress.child;
+  }
+
+  function updateHostComponent(current, workInProgress) {
+    const nextChildren = workInProgress.pendingProps.children;
+    if (
+      workInProgress.pendingProps.hidden &&
+      workInProgress.pendingWorkPriority !== OffscreenPriority
+    ) {
+      // If this host component is hidden, we can bail out on the children.
+      // We'll rerender the children later at the lower priority.
+
+      // It is unfortunate that we have to do the reconciliation of these
+      // children already since that will add them to the tree even though
+      // they are not actually done yet. If this is a large set it is also
+      // confusing that this takes time to do right now instead of later.
+
+      if (workInProgress.progressedPriority === OffscreenPriority) {
+        // If we already made some progress on the offscreen priority before,
+        // then we should continue from where we left off.
+        workInProgress.child = workInProgress.progressedChild;
+      }
+
+      // Reconcile the children and stash them for later work.
+      reconcileChildrenAtPriority(
+        current,
+        workInProgress,
+        nextChildren,
+        OffscreenPriority,
+      );
+      workInProgress.child = current ? current.child : null;
+      // Abort and don't process children yet.
+      return null;
+    } else {
+      reconcileChildren(current, workInProgress, nextChildren);
+      return workInProgress.child;
+    }
+  }
+
+  function mountIndeterminateComponent(current, workInProgress) {
+    var fn = workInProgress.type;
+    var props = workInProgress.pendingProps;
+    var value = fn(props);
+    if (
+      typeof value === 'object' &&
+      value &&
+      typeof value.render === 'function'
+    ) {
+      // Proceed under the assumption that this is a class instance
+      workInProgress.tag = ClassComponent;
+      if (current) {
+        current.tag = ClassComponent;
+      }
+      value = value.render();
+    } else {
+      // Proceed under the assumption that this is a functional component
+      workInProgress.tag = FunctionalComponent;
+      if (current) {
+        current.tag = FunctionalComponent;
+      }
+    }
+    reconcileChildren(current, workInProgress, value);
+    return workInProgress.child;
+  }
+
+  function updateCoroutineComponent(current, workInProgress) {
+    var coroutine = (workInProgress.pendingProps: ?ReactCoroutine);
+    if (!coroutine) {
+      throw new Error('Should be resolved by now');
+    }
+    reconcileChildren(current, workInProgress, coroutine.children);
+  }
+
+  /*
+  function reuseChildrenEffects(returnFiber : Fiber, firstChild : Fiber) {
+    let child = firstChild;
+    do {
+      // Ensure that the first and last effect of the parent corresponds
+      // to the children's first and last effect.
+      if (!returnFiber.firstEffect) {
+        returnFiber.firstEffect = child.firstEffect;
+      }
+      if (child.lastEffect) {
+        if (returnFiber.lastEffect) {
+          returnFiber.lastEffect.nextEffect = child.firstEffect;
+        }
+        returnFiber.lastEffect = child.lastEffect;
+      }
+    } while (child = child.sibling);
+  }
+  */
+
+  function bailoutOnAlreadyFinishedWork(
+    current,
+    workInProgress: Fiber,
+  ): ?Fiber {
+    const priorityLevel = workInProgress.pendingWorkPriority;
+
+    // TODO: We should ideally be able to bail out early if the children have no
+    // more work to do. However, since we don't have a separation of this
+    // Fiber's priority and its children yet - we don't know without doing lots
+    // of the same work we do anyway. Once we have that separation we can just
+    // bail out here if the children has no more work at this priority level.
+    // if (workInProgress.priorityOfChildren <= priorityLevel) {
+    //   // If there are side-effects in these children that have not yet been
+    //   // committed we need to ensure that they get properly transferred up.
+    //   if (current && current.child !== workInProgress.child) {
+    //     reuseChildrenEffects(workInProgress, child);
+    //   }
+    //   return null;
+    // }
+
+    cloneChildFibers(current, workInProgress);
+    markChildAsProgressed(current, workInProgress, priorityLevel);
+    return workInProgress.child;
+  }
+
+  function bailoutOnLowPriority(current, workInProgress) {
+    if (current) {
+      workInProgress.child = current.child;
+      workInProgress.memoizedProps = current.memoizedProps;
+      workInProgress.output = current.output;
+    }
+    return null;
+  }
+
+  function beginWork(
+    current: ?Fiber,
+    workInProgress: Fiber,
+    priorityLevel: PriorityLevel,
+  ): ?Fiber {
+    if (
+      workInProgress.pendingWorkPriority === NoWork ||
+      workInProgress.pendingWorkPriority > priorityLevel
+    ) {
+      return bailoutOnLowPriority(current, workInProgress);
+    }
+
+    if (workInProgress.progressedPriority === priorityLevel) {
+      // If we have progressed work on this priority level already, we can
+      // proceed this that as the child.
+      workInProgress.child = workInProgress.progressedChild;
+    }
+
+    if (
+      (workInProgress.pendingProps === null ||
+        (workInProgress.memoizedProps !== null &&
+          workInProgress.pendingProps === workInProgress.memoizedProps)) &&
+      workInProgress.updateQueue === null
+    ) {
+      return bailoutOnAlreadyFinishedWork(current, workInProgress);
+    }
+
+    switch (workInProgress.tag) {
+      case IndeterminateComponent:
+        return mountIndeterminateComponent(current, workInProgress);
+      case FunctionalComponent:
+        return updateFunctionalComponent(current, workInProgress);
+      case ClassComponent:
+        return updateClassComponent(current, workInProgress);
+      case HostContainer:
+        reconcileChildren(current, workInProgress, workInProgress.pendingProps);
+        // A yield component is just a placeholder, we can just run through the
+        // next one immediately.
+        if (workInProgress.child) {
+          return beginWork(
+            workInProgress.child.alternate,
+            workInProgress.child,
+            priorityLevel,
+          );
+        }
+        return null;
+      case HostComponent:
+        if (
+          workInProgress.stateNode &&
+          typeof config.beginUpdate === 'function'
+        ) {
+          config.beginUpdate(workInProgress.stateNode);
+        }
+        return updateHostComponent(current, workInProgress);
+      case CoroutineHandlerPhase:
+        // This is a restart. Reset the tag to the initial phase.
+        workInProgress.tag = CoroutineComponent;
+      // Intentionally fall through since this is now the same.
+      case CoroutineComponent:
+        updateCoroutineComponent(current, workInProgress);
+        // This doesn't take arbitrary time so we could synchronously just begin
+        // eagerly do the work of workInProgress.child as an optimization.
+        if (workInProgress.child) {
+          return beginWork(
+            workInProgress.child.alternate,
+            workInProgress.child,
+            priorityLevel,
+          );
+        }
+        return workInProgress.child;
+      case YieldComponent:
+        // A yield component is just a placeholder, we can just run through the
+        // next one immediately.
+        if (workInProgress.sibling) {
+          return beginWork(
+            workInProgress.sibling.alternate,
+            workInProgress.sibling,
+            priorityLevel,
+          );
+        }
+        return null;
+      default:
+        throw new Error('Unknown unit of work tag');
+    }
+  }
+
+  return {
+    beginWork,
+  };
+};
diff --git a/src/renderers/shared/fiber/ReactFiberCommitWork.js b/src/renderers/shared/fiber/ReactFiberCommitWork.js
new file mode 100644
index 000000000000..f1de612a4e35
--- /dev/null
+++ b/src/renderers/shared/fiber/ReactFiberCommitWork.js
@@ -0,0 +1,76 @@
+/**
+ * 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 ReactFiberCommitWork
+ * @flow
+ */
+
+'use strict';
+
+import type {Fiber} from 'ReactFiber';
+import type {FiberRoot} from 'ReactFiberRoot';
+import type {HostConfig} from 'ReactFiberReconciler';
+
+var ReactTypeOfWork = require('ReactTypeOfWork');
+var {ClassComponent, HostContainer, HostComponent} = ReactTypeOfWork;
+var {callCallbacks} = require('ReactFiberUpdateQueue');
+
+module.exports = function<T, P, I, C>(config: HostConfig<T, P, I, C>) {
+  const updateContainer = config.updateContainer;
+  const commitUpdate = config.commitUpdate;
+
+  function commitWork(current: ?Fiber, finishedWork: Fiber): void {
+    switch (finishedWork.tag) {
+      case ClassComponent: {
+        // Clear updates from current fiber. This must go before the callbacks
+        // are reset, in case an update is triggered from inside a callback. Is
+        // this safe? Relies on the assumption that work is only committed if
+        // the update queue is empty.
+        if (finishedWork.alternate) {
+          finishedWork.alternate.updateQueue = null;
+        }
+        if (finishedWork.callbackList) {
+          const {callbackList} = finishedWork;
+          finishedWork.callbackList = null;
+          callCallbacks(callbackList, finishedWork.stateNode);
+        }
+        // TODO: Fire componentDidMount/componentDidUpdate, update refs
+        return;
+      }
+      case HostContainer: {
+        // TODO: Attach children to root container.
+        const children = finishedWork.output;
+        const root: FiberRoot = finishedWork.stateNode;
+        const containerInfo: C = root.containerInfo;
+        updateContainer(containerInfo, children);
+        return;
+      }
+      case HostComponent: {
+        if (finishedWork.stateNode == null || !current) {
+          throw new Error('This should only be done during updates.');
+        }
+        // Commit the work prepared earlier.
+        const child = finishedWork.child;
+        const children = child && !child.sibling
+          ? (child.output: ?Fiber | I)
+          : child;
+        const newProps = finishedWork.memoizedProps;
+        const oldProps = current.memoizedProps;
+        const instance: I = finishedWork.stateNode;
+        commitUpdate(instance, oldProps, newProps, children);
+        return;
+      }
+      default:
+        throw new Error('This unit of work tag should not have side-effects.');
+    }
+  }
+
+  return {
+    commitWork,
+  };
+};
diff --git a/src/renderers/shared/fiber/ReactFiberCompleteWork.js b/src/renderers/shared/fiber/ReactFiberCompleteWork.js
new file mode 100644
index 000000000000..572736e79c93
--- /dev/null
+++ b/src/renderers/shared/fiber/ReactFiberCompleteWork.js
@@ -0,0 +1,221 @@
+/**
+ * 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 ReactFiberCompleteWork
+ * @flow
+ */
+
+'use strict';
+
+import type {ReactCoroutine} from 'ReactCoroutine';
+import type {Fiber} from 'ReactFiber';
+import type {HostConfig} from 'ReactFiberReconciler';
+import type {ReifiedYield} from 'ReactReifiedYield';
+
+var {reconcileChildFibers} = require('ReactChildFiber');
+var ReactTypeOfWork = require('ReactTypeOfWork');
+var {
+  IndeterminateComponent,
+  FunctionalComponent,
+  ClassComponent,
+  HostContainer,
+  HostComponent,
+  CoroutineComponent,
+  CoroutineHandlerPhase,
+  YieldComponent,
+} = ReactTypeOfWork;
+
+module.exports = function<T, P, I, C>(config: HostConfig<T, P, I, C>) {
+  const createInstance = config.createInstance;
+  const prepareUpdate = config.prepareUpdate;
+
+  function markForPreEffect(workInProgress: Fiber) {
+    // Schedule a side-effect on this fiber, BEFORE the children's side-effects.
+    if (workInProgress.firstEffect) {
+      workInProgress.nextEffect = workInProgress.firstEffect;
+      workInProgress.firstEffect = workInProgress;
+    } else {
+      workInProgress.firstEffect = workInProgress;
+      workInProgress.lastEffect = workInProgress;
+    }
+  }
+
+  // TODO: It's possible this will create layout thrash issues because mutations
+  // of the DOM and life-cycles are interleaved. E.g. if a componentDidMount
+  // of a sibling reads, then the next sibling updates and reads etc.
+  function markForPostEffect(workInProgress: Fiber) {
+    // Schedule a side-effect on this fiber, AFTER the children's side-effects.
+    if (workInProgress.lastEffect) {
+      workInProgress.lastEffect.nextEffect = workInProgress;
+    } else {
+      workInProgress.firstEffect = workInProgress;
+    }
+    workInProgress.lastEffect = workInProgress;
+  }
+
+  function transferOutput(child: ?Fiber, returnFiber: Fiber) {
+    // If we have a single result, we just pass that through as the output to
+    // avoid unnecessary traversal. When we have multiple output, we just pass
+    // the linked list of fibers that has the individual output values.
+    returnFiber.output = child && !child.sibling ? child.output : child;
+    returnFiber.memoizedProps = returnFiber.pendingProps;
+  }
+
+  function recursivelyFillYields(yields, output: ?Fiber | ?ReifiedYield) {
+    if (!output) {
+      // Ignore nulls etc.
+    } else if (output.tag !== undefined) {
+      // TODO: Fix this fragile duck test.
+      // Detect if this is a fiber, if so it is a fragment result.
+      // $FlowFixMe: Refinement issue.
+      var item = (output: Fiber);
+      do {
+        recursivelyFillYields(yields, item.output);
+        item = item.sibling;
+      } while (item);
+    } else {
+      // $FlowFixMe: Refinement issue. If it is not a Fiber or null, it is a yield
+      yields.push(output);
+    }
+  }
+
+  function moveCoroutineToHandlerPhase(current: ?Fiber, workInProgress: Fiber) {
+    var coroutine = (workInProgress.pendingProps: ?ReactCoroutine);
+    if (!coroutine) {
+      throw new Error('Should be resolved by now');
+    }
+
+    // First step of the coroutine has completed. Now we need to do the second.
+    // TODO: It would be nice to have a multi stage coroutine represented by a
+    // single component, or at least tail call optimize nested ones. Currently
+    // that requires additional fields that we don't want to add to the fiber.
+    // So this requires nested handlers.
+    // Note: This doesn't mutate the alternate node. I don't think it needs to
+    // since this stage is reset for every pass.
+    workInProgress.tag = CoroutineHandlerPhase;
+
+    // Build up the yields.
+    // TODO: Compare this to a generator or opaque helpers like Children.
+    var yields: Array<ReifiedYield> = [];
+    var child = workInProgress.child;
+    while (child) {
+      recursivelyFillYields(yields, child.output);
+      child = child.sibling;
+    }
+    var fn = coroutine.handler;
+    var props = coroutine.props;
+    var nextChildren = fn(props, yields);
+
+    var currentFirstChild = current ? current.stateNode : null;
+    // Inherit the priority of the returnFiber.
+    const priority = workInProgress.pendingWorkPriority;
+    workInProgress.stateNode = reconcileChildFibers(
+      workInProgress,
+      currentFirstChild,
+      nextChildren,
+      priority,
+    );
+    return workInProgress.stateNode;
+  }
+
+  function completeWork(current: ?Fiber, workInProgress: Fiber): ?Fiber {
+    switch (workInProgress.tag) {
+      case FunctionalComponent:
+        transferOutput(workInProgress.child, workInProgress);
+        return null;
+      case ClassComponent:
+        transferOutput(workInProgress.child, workInProgress);
+        // Don't use the state queue to compute the memoized state. We already
+        // merged it and assigned it to the instance. Transfer it from there.
+        // Also need to transfer the props, because pendingProps will be null
+        // in the case of an update
+        const {state, props} = workInProgress.stateNode;
+        workInProgress.memoizedState = state;
+        workInProgress.memoizedProps = props;
+        // Transfer update queue to callbackList field so callbacks can be
+        // called during commit phase.
+        workInProgress.callbackList = workInProgress.updateQueue;
+        markForPostEffect(workInProgress);
+        return null;
+      case HostContainer:
+        transferOutput(workInProgress.child, workInProgress);
+        // We don't know if a container has updated any children so we always
+        // need to update it right now. We schedule this side-effect before
+        // all the other side-effects in the subtree. We need to schedule it
+        // before so that the entire tree is up-to-date before the life-cycles
+        // are invoked.
+        markForPreEffect(workInProgress);
+        return null;
+      case HostComponent:
+        let newProps = workInProgress.pendingProps;
+        const child = workInProgress.child;
+        const children = child && !child.sibling
+          ? (child.output: ?Fiber | I)
+          : child;
+        if (current && workInProgress.stateNode != null) {
+          // If we have an alternate, that means this is an update and we need to
+          // schedule a side-effect to do the updates.
+          const oldProps = current.memoizedProps;
+          // If we get updated because one of our children updated, we don't
+          // have newProps so we'll have to reuse them.
+          // TODO: Split the update API as separate for the props vs. children.
+          // Even better would be if children weren't special cased at all tho.
+          if (!newProps) {
+            newProps = oldProps;
+          }
+          const instance: I = workInProgress.stateNode;
+          if (prepareUpdate(instance, oldProps, newProps, children)) {
+            // This returns true if there was something to update.
+            markForPreEffect(workInProgress);
+          }
+          // TODO: Is this actually ever going to change? Why set it every time?
+          workInProgress.output = instance;
+        } else {
+          if (!newProps) {
+            if (workInProgress.stateNode === null) {
+              throw new Error('We must have new props for new mounts.');
+            } else {
+              // This can happen when we abort work.
+              return null;
+            }
+          }
+          const instance = createInstance(
+            workInProgress.type,
+            newProps,
+            children,
+          );
+          // TODO: This seems like unnecessary duplication.
+          workInProgress.stateNode = instance;
+          workInProgress.output = instance;
+        }
+        workInProgress.memoizedProps = newProps;
+        return null;
+      case CoroutineComponent:
+        return moveCoroutineToHandlerPhase(current, workInProgress);
+      case CoroutineHandlerPhase:
+        transferOutput(workInProgress.stateNode, workInProgress);
+        // Reset the tag to now be a first phase coroutine.
+        workInProgress.tag = CoroutineComponent;
+        return null;
+      case YieldComponent:
+        // Does nothing.
+        return null;
+      // Error cases
+      case IndeterminateComponent:
+        throw new Error(
+          'An indeterminate component should have become determinate before completing.',
+        );
+      default:
+        throw new Error('Unknown unit of work tag');
+    }
+  }
+
+  return {
+    completeWork,
+  };
+};
diff --git a/src/renderers/shared/fiber/ReactFiberReconciler.js b/src/renderers/shared/fiber/ReactFiberReconciler.js
new file mode 100644
index 000000000000..1034d1d5c97c
--- /dev/null
+++ b/src/renderers/shared/fiber/ReactFiberReconciler.js
@@ -0,0 +1,119 @@
+/**
+ * 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 ReactFiberReconciler
+ * @flow
+ */
+
+'use strict';
+
+import type {Fiber} from 'ReactFiber';
+import type {FiberRoot} from 'ReactFiberRoot';
+import type {TypeOfWork} from 'ReactTypeOfWork';
+import type {PriorityLevel} from 'ReactPriorityLevel';
+
+var {createFiberRoot} = require('ReactFiberRoot');
+var ReactFiberScheduler = require('ReactFiberScheduler');
+
+type Deadline = {
+  timeRemaining: () => number,
+};
+
+type HostChildNode<I> = {
+  tag: TypeOfWork,
+  output: HostChildren<I>,
+  sibling: any,
+};
+
+export type HostChildren<I> = null | void | I | HostChildNode<I>;
+
+export type HostConfig<T, P, I, C> = {
+  // TODO: We don't currently have a quick way to detect that children didn't
+  // reorder so we host will always need to check the set. We should make a flag
+  // or something so that it can bailout easily.
+
+  updateContainer(containerInfo: C, children: HostChildren<I>): void,
+
+  createInstance(type: T, props: P, children: HostChildren<I>): I,
+  prepareUpdate(
+    instance: I,
+    oldProps: P,
+    newProps: P,
+    children: HostChildren<I>,
+  ): boolean,
+  commitUpdate(
+    instance: I,
+    oldProps: P,
+    newProps: P,
+    children: HostChildren<I>,
+  ): void,
+  deleteInstance(instance: I): void,
+
+  scheduleAnimationCallback(callback: () => void): void,
+  scheduleDeferredCallback(callback: (deadline: Deadline) => void): void,
+};
+
+type OpaqueNode = Fiber;
+
+export type Reconciler<C> = {
+  mountContainer(element: ReactElement<any>, containerInfo: C): OpaqueNode,
+  updateContainer(element: ReactElement<any>, container: OpaqueNode): void,
+  unmountContainer(container: OpaqueNode): void,
+  performWithPriority(priorityLevel: PriorityLevel, fn: Function): void,
+
+  // Used to extract the return value from the initial render. Legacy API.
+  getPublicRootInstance(container: OpaqueNode): C | null,
+};
+
+module.exports = function<T, P, I, C>(
+  config: HostConfig<T, P, I, C>,
+): Reconciler<C> {
+  var {scheduleWork, performWithPriority} = ReactFiberScheduler(config);
+
+  return {
+    mountContainer(element: ReactElement<any>, containerInfo: C): OpaqueNode {
+      const root = createFiberRoot(containerInfo);
+      const container = root.current;
+      // TODO: Use pending work/state instead of props.
+      // TODO: This should not override the pendingWorkPriority if there is
+      // higher priority work in the subtree.
+      container.pendingProps = element;
+
+      scheduleWork(root);
+
+      // It may seem strange that we don't return the root here, but that will
+      // allow us to have containers that are in the middle of the tree instead
+      // of being roots.
+      return container;
+    },
+
+    updateContainer(element: ReactElement<any>, container: OpaqueNode): void {
+      // TODO: If this is a nested container, this won't be the root.
+      const root: FiberRoot = (container.stateNode: any);
+      // TODO: Use pending work/state instead of props.
+      root.current.pendingProps = element;
+
+      scheduleWork(root);
+    },
+
+    unmountContainer(container: OpaqueNode): void {
+      // TODO: If this is a nested container, this won't be the root.
+      const root: FiberRoot = (container.stateNode: any);
+      // TODO: Use pending work/state instead of props.
+      root.current.pendingProps = [];
+
+      scheduleWork(root);
+    },
+
+    performWithPriority,
+
+    getPublicRootInstance(container: OpaqueNode): C | null {
+      return null;
+    },
+  };
+};
diff --git a/src/renderers/shared/fiber/ReactFiberRoot.js b/src/renderers/shared/fiber/ReactFiberRoot.js
new file mode 100644
index 000000000000..c363827951ce
--- /dev/null
+++ b/src/renderers/shared/fiber/ReactFiberRoot.js
@@ -0,0 +1,42 @@
+/**
+ * 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 ReactFiberRoot
+ * @flow
+ */
+
+'use strict';
+
+import type {Fiber} from 'ReactFiber';
+
+const {createHostContainerFiber} = require('ReactFiber');
+
+export type FiberRoot = {
+  // Any additional information from the host associated with this root.
+  containerInfo: any,
+  // The currently active root fiber. This is the mutable root of the tree.
+  current: Fiber,
+  // Determines if this root has already been added to the schedule for work.
+  isScheduled: boolean,
+  // The work schedule is a linked list.
+  nextScheduledRoot: ?FiberRoot,
+};
+
+exports.createFiberRoot = function(containerInfo: any): FiberRoot {
+  // Cyclic construction. This cheats the type system right now because
+  // stateNode is any.
+  const uninitializedFiber = createHostContainerFiber();
+  const root = {
+    current: uninitializedFiber,
+    containerInfo: containerInfo,
+    isScheduled: false,
+    nextScheduledRoot: null,
+  };
+  uninitializedFiber.stateNode = root;
+  return root;
+};
diff --git a/src/renderers/shared/fiber/ReactFiberScheduler.js b/src/renderers/shared/fiber/ReactFiberScheduler.js
new file mode 100644
index 000000000000..a8e1b77cc596
--- /dev/null
+++ b/src/renderers/shared/fiber/ReactFiberScheduler.js
@@ -0,0 +1,357 @@
+/**
+ * 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 ReactFiberScheduler
+ * @flow
+ */
+
+'use strict';
+
+import type {Fiber} from 'ReactFiber';
+import type {FiberRoot} from 'ReactFiberRoot';
+import type {HostConfig} from 'ReactFiberReconciler';
+import type {PriorityLevel} from 'ReactPriorityLevel';
+
+var ReactFiberBeginWork = require('ReactFiberBeginWork');
+var ReactFiberCompleteWork = require('ReactFiberCompleteWork');
+var ReactFiberCommitWork = require('ReactFiberCommitWork');
+
+var {cloneFiber} = require('ReactFiber');
+
+var {
+  NoWork,
+  LowPriority,
+  AnimationPriority,
+  SynchronousPriority,
+} = require('ReactPriorityLevel');
+
+var timeHeuristicForUnitOfWork = 1;
+
+export type Scheduler = {
+  scheduleDeferredWork: (root: FiberRoot, priority: PriorityLevel) => void,
+};
+
+module.exports = function<T, P, I, C>(config: HostConfig<T, P, I, C>) {
+  // Use a closure to circumvent the circular dependency between the scheduler
+  // and ReactFiberBeginWork. Don't know if there's a better way to do this.
+  let scheduler;
+  function getScheduler(): Scheduler {
+    return scheduler;
+  }
+
+  const {beginWork} = ReactFiberBeginWork(config, getScheduler);
+  const {completeWork} = ReactFiberCompleteWork(config);
+  const {commitWork} = ReactFiberCommitWork(config);
+
+  const scheduleAnimationCallback = config.scheduleAnimationCallback;
+  const scheduleDeferredCallback = config.scheduleDeferredCallback;
+
+  // The default priority to use for updates.
+  let defaultPriority: PriorityLevel = LowPriority;
+
+  // The next work in progress fiber that we're currently working on.
+  let nextUnitOfWork: ?Fiber = null;
+  let nextPriorityLevel: PriorityLevel = NoWork;
+
+  // Linked list of roots with scheduled work on them.
+  let nextScheduledRoot: ?FiberRoot = null;
+  let lastScheduledRoot: ?FiberRoot = null;
+
+  function findNextUnitOfWork() {
+    // Clear out roots with no more work on them.
+    while (
+      nextScheduledRoot &&
+      nextScheduledRoot.current.pendingWorkPriority === NoWork
+    ) {
+      nextScheduledRoot.isScheduled = false;
+      if (nextScheduledRoot === lastScheduledRoot) {
+        nextScheduledRoot = null;
+        lastScheduledRoot = null;
+        nextPriorityLevel = NoWork;
+        return null;
+      }
+      nextScheduledRoot = nextScheduledRoot.nextScheduledRoot;
+    }
+    // TODO: This is scanning one root at a time. It should be scanning all
+    // roots for high priority work before moving on to lower priorities.
+    let root = nextScheduledRoot;
+    let highestPriorityRoot = null;
+    let highestPriorityLevel = NoWork;
+    while (root) {
+      if (
+        highestPriorityLevel === NoWork ||
+        highestPriorityLevel > root.current.pendingWorkPriority
+      ) {
+        highestPriorityLevel = root.current.pendingWorkPriority;
+        highestPriorityRoot = root;
+      }
+      // We didn't find anything to do in this root, so let's try the next one.
+      root = root.nextScheduledRoot;
+    }
+    if (highestPriorityRoot) {
+      nextPriorityLevel = highestPriorityLevel;
+      return cloneFiber(highestPriorityRoot.current, highestPriorityLevel);
+    }
+
+    nextPriorityLevel = NoWork;
+    return null;
+  }
+
+  function commitAllWork(finishedWork: Fiber) {
+    // Commit all the side-effects within a tree.
+    // TODO: Error handling.
+    let effectfulFiber = finishedWork.firstEffect;
+    while (effectfulFiber) {
+      const current = effectfulFiber.alternate;
+      commitWork(current, effectfulFiber);
+      const next = effectfulFiber.nextEffect;
+      // Ensure that we clean these up so that we don't accidentally keep them.
+      // I'm not actually sure this matters because we can't reset firstEffect
+      // and lastEffect since they're on every node, not just the effectful
+      // ones. So we have to clean everything as we reuse nodes anyway.
+      effectfulFiber.nextEffect = null;
+      effectfulFiber = next;
+    }
+  }
+
+  function resetWorkPriority(workInProgress: Fiber) {
+    let newPriority = NoWork;
+    // progressedChild is going to be the child set with the highest priority.
+    // Either it is the same as child, or it just bailed out because it choose
+    // not to do the work.
+    let child = workInProgress.progressedChild;
+    while (child) {
+      // Ensure that remaining work priority bubbles up.
+      if (
+        child.pendingWorkPriority !== NoWork &&
+        (newPriority === NoWork || newPriority > child.pendingWorkPriority)
+      ) {
+        newPriority = child.pendingWorkPriority;
+      }
+      child = child.sibling;
+    }
+    workInProgress.pendingWorkPriority = newPriority;
+  }
+
+  function completeUnitOfWork(workInProgress: Fiber): ?Fiber {
+    while (true) {
+      // The current, flushed, state of this fiber is the alternate.
+      // Ideally nothing should rely on this, but relying on it here
+      // means that we don't need an additional field on the work in
+      // progress.
+      const current = workInProgress.alternate;
+      const next = completeWork(current, workInProgress);
+
+      resetWorkPriority(workInProgress);
+
+      // The work is now done. We don't need this anymore. This flags
+      // to the system not to redo any work here.
+      workInProgress.pendingProps = null;
+      workInProgress.updateQueue = null;
+
+      const returnFiber = workInProgress.return;
+
+      if (returnFiber) {
+        // Ensure that the first and last effect of the parent corresponds
+        // to the children's first and last effect. This probably relies on
+        // children completing in order.
+        if (!returnFiber.firstEffect) {
+          returnFiber.firstEffect = workInProgress.firstEffect;
+        }
+        if (workInProgress.lastEffect) {
+          if (returnFiber.lastEffect) {
+            returnFiber.lastEffect.nextEffect = workInProgress.firstEffect;
+          }
+          returnFiber.lastEffect = workInProgress.lastEffect;
+        }
+      }
+
+      if (next) {
+        // If completing this work spawned new work, do that next.
+        return next;
+      } else if (workInProgress.sibling) {
+        // If there is more work to do in this returnFiber, do that next.
+        return workInProgress.sibling;
+      } else if (returnFiber) {
+        // If there's no more work in this returnFiber. Complete the returnFiber.
+        workInProgress = returnFiber;
+        continue;
+      } else {
+        // If we're at the root, there's no more work to do. We can flush it.
+        const root: FiberRoot = (workInProgress.stateNode: any);
+        if (root.current === workInProgress) {
+          throw new Error(
+            'Cannot commit the same tree as before. This is probably a bug ' +
+              'related to the return field.',
+          );
+        }
+        root.current = workInProgress;
+        // TODO: We can be smarter here and only look for more work in the
+        // "next" scheduled work since we've already scanned passed. That
+        // also ensures that work scheduled during reconciliation gets deferred.
+        // const hasMoreWork = workInProgress.pendingWorkPriority !== NoWork;
+        commitAllWork(workInProgress);
+        const nextWork = findNextUnitOfWork();
+        // if (!nextWork && hasMoreWork) {
+        // TODO: This can happen when some deep work completes and we don't
+        // know if this was the last one. We should be able to keep track of
+        // the highest priority still in the tree for one pass. But if we
+        // terminate an update we don't know.
+        // throw new Error('FiberRoots should not have flagged more work if there is none.');
+        // }
+        return nextWork;
+      }
+    }
+  }
+
+  function performUnitOfWork(workInProgress: Fiber): ?Fiber {
+    // The current, flushed, state of this fiber is the alternate.
+    // Ideally nothing should rely on this, but relying on it here
+    // means that we don't need an additional field on the work in
+    // progress.
+    const current = workInProgress.alternate;
+    const next = beginWork(current, workInProgress, nextPriorityLevel);
+
+    if (next) {
+      // If this spawns new work, do that next.
+      return next;
+    } else {
+      // Otherwise, complete the current work.
+      return completeUnitOfWork(workInProgress);
+    }
+  }
+
+  function performDeferredWork(deadline) {
+    if (!nextUnitOfWork) {
+      nextUnitOfWork = findNextUnitOfWork();
+    }
+    while (nextUnitOfWork) {
+      if (deadline.timeRemaining() > timeHeuristicForUnitOfWork) {
+        nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
+        if (!nextUnitOfWork) {
+          // Find more work. We might have time to complete some more.
+          nextUnitOfWork = findNextUnitOfWork();
+        }
+      } else {
+        scheduleDeferredCallback(performDeferredWork);
+        return;
+      }
+    }
+  }
+
+  function scheduleDeferredWork(root: FiberRoot, priority: PriorityLevel) {
+    // We must reset the current unit of work pointer so that we restart the
+    // search from the root during the next tick, in case there is now higher
+    // priority work somewhere earlier than before.
+    if (priority <= nextPriorityLevel) {
+      nextUnitOfWork = null;
+    }
+
+    // Set the priority on the root, without deprioritizing
+    if (
+      root.current.pendingWorkPriority === NoWork ||
+      priority <= root.current.pendingWorkPriority
+    ) {
+      root.current.pendingWorkPriority = priority;
+    }
+
+    if (root.isScheduled) {
+      // If we're already scheduled, we can bail out.
+      return;
+    }
+    root.isScheduled = true;
+    if (lastScheduledRoot) {
+      // Schedule ourselves to the end.
+      lastScheduledRoot.nextScheduledRoot = root;
+      lastScheduledRoot = root;
+    } else {
+      // We're the only work scheduled.
+      nextScheduledRoot = root;
+      lastScheduledRoot = root;
+      scheduleDeferredCallback(performDeferredWork);
+    }
+  }
+
+  function performAnimationWork() {
+    // Always start from the root
+    nextUnitOfWork = findNextUnitOfWork();
+    while (nextUnitOfWork && nextPriorityLevel !== NoWork) {
+      nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
+      if (!nextUnitOfWork) {
+        // Keep searching for animation work until there's no more left
+        nextUnitOfWork = findNextUnitOfWork();
+      }
+      // Stop if the next unit of work is low priority
+      if (nextPriorityLevel > AnimationPriority) {
+        scheduleDeferredCallback(performDeferredWork);
+        return;
+      }
+    }
+  }
+
+  function scheduleAnimationWork(
+    root: FiberRoot,
+    priorityLevel: PriorityLevel,
+  ) {
+    // Set the priority on the root, without deprioritizing
+    if (
+      root.current.pendingWorkPriority === NoWork ||
+      priorityLevel <= root.current.pendingWorkPriority
+    ) {
+      root.current.pendingWorkPriority = priorityLevel;
+    }
+
+    if (root.isScheduled) {
+      // If we're already scheduled, we can bail out.
+      return;
+    }
+    root.isScheduled = true;
+    if (lastScheduledRoot) {
+      // Schedule ourselves to the end.
+      lastScheduledRoot.nextScheduledRoot = root;
+      lastScheduledRoot = root;
+    } else {
+      // We're the only work scheduled.
+      nextScheduledRoot = root;
+      lastScheduledRoot = root;
+      scheduleAnimationCallback(performAnimationWork);
+    }
+  }
+
+  function scheduleWork(root: FiberRoot) {
+    if (defaultPriority === SynchronousPriority) {
+      throw new Error('Not implemented yet');
+    }
+
+    if (defaultPriority === NoWork) {
+      return;
+    }
+    if (defaultPriority > AnimationPriority) {
+      scheduleDeferredWork(root, defaultPriority);
+      return;
+    }
+    scheduleAnimationWork(root, defaultPriority);
+  }
+
+  function performWithPriority(priorityLevel: PriorityLevel, fn: Function) {
+    const previousDefaultPriority = defaultPriority;
+    defaultPriority = priorityLevel;
+    try {
+      fn();
+    } finally {
+      defaultPriority = previousDefaultPriority;
+    }
+  }
+
+  scheduler = {
+    scheduleWork: scheduleWork,
+    scheduleDeferredWork: scheduleDeferredWork,
+    performWithPriority: performWithPriority,
+  };
+  return scheduler;
+};
diff --git a/src/renderers/shared/fiber/ReactFiberUpdateQueue.js b/src/renderers/shared/fiber/ReactFiberUpdateQueue.js
new file mode 100644
index 000000000000..65d8bb66d517
--- /dev/null
+++ b/src/renderers/shared/fiber/ReactFiberUpdateQueue.js
@@ -0,0 +1,99 @@
+/**
+ * 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 ReactFiberUpdateQueue
+ * @flow
+ */
+
+'use strict';
+
+type UpdateQueueNode = {
+  partialState: any,
+  callback: ?Function,
+  callbackWasCalled: boolean,
+  next: ?UpdateQueueNode,
+};
+
+export type UpdateQueue = UpdateQueueNode & {
+  isReplace: boolean,
+  isForced: boolean,
+  tail: UpdateQueueNode,
+};
+
+exports.createUpdateQueue = function(partialState: mixed): UpdateQueue {
+  const queue = {
+    partialState,
+    callback: null,
+    callbackWasCalled: false,
+    next: null,
+    isReplace: false,
+    isForced: false,
+    tail: (null: any),
+  };
+  queue.tail = queue;
+  return queue;
+};
+
+exports.addToQueue = function(
+  queue: UpdateQueue,
+  partialState: mixed,
+): UpdateQueue {
+  const node = {
+    partialState,
+    callback: null,
+    callbackWasCalled: false,
+    next: null,
+  };
+  queue.tail.next = node;
+  queue.tail = node;
+  return queue;
+};
+
+exports.addCallbackToQueue = function(
+  queue: UpdateQueue,
+  callback: Function,
+): UpdateQueue {
+  if (queue.tail.callback) {
+    // If the tail already as a callback, add an empty node to queue
+    exports.addToQueue(queue, null);
+  }
+  queue.tail.callback = callback;
+  return queue;
+};
+
+exports.callCallbacks = function(queue: UpdateQueue, context: any) {
+  let node: ?UpdateQueueNode = queue;
+  while (node) {
+    if (node.callback && !node.callbackWasCalled) {
+      node.callbackWasCalled = true;
+      node.callback.call(context);
+    }
+    node = node.next;
+  }
+};
+
+exports.mergeUpdateQueue = function(
+  queue: UpdateQueue,
+  prevState: any,
+  props: any,
+): any {
+  let node: ?UpdateQueueNode = queue;
+  let state = queue.isReplace ? null : Object.assign({}, prevState);
+  while (node) {
+    let partialState;
+    if (typeof node.partialState === 'function') {
+      const updateFn = node.partialState;
+      partialState = updateFn(state, props);
+    } else {
+      partialState = node.partialState;
+    }
+    state = Object.assign(state || {}, partialState);
+    node = node.next;
+  }
+  return state;
+};
diff --git a/src/renderers/shared/fiber/ReactPriorityLevel.js b/src/renderers/shared/fiber/ReactPriorityLevel.js
new file mode 100644
index 000000000000..b6930c2900a0
--- /dev/null
+++ b/src/renderers/shared/fiber/ReactPriorityLevel.js
@@ -0,0 +1,24 @@
+/**
+ * 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 ReactPriorityLevel
+ * @flow
+ */
+
+'use strict';
+
+export type PriorityLevel = 0 | 1 | 2 | 3 | 4 | 5;
+
+module.exports = {
+  NoWork: 0, // No work is pending.
+  SynchronousPriority: 1, // For controlled text inputs. Synchronous side-effects.
+  AnimationPriority: 2, // Needs to complete before the next frame.
+  HighPriority: 3, // Interaction that needs to complete pretty soon to feel responsive.
+  LowPriority: 4, // Data fetching, or result from updating stores.
+  OffscreenPriority: 5, // Won't be visible but do the work in case it becomes visible.
+};
diff --git a/src/renderers/shared/fiber/ReactReifiedYield.js b/src/renderers/shared/fiber/ReactReifiedYield.js
new file mode 100644
index 000000000000..c41676379ea4
--- /dev/null
+++ b/src/renderers/shared/fiber/ReactReifiedYield.js
@@ -0,0 +1,38 @@
+/**
+ * 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 ReactReifiedYield
+ * @flow
+ */
+
+'use strict';
+
+import type {ReactYield} from 'ReactCoroutine';
+import type {Fiber} from 'ReactFiber';
+
+var {createFiberFromElementType} = require('ReactFiber');
+
+export type ReifiedYield = {continuation: Fiber, props: Object};
+
+exports.createReifiedYield = function(yieldNode: ReactYield): ReifiedYield {
+  var fiber = createFiberFromElementType(yieldNode.continuation, yieldNode.key);
+  return {
+    continuation: fiber,
+    props: yieldNode.props,
+  };
+};
+
+exports.createUpdatedReifiedYield = function(
+  previousYield: ReifiedYield,
+  yieldNode: ReactYield,
+): ReifiedYield {
+  return {
+    continuation: previousYield.continuation,
+    props: yieldNode.props,
+  };
+};
diff --git a/src/renderers/shared/fiber/ReactTypeOfWork.js b/src/renderers/shared/fiber/ReactTypeOfWork.js
new file mode 100644
index 000000000000..b63813b1d5c4
--- /dev/null
+++ b/src/renderers/shared/fiber/ReactTypeOfWork.js
@@ -0,0 +1,26 @@
+/**
+ * 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 ReactTypeOfWork
+ * @flow
+ */
+
+'use strict';
+
+export type TypeOfWork = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7;
+
+module.exports = {
+  IndeterminateComponent: 0, // Before we know whether it is functional or class
+  FunctionalComponent: 1,
+  ClassComponent: 2,
+  HostContainer: 3, // Root of a host tree. Could be nested inside another node.
+  HostComponent: 4,
+  CoroutineComponent: 5,
+  CoroutineHandlerPhase: 6,
+  YieldComponent: 7,
+};
diff --git a/src/renderers/shared/fiber/__tests__/ReactCoroutine-test.js b/src/renderers/shared/fiber/__tests__/ReactCoroutine-test.js
new file mode 100644
index 000000000000..af56323055bc
--- /dev/null
+++ b/src/renderers/shared/fiber/__tests__/ReactCoroutine-test.js
@@ -0,0 +1,89 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var React;
+var ReactNoop;
+var ReactCoroutine;
+
+describe('ReactCoroutine', () => {
+  beforeEach(() => {
+    React = require('React');
+    ReactNoop = require('ReactNoop');
+    ReactCoroutine = require('ReactCoroutine');
+  });
+
+  xit('should render a coroutine', () => {
+    var ops = [];
+
+    function Continuation({isSame}) {
+      ops.push(['Continuation', isSame]);
+      return <span>{isSame ? 'foo==bar' : 'foo!=bar'}</span>;
+    }
+
+    // An alternative API could mark Continuation as something that needs
+    // yielding. E.g. Continuation.yieldType = 123;
+    function Child({bar}) {
+      ops.push(['Child', bar]);
+      return ReactCoroutine.createYield(
+        {
+          bar: bar,
+        },
+        Continuation,
+        null,
+      );
+    }
+
+    function Indirection() {
+      ops.push('Indirection');
+      return [<Child bar={true} />, <Child bar={false} />];
+    }
+
+    function HandleYields(props, yields) {
+      ops.push('HandleYields');
+      return yields.map(y =>
+        <y.continuation isSame={props.foo === y.props.bar} />,
+      );
+    }
+
+    // An alternative API could mark Parent as something that needs
+    // yielding. E.g. Parent.handler = HandleYields;
+    function Parent(props) {
+      ops.push('Parent');
+      return ReactCoroutine.createCoroutine(
+        props.children,
+        HandleYields,
+        props,
+      );
+    }
+
+    function App() {
+      return <div><Parent foo={true}><Indirection /></Parent></div>;
+    }
+
+    ReactNoop.render(<App />);
+    ReactNoop.flush();
+
+    expect(ops).toEqual([
+      'Parent',
+      'Indirection',
+      ['Child', true],
+      // Yield
+      ['Child', false],
+      // Yield
+      'HandleYields',
+      // Continue yields
+      ['Continuation', true],
+      ['Continuation', false],
+    ]);
+  });
+});
diff --git a/src/renderers/shared/fiber/__tests__/ReactIncremental-test.js b/src/renderers/shared/fiber/__tests__/ReactIncremental-test.js
new file mode 100644
index 000000000000..520cbd47637e
--- /dev/null
+++ b/src/renderers/shared/fiber/__tests__/ReactIncremental-test.js
@@ -0,0 +1,797 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var React;
+var ReactNoop;
+
+describe('ReactIncremental', () => {
+  beforeEach(() => {
+    React = require('React');
+    ReactNoop = require('ReactNoop');
+  });
+
+  it('should render a simple component', () => {
+    function Bar() {
+      return <div>Hello World</div>;
+    }
+
+    function Foo() {
+      return <Bar isBar={true} />;
+    }
+
+    ReactNoop.render(<Foo />);
+    ReactNoop.flush();
+  });
+
+  it('should render a simple component, in steps if needed', () => {
+    var barCalled = false;
+    function Bar() {
+      barCalled = true;
+      return <span><div>Hello World</div></span>;
+    }
+
+    var fooCalled = false;
+    function Foo() {
+      fooCalled = true;
+      return [<Bar isBar={true} />, <Bar isBar={true} />];
+    }
+
+    ReactNoop.render(<Foo />);
+    expect(fooCalled).toBe(false);
+    expect(barCalled).toBe(false);
+    // Do one step of work.
+    ReactNoop.flushDeferredPri(7);
+    expect(fooCalled).toBe(true);
+    expect(barCalled).toBe(false);
+    // Do the rest of the work.
+    ReactNoop.flushDeferredPri(50);
+    expect(fooCalled).toBe(true);
+    expect(barCalled).toBe(true);
+  });
+
+  it('updates a previous render', () => {
+    var ops = [];
+
+    function Header() {
+      ops.push('Header');
+      return <h1>Hi</h1>;
+    }
+
+    function Content(props) {
+      ops.push('Content');
+      return <div>{props.children}</div>;
+    }
+
+    function Footer() {
+      ops.push('Footer');
+      return <footer>Bye</footer>;
+    }
+
+    var header = <Header />;
+    var footer = <Footer />;
+
+    function Foo(props) {
+      ops.push('Foo');
+      return (
+        <div>
+          {header}
+          <Content>{props.text}</Content>
+          {footer}
+        </div>
+      );
+    }
+
+    ReactNoop.render(<Foo text="foo" />);
+    ReactNoop.flush();
+
+    expect(ops).toEqual(['Foo', 'Header', 'Content', 'Footer']);
+
+    ops = [];
+
+    ReactNoop.render(<Foo text="bar" />);
+    ReactNoop.flush();
+
+    // TODO: Test bail out of host components. This is currently unobservable.
+
+    // Since this is an update, it should bail out and reuse the work from
+    // Header and Content.
+    expect(ops).toEqual(['Foo', 'Content']);
+  });
+
+  it('can cancel partially rendered work and restart', () => {
+    var ops = [];
+
+    function Bar(props) {
+      ops.push('Bar');
+      return <div>{props.children}</div>;
+    }
+
+    function Foo(props) {
+      ops.push('Foo');
+      return (
+        <div>
+          <Bar>{props.text}</Bar>
+          <Bar>{props.text}</Bar>
+        </div>
+      );
+    }
+
+    // Init
+    ReactNoop.render(<Foo text="foo" />);
+    ReactNoop.flush();
+
+    ops = [];
+
+    ReactNoop.render(<Foo text="bar" />);
+    // Flush part of the work
+    ReactNoop.flushDeferredPri(20);
+
+    expect(ops).toEqual(['Foo', 'Bar']);
+
+    ops = [];
+
+    // This will abort the previous work and restart
+    ReactNoop.render(<Foo text="baz" />);
+
+    // Flush part of the new work
+    ReactNoop.flushDeferredPri(20);
+
+    expect(ops).toEqual(['Foo', 'Bar']);
+
+    // Flush the rest of the work which now includes the low priority
+    ReactNoop.flush(20);
+
+    expect(ops).toEqual(['Foo', 'Bar', 'Bar']);
+  });
+
+  it('can deprioritize unfinished work and resume it later', () => {
+    var ops = [];
+
+    function Bar(props) {
+      ops.push('Bar');
+      return <div>{props.children}</div>;
+    }
+
+    function Middle(props) {
+      ops.push('Middle');
+      return <span>{props.children}</span>;
+    }
+
+    function Foo(props) {
+      ops.push('Foo');
+      return (
+        <div>
+          <Bar>{props.text}</Bar>
+          <section hidden={true}>
+            <Middle>{props.text}</Middle>
+          </section>
+          <Bar>{props.text}</Bar>
+          <footer hidden={true}>
+            <Middle>Footer</Middle>
+          </footer>
+        </div>
+      );
+    }
+
+    // Init
+    ReactNoop.render(<Foo text="foo" />);
+    ReactNoop.flush();
+
+    expect(ops).toEqual(['Foo', 'Bar', 'Bar', 'Middle', 'Middle']);
+
+    ops = [];
+
+    // Render part of the work. This should be enough to flush everything except
+    // the middle which has lower priority.
+    ReactNoop.render(<Foo text="bar" />);
+    ReactNoop.flushDeferredPri(40);
+
+    expect(ops).toEqual(['Foo', 'Bar', 'Bar']);
+
+    ops = [];
+
+    // Flush only the remaining work
+    ReactNoop.flush();
+
+    expect(ops).toEqual(['Middle', 'Middle']);
+  });
+
+  it('can deprioritize a tree from without dropping work', () => {
+    var ops = [];
+
+    function Bar(props) {
+      ops.push('Bar');
+      return <div>{props.children}</div>;
+    }
+
+    function Middle(props) {
+      ops.push('Middle');
+      return <span>{props.children}</span>;
+    }
+
+    function Foo(props) {
+      ops.push('Foo');
+      return (
+        <div>
+          <Bar>{props.text}</Bar>
+          <section hidden={true}>
+            <Middle>{props.text}</Middle>
+          </section>
+          <Bar>{props.text}</Bar>
+          <footer hidden={true}>
+            <Middle>Footer</Middle>
+          </footer>
+        </div>
+      );
+    }
+
+    // Init
+    ReactNoop.performAnimationWork(() => {
+      ReactNoop.render(<Foo text="foo" />);
+    });
+    ReactNoop.flush();
+
+    expect(ops).toEqual(['Foo', 'Bar', 'Bar', 'Middle', 'Middle']);
+
+    ops = [];
+
+    // Render the high priority work (everying except the hidden trees).
+    ReactNoop.performAnimationWork(() => {
+      ReactNoop.render(<Foo text="foo" />);
+    });
+    ReactNoop.render(<Foo text="bar" />);
+    ReactNoop.flushAnimationPri();
+
+    expect(ops).toEqual(['Foo', 'Bar', 'Bar']);
+
+    ops = [];
+
+    // The hidden content was deprioritized from high to low priority. A low
+    // priority callback should have been scheduled. Flush it now.
+    ReactNoop.flushDeferredPri();
+
+    expect(ops).toEqual(['Middle', 'Middle']);
+  });
+
+  it('can resume work in a subtree even when a parent bails out', () => {
+    var ops = [];
+
+    function Bar(props) {
+      ops.push('Bar');
+      return <div>{props.children}</div>;
+    }
+
+    function Tester() {
+      // This component is just here to ensure that the bail out is
+      // in fact in effect in the expected place for this test.
+      ops.push('Tester');
+      return <div />;
+    }
+
+    function Middle(props) {
+      ops.push('Middle');
+      return <span>{props.children}</span>;
+    }
+
+    var middleContent = (
+      <aaa>
+        <Tester />
+        <bbb hidden={true}>
+          <ccc>
+            <Middle>Hi</Middle>
+          </ccc>
+        </bbb>
+      </aaa>
+    );
+
+    function Foo(props) {
+      ops.push('Foo');
+      return (
+        <div>
+          <Bar>{props.text}</Bar>
+          {middleContent}
+          <Bar>{props.text}</Bar>
+        </div>
+      );
+    }
+
+    // Init
+    ReactNoop.render(<Foo text="foo" />);
+    ReactNoop.flushDeferredPri(52);
+
+    expect(ops).toEqual(['Foo', 'Bar', 'Tester', 'Bar']);
+
+    ops = [];
+
+    // We're now rendering an update that will bail out on updating middle.
+    ReactNoop.render(<Foo text="bar" />);
+    ReactNoop.flushDeferredPri(45);
+
+    expect(ops).toEqual(['Foo', 'Bar', 'Bar']);
+
+    ops = [];
+
+    // Flush the rest to make sure that the bailout didn't block this work.
+    ReactNoop.flush();
+    expect(ops).toEqual(['Middle']);
+  });
+
+  it('can resume work in a bailed subtree within one pass', () => {
+    var ops = [];
+
+    function Bar(props) {
+      ops.push('Bar');
+      return <div>{props.children}</div>;
+    }
+
+    class Tester extends React.Component {
+      shouldComponentUpdate() {
+        return false;
+      }
+      render() {
+        // This component is just here to ensure that the bail out is
+        // in fact in effect in the expected place for this test.
+        ops.push('Tester');
+        return <div />;
+      }
+    }
+
+    function Middle(props) {
+      ops.push('Middle');
+      return <span>{props.children}</span>;
+    }
+
+    // Should content not just bail out on current, not workInProgress?
+
+    class Content extends React.Component {
+      shouldComponentUpdate() {
+        return false;
+      }
+      render() {
+        return [
+          <Tester unused={this.props.unused} />,
+          <bbb hidden={true}>
+            <ccc>
+              <Middle>Hi</Middle>
+            </ccc>
+          </bbb>,
+        ];
+      }
+    }
+
+    function Foo(props) {
+      ops.push('Foo');
+      return (
+        <div hidden={props.text === 'bar'}>
+          <Bar>{props.text}</Bar>
+          <Content unused={props.text} />
+          <Bar>{props.text}</Bar>
+        </div>
+      );
+    }
+
+    // Init
+    ReactNoop.render(<Foo text="foo" />);
+    ReactNoop.flushDeferredPri(52);
+
+    expect(ops).toEqual(['Foo', 'Bar', 'Tester', 'Bar']);
+
+    ops = [];
+
+    // Make a quick update which will create a low pri tree on top of the
+    // already low pri tree.
+    ReactNoop.render(<Foo text="bar" />);
+    ReactNoop.flushDeferredPri(15);
+
+    expect(ops).toEqual(['Foo']);
+
+    ops = [];
+
+    // At this point, middle will bail out but it has not yet fully rendered.
+    // Since that is the same priority as its parent tree. This should render
+    // as a single batch. Therefore, it is correct that Middle should be in the
+    // middle. If it occurs after the two "Bar" components then it was flushed
+    // after them which is not correct.
+    ReactNoop.flush();
+    expect(ops).toEqual(['Bar', 'Middle', 'Bar']);
+  });
+
+  it('can reuse work done after being preempted', () => {
+    var ops = [];
+
+    function Bar(props) {
+      ops.push('Bar');
+      return <div>{props.children}</div>;
+    }
+
+    function Middle(props) {
+      ops.push('Middle');
+      return <span>{props.children}</span>;
+    }
+
+    var middleContent = (
+      <div>
+        <Middle>Hello</Middle>
+        <Bar>-</Bar>
+        <Middle>World</Middle>
+      </div>
+    );
+
+    var step0 = (
+      <div>
+        <Middle>Hi</Middle>
+        <Bar>{'Foo'}</Bar>
+        <Middle>There</Middle>
+      </div>
+    );
+
+    function Foo(props) {
+      ops.push('Foo');
+      return (
+        <div>
+          <Bar>{props.text2}</Bar>
+          <div hidden={true}>
+            {props.step === 0 ? step0 : middleContent}
+          </div>
+        </div>
+      );
+    }
+
+    // Init
+    ReactNoop.render(<Foo text="foo" text2="foo" step={0} />);
+    ReactNoop.flushDeferredPri(55 + 25);
+
+    // We only finish the higher priority work. So the low pri content
+    // has not yet finished mounting.
+    expect(ops).toEqual(['Foo', 'Bar', 'Middle', 'Bar']);
+
+    ops = [];
+
+    // Interupt the rendering with a quick update. This should not touch the
+    // middle content.
+    ReactNoop.render(<Foo text="foo" text2="bar" step={0} />);
+    ReactNoop.flush();
+
+    // We've now rendered the entire tree but we didn't have to redo the work
+    // done by the first Middle and Bar already.
+    expect(ops).toEqual(['Foo', 'Bar', 'Middle']);
+
+    ops = [];
+
+    // Make a quick update which will schedule low priority work to
+    // update the middle content.
+    ReactNoop.render(<Foo text="bar" text2="bar" step={1} />);
+    ReactNoop.flushDeferredPri(30 + 25);
+
+    expect(ops).toEqual(['Foo', 'Bar']);
+
+    ops = [];
+
+    // The middle content is now pending rendering...
+    ReactNoop.flushDeferredPri(30);
+    expect(ops).toEqual(['Middle', 'Bar']);
+
+    ops = [];
+
+    // but we'll interupt it to render some higher priority work.
+    // The middle content will bailout so it remains untouched.
+    ReactNoop.render(<Foo text="foo" text2="bar" step={1} />);
+    ReactNoop.flushDeferredPri(30);
+
+    expect(ops).toEqual(['Foo', 'Bar']);
+
+    ops = [];
+
+    // Since we did nothing to the middle subtree during the interuption,
+    // we should be able to reuse the reconciliation work that we already did
+    // without restarting.
+    ReactNoop.flush();
+    expect(ops).toEqual(['Middle']);
+  });
+
+  it('can reuse work if shouldComponentUpdate is false, after being preempted', () => {
+    var ops = [];
+
+    function Bar(props) {
+      ops.push('Bar');
+      return <div>{props.children}</div>;
+    }
+
+    class Middle extends React.Component {
+      shouldComponentUpdate(nextProps) {
+        return this.props.children !== nextProps.children;
+      }
+      render() {
+        ops.push('Middle');
+        return <span>{this.props.children}</span>;
+      }
+    }
+
+    class Content extends React.Component {
+      shouldComponentUpdate(nextProps) {
+        return this.props.step !== nextProps.step;
+      }
+      render() {
+        ops.push('Content');
+        return (
+          <div>
+            <Middle>{this.props.step === 0 ? 'Hi' : 'Hello'}</Middle>
+            <Bar>{this.props.step === 0 ? this.props.text : '-'}</Bar>
+            <Middle>{this.props.step === 0 ? 'There' : 'World'}</Middle>
+          </div>
+        );
+      }
+    }
+
+    function Foo(props) {
+      ops.push('Foo');
+      return (
+        <div>
+          <Bar>{props.text}</Bar>
+          <div hidden={true}>
+            <Content step={props.step} text={props.text} />
+          </div>
+        </div>
+      );
+    }
+
+    // Init
+    ReactNoop.render(<Foo text="foo" step={0} />);
+    ReactNoop.flush();
+
+    expect(ops).toEqual(['Foo', 'Bar', 'Content', 'Middle', 'Bar', 'Middle']);
+
+    ops = [];
+
+    // Make a quick update which will schedule low priority work to
+    // update the middle content.
+    ReactNoop.render(<Foo text="bar" step={1} />);
+    ReactNoop.flushDeferredPri(30);
+
+    expect(ops).toEqual(['Foo', 'Bar']);
+
+    ops = [];
+
+    // The middle content is now pending rendering...
+    ReactNoop.flushDeferredPri(30 + 25);
+    expect(ops).toEqual(['Content', 'Middle', 'Bar']); // One more Middle left.
+
+    ops = [];
+
+    // but we'll interupt it to render some higher priority work.
+    // The middle content will bailout so it remains untouched.
+    ReactNoop.render(<Foo text="foo" step={1} />);
+    ReactNoop.flushDeferredPri(30);
+
+    expect(ops).toEqual(['Foo', 'Bar']);
+
+    ops = [];
+
+    // Since we did nothing to the middle subtree during the interuption,
+    // we should be able to reuse the reconciliation work that we already did
+    // without restarting.
+    ReactNoop.flush();
+    // TODO: Content never fully completed its render so can't completely bail
+    // out on the entire subtree. However, we could do a shallow bail out and
+    // not rerender Content, but keep going down the incomplete tree.
+    // Normally shouldComponentUpdate->false is not enough to determine that we
+    // can safely reuse the old props, but I think in this case it would be ok,
+    // since it is a resume of already started work.
+    // Because of the above we can also not reuse the work of Bar because the
+    // rerender of Content will generate a new element which will mean we don't
+    // auto-bail out from Bar.
+    expect(ops).toEqual(['Content', 'Bar', 'Middle']);
+  });
+
+  it('can update in the middle of a tree using setState', () => {
+    let instance;
+    class Bar extends React.Component {
+      constructor() {
+        super();
+        this.state = {a: 'a'};
+        instance = this;
+      }
+      render() {
+        return <div>{this.props.children}</div>;
+      }
+    }
+
+    function Foo() {
+      return (
+        <div>
+          <Bar />
+        </div>
+      );
+    }
+
+    ReactNoop.render(<Foo />);
+    ReactNoop.flush();
+    expect(instance.state).toEqual({a: 'a'});
+    instance.setState({b: 'b'});
+    ReactNoop.flush();
+    expect(instance.state).toEqual({a: 'a', b: 'b'});
+  });
+
+  it('can queue multiple state updates', () => {
+    let instance;
+    class Bar extends React.Component {
+      constructor() {
+        super();
+        this.state = {a: 'a'};
+        instance = this;
+      }
+      render() {
+        return <div>{this.props.children}</div>;
+      }
+    }
+
+    function Foo() {
+      return (
+        <div>
+          <Bar />
+        </div>
+      );
+    }
+
+    ReactNoop.render(<Foo />);
+    ReactNoop.flush();
+    // Call setState multiple times before flushing
+    instance.setState({b: 'b'});
+    instance.setState({c: 'c'});
+    instance.setState({d: 'd'});
+    ReactNoop.flush();
+    expect(instance.state).toEqual({a: 'a', b: 'b', c: 'c', d: 'd'});
+  });
+
+  it('can use updater form of setState', () => {
+    let instance;
+    class Bar extends React.Component {
+      constructor() {
+        super();
+        this.state = {num: 1};
+        instance = this;
+      }
+      render() {
+        return <div>{this.props.children}</div>;
+      }
+    }
+
+    function Foo({multiplier}) {
+      return (
+        <div>
+          <Bar multiplier={multiplier} />
+        </div>
+      );
+    }
+
+    function updater(state, props) {
+      return {num: state.num * props.multiplier};
+    }
+
+    ReactNoop.render(<Foo multiplier={2} />);
+    ReactNoop.flush();
+    expect(instance.state.num).toEqual(1);
+    instance.setState(updater);
+    ReactNoop.flush();
+    expect(instance.state.num).toEqual(2);
+    instance.setState(updater);
+    ReactNoop.render(<Foo multiplier={3} />);
+    ReactNoop.flush();
+    expect(instance.state.num).toEqual(6);
+  });
+
+  it('can call setState inside update callback', () => {
+    let instance;
+    class Bar extends React.Component {
+      constructor() {
+        super();
+        this.state = {num: 1};
+        instance = this;
+      }
+      render() {
+        return <div>{this.props.children}</div>;
+      }
+    }
+
+    function Foo({multiplier}) {
+      return (
+        <div>
+          <Bar multiplier={multiplier} />
+        </div>
+      );
+    }
+
+    function updater(state, props) {
+      return {num: state.num * props.multiplier};
+    }
+
+    function callback() {
+      this.setState({called: true});
+    }
+
+    ReactNoop.render(<Foo multiplier={2} />);
+    ReactNoop.flush();
+    instance.setState(updater);
+    instance.setState(updater, callback);
+    ReactNoop.flush();
+    expect(instance.state.num).toEqual(4);
+    expect(instance.state.called).toEqual(true);
+  });
+
+  it('can replaceState', () => {
+    let instance;
+    class Bar extends React.Component {
+      state = {a: 'a'};
+      render() {
+        instance = this;
+        return <div>{this.props.children}</div>;
+      }
+    }
+
+    function Foo() {
+      return (
+        <div>
+          <Bar />
+        </div>
+      );
+    }
+
+    ReactNoop.render(<Foo />);
+    ReactNoop.flush();
+    instance.setState({b: 'b'});
+    instance.setState({c: 'c'});
+    instance.updater.enqueueReplaceState(instance, {d: 'd'});
+    ReactNoop.flush();
+    expect(instance.state).toEqual({d: 'd'});
+  });
+
+  it('can forceUpdate', () => {
+    const ops = [];
+
+    function Baz() {
+      ops.push('Baz');
+      return <div />;
+    }
+
+    let instance;
+    class Bar extends React.Component {
+      constructor() {
+        super();
+        instance = this;
+      }
+      shouldComponentUpdate() {
+        return false;
+      }
+      render() {
+        ops.push('Bar');
+        return <Baz />;
+      }
+    }
+
+    function Foo() {
+      ops.push('Foo');
+      return (
+        <div>
+          <Bar />
+        </div>
+      );
+    }
+
+    ReactNoop.render(<Foo />);
+    ReactNoop.flush();
+    expect(ops).toEqual(['Foo', 'Bar', 'Baz']);
+    instance.forceUpdate();
+    ReactNoop.flush();
+    expect(ops).toEqual(['Foo', 'Bar', 'Baz', 'Bar', 'Baz']);
+  });
+});
diff --git a/src/renderers/shared/fiber/__tests__/ReactIncrementalSideEffects-test.js b/src/renderers/shared/fiber/__tests__/ReactIncrementalSideEffects-test.js
new file mode 100644
index 000000000000..d874ac7bc7de
--- /dev/null
+++ b/src/renderers/shared/fiber/__tests__/ReactIncrementalSideEffects-test.js
@@ -0,0 +1,357 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var React;
+var ReactNoop;
+
+describe('ReactIncrementalSideEffects', () => {
+  beforeEach(() => {
+    React = require('React');
+    ReactNoop = require('ReactNoop');
+  });
+
+  function div(...children) {
+    return {type: 'div', children, prop: undefined};
+  }
+
+  function span(prop) {
+    return {type: 'span', children: [], prop};
+  }
+
+  it('can update child nodes of a host instance', () => {
+    function Bar(props) {
+      return <span>{props.text}</span>;
+    }
+
+    function Foo(props) {
+      return (
+        <div>
+          <Bar text={props.text} />
+          {props.text === 'World' ? <Bar text={props.text} /> : null}
+        </div>
+      );
+    }
+
+    ReactNoop.render(<Foo text="Hello" />);
+    ReactNoop.flush();
+    expect(ReactNoop.root.children).toEqual([div(span())]);
+
+    ReactNoop.render(<Foo text="World" />);
+    ReactNoop.flush();
+    expect(ReactNoop.root.children).toEqual([div(span(), span())]);
+  });
+
+  it('does not update child nodes if a flush is aborted', () => {
+    function Bar(props) {
+      return <span prop={props.text} />;
+    }
+
+    function Foo(props) {
+      return (
+        <div>
+          <div>
+            <Bar text={props.text} />
+            {props.text === 'Hello' ? <Bar text={props.text} /> : null}
+          </div>
+          <Bar text="Yo" />
+        </div>
+      );
+    }
+
+    ReactNoop.render(<Foo text="Hello" />);
+    ReactNoop.flush();
+    expect(ReactNoop.root.children).toEqual([
+      div(div(span('Hello'), span('Hello')), span('Yo')),
+    ]);
+
+    ReactNoop.render(<Foo text="World" />);
+    ReactNoop.flushDeferredPri(35);
+    expect(ReactNoop.root.children).toEqual([
+      div(div(span('Hello'), span('Hello')), span('Yo')),
+    ]);
+  });
+
+  it('preserves a previously rendered node when deprioritized', () => {
+    function Middle(props) {
+      return <span prop={props.children} />;
+    }
+
+    function Foo(props) {
+      return (
+        <div>
+          <div hidden={true}>
+            <Middle>{props.text}</Middle>
+          </div>
+        </div>
+      );
+    }
+
+    ReactNoop.render(<Foo text="foo" />);
+    ReactNoop.flush();
+
+    expect(ReactNoop.root.children).toEqual([div(div(span('foo')))]);
+
+    ReactNoop.render(<Foo text="bar" />);
+    ReactNoop.flushDeferredPri(20);
+
+    expect(ReactNoop.root.children).toEqual([div(div(span('foo')))]);
+
+    ReactNoop.flush();
+
+    expect(ReactNoop.root.children).toEqual([div(div(span('bar')))]);
+  });
+
+  it('can reuse side-effects after being preempted', () => {
+    function Bar(props) {
+      return <span prop={props.children} />;
+    }
+
+    var middleContent = (
+      <div>
+        <Bar>Hello</Bar>
+        <Bar>World</Bar>
+      </div>
+    );
+
+    function Foo(props) {
+      return (
+        <div hidden={true}>
+          {props.step === 0
+            ? <div>
+                <Bar>Hi</Bar>
+                <Bar>{props.text}</Bar>
+              </div>
+            : middleContent}
+        </div>
+      );
+    }
+
+    // Init
+    ReactNoop.render(<Foo text="foo" step={0} />);
+    ReactNoop.flush();
+
+    expect(ReactNoop.root.children).toEqual([
+      div(div(span('Hi'), span('foo'))),
+    ]);
+
+    // Make a quick update which will schedule low priority work to
+    // update the middle content.
+    ReactNoop.render(<Foo text="bar" step={1} />);
+    ReactNoop.flushDeferredPri(30);
+
+    // The tree remains unchanged.
+    expect(ReactNoop.root.children).toEqual([
+      div(div(span('Hi'), span('foo'))),
+    ]);
+
+    // The first Bar has already completed its update but we'll interupt it to
+    // render some higher priority work. The middle content will bailout so
+    // it remains untouched which means that it should reuse it next time.
+    ReactNoop.render(<Foo text="foo" step={1} />);
+    ReactNoop.flush();
+
+    // Since we did nothing to the middle subtree during the interuption,
+    // we should be able to reuse the reconciliation work that we already did
+    // without restarting. The side-effects should still be replayed.
+
+    expect(ReactNoop.root.children).toEqual([
+      div(div(span('Hello'), span('World'))),
+    ]);
+  });
+
+  it('can reuse side-effects after being preempted, if shouldComponentUpdate is false', () => {
+    class Bar extends React.Component {
+      shouldComponentUpdate(nextProps) {
+        return this.props.children !== nextProps.children;
+      }
+      render() {
+        return <span prop={this.props.children} />;
+      }
+    }
+
+    class Content extends React.Component {
+      shouldComponentUpdate(nextProps) {
+        return this.props.step !== nextProps.step;
+      }
+      render() {
+        return (
+          <div>
+            <Bar>{this.props.step === 0 ? 'Hi' : 'Hello'}</Bar>
+            <Bar>{this.props.step === 0 ? this.props.text : 'World'}</Bar>
+          </div>
+        );
+      }
+    }
+
+    function Foo(props) {
+      return (
+        <div hidden={true}>
+          <Content step={props.step} text={props.text} />
+        </div>
+      );
+    }
+
+    // Init
+    ReactNoop.render(<Foo text="foo" step={0} />);
+    ReactNoop.flush();
+
+    expect(ReactNoop.root.children).toEqual([
+      div(div(span('Hi'), span('foo'))),
+    ]);
+
+    // Make a quick update which will schedule low priority work to
+    // update the middle content.
+    ReactNoop.render(<Foo text="bar" step={1} />);
+    ReactNoop.flushDeferredPri(35);
+
+    // The tree remains unchanged.
+    expect(ReactNoop.root.children).toEqual([
+      div(div(span('Hi'), span('foo'))),
+    ]);
+
+    // The first Bar has already completed its update but we'll interupt it to
+    // render some higher priority work. The middle content will bailout so
+    // it remains untouched which means that it should reuse it next time.
+    ReactNoop.render(<Foo text="foo" step={1} />);
+    ReactNoop.flush(30);
+
+    // Since we did nothing to the middle subtree during the interuption,
+    // we should be able to reuse the reconciliation work that we already did
+    // without restarting. The side-effects should still be replayed.
+
+    expect(ReactNoop.root.children).toEqual([
+      div(div(span('Hello'), span('World'))),
+    ]);
+  });
+
+  it('updates a child even though the old props is empty', () => {
+    function Foo(props) {
+      return (
+        <div hidden={true}>
+          <span prop={1} />
+        </div>
+      );
+    }
+
+    ReactNoop.render(<Foo />);
+    ReactNoop.flush();
+    expect(ReactNoop.root.children).toEqual([div(span(1))]);
+  });
+
+  it('can defer side-effects and resume them later on', function() {
+    class Bar extends React.Component {
+      shouldComponentUpdate(nextProps) {
+        return this.props.idx !== nextProps;
+      }
+      render() {
+        return <span prop={this.props.idx} />;
+      }
+    }
+    function Foo(props) {
+      return (
+        <div>
+          <span prop={props.tick} />
+          <div hidden={true}>
+            <Bar idx={props.idx} />
+            <Bar idx={props.idx + 1} />
+          </div>
+        </div>
+      );
+    }
+    ReactNoop.render(<Foo tick={0} idx={0} />);
+    ReactNoop.flushDeferredPri(40 + 25);
+    expect(ReactNoop.root.children).toEqual([
+      div(
+        span(0),
+        div(/*the spans are down-prioritized and not rendered yet*/),
+      ),
+    ]);
+    ReactNoop.render(<Foo tick={1} idx={0} />);
+    ReactNoop.flushDeferredPri(35 + 25);
+    expect(ReactNoop.root.children).toEqual([
+      div(span(1), div(/*still not rendered yet*/)),
+    ]);
+    ReactNoop.flushDeferredPri(30 + 25);
+    expect(ReactNoop.root.children).toEqual([
+      div(
+        span(1),
+        div(
+          // Now we had enough time to finish the spans.
+          span(0),
+          span(1),
+        ),
+      ),
+    ]);
+    var innerSpanA = ReactNoop.root.children[0].children[1].children[1];
+    ReactNoop.render(<Foo tick={2} idx={1} />);
+    ReactNoop.flushDeferredPri(30 + 25);
+    expect(ReactNoop.root.children).toEqual([
+      div(
+        span(2),
+        div(
+          // Still same old numbers.
+          span(0),
+          span(1),
+        ),
+      ),
+    ]);
+    ReactNoop.flushDeferredPri(30);
+    expect(ReactNoop.root.children).toEqual([
+      div(
+        span(2),
+        div(
+          // New numbers.
+          span(1),
+          span(2),
+        ),
+      ),
+    ]);
+
+    var innerSpanB = ReactNoop.root.children[0].children[1].children[1];
+    // This should have been an update to an existing instance, not recreation.
+    // We verify that by ensuring that the child instance was the same as
+    // before.
+    expect(innerSpanA).toBe(innerSpanB);
+  });
+
+  // TODO: Test that side-effects are not cut off when a work in progress node
+  // moves to "current" without flushing due to having lower priority. Does this
+  // even happen? Maybe a child doesn't get processed because it is lower prio?
+
+  it('calls callback after update is flushed', () => {
+    let instance;
+    class Foo extends React.Component {
+      constructor() {
+        super();
+        instance = this;
+        this.state = {text: 'foo'};
+      }
+      render() {
+        return <span prop={this.state.text} />;
+      }
+    }
+
+    ReactNoop.render(<Foo />);
+    ReactNoop.flush();
+    expect(ReactNoop.root.children).toEqual([span('foo')]);
+    let called = false;
+    instance.setState({text: 'bar'}, () => {
+      expect(ReactNoop.root.children).toEqual([span('bar')]);
+      called = true;
+    });
+    ReactNoop.flush();
+    expect(called).toBe(true);
+  });
+
+  // TODO: Test that callbacks are not lost if an update is preempted.
+});
diff --git a/src/renderers/shared/fiber/isomorphic/ReactCoroutine.js b/src/renderers/shared/fiber/isomorphic/ReactCoroutine.js
new file mode 100644
index 000000000000..7f44eb8d02de
--- /dev/null
+++ b/src/renderers/shared/fiber/isomorphic/ReactCoroutine.js
@@ -0,0 +1,126 @@
+/**
+ * Copyright 2014-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 ReactCoroutine
+ * @flow
+ */
+
+'use strict';
+
+import type {ReactNodeList} from 'ReactTypes';
+
+// The Symbol used to tag the special React types. If there is no native Symbol
+// nor polyfill, then a plain number is used for performance.
+var REACT_COROUTINE_TYPE =
+  (typeof Symbol === 'function' &&
+    Symbol.for &&
+    Symbol.for('react.coroutine')) ||
+  0xeac8;
+
+var REACT_YIELD_TYPE =
+  (typeof Symbol === 'function' && Symbol.for && Symbol.for('react.yield')) ||
+  0xeac9;
+
+type ReifiedYield = {continuation: Object, props: Object};
+type CoroutineHandler<T> = (
+  props: T,
+  yields: Array<ReifiedYield>,
+) => ReactNodeList;
+
+export type ReactCoroutine = {
+  $$typeof: Symbol | number,
+  key: null | string,
+  children: any,
+  // This should be a more specific CoroutineHandler
+  handler: (props: any, yields: Array<ReifiedYield>) => ReactNodeList,
+  /* $FlowFixMe(>=0.31.0): Which is it? mixed? Or Object? Must match
+   * `ReactYield` type.
+   */
+  props: mixed,
+};
+export type ReactYield = {
+  $$typeof: Symbol | number,
+  key: null | string,
+  props: Object,
+  continuation: mixed,
+};
+
+exports.createCoroutine = function<T>(
+  children: mixed,
+  handler: CoroutineHandler<T>,
+  props: T,
+  key: ?string = null,
+): ReactCoroutine {
+  var coroutine = {
+    // This tag allow us to uniquely identify this as a React Coroutine
+    $$typeof: REACT_COROUTINE_TYPE,
+    key: key == null ? null : '' + key,
+    children: children,
+    handler: handler,
+    props: props,
+  };
+
+  if (__DEV__) {
+    // TODO: Add _store property for marking this as validated.
+    if (Object.freeze) {
+      Object.freeze(coroutine.props);
+      Object.freeze(coroutine);
+    }
+  }
+
+  return coroutine;
+};
+
+exports.createYield = function(
+  props: mixed,
+  continuation: mixed,
+  key: ?string = null,
+) {
+  var yieldNode = {
+    // This tag allow us to uniquely identify this as a React Yield
+    $$typeof: REACT_YIELD_TYPE,
+    key: key == null ? null : '' + key,
+    props: props,
+    continuation: continuation,
+  };
+
+  if (__DEV__) {
+    // TODO: Add _store property for marking this as validated.
+    if (Object.freeze) {
+      Object.freeze(yieldNode.props);
+      Object.freeze(yieldNode);
+    }
+  }
+
+  return yieldNode;
+};
+
+/**
+ * Verifies the object is a coroutine object.
+ */
+exports.isCoroutine = function(object: mixed): boolean {
+  return (
+    typeof object === 'object' &&
+    object !== null &&
+    object.$$typeof === REACT_COROUTINE_TYPE
+  );
+};
+
+/**
+ * Verifies the object is a yield object.
+ */
+exports.isYield = function(object: mixed): boolean {
+  return (
+    typeof object === 'object' &&
+    object !== null &&
+    object.$$typeof === REACT_YIELD_TYPE
+  );
+};
+
+exports.REACT_YIELD_TYPE = REACT_YIELD_TYPE;
+exports.REACT_COROUTINE_TYPE = REACT_COROUTINE_TYPE;
diff --git a/src/renderers/shared/fiber/isomorphic/ReactTypes.js b/src/renderers/shared/fiber/isomorphic/ReactTypes.js
new file mode 100644
index 000000000000..2ba79535dc0b
--- /dev/null
+++ b/src/renderers/shared/fiber/isomorphic/ReactTypes.js
@@ -0,0 +1,30 @@
+/**
+ * Copyright 2014-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 ReactTypes
+ * @flow
+ */
+
+'use strict';
+
+import type {ReactCoroutine, ReactYield} from 'ReactCoroutine';
+
+export type ReactNode =
+  | ReactElement<any>
+  | ReactCoroutine
+  | ReactYield
+  | ReactText
+  | ReactFragment;
+
+export type ReactFragment = ReactEmpty | Iterable<ReactNode>;
+
+export type ReactNodeList = ReactEmpty | ReactNode;
+
+export type ReactText = string | number;
+
+export type ReactEmpty = null | void | boolean;
diff --git a/src/renderers/shared/hooks/ReactHostOperationHistoryHook.js b/src/renderers/shared/hooks/ReactHostOperationHistoryHook.js
new file mode 100644
index 000000000000..bbe1aa8904b5
--- /dev/null
+++ b/src/renderers/shared/hooks/ReactHostOperationHistoryHook.js
@@ -0,0 +1,49 @@
+/**
+ * Copyright 2016-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 ReactHostOperationHistoryHook
+ * @flow
+ */
+
+'use strict';
+
+import type {DebugID} from 'ReactInstanceType';
+
+export type Operation = {instanceID: DebugID} & (
+  | {type: 'mount', payload: string}
+  | {type: 'insert child', payload: {toIndex: number, content: string}}
+  | {type: 'move child', payload: {fromIndex: number, toIndex: number}}
+  | {type: 'replace children', payload: string}
+  | {type: 'replace text', payload: string}
+  | {type: 'replace with', payload: string}
+  | {type: 'update styles', payload: mixed /* Style Object */}
+  | {type: 'update attribute', payload: {[name: string]: string}}
+  | {type: 'remove attribute', payload: string});
+
+var history: Array<Operation> = [];
+
+var ReactHostOperationHistoryHook = {
+  onHostOperation(operation: Operation) {
+    history.push(operation);
+  },
+
+  clearHistory(): void {
+    if (ReactHostOperationHistoryHook._preventClearing) {
+      // Should only be used for tests.
+      return;
+    }
+
+    history = [];
+  },
+
+  getHistory(): Array<Operation> {
+    return history;
+  },
+};
+
+module.exports = ReactHostOperationHistoryHook;
diff --git a/src/renderers/shared/hooks/ReactInvalidSetStateWarningHook.js b/src/renderers/shared/hooks/ReactInvalidSetStateWarningHook.js
new file mode 100644
index 000000000000..3c309ed0f549
--- /dev/null
+++ b/src/renderers/shared/hooks/ReactInvalidSetStateWarningHook.js
@@ -0,0 +1,40 @@
+/**
+ * Copyright 2016-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 ReactInvalidSetStateWarningHook
+ * @flow
+ */
+
+'use strict';
+
+var warning = require('warning');
+
+if (__DEV__) {
+  var processingChildContext = false;
+
+  var warnInvalidSetState = function() {
+    warning(
+      !processingChildContext,
+      'setState(...): Cannot call setState() inside getChildContext()',
+    );
+  };
+}
+
+var ReactInvalidSetStateWarningHook = {
+  onBeginProcessingChildContext(): void {
+    processingChildContext = true;
+  },
+  onEndProcessingChildContext(): void {
+    processingChildContext = false;
+  },
+  onSetState(): void {
+    warnInvalidSetState();
+  },
+};
+
+module.exports = ReactInvalidSetStateWarningHook;
diff --git a/src/renderers/shared/hooks/__tests__/ReactComponentTreeHook-test.js b/src/renderers/shared/hooks/__tests__/ReactComponentTreeHook-test.js
new file mode 100644
index 000000000000..974ed201b019
--- /dev/null
+++ b/src/renderers/shared/hooks/__tests__/ReactComponentTreeHook-test.js
@@ -0,0 +1,2214 @@
+/**
+ * Copyright 2016-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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+describe('ReactComponentTreeHook', () => {
+  var React;
+  var ReactDOM;
+  var ReactDOMServer;
+  var ReactInstanceMap;
+  var ReactComponentTreeHook;
+  var ReactComponentTreeTestUtils;
+
+  beforeEach(() => {
+    jest.resetModuleRegistry();
+
+    React = require('React');
+    ReactDOM = require('ReactDOM');
+    ReactDOMServer = require('ReactDOMServer');
+    ReactInstanceMap = require('ReactInstanceMap');
+    ReactComponentTreeHook = require('ReactComponentTreeHook');
+    ReactComponentTreeTestUtils = require('ReactComponentTreeTestUtils');
+  });
+
+  function assertTreeMatches(pairs) {
+    if (!Array.isArray(pairs[0])) {
+      pairs = [pairs];
+    }
+
+    var node = document.createElement('div');
+    var currentElement;
+    var rootInstance;
+
+    class Wrapper extends React.Component {
+      render() {
+        rootInstance = ReactInstanceMap.get(this);
+        return currentElement;
+      }
+    }
+
+    function expectWrapperTreeToEqual(expectedTree, andStayMounted) {
+      ReactComponentTreeTestUtils.expectTree(rootInstance._debugID, {
+        displayName: 'Wrapper',
+        children: expectedTree ? [expectedTree] : [],
+      });
+      var rootDisplayNames = ReactComponentTreeTestUtils.getRootDisplayNames();
+      var registeredDisplayNames = ReactComponentTreeTestUtils.getRegisteredDisplayNames();
+      if (!expectedTree) {
+        expect(rootDisplayNames).toEqual([]);
+        expect(registeredDisplayNames).toEqual([]);
+      } else if (andStayMounted) {
+        expect(rootDisplayNames).toContain('Wrapper');
+        expect(registeredDisplayNames).toContain('Wrapper');
+      }
+    }
+
+    // Mount once, render updates, then unmount.
+    // Ensure the tree is correct on every step.
+    pairs.forEach(([element, expectedTree]) => {
+      currentElement = element;
+
+      // Mount a new tree or update the existing tree.
+      ReactDOM.render(<Wrapper />, node);
+      expectWrapperTreeToEqual(expectedTree, true);
+
+      // Purging should have no effect
+      // on the tree we expect to see.
+      ReactComponentTreeHook.purgeUnmountedComponents();
+      expectWrapperTreeToEqual(expectedTree, true);
+    });
+
+    // Unmounting the root node should purge
+    // the whole subtree automatically.
+    ReactDOM.unmountComponentAtNode(node);
+    expectWrapperTreeToEqual(null);
+
+    // Server render every pair.
+    // Ensure the tree is correct on every step.
+    pairs.forEach(([element, expectedTree]) => {
+      currentElement = element;
+
+      // Rendering to string should not produce any entries
+      // because ReactDebugTool purges it when the flush ends.
+      ReactDOMServer.renderToString(<Wrapper />);
+      expectWrapperTreeToEqual(null);
+
+      // To test it, we tell the hook to ignore next purge
+      // so the cleanup request by ReactDebugTool is ignored.
+      // This lets us make assertions on the actual tree.
+      ReactComponentTreeHook._preventPurging = true;
+      ReactDOMServer.renderToString(<Wrapper />);
+      ReactComponentTreeHook._preventPurging = false;
+      expectWrapperTreeToEqual(expectedTree);
+
+      // Purge manually since we skipped the automatic purge.
+      ReactComponentTreeHook.purgeUnmountedComponents();
+      expectWrapperTreeToEqual(null);
+    });
+  }
+
+  describe('mount', () => {
+    it('uses displayName or Unknown for classic components', () => {
+      class Foo extends React.Component {
+        render() {
+          return null;
+        }
+      }
+
+      Foo.displayName = 'Bar';
+
+      class Baz extends React.Component {
+        render() {
+          return null;
+        }
+      }
+
+      class Qux extends React.Component {
+        render() {
+          return null;
+        }
+      }
+
+      delete Qux.displayName;
+
+      var element = <div><Foo /><Baz /><Qux /></div>;
+      var tree = {
+        displayName: 'div',
+        children: [
+          {
+            displayName: 'Bar',
+            children: [],
+          },
+          {
+            displayName: 'Baz',
+            children: [],
+          },
+          {
+            displayName: 'Unknown',
+            children: [],
+          },
+        ],
+      };
+      assertTreeMatches([element, tree]);
+    });
+
+    it('uses displayName, name, or ReactComponent for modern components', () => {
+      class Foo extends React.Component {
+        render() {
+          return null;
+        }
+      }
+      Foo.displayName = 'Bar';
+      class Baz extends React.Component {
+        render() {
+          return null;
+        }
+      }
+      class Qux extends React.Component {
+        render() {
+          return null;
+        }
+      }
+      delete Qux.name;
+
+      var element = <div><Foo /><Baz /><Qux /></div>;
+      var tree = {
+        displayName: 'div',
+        element,
+        children: [
+          {
+            displayName: 'Bar',
+            children: [],
+          },
+          {
+            displayName: 'Baz',
+            children: [],
+          },
+          {
+            // Note: Ideally fallback name should be consistent (e.g. "Unknown")
+            displayName: 'ReactComponent',
+            children: [],
+          },
+        ],
+      };
+      assertTreeMatches([element, tree]);
+    });
+
+    it('uses displayName, name, or Object for factory components', () => {
+      function Foo() {
+        return {
+          render() {
+            return null;
+          },
+        };
+      }
+      Foo.displayName = 'Bar';
+      function Baz() {
+        return {
+          render() {
+            return null;
+          },
+        };
+      }
+      function Qux() {
+        return {
+          render() {
+            return null;
+          },
+        };
+      }
+      delete Qux.name;
+
+      var element = <div><Foo /><Baz /><Qux /></div>;
+      var tree = {
+        displayName: 'div',
+        element,
+        children: [
+          {
+            displayName: 'Bar',
+            children: [],
+          },
+          {
+            displayName: 'Baz',
+            children: [],
+          },
+          {
+            displayName: 'Unknown',
+            children: [],
+          },
+        ],
+      };
+      assertTreeMatches([element, tree]);
+    });
+
+    it('uses displayName, name, or StatelessComponent for functional components', () => {
+      function Foo() {
+        return null;
+      }
+      Foo.displayName = 'Bar';
+      function Baz() {
+        return null;
+      }
+      function Qux() {
+        return null;
+      }
+      delete Qux.name;
+
+      var element = <div><Foo /><Baz /><Qux /></div>;
+      var tree = {
+        displayName: 'div',
+        element,
+        children: [
+          {
+            displayName: 'Bar',
+            children: [],
+          },
+          {
+            displayName: 'Baz',
+            children: [],
+          },
+          {
+            displayName: 'Unknown',
+            children: [],
+          },
+        ],
+      };
+      assertTreeMatches([element, tree]);
+    });
+
+    it('reports a host tree correctly', () => {
+      var element = (
+        <div>
+          <p>
+            <span>
+              Hi!
+            </span>
+            Wow.
+          </p>
+          <hr />
+        </div>
+      );
+      var tree = {
+        displayName: 'div',
+        children: [
+          {
+            displayName: 'p',
+            children: [
+              {
+                displayName: 'span',
+                children: [
+                  {
+                    displayName: '#text',
+                    text: 'Hi!',
+                  },
+                ],
+              },
+              {
+                displayName: '#text',
+                text: 'Wow.',
+              },
+            ],
+          },
+          {
+            displayName: 'hr',
+            element: <hr />,
+            children: [],
+          },
+        ],
+      };
+      assertTreeMatches([element, tree]);
+    });
+
+    it('reports a simple tree with composites correctly', () => {
+      class Foo extends React.Component {
+        render() {
+          return <div />;
+        }
+      }
+
+      var element = <Foo />;
+      var tree = {
+        displayName: 'Foo',
+        element,
+        children: [
+          {
+            displayName: 'div',
+            element: <div />,
+            children: [],
+          },
+        ],
+      };
+      assertTreeMatches([element, tree]);
+    });
+
+    it('reports a tree with composites correctly', () => {
+      class Qux extends React.Component {
+        render() {
+          return null;
+        }
+      }
+
+      function Foo() {
+        return {
+          render() {
+            return <Qux />;
+          },
+        };
+      }
+      function Bar({children}) {
+        return <h1>{children}</h1>;
+      }
+      class Baz extends React.Component {
+        render() {
+          return (
+            <div>
+              <Foo />
+              <Bar>
+                <span>Hi,</span>
+                Mom
+              </Bar>
+              <a href="#">Click me.</a>
+            </div>
+          );
+        }
+      }
+
+      var element = <Baz />;
+      var tree = {
+        displayName: 'Baz',
+        element,
+        children: [
+          {
+            displayName: 'div',
+            children: [
+              {
+                displayName: 'Foo',
+                element: <Foo />,
+                children: [
+                  {
+                    displayName: 'Qux',
+                    element: <Qux />,
+                    children: [],
+                  },
+                ],
+              },
+              {
+                displayName: 'Bar',
+                children: [
+                  {
+                    displayName: 'h1',
+                    children: [
+                      {
+                        displayName: 'span',
+                        children: [
+                          {
+                            displayName: '#text',
+                            element: 'Hi,',
+                            text: 'Hi,',
+                          },
+                        ],
+                      },
+                      {
+                        displayName: '#text',
+                        text: 'Mom',
+                        element: 'Mom',
+                      },
+                    ],
+                  },
+                ],
+              },
+              {
+                displayName: 'a',
+                children: [
+                  {
+                    displayName: '#text',
+                    text: 'Click me.',
+                    element: 'Click me.',
+                  },
+                ],
+              },
+            ],
+          },
+        ],
+      };
+      assertTreeMatches([element, tree]);
+    });
+
+    it('ignores null children', () => {
+      class Foo extends React.Component {
+        render() {
+          return null;
+        }
+      }
+      var element = <Foo />;
+      var tree = {
+        displayName: 'Foo',
+        children: [],
+      };
+      assertTreeMatches([element, tree]);
+    });
+
+    it('ignores false children', () => {
+      class Foo extends React.Component {
+        render() {
+          return false;
+        }
+      }
+      var element = <Foo />;
+      var tree = {
+        displayName: 'Foo',
+        children: [],
+      };
+      assertTreeMatches([element, tree]);
+    });
+
+    it('reports text nodes as children', () => {
+      var element = <div>{'1'}{2}</div>;
+      var tree = {
+        displayName: 'div',
+        element,
+        children: [
+          {
+            displayName: '#text',
+            text: '1',
+          },
+          {
+            displayName: '#text',
+            text: '2',
+          },
+        ],
+      };
+      assertTreeMatches([element, tree]);
+    });
+
+    it('reports a single text node as a child', () => {
+      var element = <div>{'1'}</div>;
+      var tree = {
+        displayName: 'div',
+        element,
+        children: [
+          {
+            displayName: '#text',
+            text: '1',
+          },
+        ],
+      };
+      assertTreeMatches([element, tree]);
+    });
+
+    it('reports a single number node as a child', () => {
+      var element = <div>{42}</div>;
+      var tree = {
+        displayName: 'div',
+        element,
+        children: [
+          {
+            displayName: '#text',
+            text: '42',
+          },
+        ],
+      };
+      assertTreeMatches([element, tree]);
+    });
+
+    it('reports a zero as a child', () => {
+      var element = <div>{0}</div>;
+      var tree = {
+        displayName: 'div',
+        element,
+        children: [
+          {
+            displayName: '#text',
+            text: '0',
+          },
+        ],
+      };
+      assertTreeMatches([element, tree]);
+    });
+
+    it('skips empty nodes for multiple children', () => {
+      function Foo() {
+        return <div />;
+      }
+      var element = (
+        <div>
+          {'hi'}
+          {false}
+          {42}
+          {null}
+          <Foo />
+        </div>
+      );
+      var tree = {
+        displayName: 'div',
+        element,
+        children: [
+          {
+            displayName: '#text',
+            text: 'hi',
+            element: 'hi',
+          },
+          {
+            displayName: '#text',
+            text: '42',
+            element: 42,
+          },
+          {
+            displayName: 'Foo',
+            element: <Foo />,
+            children: [
+              {
+                displayName: 'div',
+                element: <div />,
+                children: [],
+              },
+            ],
+          },
+        ],
+      };
+      assertTreeMatches([element, tree]);
+    });
+
+    it('reports html content as no children', () => {
+      var element = <div dangerouslySetInnerHTML={{__html: 'Bye.'}} />;
+      var tree = {
+        displayName: 'div',
+        children: [],
+      };
+      assertTreeMatches([element, tree]);
+    });
+  });
+
+  describe('update', () => {
+    describe('host component', () => {
+      it('updates text of a single text child', () => {
+        var elementBefore = <div>Hi.</div>;
+        var treeBefore = {
+          displayName: 'div',
+          children: [
+            {
+              displayName: '#text',
+              text: 'Hi.',
+            },
+          ],
+        };
+
+        var elementAfter = <div>Bye.</div>;
+        var treeAfter = {
+          displayName: 'div',
+          children: [
+            {
+              displayName: '#text',
+              text: 'Bye.',
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from no children to a single text child', () => {
+        var elementBefore = <div />;
+        var treeBefore = {
+          displayName: 'div',
+          children: [],
+        };
+
+        var elementAfter = <div>Hi.</div>;
+        var treeAfter = {
+          displayName: 'div',
+          children: [
+            {
+              displayName: '#text',
+              text: 'Hi.',
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from a single text child to no children', () => {
+        var elementBefore = <div>Hi.</div>;
+        var treeBefore = {
+          displayName: 'div',
+          children: [
+            {
+              displayName: '#text',
+              text: 'Hi.',
+            },
+          ],
+        };
+
+        var elementAfter = <div />;
+        var treeAfter = {
+          displayName: 'div',
+          children: [],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from html content to a single text child', () => {
+        var elementBefore = <div dangerouslySetInnerHTML={{__html: 'Hi.'}} />;
+        var treeBefore = {
+          displayName: 'div',
+          children: [],
+        };
+
+        var elementAfter = <div>Hi.</div>;
+        var treeAfter = {
+          displayName: 'div',
+          children: [
+            {
+              displayName: '#text',
+              text: 'Hi.',
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from a single text child to html content', () => {
+        var elementBefore = <div>Hi.</div>;
+        var treeBefore = {
+          displayName: 'div',
+          children: [
+            {
+              displayName: '#text',
+              text: 'Hi.',
+            },
+          ],
+        };
+
+        var elementAfter = <div dangerouslySetInnerHTML={{__html: 'Hi.'}} />;
+        var treeAfter = {
+          displayName: 'div',
+          children: [],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from no children to multiple text children', () => {
+        var elementBefore = <div />;
+        var treeBefore = {
+          displayName: 'div',
+          children: [],
+        };
+
+        var elementAfter = <div>{'Hi.'}{'Bye.'}</div>;
+        var treeAfter = {
+          displayName: 'div',
+          children: [
+            {
+              displayName: '#text',
+              text: 'Hi.',
+            },
+            {
+              displayName: '#text',
+              text: 'Bye.',
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from multiple text children to no children', () => {
+        var elementBefore = <div>{'Hi.'}{'Bye.'}</div>;
+        var treeBefore = {
+          displayName: 'div',
+          children: [
+            {
+              displayName: '#text',
+              text: 'Hi.',
+            },
+            {
+              displayName: '#text',
+              text: 'Bye.',
+            },
+          ],
+        };
+
+        var elementAfter = <div />;
+        var treeAfter = {
+          displayName: 'div',
+          children: [],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from html content to multiple text children', () => {
+        var elementBefore = <div dangerouslySetInnerHTML={{__html: 'Hi.'}} />;
+        var treeBefore = {
+          displayName: 'div',
+          children: [],
+        };
+
+        var elementAfter = <div>{'Hi.'}{'Bye.'}</div>;
+        var treeAfter = {
+          displayName: 'div',
+          children: [
+            {
+              displayName: '#text',
+              text: 'Hi.',
+            },
+            {
+              displayName: '#text',
+              text: 'Bye.',
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from multiple text children to html content', () => {
+        var elementBefore = <div>{'Hi.'}{'Bye.'}</div>;
+        var treeBefore = {
+          displayName: 'div',
+          children: [
+            {
+              displayName: '#text',
+              text: 'Hi.',
+            },
+            {
+              displayName: '#text',
+              text: 'Bye.',
+            },
+          ],
+        };
+
+        var elementAfter = <div dangerouslySetInnerHTML={{__html: 'Hi.'}} />;
+        var treeAfter = {
+          displayName: 'div',
+          children: [],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from html content to no children', () => {
+        var elementBefore = <div dangerouslySetInnerHTML={{__html: 'Hi.'}} />;
+        var treeBefore = {
+          displayName: 'div',
+          children: [],
+        };
+
+        var elementAfter = <div />;
+        var treeAfter = {
+          displayName: 'div',
+          children: [],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from no children to html content', () => {
+        var elementBefore = <div />;
+        var treeBefore = {
+          displayName: 'div',
+          children: [],
+        };
+
+        var elementAfter = <div dangerouslySetInnerHTML={{__html: 'Hi.'}} />;
+        var treeAfter = {
+          displayName: 'div',
+          children: [],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from one text child to multiple text children', () => {
+        var elementBefore = <div>Hi.</div>;
+        var treeBefore = {
+          displayName: 'div',
+          children: [
+            {
+              displayName: '#text',
+              text: 'Hi.',
+            },
+          ],
+        };
+
+        var elementAfter = <div>{'Hi.'}{'Bye.'}</div>;
+        var treeAfter = {
+          displayName: 'div',
+          children: [
+            {
+              displayName: '#text',
+              text: 'Hi.',
+            },
+            {
+              displayName: '#text',
+              text: 'Bye.',
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from multiple text children to one text child', () => {
+        var elementBefore = <div>{'Hi.'}{'Bye.'}</div>;
+        var treeBefore = {
+          displayName: 'div',
+          children: [
+            {
+              displayName: '#text',
+              text: 'Hi.',
+            },
+            {
+              displayName: '#text',
+              text: 'Bye.',
+            },
+          ],
+        };
+
+        var elementAfter = <div>Hi.</div>;
+        var treeAfter = {
+          displayName: 'div',
+          children: [
+            {
+              displayName: '#text',
+              text: 'Hi.',
+            },
+          ],
+        };
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates text nodes when reordering', () => {
+        var elementBefore = <div>{'Hi.'}{'Bye.'}</div>;
+        var treeBefore = {
+          displayName: 'div',
+          children: [
+            {
+              displayName: '#text',
+              text: 'Hi.',
+            },
+            {
+              displayName: '#text',
+              text: 'Bye.',
+            },
+          ],
+        };
+
+        var elementAfter = <div>{'Bye.'}{'Hi.'}</div>;
+        var treeAfter = {
+          displayName: 'div',
+          children: [
+            {
+              displayName: '#text',
+              text: 'Bye.',
+            },
+            {
+              displayName: '#text',
+              text: 'Hi.',
+            },
+          ],
+        };
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates host nodes when reordering with keys', () => {
+        var elementBefore = (
+          <div>
+            <div key="a">Hi.</div>
+            <div key="b">Bye.</div>
+          </div>
+        );
+        var treeBefore = {
+          displayName: 'div',
+          children: [
+            {
+              displayName: 'div',
+              children: [
+                {
+                  displayName: '#text',
+                  text: 'Hi.',
+                },
+              ],
+            },
+            {
+              displayName: 'div',
+              children: [
+                {
+                  displayName: '#text',
+                  text: 'Bye.',
+                },
+              ],
+            },
+          ],
+        };
+
+        var elementAfter = (
+          <div>
+            <div key="b">Bye.</div>
+            <div key="a">Hi.</div>
+          </div>
+        );
+        var treeAfter = {
+          displayName: 'div',
+          children: [
+            {
+              displayName: 'div',
+              children: [
+                {
+                  displayName: '#text',
+                  text: 'Bye.',
+                },
+              ],
+            },
+            {
+              displayName: 'div',
+              children: [
+                {
+                  displayName: '#text',
+                  text: 'Hi.',
+                },
+              ],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates host nodes when reordering without keys', () => {
+        var elementBefore = (
+          <div>
+            <div>Hi.</div>
+            <div>Bye.</div>
+          </div>
+        );
+        var treeBefore = {
+          displayName: 'div',
+          children: [
+            {
+              displayName: 'div',
+              children: [
+                {
+                  displayName: '#text',
+                  text: 'Hi.',
+                },
+              ],
+            },
+            {
+              displayName: 'div',
+              children: [
+                {
+                  displayName: '#text',
+                  text: 'Bye.',
+                },
+              ],
+            },
+          ],
+        };
+
+        var elementAfter = (
+          <div>
+            <div>Bye.</div>
+            <div>Hi.</div>
+          </div>
+        );
+        var treeAfter = {
+          displayName: 'div',
+          children: [
+            {
+              displayName: 'div',
+              children: [
+                {
+                  displayName: '#text',
+                  text: 'Bye.',
+                },
+              ],
+            },
+            {
+              displayName: 'div',
+              children: [
+                {
+                  displayName: '#text',
+                  text: 'Hi.',
+                },
+              ],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates a single composite child of a different type', () => {
+        function Foo() {
+          return null;
+        }
+
+        function Bar() {
+          return null;
+        }
+
+        var elementBefore = <div><Foo /></div>;
+        var treeBefore = {
+          displayName: 'div',
+          children: [
+            {
+              displayName: 'Foo',
+              children: [],
+            },
+          ],
+        };
+
+        var elementAfter = <div><Bar /></div>;
+        var treeAfter = {
+          displayName: 'div',
+          children: [
+            {
+              displayName: 'Bar',
+              children: [],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates a single composite child of the same type', () => {
+        function Foo({children}) {
+          return children;
+        }
+
+        var elementBefore = <div><Foo><div /></Foo></div>;
+        var treeBefore = {
+          displayName: 'div',
+          children: [
+            {
+              displayName: 'Foo',
+              children: [
+                {
+                  displayName: 'div',
+                  children: [],
+                },
+              ],
+            },
+          ],
+        };
+
+        var elementAfter = <div><Foo><span /></Foo></div>;
+        var treeAfter = {
+          displayName: 'div',
+          children: [
+            {
+              displayName: 'Foo',
+              children: [
+                {
+                  displayName: 'span',
+                  children: [],
+                },
+              ],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from no children to a single composite child', () => {
+        function Foo() {
+          return null;
+        }
+
+        var elementBefore = <div />;
+        var treeBefore = {
+          displayName: 'div',
+          children: [],
+        };
+
+        var elementAfter = <div><Foo /></div>;
+        var treeAfter = {
+          displayName: 'div',
+          children: [
+            {
+              displayName: 'Foo',
+              children: [],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from a single composite child to no children', () => {
+        function Foo() {
+          return null;
+        }
+
+        var elementBefore = <div><Foo /></div>;
+        var treeBefore = {
+          displayName: 'div',
+          children: [
+            {
+              displayName: 'Foo',
+              children: [],
+            },
+          ],
+        };
+
+        var elementAfter = <div />;
+        var treeAfter = {
+          displayName: 'div',
+          children: [],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates mixed children', () => {
+        function Foo() {
+          return <div />;
+        }
+        var element1 = (
+          <div>
+            {'hi'}
+            {false}
+            {42}
+            {null}
+            <Foo />
+          </div>
+        );
+        var tree1 = {
+          displayName: 'div',
+          children: [
+            {
+              displayName: '#text',
+              text: 'hi',
+            },
+            {
+              displayName: '#text',
+              text: '42',
+            },
+            {
+              displayName: 'Foo',
+              children: [
+                {
+                  displayName: 'div',
+                  children: [],
+                },
+              ],
+            },
+          ],
+        };
+
+        var element2 = (
+          <div>
+            <Foo />
+            {false}
+            {'hi'}
+            {null}
+          </div>
+        );
+        var tree2 = {
+          displayName: 'div',
+          children: [
+            {
+              displayName: 'Foo',
+              children: [
+                {
+                  displayName: 'div',
+                  children: [],
+                },
+              ],
+            },
+            {
+              displayName: '#text',
+              text: 'hi',
+            },
+          ],
+        };
+
+        var element3 = (
+          <div>
+            <Foo />
+          </div>
+        );
+        var tree3 = {
+          displayName: 'div',
+          children: [
+            {
+              displayName: 'Foo',
+              children: [
+                {
+                  displayName: 'div',
+                  children: [],
+                },
+              ],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [element1, tree1],
+          [element2, tree2],
+          [element3, tree3],
+        ]);
+      });
+    });
+
+    describe('functional component', () => {
+      it('updates with a host child', () => {
+        function Foo({children}) {
+          return children;
+        }
+
+        var elementBefore = <Foo><div /></Foo>;
+        var treeBefore = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'div',
+              children: [],
+            },
+          ],
+        };
+
+        var elementAfter = <Foo><span /></Foo>;
+        var treeAfter = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'span',
+              children: [],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from null to a host child', () => {
+        function Foo({children}) {
+          return children;
+        }
+
+        var elementBefore = <Foo>{null}</Foo>;
+        var treeBefore = {
+          displayName: 'Foo',
+          children: [],
+        };
+
+        var elementAfter = <Foo><div /></Foo>;
+        var treeAfter = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'div',
+              children: [],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from a host child to null', () => {
+        function Foo({children}) {
+          return children;
+        }
+
+        var elementBefore = <Foo><div /></Foo>;
+        var treeBefore = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'div',
+              children: [],
+            },
+          ],
+        };
+
+        var elementAfter = <Foo>{null}</Foo>;
+        var treeAfter = {
+          displayName: 'Foo',
+          children: [],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from a host child to a composite child', () => {
+        function Bar() {
+          return null;
+        }
+
+        function Foo({children}) {
+          return children;
+        }
+
+        var elementBefore = <Foo><div /></Foo>;
+        var treeBefore = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'div',
+              children: [],
+            },
+          ],
+        };
+
+        var elementAfter = <Foo><Bar /></Foo>;
+        var treeAfter = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'Bar',
+              children: [],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from a composite child to a host child', () => {
+        function Bar() {
+          return null;
+        }
+
+        function Foo({children}) {
+          return children;
+        }
+
+        var elementBefore = <Foo><Bar /></Foo>;
+        var treeBefore = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'Bar',
+              children: [],
+            },
+          ],
+        };
+
+        var elementAfter = <Foo><div /></Foo>;
+        var treeAfter = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'div',
+              children: [],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from null to a composite child', () => {
+        function Bar() {
+          return null;
+        }
+
+        function Foo({children}) {
+          return children;
+        }
+
+        var elementBefore = <Foo>{null}</Foo>;
+        var treeBefore = {
+          displayName: 'Foo',
+          children: [],
+        };
+
+        var elementAfter = <Foo><Bar /></Foo>;
+        var treeAfter = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'Bar',
+              children: [],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from a composite child to null', () => {
+        function Bar() {
+          return null;
+        }
+
+        function Foo({children}) {
+          return children;
+        }
+
+        var elementBefore = <Foo><Bar /></Foo>;
+        var treeBefore = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'Bar',
+              children: [],
+            },
+          ],
+        };
+
+        var elementAfter = <Foo>{null}</Foo>;
+        var treeAfter = {
+          displayName: 'Foo',
+          children: [],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+    });
+
+    describe('class component', () => {
+      it('updates with a host child', () => {
+        class Foo extends React.Component {
+          render() {
+            return this.props.children;
+          }
+        }
+
+        var elementBefore = <Foo><div /></Foo>;
+        var treeBefore = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'div',
+              children: [],
+            },
+          ],
+        };
+
+        var elementAfter = <Foo><span /></Foo>;
+        var treeAfter = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'span',
+              children: [],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from null to a host child', () => {
+        class Foo extends React.Component {
+          render() {
+            return this.props.children;
+          }
+        }
+
+        var elementBefore = <Foo>{null}</Foo>;
+        var treeBefore = {
+          displayName: 'Foo',
+          children: [],
+        };
+
+        var elementAfter = <Foo><div /></Foo>;
+        var treeAfter = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'div',
+              children: [],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from a host child to null', () => {
+        class Foo extends React.Component {
+          render() {
+            return this.props.children;
+          }
+        }
+
+        var elementBefore = <Foo><div /></Foo>;
+        var treeBefore = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'div',
+              children: [],
+            },
+          ],
+        };
+
+        var elementAfter = <Foo>{null}</Foo>;
+        var treeAfter = {
+          displayName: 'Foo',
+          children: [],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from a host child to a composite child', () => {
+        class Bar extends React.Component {
+          render() {
+            return null;
+          }
+        }
+
+        class Foo extends React.Component {
+          render() {
+            return this.props.children;
+          }
+        }
+
+        var elementBefore = <Foo><div /></Foo>;
+        var treeBefore = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'div',
+              children: [],
+            },
+          ],
+        };
+
+        var elementAfter = <Foo><Bar /></Foo>;
+        var treeAfter = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'Bar',
+              children: [],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from a composite child to a host child', () => {
+        class Bar extends React.Component {
+          render() {
+            return null;
+          }
+        }
+
+        class Foo extends React.Component {
+          render() {
+            return this.props.children;
+          }
+        }
+
+        var elementBefore = <Foo><Bar /></Foo>;
+        var treeBefore = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'Bar',
+              children: [],
+            },
+          ],
+        };
+
+        var elementAfter = <Foo><div /></Foo>;
+        var treeAfter = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'div',
+              children: [],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from null to a composite child', () => {
+        class Bar extends React.Component {
+          render() {
+            return null;
+          }
+        }
+
+        class Foo extends React.Component {
+          render() {
+            return this.props.children;
+          }
+        }
+
+        var elementBefore = <Foo>{null}</Foo>;
+        var treeBefore = {
+          displayName: 'Foo',
+          children: [],
+        };
+
+        var elementAfter = <Foo><Bar /></Foo>;
+        var treeAfter = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'Bar',
+              children: [],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from a composite child to null', () => {
+        class Bar extends React.Component {
+          render() {
+            return null;
+          }
+        }
+
+        class Foo extends React.Component {
+          render() {
+            return this.props.children;
+          }
+        }
+
+        var elementBefore = <Foo><Bar /></Foo>;
+        var treeBefore = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'Bar',
+              children: [],
+            },
+          ],
+        };
+
+        var elementAfter = <Foo>{null}</Foo>;
+        var treeAfter = {
+          displayName: 'Foo',
+          children: [],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+    });
+  });
+
+  it('tracks owner correctly', () => {
+    class Foo extends React.Component {
+      render() {
+        return <Bar><h1>Hi.</h1></Bar>;
+      }
+    }
+    function Bar({children}) {
+      return <div>{children} Mom</div>;
+    }
+
+    // Note that owner is not calculated for text nodes
+    // because they are not created from real elements.
+    var element = <article><Foo /></article>;
+    var tree = {
+      displayName: 'article',
+      children: [
+        {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'Bar',
+              ownerDisplayName: 'Foo',
+              children: [
+                {
+                  displayName: 'div',
+                  ownerDisplayName: 'Bar',
+                  children: [
+                    {
+                      displayName: 'h1',
+                      ownerDisplayName: 'Foo',
+                      children: [
+                        {
+                          displayName: '#text',
+                          text: 'Hi.',
+                        },
+                      ],
+                    },
+                    {
+                      displayName: '#text',
+                      text: ' Mom',
+                    },
+                  ],
+                },
+              ],
+            },
+          ],
+        },
+      ],
+    };
+    assertTreeMatches([element, tree]);
+  });
+
+  it('purges unmounted components automatically', () => {
+    var node = document.createElement('div');
+    var renderBar = true;
+    var fooInstance;
+    var barInstance;
+
+    class Foo extends React.Component {
+      render() {
+        fooInstance = ReactInstanceMap.get(this);
+        return renderBar ? <Bar /> : null;
+      }
+    }
+
+    class Bar extends React.Component {
+      render() {
+        barInstance = ReactInstanceMap.get(this);
+        return null;
+      }
+    }
+
+    ReactDOM.render(<Foo />, node);
+    ReactComponentTreeTestUtils.expectTree(
+      barInstance._debugID,
+      {
+        displayName: 'Bar',
+        parentDisplayName: 'Foo',
+        parentID: fooInstance._debugID,
+        children: [],
+      },
+      'Foo',
+    );
+
+    renderBar = false;
+    ReactDOM.render(<Foo />, node);
+    ReactDOM.render(<Foo />, node);
+    ReactComponentTreeTestUtils.expectTree(
+      barInstance._debugID,
+      {
+        displayName: 'Unknown',
+        children: [],
+        parentID: null,
+      },
+      'Foo',
+    );
+
+    ReactDOM.unmountComponentAtNode(node);
+    ReactComponentTreeTestUtils.expectTree(
+      barInstance._debugID,
+      {
+        displayName: 'Unknown',
+        children: [],
+        parentID: null,
+      },
+      'Foo',
+    );
+  });
+
+  it('reports update counts', () => {
+    var node = document.createElement('div');
+
+    ReactDOM.render(<div className="a" />, node);
+    var divID = ReactComponentTreeHook.getRootIDs()[0];
+    expect(ReactComponentTreeHook.getUpdateCount(divID)).toEqual(0);
+
+    ReactDOM.render(<span className="a" />, node);
+    var spanID = ReactComponentTreeHook.getRootIDs()[0];
+    expect(ReactComponentTreeHook.getUpdateCount(divID)).toEqual(0);
+    expect(ReactComponentTreeHook.getUpdateCount(spanID)).toEqual(0);
+
+    ReactDOM.render(<span className="b" />, node);
+    expect(ReactComponentTreeHook.getUpdateCount(divID)).toEqual(0);
+    expect(ReactComponentTreeHook.getUpdateCount(spanID)).toEqual(1);
+
+    ReactDOM.render(<span className="c" />, node);
+    expect(ReactComponentTreeHook.getUpdateCount(divID)).toEqual(0);
+    expect(ReactComponentTreeHook.getUpdateCount(spanID)).toEqual(2);
+
+    ReactDOM.unmountComponentAtNode(node);
+    expect(ReactComponentTreeHook.getUpdateCount(divID)).toEqual(0);
+    expect(ReactComponentTreeHook.getUpdateCount(spanID)).toEqual(0);
+  });
+
+  it('does not report top-level wrapper as a root', () => {
+    var node = document.createElement('div');
+
+    ReactDOM.render(<div className="a" />, node);
+    expect(ReactComponentTreeTestUtils.getRootDisplayNames()).toEqual(['div']);
+
+    ReactDOM.render(<div className="b" />, node);
+    expect(ReactComponentTreeTestUtils.getRootDisplayNames()).toEqual(['div']);
+
+    ReactDOM.unmountComponentAtNode(node);
+    expect(ReactComponentTreeTestUtils.getRootDisplayNames()).toEqual([]);
+    expect(ReactComponentTreeTestUtils.getRegisteredDisplayNames()).toEqual([]);
+  });
+
+  it('registers inlined text nodes', () => {
+    var node = document.createElement('div');
+
+    ReactDOM.render(<div>hi</div>, node);
+    expect(ReactComponentTreeTestUtils.getRegisteredDisplayNames()).toEqual([
+      'div',
+      '#text',
+    ]);
+
+    ReactDOM.unmountComponentAtNode(node);
+    expect(ReactComponentTreeTestUtils.getRegisteredDisplayNames()).toEqual([]);
+  });
+
+  describe('stack addenda', () => {
+    it('gets created', () => {
+      function getAddendum(element) {
+        var addendum = ReactComponentTreeHook.getCurrentStackAddendum(element);
+        return addendum.replace(/\(at .+?:\d+\)/g, '(at **)');
+      }
+
+      function Anon() {
+        return null;
+      }
+      Object.defineProperty(Anon, 'name', {
+        value: null,
+      });
+      function Orange() {
+        return null;
+      }
+
+      expect(getAddendum()).toBe('');
+      expect(getAddendum(<div />)).toBe('\n    in div (at **)');
+      expect(getAddendum(<Anon />)).toBe('\n    in Unknown (at **)');
+      expect(getAddendum(<Orange />)).toBe('\n    in Orange (at **)');
+      expect(getAddendum(React.createElement(Orange))).toBe('\n    in Orange');
+
+      var renders = 0;
+      var rOwnedByQ;
+
+      function Q() {
+        return (rOwnedByQ = React.createElement(R));
+      }
+      function R() {
+        return <div><S /></div>;
+      }
+      class S extends React.Component {
+        componentDidMount() {
+          // Check that the parent path is still fetched when only S itself is on
+          // the stack.
+          this.forceUpdate();
+        }
+        render() {
+          expect(getAddendum()).toBe(
+            '\n    in S (at **)' +
+              '\n    in div (at **)' +
+              '\n    in R (created by Q)' +
+              '\n    in Q (at **)',
+          );
+          expect(getAddendum(<span />)).toBe(
+            '\n    in span (at **)' +
+              '\n    in S (at **)' +
+              '\n    in div (at **)' +
+              '\n    in R (created by Q)' +
+              '\n    in Q (at **)',
+          );
+          expect(getAddendum(React.createElement('span'))).toBe(
+            '\n    in span (created by S)' +
+              '\n    in S (at **)' +
+              '\n    in div (at **)' +
+              '\n    in R (created by Q)' +
+              '\n    in Q (at **)',
+          );
+          renders++;
+          return null;
+        }
+      }
+      ReactDOM.render(<Q />, document.createElement('div'));
+      expect(renders).toBe(2);
+
+      // Make sure owner is fetched for the top element too.
+      expect(getAddendum(rOwnedByQ)).toBe('\n    in R (created by Q)');
+    });
+
+    it('can be retrieved by ID', () => {
+      function getAddendum(id) {
+        var addendum = ReactComponentTreeHook.getStackAddendumByID(id);
+        return addendum.replace(/\(at .+?:\d+\)/g, '(at **)');
+      }
+
+      class Q extends React.Component {
+        render() {
+          return null;
+        }
+      }
+
+      var q = ReactDOM.render(<Q />, document.createElement('div'));
+      expect(getAddendum(ReactInstanceMap.get(q)._debugID)).toBe(
+        '\n    in Q (at **)',
+      );
+
+      spyOn(console, 'error');
+      getAddendum(-17);
+      expect(console.error.calls.count()).toBe(1);
+      expect(console.error.calls.argsFor(0)[0]).toBe(
+        'Warning: ReactComponentTreeHook: Missing React element for ' +
+          'debugID -17 when building stack',
+      );
+    });
+
+    it('is created during mounting', () => {
+      // https://github.com/facebook/react/issues/7187
+      var el = document.createElement('div');
+      var portalEl = document.createElement('div');
+      class Foo extends React.Component {
+        componentWillMount() {
+          ReactDOM.render(<div />, portalEl);
+        }
+        render() {
+          return <div><div /></div>;
+        }
+      }
+      ReactDOM.render(<Foo />, el);
+    });
+
+    it('is created when calling renderToString during render', () => {
+      // https://github.com/facebook/react/issues/7190
+      var el = document.createElement('div');
+      class Foo extends React.Component {
+        render() {
+          return (
+            <div>
+              <div>
+                {ReactDOMServer.renderToString(<div />)}
+              </div>
+            </div>
+          );
+        }
+      }
+      ReactDOM.render(<Foo />, el);
+    });
+  });
+
+  describe('in environment without Map, Set and Array.from', () => {
+    var realMap;
+    var realSet;
+    var realArrayFrom;
+
+    beforeEach(() => {
+      realMap = global.Map;
+      realSet = global.Set;
+      realArrayFrom = Array.from;
+
+      global.Map = undefined;
+      global.Set = undefined;
+      Array.from = undefined;
+
+      jest.resetModuleRegistry();
+
+      React = require('React');
+      ReactDOM = require('ReactDOM');
+      ReactDOMServer = require('ReactDOMServer');
+      ReactInstanceMap = require('ReactInstanceMap');
+      ReactComponentTreeHook = require('ReactComponentTreeHook');
+      ReactComponentTreeTestUtils = require('ReactComponentTreeTestUtils');
+    });
+
+    afterEach(() => {
+      global.Map = realMap;
+      global.Set = realSet;
+      Array.from = realArrayFrom;
+    });
+
+    it('works', () => {
+      class Qux extends React.Component {
+        render() {
+          return null;
+        }
+      }
+
+      function Foo() {
+        return {
+          render() {
+            return <Qux />;
+          },
+        };
+      }
+      function Bar({children}) {
+        return <h1>{children}</h1>;
+      }
+      class Baz extends React.Component {
+        render() {
+          return (
+            <div>
+              <Foo />
+              <Bar>
+                <span>Hi,</span>
+                Mom
+              </Bar>
+              <a href="#">Click me.</a>
+            </div>
+          );
+        }
+      }
+
+      var element = <Baz />;
+      var tree = {
+        displayName: 'Baz',
+        element,
+        children: [
+          {
+            displayName: 'div',
+            children: [
+              {
+                displayName: 'Foo',
+                element: <Foo />,
+                children: [
+                  {
+                    displayName: 'Qux',
+                    element: <Qux />,
+                    children: [],
+                  },
+                ],
+              },
+              {
+                displayName: 'Bar',
+                children: [
+                  {
+                    displayName: 'h1',
+                    children: [
+                      {
+                        displayName: 'span',
+                        children: [
+                          {
+                            displayName: '#text',
+                            element: 'Hi,',
+                            text: 'Hi,',
+                          },
+                        ],
+                      },
+                      {
+                        displayName: '#text',
+                        text: 'Mom',
+                        element: 'Mom',
+                      },
+                    ],
+                  },
+                ],
+              },
+              {
+                displayName: 'a',
+                children: [
+                  {
+                    displayName: '#text',
+                    text: 'Click me.',
+                    element: 'Click me.',
+                  },
+                ],
+              },
+            ],
+          },
+        ],
+      };
+      assertTreeMatches([element, tree]);
+    });
+  });
+});
diff --git a/src/renderers/shared/hooks/__tests__/ReactComponentTreeHook-test.native.js b/src/renderers/shared/hooks/__tests__/ReactComponentTreeHook-test.native.js
new file mode 100644
index 000000000000..15cbde7b57e9
--- /dev/null
+++ b/src/renderers/shared/hooks/__tests__/ReactComponentTreeHook-test.native.js
@@ -0,0 +1,1985 @@
+/**
+ * Copyright 2016-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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+describe('ReactComponentTreeHook', () => {
+  var PropTypes;
+  var React;
+  var ReactNative;
+  var ReactInstanceMap;
+  var ReactComponentTreeHook;
+  var ReactComponentTreeTestUtils;
+  var createReactNativeComponentClass;
+  var View;
+  var Image;
+  var Text;
+
+  beforeEach(() => {
+    jest.resetModuleRegistry();
+
+    PropTypes = require('prop-types');
+    React = require('React');
+    ReactNative = require('ReactNative');
+    ReactInstanceMap = require('ReactInstanceMap');
+    ReactComponentTreeHook = require('ReactComponentTreeHook');
+    ReactComponentTreeTestUtils = require('ReactComponentTreeTestUtils');
+    View = require('View');
+    createReactNativeComponentClass = require('createReactNativeComponentClass');
+    Image = createReactNativeComponentClass({
+      validAttributes: {},
+      uiViewClassName: 'Image',
+    });
+    var RCText = createReactNativeComponentClass({
+      validAttributes: {},
+      uiViewClassName: 'RCText',
+    });
+    Text = class extends React.Component {
+      static childContextTypes = {
+        isInAParentText: PropTypes.bool,
+      };
+
+      getChildContext() {
+        return {isInAParentText: true};
+      }
+
+      render() {
+        return <RCText {...this.props} />;
+      }
+    };
+  });
+
+  function assertTreeMatches(pairs, options) {
+    if (!Array.isArray(pairs[0])) {
+      pairs = [pairs];
+    }
+
+    var currentElement;
+    var rootInstance;
+
+    class Wrapper extends React.Component {
+      render() {
+        rootInstance = ReactInstanceMap.get(this);
+        return currentElement;
+      }
+    }
+
+    function expectWrapperTreeToEqual(expectedTree, andStayMounted) {
+      ReactComponentTreeTestUtils.expectTree(rootInstance._debugID, {
+        displayName: 'Wrapper',
+        children: expectedTree ? [expectedTree] : [],
+      });
+      var rootDisplayNames = ReactComponentTreeTestUtils.getRootDisplayNames();
+      var registeredDisplayNames = ReactComponentTreeTestUtils.getRegisteredDisplayNames();
+      if (!expectedTree) {
+        expect(rootDisplayNames).toEqual([]);
+        expect(registeredDisplayNames).toEqual([]);
+      } else if (andStayMounted) {
+        expect(rootDisplayNames).toContain('Wrapper');
+        expect(registeredDisplayNames).toContain('Wrapper');
+      }
+    }
+
+    // Mount once, render updates, then unmount.
+    // Ensure the tree is correct on every step.
+    pairs.forEach(([element, expectedTree]) => {
+      currentElement = element;
+
+      // Mount a new tree or update the existing tree.
+      ReactNative.render(<Wrapper />, 1);
+      expectWrapperTreeToEqual(expectedTree, true);
+
+      // Purging should have no effect
+      // on the tree we expect to see.
+      ReactComponentTreeHook.purgeUnmountedComponents();
+      expectWrapperTreeToEqual(expectedTree, true);
+    });
+
+    // Unmounting the root node should purge
+    // the whole subtree automatically.
+    ReactNative.unmountComponentAtNode(1);
+    expectWrapperTreeToEqual(null);
+
+    // Mount and unmount for every pair.
+    // Ensure the tree is correct on every step.
+    pairs.forEach(([element, expectedTree]) => {
+      currentElement = element;
+
+      // Mount a new tree.
+      ReactNative.render(<Wrapper />, 1);
+      expectWrapperTreeToEqual(expectedTree);
+
+      // Unmounting should clean it up.
+      ReactNative.unmountComponentAtNode(1);
+      expectWrapperTreeToEqual(null);
+    });
+  }
+
+  describe('mount', () => {
+    it('uses displayName or Unknown for classic components', () => {
+      class Foo extends React.Component {
+        render() {
+          return null;
+        }
+      }
+
+      Foo.displayName = 'Bar';
+
+      class Baz extends React.Component {
+        render() {
+          return null;
+        }
+      }
+
+      class Qux extends React.Component {
+        render() {
+          return null;
+        }
+      }
+
+      delete Qux.displayName;
+
+      var element = <View><Foo /><Baz /><Qux /></View>;
+      var tree = {
+        displayName: 'View',
+        element,
+        children: [
+          {
+            displayName: 'Bar',
+            children: [],
+          },
+          {
+            displayName: 'Baz',
+            children: [],
+          },
+          {
+            displayName: 'Unknown',
+            children: [],
+          },
+        ],
+      };
+      assertTreeMatches([element, tree]);
+    });
+
+    it('uses displayName, name, or ReactComponent for modern components', () => {
+      class Foo extends React.Component {
+        render() {
+          return null;
+        }
+      }
+      Foo.displayName = 'Bar';
+      class Baz extends React.Component {
+        render() {
+          return null;
+        }
+      }
+      class Qux extends React.Component {
+        render() {
+          return null;
+        }
+      }
+      delete Qux.name;
+
+      var element = <View><Foo /><Baz /><Qux /></View>;
+      var tree = {
+        displayName: 'View',
+        children: [
+          {
+            displayName: 'Bar',
+            children: [],
+          },
+          {
+            displayName: 'Baz',
+            children: [],
+          },
+          {
+            // Note: Ideally fallback name should be consistent (e.g. "Unknown")
+            displayName: 'ReactComponent',
+            children: [],
+          },
+        ],
+      };
+      assertTreeMatches([element, tree]);
+    });
+
+    it('uses displayName, name, or Object for factory components', () => {
+      function Foo() {
+        return {
+          render() {
+            return null;
+          },
+        };
+      }
+      Foo.displayName = 'Bar';
+      function Baz() {
+        return {
+          render() {
+            return null;
+          },
+        };
+      }
+      function Qux() {
+        return {
+          render() {
+            return null;
+          },
+        };
+      }
+      delete Qux.name;
+
+      var element = <View><Foo /><Baz /><Qux /></View>;
+      var tree = {
+        displayName: 'View',
+        children: [
+          {
+            displayName: 'Bar',
+            children: [],
+          },
+          {
+            displayName: 'Baz',
+            children: [],
+          },
+          {
+            displayName: 'Unknown',
+            children: [],
+          },
+        ],
+      };
+      assertTreeMatches([element, tree]);
+    });
+
+    it('uses displayName, name, or StatelessComponent for functional components', () => {
+      function Foo() {
+        return null;
+      }
+      Foo.displayName = 'Bar';
+      function Baz() {
+        return null;
+      }
+      function Qux() {
+        return null;
+      }
+      delete Qux.name;
+
+      var element = <View><Foo /><Baz /><Qux /></View>;
+      var tree = {
+        displayName: 'View',
+        children: [
+          {
+            displayName: 'Bar',
+            children: [],
+          },
+          {
+            displayName: 'Baz',
+            children: [],
+          },
+          {
+            displayName: 'Unknown',
+            children: [],
+          },
+        ],
+      };
+      assertTreeMatches([element, tree]);
+    });
+
+    it('reports a host tree correctly', () => {
+      var element = (
+        <View>
+          <View>
+            <Text>
+              Hi!
+            </Text>
+          </View>
+          <Image />
+        </View>
+      );
+      var tree = {
+        displayName: 'View',
+        element,
+        children: [
+          {
+            displayName: 'View',
+            children: [
+              {
+                displayName: 'Text',
+                children: [
+                  {
+                    displayName: 'RCText',
+                    children: [
+                      {
+                        displayName: '#text',
+                        element: 'Hi!',
+                        text: 'Hi!',
+                      },
+                    ],
+                  },
+                ],
+              },
+            ],
+          },
+          {
+            displayName: 'Image',
+            element: <Image />,
+            children: [],
+          },
+        ],
+      };
+      assertTreeMatches([element, tree]);
+    });
+
+    it('reports a simple tree with composites correctly', () => {
+      class Foo extends React.Component {
+        render() {
+          return <Image />;
+        }
+      }
+
+      var element = <Foo />;
+      var tree = {
+        displayName: 'Foo',
+        element,
+        children: [
+          {
+            displayName: 'Image',
+            element: <Image />,
+            children: [],
+          },
+        ],
+      };
+      assertTreeMatches([element, tree]);
+    });
+
+    it('reports a tree with composites correctly', () => {
+      class Qux extends React.Component {
+        render() {
+          return null;
+        }
+      }
+
+      function Foo() {
+        return {
+          render() {
+            return <Qux />;
+          },
+        };
+      }
+      function Bar({children}) {
+        return <View>{children}</View>;
+      }
+      class Baz extends React.Component {
+        render() {
+          return (
+            <View>
+              <Foo />
+              <Bar>
+                <Text>Hi,</Text>
+              </Bar>
+              <Image />
+            </View>
+          );
+        }
+      }
+
+      var element = <Baz />;
+      var tree = {
+        displayName: 'Baz',
+        element,
+        children: [
+          {
+            displayName: 'View',
+            children: [
+              {
+                displayName: 'Foo',
+                element: <Foo />,
+                children: [
+                  {
+                    displayName: 'Qux',
+                    element: <Qux />,
+                    children: [],
+                  },
+                ],
+              },
+              {
+                displayName: 'Bar',
+                children: [
+                  {
+                    displayName: 'View',
+                    children: [
+                      {
+                        displayName: 'Text',
+                        children: [
+                          {
+                            displayName: 'RCText',
+                            children: [
+                              {
+                                displayName: '#text',
+                                element: 'Hi,',
+                                text: 'Hi,',
+                              },
+                            ],
+                          },
+                        ],
+                      },
+                    ],
+                  },
+                ],
+              },
+              {
+                displayName: 'Image',
+                element: <Image />,
+                children: [],
+              },
+            ],
+          },
+        ],
+      };
+      assertTreeMatches([element, tree]);
+    });
+
+    it('ignores null children', () => {
+      class Foo extends React.Component {
+        render() {
+          return null;
+        }
+      }
+      var element = <Foo />;
+      var tree = {
+        displayName: 'Foo',
+        children: [],
+      };
+      assertTreeMatches([element, tree]);
+    });
+
+    it('ignores false children', () => {
+      class Foo extends React.Component {
+        render() {
+          return false;
+        }
+      }
+      var element = <Foo />;
+      var tree = {
+        displayName: 'Foo',
+        children: [],
+      };
+      assertTreeMatches([element, tree]);
+    });
+
+    it('reports text nodes as children', () => {
+      var element = <Text>{'1'}{2}</Text>;
+      var tree = {
+        displayName: 'Text',
+        children: [
+          {
+            displayName: 'RCText',
+            children: [
+              {
+                displayName: '#text',
+                text: '1',
+              },
+              {
+                displayName: '#text',
+                text: '2',
+              },
+            ],
+          },
+        ],
+      };
+      assertTreeMatches([element, tree]);
+    });
+
+    it('reports a single text node as a child', () => {
+      var element = <Text>{'1'}</Text>;
+      var tree = {
+        displayName: 'Text',
+        children: [
+          {
+            displayName: 'RCText',
+            children: [
+              {
+                displayName: '#text',
+                text: '1',
+              },
+            ],
+          },
+        ],
+      };
+      assertTreeMatches([element, tree]);
+    });
+
+    it('reports a single number node as a child', () => {
+      var element = <Text>{42}</Text>;
+      var tree = {
+        displayName: 'Text',
+        children: [
+          {
+            displayName: 'RCText',
+            children: [
+              {
+                displayName: '#text',
+                text: '42',
+              },
+            ],
+          },
+        ],
+      };
+      assertTreeMatches([element, tree]);
+    });
+
+    it('reports a zero as a child', () => {
+      var element = <Text>{0}</Text>;
+      var tree = {
+        displayName: 'Text',
+        children: [
+          {
+            displayName: 'RCText',
+            children: [
+              {
+                displayName: '#text',
+                text: '0',
+              },
+            ],
+          },
+        ],
+      };
+      assertTreeMatches([element, tree]);
+    });
+
+    it('skips empty nodes for multiple children', () => {
+      function Foo() {
+        return <Image />;
+      }
+      var element = (
+        <View>
+          {false}
+          <Foo />
+          {null}
+          <Foo />
+        </View>
+      );
+      var tree = {
+        displayName: 'View',
+        element,
+        children: [
+          {
+            displayName: 'Foo',
+            element: <Foo />,
+            children: [
+              {
+                displayName: 'Image',
+                element: <Image />,
+                children: [],
+              },
+            ],
+          },
+          {
+            displayName: 'Foo',
+            element: <Foo />,
+            children: [
+              {
+                displayName: 'Image',
+                element: <Image />,
+                children: [],
+              },
+            ],
+          },
+        ],
+      };
+      assertTreeMatches([element, tree]);
+    });
+  });
+
+  describe('update', () => {
+    describe('host component', () => {
+      it('updates text of a single text child', () => {
+        var elementBefore = <Text>Hi.</Text>;
+        var treeBefore = {
+          displayName: 'Text',
+          children: [
+            {
+              displayName: 'RCText',
+              children: [
+                {
+                  displayName: '#text',
+                  text: 'Hi.',
+                },
+              ],
+            },
+          ],
+        };
+
+        var elementAfter = <Text>Bye.</Text>;
+        var treeAfter = {
+          displayName: 'Text',
+          children: [
+            {
+              displayName: 'RCText',
+              children: [
+                {
+                  displayName: '#text',
+                  text: 'Bye.',
+                },
+              ],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from no children to a single text child', () => {
+        var elementBefore = <Text />;
+        var treeBefore = {
+          displayName: 'Text',
+          children: [
+            {
+              displayName: 'RCText',
+              children: [],
+            },
+          ],
+        };
+
+        var elementAfter = <Text>Hi.</Text>;
+        var treeAfter = {
+          displayName: 'Text',
+          children: [
+            {
+              displayName: 'RCText',
+              children: [
+                {
+                  displayName: '#text',
+                  text: 'Hi.',
+                },
+              ],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from a single text child to no children', () => {
+        var elementBefore = <Text>Hi.</Text>;
+        var treeBefore = {
+          displayName: 'Text',
+          children: [
+            {
+              displayName: 'RCText',
+              children: [
+                {
+                  displayName: '#text',
+                  text: 'Hi.',
+                },
+              ],
+            },
+          ],
+        };
+
+        var elementAfter = <Text />;
+        var treeAfter = {
+          displayName: 'Text',
+          children: [
+            {
+              displayName: 'RCText',
+              children: [],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from no children to multiple text children', () => {
+        var elementBefore = <Text />;
+        var treeBefore = {
+          displayName: 'Text',
+          children: [
+            {
+              displayName: 'RCText',
+              children: [],
+            },
+          ],
+        };
+
+        var elementAfter = <Text>{'Hi.'}{'Bye.'}</Text>;
+        var treeAfter = {
+          displayName: 'Text',
+          children: [
+            {
+              displayName: 'RCText',
+              children: [
+                {
+                  displayName: '#text',
+                  text: 'Hi.',
+                },
+                {
+                  displayName: '#text',
+                  text: 'Bye.',
+                },
+              ],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from multiple text children to no children', () => {
+        var elementBefore = <Text>{'Hi.'}{'Bye.'}</Text>;
+        var treeBefore = {
+          displayName: 'Text',
+          children: [
+            {
+              displayName: 'RCText',
+              children: [
+                {
+                  displayName: '#text',
+                  text: 'Hi.',
+                },
+                {
+                  displayName: '#text',
+                  text: 'Bye.',
+                },
+              ],
+            },
+          ],
+        };
+
+        var elementAfter = <Text />;
+        var treeAfter = {
+          displayName: 'Text',
+          children: [
+            {
+              displayName: 'RCText',
+              children: [],
+            },
+          ],
+        };
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from one text child to multiple text children', () => {
+        var elementBefore = <Text>Hi.</Text>;
+        var treeBefore = {
+          displayName: 'Text',
+          children: [
+            {
+              displayName: 'RCText',
+              children: [
+                {
+                  displayName: '#text',
+                  text: 'Hi.',
+                },
+              ],
+            },
+          ],
+        };
+
+        var elementAfter = <Text>{'Hi.'}{'Bye.'}</Text>;
+        var treeAfter = {
+          displayName: 'Text',
+          children: [
+            {
+              displayName: 'RCText',
+              children: [
+                {
+                  displayName: '#text',
+                  text: 'Hi.',
+                },
+                {
+                  displayName: '#text',
+                  text: 'Bye.',
+                },
+              ],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from multiple text children to one text child', () => {
+        var elementBefore = <Text>{'Hi.'}{'Bye.'}</Text>;
+        var treeBefore = {
+          displayName: 'Text',
+          children: [
+            {
+              displayName: 'RCText',
+              children: [
+                {
+                  displayName: '#text',
+                  text: 'Hi.',
+                },
+                {
+                  displayName: '#text',
+                  text: 'Bye.',
+                },
+              ],
+            },
+          ],
+        };
+
+        var elementAfter = <Text>Hi.</Text>;
+        var treeAfter = {
+          displayName: 'Text',
+          children: [
+            {
+              displayName: 'RCText',
+              children: [
+                {
+                  displayName: '#text',
+                  text: 'Hi.',
+                },
+              ],
+            },
+          ],
+        };
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates text nodes when reordering', () => {
+        var elementBefore = <Text>{'Hi.'}{'Bye.'}</Text>;
+        var treeBefore = {
+          displayName: 'Text',
+          children: [
+            {
+              displayName: 'RCText',
+              children: [
+                {
+                  displayName: '#text',
+                  text: 'Hi.',
+                },
+                {
+                  displayName: '#text',
+                  text: 'Bye.',
+                },
+              ],
+            },
+          ],
+        };
+
+        var elementAfter = <Text>{'Bye.'}{'Hi.'}</Text>;
+        var treeAfter = {
+          displayName: 'Text',
+          children: [
+            {
+              displayName: 'RCText',
+              children: [
+                {
+                  displayName: '#text',
+                  text: 'Bye.',
+                },
+                {
+                  displayName: '#text',
+                  text: 'Hi.',
+                },
+              ],
+            },
+          ],
+        };
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates host nodes when reordering with keys', () => {
+        var elementBefore = (
+          <View>
+            <Text key="a">Hi.</Text>
+            <Text key="b">Bye.</Text>
+          </View>
+        );
+        var treeBefore = {
+          displayName: 'View',
+          children: [
+            {
+              displayName: 'Text',
+              children: [
+                {
+                  displayName: 'RCText',
+                  children: [
+                    {
+                      displayName: '#text',
+                      text: 'Hi.',
+                    },
+                  ],
+                },
+              ],
+            },
+            {
+              displayName: 'Text',
+              children: [
+                {
+                  displayName: 'RCText',
+                  children: [
+                    {
+                      displayName: '#text',
+                      text: 'Bye.',
+                    },
+                  ],
+                },
+              ],
+            },
+          ],
+        };
+
+        var elementAfter = (
+          <View>
+            <Text key="b">Bye.</Text>
+            <Text key="a">Hi.</Text>
+          </View>
+        );
+        var treeAfter = {
+          displayName: 'View',
+          children: [
+            {
+              displayName: 'Text',
+              children: [
+                {
+                  displayName: 'RCText',
+                  children: [
+                    {
+                      displayName: '#text',
+                      text: 'Bye.',
+                    },
+                  ],
+                },
+              ],
+            },
+            {
+              displayName: 'Text',
+              children: [
+                {
+                  displayName: 'RCText',
+                  children: [
+                    {
+                      displayName: '#text',
+                      text: 'Hi.',
+                    },
+                  ],
+                },
+              ],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates host nodes when reordering with keys', () => {
+        var elementBefore = (
+          <View>
+            <Text>Hi.</Text>
+            <Text>Bye.</Text>
+          </View>
+        );
+        var treeBefore = {
+          displayName: 'View',
+          children: [
+            {
+              displayName: 'Text',
+              children: [
+                {
+                  displayName: 'RCText',
+                  children: [
+                    {
+                      displayName: '#text',
+                      text: 'Hi.',
+                    },
+                  ],
+                },
+              ],
+            },
+            {
+              displayName: 'Text',
+              children: [
+                {
+                  displayName: 'RCText',
+                  children: [
+                    {
+                      displayName: '#text',
+                      text: 'Bye.',
+                    },
+                  ],
+                },
+              ],
+            },
+          ],
+        };
+
+        var elementAfter = (
+          <View>
+            <Text>Bye.</Text>
+            <Text>Hi.</Text>
+          </View>
+        );
+        var treeAfter = {
+          displayName: 'View',
+          children: [
+            {
+              displayName: 'Text',
+              children: [
+                {
+                  displayName: 'RCText',
+                  children: [
+                    {
+                      displayName: '#text',
+                      text: 'Bye.',
+                    },
+                  ],
+                },
+              ],
+            },
+            {
+              displayName: 'Text',
+              children: [
+                {
+                  displayName: 'RCText',
+                  children: [
+                    {
+                      displayName: '#text',
+                      text: 'Hi.',
+                    },
+                  ],
+                },
+              ],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates a single composite child of a different type', () => {
+        function Foo() {
+          return null;
+        }
+
+        function Bar() {
+          return null;
+        }
+
+        var elementBefore = <View><Foo /></View>;
+        var treeBefore = {
+          displayName: 'View',
+          children: [
+            {
+              displayName: 'Foo',
+              children: [],
+            },
+          ],
+        };
+
+        var elementAfter = <View><Bar /></View>;
+        var treeAfter = {
+          displayName: 'View',
+          children: [
+            {
+              displayName: 'Bar',
+              children: [],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates a single composite child of the same type', () => {
+        function Foo({children}) {
+          return children;
+        }
+
+        var elementBefore = <View><Foo><View /></Foo></View>;
+        var treeBefore = {
+          displayName: 'View',
+          children: [
+            {
+              displayName: 'Foo',
+              children: [
+                {
+                  displayName: 'View',
+                  children: [],
+                },
+              ],
+            },
+          ],
+        };
+
+        var elementAfter = <View><Foo><Image /></Foo></View>;
+        var treeAfter = {
+          displayName: 'View',
+          children: [
+            {
+              displayName: 'Foo',
+              children: [
+                {
+                  displayName: 'Image',
+                  children: [],
+                },
+              ],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from no children to a single composite child', () => {
+        function Foo() {
+          return null;
+        }
+
+        var elementBefore = <View />;
+        var treeBefore = {
+          displayName: 'View',
+          children: [],
+        };
+
+        var elementAfter = <View><Foo /></View>;
+        var treeAfter = {
+          displayName: 'View',
+          children: [
+            {
+              displayName: 'Foo',
+              children: [],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from a single composite child to no children', () => {
+        function Foo() {
+          return null;
+        }
+
+        var elementBefore = <View><Foo /></View>;
+        var treeBefore = {
+          displayName: 'View',
+          children: [
+            {
+              displayName: 'Foo',
+              children: [],
+            },
+          ],
+        };
+
+        var elementAfter = <View />;
+        var treeAfter = {
+          displayName: 'View',
+          children: [],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates mixed children', () => {
+        function Foo() {
+          return <View />;
+        }
+        var element1 = (
+          <View>
+            <Text>hi</Text>
+            {false}
+            <Text>{42}</Text>
+            {null}
+            <Foo />
+          </View>
+        );
+        var tree1 = {
+          displayName: 'View',
+          children: [
+            {
+              displayName: 'Text',
+              children: [
+                {
+                  displayName: 'RCText',
+                  children: [
+                    {
+                      displayName: '#text',
+                      text: 'hi',
+                    },
+                  ],
+                },
+              ],
+            },
+            {
+              displayName: 'Text',
+              children: [
+                {
+                  displayName: 'RCText',
+                  children: [
+                    {
+                      displayName: '#text',
+                      text: '42',
+                    },
+                  ],
+                },
+              ],
+            },
+            {
+              displayName: 'Foo',
+              children: [
+                {
+                  displayName: 'View',
+                  children: [],
+                },
+              ],
+            },
+          ],
+        };
+
+        var element2 = (
+          <View>
+            <Foo />
+            {false}
+            <Text>hi</Text>
+            {null}
+          </View>
+        );
+        var tree2 = {
+          displayName: 'View',
+          children: [
+            {
+              displayName: 'Foo',
+              children: [
+                {
+                  displayName: 'View',
+                  children: [],
+                },
+              ],
+            },
+            {
+              displayName: 'Text',
+              children: [
+                {
+                  displayName: 'RCText',
+                  children: [
+                    {
+                      displayName: '#text',
+                      text: 'hi',
+                    },
+                  ],
+                },
+              ],
+            },
+          ],
+        };
+
+        var element3 = (
+          <View>
+            <Foo />
+          </View>
+        );
+        var tree3 = {
+          displayName: 'View',
+          children: [
+            {
+              displayName: 'Foo',
+              children: [
+                {
+                  displayName: 'View',
+                  children: [],
+                },
+              ],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [element1, tree1],
+          [element2, tree2],
+          [element3, tree3],
+        ]);
+      });
+    });
+
+    describe('functional component', () => {
+      it('updates with a host child', () => {
+        function Foo({children}) {
+          return children;
+        }
+
+        var elementBefore = <Foo><View /></Foo>;
+        var treeBefore = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'View',
+              children: [],
+            },
+          ],
+        };
+
+        var elementAfter = <Foo><Image /></Foo>;
+        var treeAfter = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'Image',
+              children: [],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from null to a host child', () => {
+        function Foo({children}) {
+          return children;
+        }
+
+        var elementBefore = <Foo>{null}</Foo>;
+        var treeBefore = {
+          displayName: 'Foo',
+          children: [],
+        };
+
+        var elementAfter = <Foo><View /></Foo>;
+        var treeAfter = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'View',
+              children: [],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from a host child to null', () => {
+        function Foo({children}) {
+          return children;
+        }
+
+        var elementBefore = <Foo><View /></Foo>;
+        var treeBefore = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'View',
+              children: [],
+            },
+          ],
+        };
+
+        var elementAfter = <Foo>{null}</Foo>;
+        var treeAfter = {
+          displayName: 'Foo',
+          children: [],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from a host child to a composite child', () => {
+        function Bar() {
+          return null;
+        }
+
+        function Foo({children}) {
+          return children;
+        }
+
+        var elementBefore = <Foo><View /></Foo>;
+        var treeBefore = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'View',
+              children: [],
+            },
+          ],
+        };
+
+        var elementAfter = <Foo><Bar /></Foo>;
+        var treeAfter = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'Bar',
+              children: [],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from a composite child to a host child', () => {
+        function Bar() {
+          return null;
+        }
+
+        function Foo({children}) {
+          return children;
+        }
+
+        var elementBefore = <Foo><Bar /></Foo>;
+        var treeBefore = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'Bar',
+              children: [],
+            },
+          ],
+        };
+
+        var elementAfter = <Foo><View /></Foo>;
+        var treeAfter = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'View',
+              children: [],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from null to a composite child', () => {
+        function Bar() {
+          return null;
+        }
+
+        function Foo({children}) {
+          return children;
+        }
+
+        var elementBefore = <Foo>{null}</Foo>;
+        var treeBefore = {
+          displayName: 'Foo',
+          children: [],
+        };
+
+        var elementAfter = <Foo><Bar /></Foo>;
+        var treeAfter = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'Bar',
+              children: [],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from a composite child to null', () => {
+        function Bar() {
+          return null;
+        }
+
+        function Foo({children}) {
+          return children;
+        }
+
+        var elementBefore = <Foo><Bar /></Foo>;
+        var treeBefore = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'Bar',
+              children: [],
+            },
+          ],
+        };
+
+        var elementAfter = <Foo>{null}</Foo>;
+        var treeAfter = {
+          displayName: 'Foo',
+          children: [],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+    });
+
+    describe('class component', () => {
+      it('updates with a host child', () => {
+        class Foo extends React.Component {
+          render() {
+            return this.props.children;
+          }
+        }
+
+        var elementBefore = <Foo><View /></Foo>;
+        var treeBefore = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'View',
+              children: [],
+            },
+          ],
+        };
+
+        var elementAfter = <Foo><Image /></Foo>;
+        var treeAfter = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'Image',
+              children: [],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from null to a host child', () => {
+        class Foo extends React.Component {
+          render() {
+            return this.props.children;
+          }
+        }
+
+        var elementBefore = <Foo>{null}</Foo>;
+        var treeBefore = {
+          displayName: 'Foo',
+          children: [],
+        };
+
+        var elementAfter = <Foo><View /></Foo>;
+        var treeAfter = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'View',
+              children: [],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from a host child to null', () => {
+        class Foo extends React.Component {
+          render() {
+            return this.props.children;
+          }
+        }
+
+        var elementBefore = <Foo><View /></Foo>;
+        var treeBefore = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'View',
+              children: [],
+            },
+          ],
+        };
+
+        var elementAfter = <Foo>{null}</Foo>;
+        var treeAfter = {
+          displayName: 'Foo',
+          children: [],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from a host child to a composite child', () => {
+        class Bar extends React.Component {
+          render() {
+            return null;
+          }
+        }
+
+        class Foo extends React.Component {
+          render() {
+            return this.props.children;
+          }
+        }
+
+        var elementBefore = <Foo><View /></Foo>;
+        var treeBefore = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'View',
+              children: [],
+            },
+          ],
+        };
+
+        var elementAfter = <Foo><Bar /></Foo>;
+        var treeAfter = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'Bar',
+              children: [],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from a composite child to a host child', () => {
+        class Bar extends React.Component {
+          render() {
+            return null;
+          }
+        }
+
+        class Foo extends React.Component {
+          render() {
+            return this.props.children;
+          }
+        }
+
+        var elementBefore = <Foo><Bar /></Foo>;
+        var treeBefore = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'Bar',
+              children: [],
+            },
+          ],
+        };
+
+        var elementAfter = <Foo><View /></Foo>;
+        var treeAfter = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'View',
+              children: [],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from null to a composite child', () => {
+        class Bar extends React.Component {
+          render() {
+            return null;
+          }
+        }
+
+        class Foo extends React.Component {
+          render() {
+            return this.props.children;
+          }
+        }
+
+        var elementBefore = <Foo>{null}</Foo>;
+        var treeBefore = {
+          displayName: 'Foo',
+          children: [],
+        };
+
+        var elementAfter = <Foo><Bar /></Foo>;
+        var treeAfter = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'Bar',
+              children: [],
+            },
+          ],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+
+      it('updates from a composite child to null', () => {
+        class Bar extends React.Component {
+          render() {
+            return null;
+          }
+        }
+
+        class Foo extends React.Component {
+          render() {
+            return this.props.children;
+          }
+        }
+
+        var elementBefore = <Foo><Bar /></Foo>;
+        var treeBefore = {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'Bar',
+              children: [],
+            },
+          ],
+        };
+
+        var elementAfter = <Foo>{null}</Foo>;
+        var treeAfter = {
+          displayName: 'Foo',
+          children: [],
+        };
+
+        assertTreeMatches([
+          [elementBefore, treeBefore],
+          [elementAfter, treeAfter],
+        ]);
+      });
+    });
+  });
+
+  it('tracks owner correctly', () => {
+    class Foo extends React.Component {
+      render() {
+        return <Bar><Text>Hi.</Text></Bar>;
+      }
+    }
+    function Bar({children}) {
+      return <View>{children}<Text>Mom</Text></View>;
+    }
+
+    // Note that owner is not calculated for text nodes
+    // because they are not created from real elements.
+    var element = <View><Foo /></View>;
+    var tree = {
+      displayName: 'View',
+      children: [
+        {
+          displayName: 'Foo',
+          children: [
+            {
+              displayName: 'Bar',
+              ownerDisplayName: 'Foo',
+              children: [
+                {
+                  displayName: 'View',
+                  ownerDisplayName: 'Bar',
+                  children: [
+                    {
+                      displayName: 'Text',
+                      ownerDisplayName: 'Foo',
+                      children: [
+                        {
+                          displayName: 'RCText',
+                          ownerDisplayName: 'Text',
+                          children: [
+                            {
+                              displayName: '#text',
+                              text: 'Hi.',
+                            },
+                          ],
+                        },
+                      ],
+                    },
+                    {
+                      displayName: 'Text',
+                      ownerDisplayName: 'Bar',
+                      children: [
+                        {
+                          displayName: 'RCText',
+                          ownerDisplayName: 'Text',
+                          children: [
+                            {
+                              displayName: '#text',
+                              text: 'Mom',
+                            },
+                          ],
+                        },
+                      ],
+                    },
+                  ],
+                },
+              ],
+            },
+          ],
+        },
+      ],
+    };
+    assertTreeMatches([element, tree], {includeOwnerDisplayName: true});
+  });
+
+  it('purges unmounted components automatically', () => {
+    var renderBar = true;
+    var fooInstance;
+    var barInstance;
+
+    class Foo extends React.Component {
+      render() {
+        fooInstance = ReactInstanceMap.get(this);
+        return renderBar ? <Bar /> : null;
+      }
+    }
+
+    class Bar extends React.Component {
+      render() {
+        barInstance = ReactInstanceMap.get(this);
+        return null;
+      }
+    }
+
+    ReactNative.render(<Foo />, 1);
+    ReactComponentTreeTestUtils.expectTree(
+      barInstance._debugID,
+      {
+        displayName: 'Bar',
+        parentDisplayName: 'Foo',
+        parentID: fooInstance._debugID,
+        children: [],
+      },
+      'Foo',
+    );
+
+    renderBar = false;
+    ReactNative.render(<Foo />, 1);
+    ReactComponentTreeTestUtils.expectTree(
+      barInstance._debugID,
+      {
+        displayName: 'Unknown',
+        children: [],
+        parentID: null,
+      },
+      'Foo',
+    );
+
+    ReactNative.unmountComponentAtNode(1);
+    ReactComponentTreeTestUtils.expectTree(
+      barInstance._debugID,
+      {
+        displayName: 'Unknown',
+        children: [],
+        parentID: null,
+      },
+      'Foo',
+    );
+  });
+
+  it('reports update counts', () => {
+    ReactNative.render(<View />, 1);
+    var viewID = ReactComponentTreeHook.getRootIDs()[0];
+    expect(ReactComponentTreeHook.getUpdateCount(viewID)).toEqual(0);
+
+    ReactNative.render(<Image />, 1);
+    var imageID = ReactComponentTreeHook.getRootIDs()[0];
+    expect(ReactComponentTreeHook.getUpdateCount(viewID)).toEqual(0);
+    expect(ReactComponentTreeHook.getUpdateCount(imageID)).toEqual(0);
+
+    ReactNative.render(<Image />, 1);
+    expect(ReactComponentTreeHook.getUpdateCount(viewID)).toEqual(0);
+    expect(ReactComponentTreeHook.getUpdateCount(imageID)).toEqual(1);
+
+    ReactNative.render(<Image />, 1);
+    expect(ReactComponentTreeHook.getUpdateCount(viewID)).toEqual(0);
+    expect(ReactComponentTreeHook.getUpdateCount(imageID)).toEqual(2);
+
+    ReactNative.unmountComponentAtNode(1);
+    expect(ReactComponentTreeHook.getUpdateCount(viewID)).toEqual(0);
+    expect(ReactComponentTreeHook.getUpdateCount(imageID)).toEqual(0);
+  });
+
+  it('does not report top-level wrapper as a root', () => {
+    ReactNative.render(<View><Image /></View>, 1);
+    expect(ReactComponentTreeTestUtils.getRootDisplayNames()).toEqual(['View']);
+
+    ReactNative.render(<View><Text /></View>, 1);
+    expect(ReactComponentTreeTestUtils.getRootDisplayNames()).toEqual(['View']);
+
+    ReactNative.unmountComponentAtNode(1);
+    expect(ReactComponentTreeTestUtils.getRootDisplayNames()).toEqual([]);
+    expect(ReactComponentTreeTestUtils.getRegisteredDisplayNames()).toEqual([]);
+  });
+});
diff --git a/src/renderers/shared/hooks/__tests__/ReactHostOperationHistoryHook-test.js b/src/renderers/shared/hooks/__tests__/ReactHostOperationHistoryHook-test.js
new file mode 100644
index 000000000000..87877916acf9
--- /dev/null
+++ b/src/renderers/shared/hooks/__tests__/ReactHostOperationHistoryHook-test.js
@@ -0,0 +1,831 @@
+/**
+ * Copyright 2016-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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+describe('ReactHostOperationHistoryHook', () => {
+  var React;
+  var ReactPerf;
+  var ReactDOM;
+  var ReactDOMComponentTree;
+  var ReactDOMFeatureFlags;
+  var ReactHostOperationHistoryHook;
+
+  beforeEach(() => {
+    jest.resetModuleRegistry();
+
+    React = require('React');
+    ReactPerf = require('ReactPerf');
+    ReactDOM = require('ReactDOM');
+    ReactDOMComponentTree = require('ReactDOMComponentTree');
+    ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
+    ReactHostOperationHistoryHook = require('ReactHostOperationHistoryHook');
+
+    ReactPerf.start();
+  });
+
+  afterEach(() => {
+    ReactPerf.stop();
+  });
+
+  function assertHistoryMatches(expectedHistory) {
+    var actualHistory = ReactHostOperationHistoryHook.getHistory();
+    expect(actualHistory).toEqual(expectedHistory);
+  }
+
+  describe('mount', () => {
+    it('gets recorded for host roots', () => {
+      var node = document.createElement('div');
+      ReactHostOperationHistoryHook._preventClearing = true;
+      ReactDOM.render(<div><p>Hi.</p></div>, node);
+
+      var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
+      assertHistoryMatches([
+        {
+          instanceID: inst._debugID,
+          type: 'mount',
+          payload: ReactDOMFeatureFlags.useCreateElement
+            ? 'DIV'
+            : '<div data-reactroot="" data-reactid="1"><p data-reactid="2">Hi.</p></div>',
+        },
+      ]);
+    });
+
+    it('gets recorded for composite roots', () => {
+      function Foo() {
+        return <div><p>Hi.</p></div>;
+      }
+      var node = document.createElement('div');
+
+      ReactHostOperationHistoryHook._preventClearing = true;
+      ReactDOM.render(<Foo />, node);
+
+      var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
+      assertHistoryMatches([
+        {
+          instanceID: inst._debugID,
+          type: 'mount',
+          payload: ReactDOMFeatureFlags.useCreateElement
+            ? 'DIV'
+            : '<div data-reactroot="" data-reactid="1">' +
+                '<p data-reactid="2">Hi.</p></div>',
+        },
+      ]);
+    });
+
+    it('gets ignored for composite roots that return null', () => {
+      function Foo() {
+        return null;
+      }
+      var node = document.createElement('div');
+
+      ReactHostOperationHistoryHook._preventClearing = true;
+      ReactDOM.render(<Foo />, node);
+
+      // Empty DOM components should be invisible to hooks.
+      assertHistoryMatches([]);
+    });
+
+    it('gets recorded when a native is mounted deeply instead of null', () => {
+      var element;
+      function Foo() {
+        return element;
+      }
+
+      ReactHostOperationHistoryHook._preventClearing = true;
+
+      var node = document.createElement('div');
+      element = null;
+      ReactDOM.render(<Foo />, node);
+
+      element = <span />;
+      ReactDOM.render(<Foo />, node);
+      var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
+
+      // Since empty components should be invisible to hooks,
+      // we record a "mount" event rather than a "replace with".
+      assertHistoryMatches([
+        {
+          instanceID: inst._debugID,
+          type: 'mount',
+          payload: 'SPAN',
+        },
+      ]);
+    });
+  });
+
+  describe('update styles', () => {
+    it('gets recorded during mount', () => {
+      var node = document.createElement('div');
+
+      ReactHostOperationHistoryHook._preventClearing = true;
+      ReactDOM.render(
+        <div
+          style={{
+            color: 'red',
+            backgroundColor: 'yellow',
+          }}
+        />,
+        node,
+      );
+
+      var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
+      if (ReactDOMFeatureFlags.useCreateElement) {
+        assertHistoryMatches([
+          {
+            instanceID: inst._debugID,
+            type: 'update styles',
+            payload: {
+              color: 'red',
+              backgroundColor: 'yellow',
+            },
+          },
+          {
+            instanceID: inst._debugID,
+            type: 'mount',
+            payload: 'DIV',
+          },
+        ]);
+      } else {
+        assertHistoryMatches([
+          {
+            instanceID: inst._debugID,
+            type: 'mount',
+            payload:
+              '<div style="color:red;background-color:yellow;" ' +
+                'data-reactroot="" data-reactid="1"></div>',
+          },
+        ]);
+      }
+    });
+
+    it('gets recorded during an update', () => {
+      var node = document.createElement('div');
+      ReactDOM.render(<div />, node);
+      var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
+
+      ReactHostOperationHistoryHook._preventClearing = true;
+      ReactDOM.render(<div style={{color: 'red'}} />, node);
+      ReactDOM.render(
+        <div
+          style={{
+            color: 'blue',
+            backgroundColor: 'yellow',
+          }}
+        />,
+        node,
+      );
+      ReactDOM.render(<div style={{backgroundColor: 'green'}} />, node);
+      ReactDOM.render(<div />, node);
+
+      assertHistoryMatches([
+        {
+          instanceID: inst._debugID,
+          type: 'update styles',
+          payload: {color: 'red'},
+        },
+        {
+          instanceID: inst._debugID,
+          type: 'update styles',
+          payload: {color: 'blue', backgroundColor: 'yellow'},
+        },
+        {
+          instanceID: inst._debugID,
+          type: 'update styles',
+          payload: {color: '', backgroundColor: 'green'},
+        },
+        {
+          instanceID: inst._debugID,
+          type: 'update styles',
+          payload: {backgroundColor: ''},
+        },
+      ]);
+    });
+
+    it('gets ignored if the styles are shallowly equal', () => {
+      var node = document.createElement('div');
+      ReactDOM.render(<div />, node);
+      var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
+
+      ReactHostOperationHistoryHook._preventClearing = true;
+      ReactDOM.render(
+        <div
+          style={{
+            color: 'red',
+            backgroundColor: 'yellow',
+          }}
+        />,
+        node,
+      );
+      ReactDOM.render(
+        <div
+          style={{
+            color: 'red',
+            backgroundColor: 'yellow',
+          }}
+        />,
+        node,
+      );
+
+      assertHistoryMatches([
+        {
+          instanceID: inst._debugID,
+          type: 'update styles',
+          payload: {
+            color: 'red',
+            backgroundColor: 'yellow',
+          },
+        },
+      ]);
+    });
+  });
+
+  describe('update attribute', () => {
+    describe('simple attribute', () => {
+      it('gets recorded during mount', () => {
+        var node = document.createElement('div');
+
+        ReactHostOperationHistoryHook._preventClearing = true;
+        ReactDOM.render(<div className="rad" tabIndex={42} />, node);
+
+        var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
+        if (ReactDOMFeatureFlags.useCreateElement) {
+          assertHistoryMatches([
+            {
+              instanceID: inst._debugID,
+              type: 'update attribute',
+              payload: {className: 'rad'},
+            },
+            {
+              instanceID: inst._debugID,
+              type: 'update attribute',
+              payload: {tabIndex: 42},
+            },
+            {
+              instanceID: inst._debugID,
+              type: 'mount',
+              payload: 'DIV',
+            },
+          ]);
+        } else {
+          assertHistoryMatches([
+            {
+              instanceID: inst._debugID,
+              type: 'mount',
+              payload:
+                '<div class="rad" tabindex="42" data-reactroot="" ' +
+                  'data-reactid="1"></div>',
+            },
+          ]);
+        }
+      });
+
+      it('gets recorded during an update', () => {
+        var node = document.createElement('div');
+        ReactDOM.render(<div />, node);
+        var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
+
+        ReactHostOperationHistoryHook._preventClearing = true;
+        ReactDOM.render(<div className="rad" />, node);
+        ReactDOM.render(<div className="mad" tabIndex={42} />, node);
+        ReactDOM.render(<div tabIndex={43} />, node);
+
+        assertHistoryMatches([
+          {
+            instanceID: inst._debugID,
+            type: 'update attribute',
+            payload: {className: 'rad'},
+          },
+          {
+            instanceID: inst._debugID,
+            type: 'update attribute',
+            payload: {className: 'mad'},
+          },
+          {
+            instanceID: inst._debugID,
+            type: 'update attribute',
+            payload: {tabIndex: 42},
+          },
+          {
+            instanceID: inst._debugID,
+            type: 'remove attribute',
+            payload: 'className',
+          },
+          {
+            instanceID: inst._debugID,
+            type: 'update attribute',
+            payload: {tabIndex: 43},
+          },
+        ]);
+      });
+    });
+
+    describe('attribute that gets removed with certain values', () => {
+      it('gets recorded as a removal during an update', () => {
+        var node = document.createElement('div');
+        ReactDOM.render(<div />, node);
+        var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
+
+        ReactHostOperationHistoryHook._preventClearing = true;
+        ReactDOM.render(<div disabled={true} />, node);
+        ReactDOM.render(<div disabled={false} />, node);
+
+        assertHistoryMatches([
+          {
+            instanceID: inst._debugID,
+            type: 'update attribute',
+            payload: {disabled: true},
+          },
+          {
+            instanceID: inst._debugID,
+            type: 'remove attribute',
+            payload: 'disabled',
+          },
+        ]);
+      });
+    });
+
+    describe('custom attribute', () => {
+      it('gets recorded during mount', () => {
+        var node = document.createElement('div');
+
+        ReactHostOperationHistoryHook._preventClearing = true;
+        ReactDOM.render(<div data-x="rad" data-y={42} />, node);
+
+        var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
+        if (ReactDOMFeatureFlags.useCreateElement) {
+          assertHistoryMatches([
+            {
+              instanceID: inst._debugID,
+              type: 'update attribute',
+              payload: {'data-x': 'rad'},
+            },
+            {
+              instanceID: inst._debugID,
+              type: 'update attribute',
+              payload: {'data-y': 42},
+            },
+            {
+              instanceID: inst._debugID,
+              type: 'mount',
+              payload: 'DIV',
+            },
+          ]);
+        } else {
+          assertHistoryMatches([
+            {
+              instanceID: inst._debugID,
+              type: 'mount',
+              payload:
+                '<div data-x="rad" data-y="42" data-reactroot="" ' +
+                  'data-reactid="1"></div>',
+            },
+          ]);
+        }
+      });
+
+      it('gets recorded during an update', () => {
+        var node = document.createElement('div');
+        ReactDOM.render(<div />, node);
+        var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
+
+        ReactHostOperationHistoryHook._preventClearing = true;
+        ReactDOM.render(<div data-x="rad" />, node);
+        ReactDOM.render(<div data-x="mad" data-y={42} />, node);
+        ReactDOM.render(<div data-y={43} />, node);
+
+        assertHistoryMatches([
+          {
+            instanceID: inst._debugID,
+            type: 'update attribute',
+            payload: {'data-x': 'rad'},
+          },
+          {
+            instanceID: inst._debugID,
+            type: 'update attribute',
+            payload: {'data-x': 'mad'},
+          },
+          {
+            instanceID: inst._debugID,
+            type: 'update attribute',
+            payload: {'data-y': 42},
+          },
+          {
+            instanceID: inst._debugID,
+            type: 'remove attribute',
+            payload: 'data-x',
+          },
+          {
+            instanceID: inst._debugID,
+            type: 'update attribute',
+            payload: {'data-y': 43},
+          },
+        ]);
+      });
+    });
+
+    describe('attribute on a web component', () => {
+      it('gets recorded during mount', () => {
+        var node = document.createElement('div');
+
+        ReactHostOperationHistoryHook._preventClearing = true;
+        ReactDOM.render(<my-component className="rad" tabIndex={42} />, node);
+
+        var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
+        if (ReactDOMFeatureFlags.useCreateElement) {
+          assertHistoryMatches([
+            {
+              instanceID: inst._debugID,
+              type: 'update attribute',
+              payload: {className: 'rad'},
+            },
+            {
+              instanceID: inst._debugID,
+              type: 'update attribute',
+              payload: {tabIndex: 42},
+            },
+            {
+              instanceID: inst._debugID,
+              type: 'mount',
+              payload: 'MY-COMPONENT',
+            },
+          ]);
+        } else {
+          assertHistoryMatches([
+            {
+              instanceID: inst._debugID,
+              type: 'mount',
+              payload:
+                '<my-component className="rad" tabIndex="42" ' +
+                  'data-reactroot="" data-reactid="1"></my-component>',
+            },
+          ]);
+        }
+      });
+
+      it('gets recorded during an update', () => {
+        var node = document.createElement('div');
+        ReactDOM.render(<my-component />, node);
+        var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
+
+        ReactHostOperationHistoryHook._preventClearing = true;
+        ReactDOM.render(<my-component className="rad" />, node);
+        ReactDOM.render(<my-component className="mad" tabIndex={42} />, node);
+        ReactDOM.render(<my-component tabIndex={43} />, node);
+
+        assertHistoryMatches([
+          {
+            instanceID: inst._debugID,
+            type: 'update attribute',
+            payload: {className: 'rad'},
+          },
+          {
+            instanceID: inst._debugID,
+            type: 'update attribute',
+            payload: {className: 'mad'},
+          },
+          {
+            instanceID: inst._debugID,
+            type: 'update attribute',
+            payload: {tabIndex: 42},
+          },
+          {
+            instanceID: inst._debugID,
+            type: 'remove attribute',
+            payload: 'className',
+          },
+          {
+            instanceID: inst._debugID,
+            type: 'update attribute',
+            payload: {tabIndex: 43},
+          },
+        ]);
+      });
+    });
+  });
+
+  describe('replace text', () => {
+    describe('text content', () => {
+      it('gets recorded during an update from text content', () => {
+        var node = document.createElement('div');
+        ReactDOM.render(<div>Hi.</div>, node);
+        var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
+
+        ReactHostOperationHistoryHook._preventClearing = true;
+        ReactDOM.render(<div>Bye.</div>, node);
+
+        assertHistoryMatches([
+          {
+            instanceID: inst._debugID,
+            type: 'replace text',
+            payload: 'Bye.',
+          },
+        ]);
+      });
+
+      it('gets recorded during an update from html', () => {
+        var node = document.createElement('div');
+        ReactDOM.render(
+          <div dangerouslySetInnerHTML={{__html: 'Hi.'}} />,
+          node,
+        );
+        var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
+
+        ReactHostOperationHistoryHook._preventClearing = true;
+        ReactDOM.render(<div>Bye.</div>, node);
+
+        assertHistoryMatches([
+          {
+            instanceID: inst._debugID,
+            type: 'replace text',
+            payload: 'Bye.',
+          },
+        ]);
+      });
+
+      it('gets recorded during an update from children', () => {
+        var node = document.createElement('div');
+        ReactDOM.render(<div><span /><p /></div>, node);
+        var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
+
+        ReactHostOperationHistoryHook._preventClearing = true;
+        ReactDOM.render(<div>Bye.</div>, node);
+
+        assertHistoryMatches([
+          {
+            instanceID: inst._debugID,
+            type: 'remove child',
+            payload: {fromIndex: 0},
+          },
+          {
+            instanceID: inst._debugID,
+            type: 'remove child',
+            payload: {fromIndex: 1},
+          },
+          {
+            instanceID: inst._debugID,
+            type: 'replace text',
+            payload: 'Bye.',
+          },
+        ]);
+      });
+
+      it('gets ignored if new text is equal', () => {
+        var node = document.createElement('div');
+        ReactDOM.render(<div>Hi.</div>, node);
+
+        ReactHostOperationHistoryHook._preventClearing = true;
+        ReactDOM.render(<div>Hi.</div>, node);
+
+        assertHistoryMatches([]);
+      });
+    });
+
+    describe('text node', () => {
+      it('gets recorded during an update', () => {
+        var node = document.createElement('div');
+        ReactDOM.render(<div>{'Hi.'}{42}</div>, node);
+        var inst1 = ReactDOMComponentTree.getInstanceFromNode(
+          node.firstChild.childNodes[0],
+        );
+        var inst2 = ReactDOMComponentTree.getInstanceFromNode(
+          node.firstChild.childNodes[3],
+        );
+
+        ReactHostOperationHistoryHook._preventClearing = true;
+        ReactDOM.render(<div>{'Bye.'}{43}</div>, node);
+
+        assertHistoryMatches([
+          {
+            instanceID: inst1._debugID,
+            type: 'replace text',
+            payload: 'Bye.',
+          },
+          {
+            instanceID: inst2._debugID,
+            type: 'replace text',
+            payload: '43',
+          },
+        ]);
+      });
+
+      it('gets ignored if new text is equal', () => {
+        var node = document.createElement('div');
+        ReactDOM.render(<div>{'Hi.'}{42}</div>, node);
+
+        ReactHostOperationHistoryHook._preventClearing = true;
+        ReactDOM.render(<div>{'Hi.'}{42}</div>, node);
+
+        assertHistoryMatches([]);
+      });
+    });
+  });
+
+  describe('replace with', () => {
+    it('gets recorded when composite renders to a different type', () => {
+      var element;
+      function Foo() {
+        return element;
+      }
+
+      var node = document.createElement('div');
+      element = <div />;
+      ReactDOM.render(<Foo />, node);
+      var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
+
+      element = <span />;
+
+      ReactHostOperationHistoryHook._preventClearing = true;
+      ReactDOM.render(<Foo />, node);
+
+      assertHistoryMatches([
+        {
+          instanceID: inst._debugID,
+          type: 'replace with',
+          payload: 'SPAN',
+        },
+      ]);
+    });
+
+    it('gets recorded when composite renders to null after a native', () => {
+      var element;
+      function Foo() {
+        return element;
+      }
+
+      var node = document.createElement('div');
+      element = <span />;
+      ReactDOM.render(<Foo />, node);
+
+      var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
+      element = null;
+
+      ReactHostOperationHistoryHook._preventClearing = true;
+      ReactDOM.render(<Foo />, node);
+
+      assertHistoryMatches([
+        {
+          instanceID: inst._debugID,
+          type: 'replace with',
+          payload: '#comment',
+        },
+      ]);
+    });
+
+    it('gets ignored if the type has not changed', () => {
+      var element;
+      function Foo() {
+        return element;
+      }
+
+      var node = document.createElement('div');
+      element = <div />;
+      ReactDOM.render(<Foo />, node);
+
+      element = <div />;
+
+      ReactHostOperationHistoryHook._preventClearing = true;
+      ReactDOM.render(<Foo />, node);
+
+      assertHistoryMatches([]);
+    });
+  });
+
+  describe('replace children', () => {
+    it('gets recorded during an update from text content', () => {
+      var node = document.createElement('div');
+      ReactDOM.render(<div>Hi.</div>, node);
+      var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
+
+      ReactHostOperationHistoryHook._preventClearing = true;
+      ReactDOM.render(<div dangerouslySetInnerHTML={{__html: 'Bye.'}} />, node);
+
+      assertHistoryMatches([
+        {
+          instanceID: inst._debugID,
+          type: 'replace children',
+          payload: 'Bye.',
+        },
+      ]);
+    });
+
+    it('gets recorded during an update from html', () => {
+      var node = document.createElement('div');
+      ReactDOM.render(<div dangerouslySetInnerHTML={{__html: 'Hi.'}} />, node);
+      var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
+
+      ReactHostOperationHistoryHook._preventClearing = true;
+      ReactDOM.render(<div dangerouslySetInnerHTML={{__html: 'Bye.'}} />, node);
+
+      assertHistoryMatches([
+        {
+          instanceID: inst._debugID,
+          type: 'replace children',
+          payload: 'Bye.',
+        },
+      ]);
+    });
+
+    it('gets recorded during an update from children', () => {
+      var node = document.createElement('div');
+      ReactDOM.render(<div><span /><p /></div>, node);
+      var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
+
+      ReactHostOperationHistoryHook._preventClearing = true;
+      ReactDOM.render(<div dangerouslySetInnerHTML={{__html: 'Hi.'}} />, node);
+
+      assertHistoryMatches([
+        {
+          instanceID: inst._debugID,
+          type: 'remove child',
+          payload: {fromIndex: 0},
+        },
+        {
+          instanceID: inst._debugID,
+          type: 'remove child',
+          payload: {fromIndex: 1},
+        },
+        {
+          instanceID: inst._debugID,
+          type: 'replace children',
+          payload: 'Hi.',
+        },
+      ]);
+    });
+
+    it('gets ignored if new html is equal', () => {
+      var node = document.createElement('div');
+      ReactDOM.render(<div dangerouslySetInnerHTML={{__html: 'Hi.'}} />, node);
+
+      ReactHostOperationHistoryHook._preventClearing = true;
+      ReactDOM.render(<div dangerouslySetInnerHTML={{__html: 'Hi.'}} />, node);
+
+      assertHistoryMatches([]);
+    });
+  });
+
+  describe('insert child', () => {
+    it('gets reported when a child is inserted', () => {
+      var node = document.createElement('div');
+      ReactDOM.render(<div><span /></div>, node);
+      var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
+
+      ReactHostOperationHistoryHook._preventClearing = true;
+      ReactDOM.render(<div><span /><p /></div>, node);
+
+      assertHistoryMatches([
+        {
+          instanceID: inst._debugID,
+          type: 'insert child',
+          payload: {toIndex: 1, content: 'P'},
+        },
+      ]);
+    });
+  });
+
+  describe('move child', () => {
+    it('gets reported when a child is inserted', () => {
+      var node = document.createElement('div');
+      ReactDOM.render(<div><span key="a" /><p key="b" /></div>, node);
+      var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
+
+      ReactHostOperationHistoryHook._preventClearing = true;
+      ReactDOM.render(<div><p key="b" /><span key="a" /></div>, node);
+
+      assertHistoryMatches([
+        {
+          instanceID: inst._debugID,
+          type: 'move child',
+          payload: {fromIndex: 0, toIndex: 1},
+        },
+      ]);
+    });
+  });
+
+  describe('remove child', () => {
+    it('gets reported when a child is removed', () => {
+      var node = document.createElement('div');
+      ReactDOM.render(<div><span key="a" /><p key="b" /></div>, node);
+      var inst = ReactDOMComponentTree.getInstanceFromNode(node.firstChild);
+
+      ReactHostOperationHistoryHook._preventClearing = true;
+      ReactDOM.render(<div><span key="a" /></div>, node);
+
+      assertHistoryMatches([
+        {
+          instanceID: inst._debugID,
+          type: 'remove child',
+          payload: {fromIndex: 1},
+        },
+      ]);
+    });
+  });
+});
diff --git a/src/renderers/shared/reconciler/ReactChildReconciler.js b/src/renderers/shared/reconciler/ReactChildReconciler.js
deleted file mode 100644
index 634b3444c715..000000000000
--- a/src/renderers/shared/reconciler/ReactChildReconciler.js
+++ /dev/null
@@ -1,139 +0,0 @@
-/**
- * Copyright 2014-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 ReactChildReconciler
- */
-
-'use strict';
-
-var ReactReconciler = require('ReactReconciler');
-
-var instantiateReactComponent = require('instantiateReactComponent');
-var shouldUpdateReactComponent = require('shouldUpdateReactComponent');
-var traverseAllChildren = require('traverseAllChildren');
-var warning = require('warning');
-
-function instantiateChild(childInstances, child, name) {
-  // We found a component instance.
-  var keyUnique = (childInstances[name] === undefined);
-  if (__DEV__) {
-    warning(
-      keyUnique,
-      '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.',
-      name
-    );
-  }
-  if (child != null && keyUnique) {
-    childInstances[name] = instantiateReactComponent(child);
-  }
-}
-
-/**
- * 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) {
-    if (nestedChildNodes == null) {
-      return null;
-    }
-    var childInstances = {};
-    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,
-    removedNodes,
-    transaction,
-    context) {
-    // 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.getNativeNode(prevChild);
-          ReactReconciler.unmountComponent(prevChild, false);
-        }
-        // The child must be instantiated before it's mounted.
-        var nextChildInstance = instantiateReactComponent(nextElement);
-        nextChildren[name] = nextChildInstance;
-      }
-    }
-    // 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.getNativeNode(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;
diff --git a/src/renderers/shared/reconciler/ReactComponentEnvironment.js b/src/renderers/shared/reconciler/ReactComponentEnvironment.js
deleted file mode 100644
index 6dd870e0eba5..000000000000
--- a/src/renderers/shared/reconciler/ReactComponentEnvironment.js
+++ /dev/null
@@ -1,57 +0,0 @@
-/**
- * Copyright 2014-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 ReactComponentEnvironment
- */
-
-'use strict';
-
-var invariant = require('invariant');
-
-var injected = false;
-
-var ReactComponentEnvironment = {
-
-  /**
-   * Optionally injectable environment dependent cleanup hook. (server vs.
-   * browser etc). Example: A browser system caches DOM nodes based on component
-   * ID and must remove that cache entry when this instance is unmounted.
-   */
-  unmountIDFromEnvironment: null,
-
-  /**
-   * 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) {
-      invariant(
-        !injected,
-        'ReactCompositeComponent: injectEnvironment() can only be called once.'
-      );
-      ReactComponentEnvironment.unmountIDFromEnvironment =
-        environment.unmountIDFromEnvironment;
-      ReactComponentEnvironment.replaceNodeWithMarkup =
-        environment.replaceNodeWithMarkup;
-      ReactComponentEnvironment.processChildrenUpdates =
-        environment.processChildrenUpdates;
-      injected = true;
-    },
-  },
-
-};
-
-module.exports = ReactComponentEnvironment;
diff --git a/src/renderers/shared/reconciler/ReactCompositeComponent.js b/src/renderers/shared/reconciler/ReactCompositeComponent.js
deleted file mode 100644
index 0472e1fa86e8..000000000000
--- a/src/renderers/shared/reconciler/ReactCompositeComponent.js
+++ /dev/null
@@ -1,1010 +0,0 @@
-/**
- * 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 ReactCompositeComponent
- */
-
-'use strict';
-
-var ReactComponentEnvironment = require('ReactComponentEnvironment');
-var ReactCurrentOwner = require('ReactCurrentOwner');
-var ReactElement = require('ReactElement');
-var ReactErrorUtils = require('ReactErrorUtils');
-var ReactInstanceMap = require('ReactInstanceMap');
-var ReactInstrumentation = require('ReactInstrumentation');
-var ReactNodeTypes = require('ReactNodeTypes');
-var ReactPerf = require('ReactPerf');
-var ReactPropTypeLocations = require('ReactPropTypeLocations');
-var ReactPropTypeLocationNames = require('ReactPropTypeLocationNames');
-var ReactReconciler = require('ReactReconciler');
-var ReactUpdateQueue = require('ReactUpdateQueue');
-
-var emptyObject = require('emptyObject');
-var invariant = require('invariant');
-var shouldUpdateReactComponent = require('shouldUpdateReactComponent');
-var warning = require('warning');
-
-function getDeclarationErrorAddendum(component) {
-  var owner = component._currentElement._owner || null;
-  if (owner) {
-    var name = owner.getName();
-    if (name) {
-      return ' Check the render method of `' + name + '`.';
-    }
-  }
-  return '';
-}
-
-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 (__DEV__) {
-    warning(
-      element === null || element === false || ReactElement.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'
-    );
-  }
-}
-
-/**
- * ------------------ 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 ReactCompositeComponentMixin = {
-
-  /**
-   * Base constructor for all composite component.
-   *
-   * @param {ReactElement} element
-   * @final
-   * @internal
-   */
-  construct: function(element) {
-    this._currentElement = element;
-    this._rootNodeID = null;
-    this._instance = null;
-    this._nativeParent = null;
-    this._nativeContainerInfo = null;
-
-    // See ReactUpdateQueue
-    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;
-  },
-
-  /**
-   * Initializes the component, renders markup, and registers event listeners.
-   *
-   * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
-   * @param {?object} nativeParent
-   * @param {?object} nativeContainerInfo
-   * @param {?object} context
-   * @return {?string} Rendered markup to be inserted into the DOM.
-   * @final
-   * @internal
-   */
-  mountComponent: function(
-    transaction,
-    nativeParent,
-    nativeContainerInfo,
-    context
-  ) {
-    this._context = context;
-    this._mountOrder = nextMountID++;
-    this._nativeParent = nativeParent;
-    this._nativeContainerInfo = nativeContainerInfo;
-
-    var publicProps = this._processProps(this._currentElement.props);
-    var publicContext = this._processContext(context);
-
-    var Component = this._currentElement.type;
-
-    // Initialize the public class
-    var inst;
-    var renderedElement;
-
-    if (Component.prototype && Component.prototype.isReactComponent) {
-      if (__DEV__) {
-        ReactCurrentOwner.current = this;
-        try {
-          inst = new Component(publicProps, publicContext, ReactUpdateQueue);
-        } finally {
-          ReactCurrentOwner.current = null;
-        }
-      } else {
-        inst = new Component(publicProps, publicContext, ReactUpdateQueue);
-      }
-    } else {
-      if (__DEV__) {
-        ReactCurrentOwner.current = this;
-        try {
-          inst = Component(publicProps, publicContext, ReactUpdateQueue);
-        } finally {
-          ReactCurrentOwner.current = null;
-        }
-      } else {
-        inst = Component(publicProps, publicContext, ReactUpdateQueue);
-      }
-      if (inst == null || inst.render == null) {
-        renderedElement = inst;
-        warnIfInvalidElement(Component, renderedElement);
-        invariant(
-          inst === null ||
-          inst === false ||
-          ReactElement.isValidElement(inst),
-          '%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'
-        );
-        inst = new StatelessComponent(Component);
-      }
-    }
-
-    if (__DEV__) {
-      // This will throw later in _renderValidatedComponent, but add an early
-      // warning now to help debugging
-      if (inst.render == null) {
-        warning(
-          false,
-          '%s(...): No `render` method found on the returned component ' +
-          'instance: you may have forgotten to define `render`.',
-          Component.displayName || Component.name || 'Component'
-        );
-      }
-
-      var propsMutated = inst.props !== publicProps;
-      var componentName =
-        Component.displayName || Component.name || 'Component';
-
-      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
-      );
-    }
-
-    // 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 = ReactUpdateQueue;
-
-    this._instance = inst;
-
-    // Store a reference from the instance back to the internal representation
-    ReactInstanceMap.set(inst, this);
-
-    if (__DEV__) {
-      // 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.
-      warning(
-        !inst.getInitialState ||
-        inst.getInitialState.isReactClassApproved,
-        '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'
-      );
-      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'
-      );
-      warning(
-        !inst.propTypes,
-        'propTypes was defined as an instance property on %s. Use a static ' +
-        'property to define propTypes instead.',
-        this.getName() || 'a component'
-      );
-      warning(
-        !inst.contextTypes,
-        'contextTypes was defined as an instance property on %s. Use a ' +
-        'static property to define contextTypes instead.',
-        this.getName() || 'a component'
-      );
-      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')
-      );
-      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'
-      );
-      warning(
-        typeof inst.componentWillRecieveProps !== 'function',
-        '%s has a method called ' +
-        'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?',
-        (this.getName() || 'A component')
-      );
-    }
-
-    var initialState = inst.state;
-    if (initialState === undefined) {
-      inst.state = initialState = null;
-    }
-    invariant(
-      typeof initialState === 'object' && !Array.isArray(initialState),
-      '%s.state: must be set to an object or null',
-      this.getName() || 'ReactCompositeComponent'
-    );
-
-    this._pendingStateQueue = null;
-    this._pendingReplaceState = false;
-    this._pendingForceUpdate = false;
-
-    var markup;
-    if (inst.unstable_handleError) {
-      markup = this.performInitialMountWithErrorHandling(
-        renderedElement,
-        nativeParent,
-        nativeContainerInfo,
-        transaction,
-        context
-      );
-    } else {
-      markup = this.performInitialMount(renderedElement, nativeParent, nativeContainerInfo, transaction, context);
-    }
-
-    if (inst.componentDidMount) {
-      transaction.getReactMountReady().enqueue(inst.componentDidMount, inst);
-    }
-
-    return markup;
-  },
-
-  performInitialMountWithErrorHandling: function(
-    renderedElement,
-    nativeParent,
-    nativeContainerInfo,
-    transaction,
-    context
-  ) {
-    var markup;
-    var checkpoint = transaction.checkpoint();
-    try {
-      markup = this.performInitialMount(renderedElement, nativeParent, nativeContainerInfo, 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, nativeParent, nativeContainerInfo, transaction, context);
-    }
-    return markup;
-  },
-
-  performInitialMount: function(renderedElement, nativeParent, nativeContainerInfo, transaction, context) {
-    var inst = this._instance;
-    if (inst.componentWillMount) {
-      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();
-    }
-
-    this._renderedNodeType = ReactNodeTypes.getType(renderedElement);
-    this._renderedComponent = this._instantiateReactComponent(
-      renderedElement
-    );
-
-    var markup = ReactReconciler.mountComponent(
-      this._renderedComponent,
-      transaction,
-      nativeParent,
-      nativeContainerInfo,
-      this._processChildContext(context)
-    );
-
-    return markup;
-  },
-
-  getNativeNode: function() {
-    return ReactReconciler.getNativeNode(this._renderedComponent);
-  },
-
-  /**
-   * Releases any resources allocated by `mountComponent`.
-   *
-   * @final
-   * @internal
-   */
-  unmountComponent: function(safely) {
-    if (!this._renderedComponent) {
-      return;
-    }
-    var inst = this._instance;
-
-    if (inst.componentWillUnmount) {
-      if (safely) {
-        var name = this.getName() + '.componentWillUnmount()';
-        ReactErrorUtils.invokeGuardedCallback(name, inst.componentWillUnmount.bind(inst));
-      } 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 = null;
-    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 (__DEV__) {
-      var Component = this._currentElement.type;
-      if (Component.contextTypes) {
-        this._checkPropTypes(
-          Component.contextTypes,
-          maskedContext,
-          ReactPropTypeLocations.context
-        );
-      }
-    }
-    return maskedContext;
-  },
-
-  /**
-   * @param {object} currentContext
-   * @return {object}
-   * @private
-   */
-  _processChildContext: function(currentContext) {
-    var Component = this._currentElement.type;
-    var inst = this._instance;
-    if (__DEV__) {
-      ReactInstrumentation.debugTool.onBeginProcessingChildContext();
-    }
-    var childContext = inst.getChildContext && inst.getChildContext();
-    if (__DEV__) {
-      ReactInstrumentation.debugTool.onEndProcessingChildContext();
-    }
-    if (childContext) {
-      invariant(
-        typeof Component.childContextTypes === 'object',
-        '%s.getChildContext(): childContextTypes must be defined in order to ' +
-        'use getChildContext().',
-        this.getName() || 'ReactCompositeComponent'
-      );
-      if (__DEV__) {
-        this._checkPropTypes(
-          Component.childContextTypes,
-          childContext,
-          ReactPropTypeLocations.childContext
-        );
-      }
-      for (var name in childContext) {
-        invariant(
-          name in Component.childContextTypes,
-          '%s.getChildContext(): key "%s" is not defined in childContextTypes.',
-          this.getName() || 'ReactCompositeComponent',
-          name
-        );
-      }
-      return Object.assign({}, currentContext, childContext);
-    }
-    return currentContext;
-  },
-
-  /**
-   * Processes props by setting default values for unspecified props and
-   * asserting that the props are valid. Does not mutate its argument; returns
-   * a new props object with defaults merged in.
-   *
-   * @param {object} newProps
-   * @return {object}
-   * @private
-   */
-  _processProps: function(newProps) {
-    if (__DEV__) {
-      var Component = this._currentElement.type;
-      if (Component.propTypes) {
-        this._checkPropTypes(
-          Component.propTypes,
-          newProps,
-          ReactPropTypeLocations.prop
-        );
-      }
-    }
-    return newProps;
-  },
-
-  /**
-   * Assert that the props are valid
-   *
-   * @param {object} propTypes Map of prop name to a ReactPropType
-   * @param {object} props
-   * @param {string} location e.g. "prop", "context", "child context"
-   * @private
-   */
-  _checkPropTypes: function(propTypes, props, location) {
-    // TODO: Stop validating prop types here and only use the element
-    // validation.
-    var componentName = this.getName();
-    for (var propName in propTypes) {
-      if (propTypes.hasOwnProperty(propName)) {
-        var error;
-        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 propTypes[propName] === 'function',
-            '%s: %s type `%s` is invalid; it must be a function, usually ' +
-            'from React.PropTypes.',
-            componentName || 'React class',
-            ReactPropTypeLocationNames[location],
-            propName
-          );
-          error = propTypes[propName](props, propName, componentName, location);
-        } catch (ex) {
-          error = ex;
-        }
-        if (error instanceof Error) {
-          // We may want to extend this logic for similar errors in
-          // top-level render calls, so I'm abstracting it away into
-          // a function to minimize refactoring in the future
-          var addendum = getDeclarationErrorAddendum(this);
-
-          if (location === ReactPropTypeLocations.prop) {
-            // Preface gives us something to blacklist in warning module
-            warning(
-              false,
-              'Failed Composite propType: %s%s',
-              error.message,
-              addendum
-            );
-          } else {
-            warning(
-              false,
-              'Failed Context Types: %s%s',
-              error.message,
-              addendum
-            );
-          }
-        }
-      }
-    }
-  },
-
-  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
-      );
-    }
-
-    if (this._pendingStateQueue !== null || this._pendingForceUpdate) {
-      this.updateComponent(
-        transaction,
-        this._currentElement,
-        this._currentElement,
-        this._context,
-        this._context
-      );
-    }
-  },
-
-  /**
-   * 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;
-    var willReceive = false;
-    var nextContext;
-    var nextProps;
-
-    // Determine if the context has changed or not
-    if (this._context === nextUnmaskedContext) {
-      nextContext = inst.context;
-    } else {
-      nextContext = this._processContext(nextUnmaskedContext);
-      willReceive = true;
-    }
-
-    // Distinguish between a props update versus a simple state update
-    if (prevParentElement === nextParentElement) {
-      // Skip checking prop types again -- we don't read inst.props to avoid
-      // warning for DOM component props in this upgrade
-      nextProps = nextParentElement.props;
-    } else {
-      nextProps = this._processProps(nextParentElement.props);
-      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) {
-      inst.componentWillReceiveProps(nextProps, nextContext);
-    }
-
-    var nextState = this._processPendingState(nextProps, nextContext);
-
-    var shouldUpdate =
-      this._pendingForceUpdate ||
-      !inst.shouldComponentUpdate ||
-      inst.shouldComponentUpdate(nextProps, nextState, nextContext);
-
-    if (__DEV__) {
-      warning(
-        shouldUpdate !== undefined,
-        '%s.shouldComponentUpdate(): Returned undefined instead of a ' +
-        'boolean value. Make sure to return true or false.',
-        this.getName() || 'ReactCompositeComponent'
-      );
-    }
-
-    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 = Object.assign({}, replace ? queue[0] : inst.state);
-    for (var i = replace ? 1 : 0; i < queue.length; i++) {
-      var partial = queue[i];
-      Object.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 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) {
-      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) {
-      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();
-    if (shouldUpdateReactComponent(prevRenderedElement, nextRenderedElement)) {
-      ReactReconciler.receiveComponent(
-        prevComponentInstance,
-        nextRenderedElement,
-        transaction,
-        this._processChildContext(context)
-      );
-    } else {
-      var oldNativeNode = ReactReconciler.getNativeNode(prevComponentInstance);
-      ReactReconciler.unmountComponent(prevComponentInstance, false);
-
-      this._renderedNodeType = ReactNodeTypes.getType(nextRenderedElement);
-      this._renderedComponent = this._instantiateReactComponent(
-        nextRenderedElement
-      );
-      var nextMarkup = ReactReconciler.mountComponent(
-        this._renderedComponent,
-        transaction,
-        this._nativeParent,
-        this._nativeContainerInfo,
-        this._processChildContext(context)
-      );
-      this._replaceNodeWithMarkup(oldNativeNode, nextMarkup);
-    }
-  },
-
-  /**
-   * Overridden in shallow rendering.
-   *
-   * @protected
-   */
-  _replaceNodeWithMarkup: function(oldNativeNode, nextMarkup) {
-    ReactComponentEnvironment.replaceNodeWithMarkup(
-      oldNativeNode,
-      nextMarkup
-    );
-  },
-
-  /**
-   * @protected
-   */
-  _renderValidatedComponentWithoutOwnerOrContext: function() {
-    var inst = this._instance;
-    var renderedComponent = inst.render();
-    if (__DEV__) {
-      // We allow auto-mocks to proceed as if they're returning null.
-      if (renderedComponent === undefined &&
-          inst.render._isMockFunction) {
-        // This is probably bad practice. Consider warning here and
-        // deprecating this convenience.
-        renderedComponent = null;
-      }
-    }
-
-    return renderedComponent;
-  },
-
-  /**
-   * @private
-   */
-  _renderValidatedComponent: function() {
-    var renderedComponent;
-    ReactCurrentOwner.current = this;
-    try {
-      renderedComponent =
-        this._renderValidatedComponentWithoutOwnerOrContext();
-    } finally {
-      ReactCurrentOwner.current = null;
-    }
-    invariant(
-      // TODO: An `isValidNode` function would probably be more appropriate
-      renderedComponent === null || renderedComponent === false ||
-      ReactElement.isValidElement(renderedComponent),
-      '%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'
-    );
-    return renderedComponent;
-  },
-
-  /**
-   * 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();
-    invariant(inst != null, 'Stateless function components cannot have refs.');
-    var publicComponentInstance = component.getPublicInstance();
-    if (__DEV__) {
-      var componentName = component && component.getName ?
-        component.getName() : 'a component';
-      warning(publicComponentInstance != null,
-        '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()
-      );
-    }
-    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 (inst instanceof StatelessComponent) {
-      return null;
-    }
-    return inst;
-  },
-
-  // Stub
-  _instantiateReactComponent: null,
-
-};
-
-ReactPerf.measureMethods(
-  ReactCompositeComponentMixin,
-  'ReactCompositeComponent',
-  {
-    mountComponent: 'mountComponent',
-    updateComponent: 'updateComponent',
-    _renderValidatedComponent: '_renderValidatedComponent',
-  }
-);
-
-var ReactCompositeComponent = {
-
-  Mixin: ReactCompositeComponentMixin,
-
-};
-
-module.exports = ReactCompositeComponent;
diff --git a/src/renderers/shared/reconciler/ReactInstanceHandles.js b/src/renderers/shared/reconciler/ReactInstanceHandles.js
deleted file mode 100644
index 11d4a3eea398..000000000000
--- a/src/renderers/shared/reconciler/ReactInstanceHandles.js
+++ /dev/null
@@ -1,337 +0,0 @@
-/**
- * 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 ReactInstanceHandles
- */
-
-'use strict';
-
-var invariant = require('invariant');
-
-var SEPARATOR = '.';
-var SEPARATOR_LENGTH = SEPARATOR.length;
-
-/**
- * Maximum depth of traversals before we consider the possibility of a bad ID.
- */
-var MAX_TREE_DEPTH = 10000;
-
-/**
- * Creates a DOM ID prefix to use when mounting React components.
- *
- * @param {number} index A unique integer
- * @return {string} React root ID.
- * @internal
- */
-function getReactRootIDString(index) {
-  return SEPARATOR + index.toString(36);
-}
-
-/**
- * Checks if a character in the supplied ID is a separator or the end.
- *
- * @param {string} id A React DOM ID.
- * @param {number} index Index of the character to check.
- * @return {boolean} True if the character is a separator or end of the ID.
- * @private
- */
-function isBoundary(id, index) {
-  return id.charAt(index) === SEPARATOR || index === id.length;
-}
-
-/**
- * Checks if the supplied string is a valid React DOM ID.
- *
- * @param {string} id A React DOM ID, maybe.
- * @return {boolean} True if the string is a valid React DOM ID.
- * @private
- */
-function isValidID(id) {
-  return id === '' || (
-    id.charAt(0) === SEPARATOR && id.charAt(id.length - 1) !== SEPARATOR
-  );
-}
-
-/**
- * Checks if the first ID is an ancestor of or equal to the second ID.
- *
- * @param {string} ancestorID
- * @param {string} descendantID
- * @return {boolean} True if `ancestorID` is an ancestor of `descendantID`.
- * @internal
- */
-function isAncestorIDOf(ancestorID, descendantID) {
-  return (
-    descendantID.indexOf(ancestorID) === 0 &&
-    isBoundary(descendantID, ancestorID.length)
-  );
-}
-
-/**
- * Gets the parent ID of the supplied React DOM ID, `id`.
- *
- * @param {string} id ID of a component.
- * @return {string} ID of the parent, or an empty string.
- * @private
- */
-function getParentID(id) {
-  return id ? id.substr(0, id.lastIndexOf(SEPARATOR)) : '';
-}
-
-/**
- * Gets the next DOM ID on the tree path from the supplied `ancestorID` to the
- * supplied `destinationID`. If they are equal, the ID is returned.
- *
- * @param {string} ancestorID ID of an ancestor node of `destinationID`.
- * @param {string} destinationID ID of the destination node.
- * @return {string} Next ID on the path from `ancestorID` to `destinationID`.
- * @private
- */
-function getNextDescendantID(ancestorID, destinationID) {
-  invariant(
-    isValidID(ancestorID) && isValidID(destinationID),
-    'getNextDescendantID(%s, %s): Received an invalid React DOM ID.',
-    ancestorID,
-    destinationID
-  );
-  invariant(
-    isAncestorIDOf(ancestorID, destinationID),
-    'getNextDescendantID(...): React has made an invalid assumption about ' +
-    'the DOM hierarchy. Expected `%s` to be an ancestor of `%s`.',
-    ancestorID,
-    destinationID
-  );
-  if (ancestorID === destinationID) {
-    return ancestorID;
-  }
-  // Skip over the ancestor and the immediate separator. Traverse until we hit
-  // another separator or we reach the end of `destinationID`.
-  var start = ancestorID.length + SEPARATOR_LENGTH;
-  var i;
-  for (i = start; i < destinationID.length; i++) {
-    if (isBoundary(destinationID, i)) {
-      break;
-    }
-  }
-  return destinationID.substr(0, i);
-}
-
-/**
- * Gets the nearest common ancestor ID of two IDs.
- *
- * Using this ID scheme, the nearest common ancestor ID is the longest common
- * prefix of the two IDs that immediately preceded a "marker" in both strings.
- *
- * @param {string} oneID
- * @param {string} twoID
- * @return {string} Nearest common ancestor ID, or the empty string if none.
- * @private
- */
-function getFirstCommonAncestorID(oneID, twoID) {
-  var minLength = Math.min(oneID.length, twoID.length);
-  if (minLength === 0) {
-    return '';
-  }
-  var lastCommonMarkerIndex = 0;
-  // Use `<=` to traverse until the "EOL" of the shorter string.
-  for (var i = 0; i <= minLength; i++) {
-    if (isBoundary(oneID, i) && isBoundary(twoID, i)) {
-      lastCommonMarkerIndex = i;
-    } else if (oneID.charAt(i) !== twoID.charAt(i)) {
-      break;
-    }
-  }
-  var longestCommonID = oneID.substr(0, lastCommonMarkerIndex);
-  invariant(
-    isValidID(longestCommonID),
-    'getFirstCommonAncestorID(%s, %s): Expected a valid React DOM ID: %s',
-    oneID,
-    twoID,
-    longestCommonID
-  );
-  return longestCommonID;
-}
-
-/**
- * Traverses the parent path between two IDs (either up or down). The IDs must
- * not be the same, and there must exist a parent path between them. If the
- * callback returns `false`, traversal is stopped.
- *
- * @param {?string} start ID at which to start traversal.
- * @param {?string} stop ID at which to end traversal.
- * @param {function} cb Callback to invoke each ID with.
- * @param {*} arg Argument to invoke the callback with.
- * @param {?boolean} skipFirst Whether or not to skip the first node.
- * @param {?boolean} skipLast Whether or not to skip the last node.
- * @private
- */
-function traverseParentPath(start, stop, cb, arg, skipFirst, skipLast) {
-  start = start || '';
-  stop = stop || '';
-  invariant(
-    start !== stop,
-    'traverseParentPath(...): Cannot traverse from and to the same ID, `%s`.',
-    start
-  );
-  var traverseUp = isAncestorIDOf(stop, start);
-  invariant(
-    traverseUp || isAncestorIDOf(start, stop),
-    'traverseParentPath(%s, %s, ...): Cannot traverse from two IDs that do ' +
-    'not have a parent path.',
-    start,
-    stop
-  );
-  // Traverse from `start` to `stop` one depth at a time.
-  var depth = 0;
-  var traverse = traverseUp ? getParentID : getNextDescendantID;
-  for (var id = start; /* until break */; id = traverse(id, stop)) {
-    var ret;
-    if ((!skipFirst || id !== start) && (!skipLast || id !== stop)) {
-      ret = cb(id, traverseUp, arg);
-    }
-    if (ret === false || id === stop) {
-      // Only break //after// visiting `stop`.
-      break;
-    }
-    invariant(
-      depth++ < MAX_TREE_DEPTH,
-      'traverseParentPath(%s, %s, ...): Detected an infinite loop while ' +
-      'traversing the React DOM ID tree. This may be due to malformed IDs: %s',
-      start, stop, id
-    );
-  }
-}
-
-/**
- * Manages the IDs assigned to DOM representations of React components. This
- * uses a specific scheme in order to traverse the DOM efficiently (e.g. in
- * order to simulate events).
- *
- * @internal
- */
-var ReactInstanceHandles = {
-
-  /**
-   * Constructs a React root ID
-   * @param {number} index A unique integer
-   * @return {string} A React root ID.
-   */
-  createReactRootID: function(index) {
-    return getReactRootIDString(index);
-  },
-
-  /**
-   * Constructs a React ID by joining a root ID with a name.
-   *
-   * @param {string} rootID Root ID of a parent component.
-   * @param {string} name A component's name (as flattened children).
-   * @return {string} A React ID.
-   * @internal
-   */
-  createReactID: function(rootID, name) {
-    return rootID + name;
-  },
-
-  /**
-   * Gets the DOM ID of the React component that is the root of the tree that
-   * contains the React component with the supplied DOM ID.
-   *
-   * @param {string} id DOM ID of a React component.
-   * @return {?string} DOM ID of the React component that is the root.
-   * @internal
-   */
-  getReactRootIDFromNodeID: function(id) {
-    if (id && id.charAt(0) === SEPARATOR && id.length > 1) {
-      var index = id.indexOf(SEPARATOR, 1);
-      return index > -1 ? id.substr(0, index) : id;
-    }
-    return null;
-  },
-
-  /**
-   * Traverses the ID hierarchy and invokes the supplied `cb` on any IDs that
-   * should would receive a `mouseEnter` or `mouseLeave` event.
-   *
-   * NOTE: Does not invoke the callback on the nearest common ancestor because
-   * nothing "entered" or "left" that element.
-   *
-   * @param {string} leaveID ID being left.
-   * @param {string} enterID ID being entered.
-   * @param {function} cb Callback to invoke on each entered/left ID.
-   * @param {*} upArg Argument to invoke the callback with on left IDs.
-   * @param {*} downArg Argument to invoke the callback with on entered IDs.
-   * @internal
-   */
-  traverseEnterLeave: function(leaveID, enterID, cb, upArg, downArg) {
-    var ancestorID = getFirstCommonAncestorID(leaveID, enterID);
-    if (ancestorID !== leaveID) {
-      traverseParentPath(leaveID, ancestorID, cb, upArg, false, true);
-    }
-    if (ancestorID !== enterID) {
-      traverseParentPath(ancestorID, enterID, cb, downArg, true, false);
-    }
-  },
-
-  /**
-   * Simulates the traversal of a two-phase, capture/bubble event dispatch.
-   *
-   * NOTE: This traversal happens on IDs without touching the DOM.
-   *
-   * @param {string} targetID ID of the target node.
-   * @param {function} cb Callback to invoke.
-   * @param {*} arg Argument to invoke the callback with.
-   * @internal
-   */
-  traverseTwoPhase: function(targetID, cb, arg) {
-    if (targetID) {
-      traverseParentPath('', targetID, cb, arg, true, false);
-      traverseParentPath(targetID, '', cb, arg, false, true);
-    }
-  },
-
-  /**
-   * Same as `traverseTwoPhase` but skips the `targetID`.
-   */
-  traverseTwoPhaseSkipTarget: function(targetID, cb, arg) {
-    if (targetID) {
-      traverseParentPath('', targetID, cb, arg, true, true);
-      traverseParentPath(targetID, '', cb, arg, true, true);
-    }
-  },
-
-  /**
-   * Traverse a node ID, calling the supplied `cb` for each ancestor ID. For
-   * example, passing `.0.$row-0.1` would result in `cb` getting called
-   * with `.0`, `.0.$row-0`, and `.0.$row-0.1`.
-   *
-   * NOTE: This traversal happens on IDs without touching the DOM.
-   *
-   * @param {string} targetID ID of the target node.
-   * @param {function} cb Callback to invoke.
-   * @param {*} arg Argument to invoke the callback with.
-   * @internal
-   */
-  traverseAncestors: function(targetID, cb, arg) {
-    traverseParentPath('', targetID, cb, arg, true, false);
-  },
-
-  getFirstCommonAncestorID: getFirstCommonAncestorID,
-
-  /**
-   * Exposed for unit testing.
-   * @private
-   */
-  _getNextDescendantID: getNextDescendantID,
-
-  isAncestorIDOf: isAncestorIDOf,
-
-  SEPARATOR: SEPARATOR,
-
-};
-
-module.exports = ReactInstanceHandles;
diff --git a/src/renderers/shared/reconciler/ReactMultiChildUpdateTypes.js b/src/renderers/shared/reconciler/ReactMultiChildUpdateTypes.js
deleted file mode 100644
index 8e123549dead..000000000000
--- a/src/renderers/shared/reconciler/ReactMultiChildUpdateTypes.js
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * 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 ReactMultiChildUpdateTypes
- */
-
-'use strict';
-
-var keyMirror = require('keyMirror');
-
-/**
- * When a component's children are updated, a series of update configuration
- * objects are created in order to batch and serialize the required changes.
- *
- * Enumerates all the possible types of update configurations.
- *
- * @internal
- */
-var ReactMultiChildUpdateTypes = keyMirror({
-  INSERT_MARKUP: null,
-  MOVE_EXISTING: null,
-  REMOVE_NODE: null,
-  SET_MARKUP: null,
-  TEXT_CONTENT: null,
-});
-
-module.exports = ReactMultiChildUpdateTypes;
diff --git a/src/renderers/shared/reconciler/ReactNativeComponent.js b/src/renderers/shared/reconciler/ReactNativeComponent.js
deleted file mode 100644
index 7f280349556f..000000000000
--- a/src/renderers/shared/reconciler/ReactNativeComponent.js
+++ /dev/null
@@ -1,97 +0,0 @@
-/**
- * Copyright 2014-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 ReactNativeComponent
- */
-
-'use strict';
-
-var invariant = require('invariant');
-
-var autoGenerateWrapperClass = null;
-var genericComponentClass = null;
-// This registry keeps track of wrapper classes around native tags.
-var tagToComponentClass = {};
-var textComponentClass = null;
-
-var ReactNativeComponentInjection = {
-  // 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;
-  },
-  // This accepts a keyed object with classes as values. Each key represents a
-  // tag. That particular tag will use this class instead of the generic one.
-  injectComponentClasses: function(componentClasses) {
-    Object.assign(tagToComponentClass, componentClasses);
-  },
-};
-
-/**
- * Get a composite component wrapper class for a specific tag.
- *
- * @param {ReactElement} element The tag for which to get the class.
- * @return {function} The React class constructor function.
- */
-function getComponentClassForElement(element) {
-  if (typeof element.type === 'function') {
-    return element.type;
-  }
-  var tag = element.type;
-  var componentClass = tagToComponentClass[tag];
-  if (componentClass == null) {
-    tagToComponentClass[tag] = componentClass = autoGenerateWrapperClass(tag);
-  }
-  return componentClass;
-}
-
-/**
- * Get a native internal component class for a specific tag.
- *
- * @param {ReactElement} element The element to create.
- * @return {function} The internal class constructor function.
- */
-function createInternalComponent(element) {
-  invariant(
-    genericComponentClass,
-    'There is no registered component for the tag %s',
-    element.type
-  );
-  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 ReactNativeComponent = {
-  getComponentClassForElement: getComponentClassForElement,
-  createInternalComponent: createInternalComponent,
-  createInstanceForText: createInstanceForText,
-  isTextComponent: isTextComponent,
-  injection: ReactNativeComponentInjection,
-};
-
-module.exports = ReactNativeComponent;
diff --git a/src/renderers/shared/reconciler/ReactOwner.js b/src/renderers/shared/reconciler/ReactOwner.js
deleted file mode 100644
index df2bfb8d7b8e..000000000000
--- a/src/renderers/shared/reconciler/ReactOwner.js
+++ /dev/null
@@ -1,108 +0,0 @@
-/**
- * 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 ReactOwner
- */
-
-'use strict';
-
-var invariant = require('invariant');
-
-/**
- * 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 = {
-
-  /**
-   * @param {?object} object
-   * @return {boolean} True if `object` is a valid owner.
-   * @final
-   */
-  isValidOwner: function(object) {
-    return !!(
-      object &&
-      typeof object.attachRef === 'function' &&
-      typeof object.detachRef === 'function'
-    );
-  },
-
-  /**
-   * 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) {
-    invariant(
-      ReactOwner.isValidOwner(owner),
-      '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).'
-    );
-    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) {
-    invariant(
-      ReactOwner.isValidOwner(owner),
-      '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).'
-    );
-    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;
diff --git a/src/renderers/shared/reconciler/ReactReconciler.js b/src/renderers/shared/reconciler/ReactReconciler.js
deleted file mode 100644
index ae7806e4fc0e..000000000000
--- a/src/renderers/shared/reconciler/ReactReconciler.js
+++ /dev/null
@@ -1,154 +0,0 @@
-/**
- * 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 ReactReconciler
- */
-
-'use strict';
-
-var ReactRef = require('ReactRef');
-var ReactInstrumentation = require('ReactInstrumentation');
-
-/**
- * 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 native component instance
-   * @param {?object} info about the native container
-   * @return {?string} Rendered markup to be inserted into the DOM.
-   * @final
-   * @internal
-   */
-  mountComponent: function(
-    internalInstance,
-    transaction,
-    nativeParent,
-    nativeContainerInfo,
-    context
-  ) {
-    var markup = internalInstance.mountComponent(
-      transaction,
-      nativeParent,
-      nativeContainerInfo,
-      context
-    );
-    if (internalInstance._currentElement &&
-        internalInstance._currentElement.ref != null) {
-      transaction.getReactMountReady().enqueue(attachRefs, internalInstance);
-    }
-    if (__DEV__) {
-      ReactInstrumentation.debugTool.onMountComponent(internalInstance);
-    }
-    return markup;
-  },
-
-  /**
-   * Returns a value that can be passed to
-   * ReactComponentEnvironment.replaceNodeWithMarkup.
-   */
-  getNativeNode: function(internalInstance) {
-    return internalInstance.getNativeNode();
-  },
-
-  /**
-   * Releases any resources allocated by `mountComponent`.
-   *
-   * @final
-   * @internal
-   */
-  unmountComponent: function(internalInstance, safely) {
-    ReactRef.detachRefs(internalInstance, internalInstance._currentElement);
-    internalInstance.unmountComponent(safely);
-    if (__DEV__) {
-      ReactInstrumentation.debugTool.onUnmountComponent(internalInstance);
-    }
-  },
-
-  /**
-   * 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;
-    }
-
-    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 (__DEV__) {
-      ReactInstrumentation.debugTool.onUpdateComponent(internalInstance);
-    }
-  },
-
-  /**
-   * Flush any dirty changes in a component.
-   *
-   * @param {ReactComponent} internalInstance
-   * @param {ReactReconcileTransaction} transaction
-   * @internal
-   */
-  performUpdateIfNecessary: function(
-    internalInstance,
-    transaction
-  ) {
-    internalInstance.performUpdateIfNecessary(transaction);
-    if (__DEV__) {
-      ReactInstrumentation.debugTool.onUpdateComponent(internalInstance);
-    }
-  },
-
-};
-
-module.exports = ReactReconciler;
diff --git a/src/renderers/shared/reconciler/ReactRef.js b/src/renderers/shared/reconciler/ReactRef.js
deleted file mode 100644
index 3ddc23fbd6c2..000000000000
--- a/src/renderers/shared/reconciler/ReactRef.js
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * 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 ReactRef
- */
-
-'use strict';
-
-var ReactOwner = require('ReactOwner');
-
-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 || element === false) {
-    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 prevEmpty = prevElement === null || prevElement === false;
-  var nextEmpty = nextElement === null || nextElement === false;
-
-  return (
-    // This has a few false positives w/r/t empty components.
-    prevEmpty || nextEmpty ||
-    nextElement._owner !== prevElement._owner ||
-    nextElement.ref !== prevElement.ref
-  );
-};
-
-ReactRef.detachRefs = function(instance, element) {
-  if (element === null || element === false) {
-    return;
-  }
-  var ref = element.ref;
-  if (ref != null) {
-    detachRef(ref, instance, element._owner);
-  }
-};
-
-module.exports = ReactRef;
diff --git a/src/renderers/shared/reconciler/__tests__/ReactComponent-test.js b/src/renderers/shared/reconciler/__tests__/ReactComponent-test.js
deleted file mode 100644
index 444bedddb809..000000000000
--- a/src/renderers/shared/reconciler/__tests__/ReactComponent-test.js
+++ /dev/null
@@ -1,293 +0,0 @@
-/**
- * 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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-var React;
-var ReactDOM;
-var ReactTestUtils;
-
-describe('ReactComponent', function() {
-  beforeEach(function() {
-    React = require('React');
-    ReactDOM = require('ReactDOM');
-    ReactTestUtils = require('ReactTestUtils');
-  });
-
-  it('should throw on invalid render targets', function() {
-    var container = document.createElement('div');
-    // jQuery objects are basically arrays; people often pass them in by mistake
-    expect(function() {
-      ReactDOM.render(<div></div>, [container]);
-    }).toThrow(
-      '_registerComponent(...): Target container is not a DOM element.'
-    );
-
-    expect(function() {
-      ReactDOM.render(<div></div>, null);
-    }).toThrow(
-      '_registerComponent(...): Target container is not a DOM element.'
-    );
-  });
-
-  it('should throw when supplying a ref outside of render method', function() {
-    var instance = <div ref="badDiv" />;
-    expect(function() {
-      instance = ReactTestUtils.renderIntoDocument(instance);
-    }).toThrow();
-  });
-
-  it('should support refs on owned components', function() {
-    var innerObj = {};
-    var outerObj = {};
-
-    var Wrapper = React.createClass({
-
-      getObject: function() {
-        return this.props.object;
-      },
-
-      render: function() {
-        return <div>{this.props.children}</div>;
-      },
-
-    });
-
-    var Component = React.createClass({
-      render: function() {
-        var inner = <Wrapper object={innerObj} ref="inner" />;
-        var outer = <Wrapper object={outerObj} ref="outer">{inner}</Wrapper>;
-        return outer;
-      },
-      componentDidMount: function() {
-        expect(this.refs.inner.getObject()).toEqual(innerObj);
-        expect(this.refs.outer.getObject()).toEqual(outerObj);
-      },
-    });
-
-    var instance = <Component />;
-    instance = ReactTestUtils.renderIntoDocument(instance);
-  });
-
-  it('should not have refs on unmounted components', function() {
-    var Parent = React.createClass({
-      render: function() {
-        return <Child><div ref="test" /></Child>;
-      },
-      componentDidMount: function() {
-        expect(this.refs && this.refs.test).toEqual(undefined);
-      },
-    });
-    var Child = React.createClass({
-      render: function() {
-        return <div />;
-      },
-    });
-
-    var instance = <Parent child={<span />} />;
-    instance = ReactTestUtils.renderIntoDocument(instance);
-  });
-
-  it('should support new-style refs', function() {
-    var innerObj = {};
-    var outerObj = {};
-
-    var Wrapper = React.createClass({
-      getObject: function() {
-        return this.props.object;
-      },
-      render: function() {
-        return <div>{this.props.children}</div>;
-      },
-    });
-
-    var mounted = false;
-    var Component = React.createClass({
-      render: function() {
-        var inner = <Wrapper object={innerObj} ref={(c) => this.innerRef = c} />;
-        var outer = (
-          <Wrapper object={outerObj} ref={(c) => this.outerRef = c}>
-            {inner}
-          </Wrapper>
-        );
-        return outer;
-      },
-      componentDidMount: function() {
-        expect(this.innerRef.getObject()).toEqual(innerObj);
-        expect(this.outerRef.getObject()).toEqual(outerObj);
-        mounted = true;
-      },
-    });
-
-    var instance = <Component />;
-    instance = ReactTestUtils.renderIntoDocument(instance);
-    expect(mounted).toBe(true);
-  });
-
-  it('should support new-style refs with mixed-up owners', function() {
-    var Wrapper = React.createClass({
-      getTitle: function() {
-        return this.props.title;
-      },
-      render: function() {
-        return this.props.getContent();
-      },
-    });
-
-    var mounted = false;
-    var Component = React.createClass({
-      getInner: function() {
-        // (With old-style refs, it's impossible to get a ref to this div
-        // because Wrapper is the current owner when this function is called.)
-        return <div title="inner" ref={(c) => this.innerRef = c} />;
-      },
-      render: function() {
-        return (
-          <Wrapper
-            title="wrapper"
-            ref={(c) => this.wrapperRef = c}
-            getContent={this.getInner}
-            />
-        );
-      },
-      componentDidMount: function() {
-        // Check .props.title to make sure we got the right elements back
-        expect(this.wrapperRef.getTitle()).toBe('wrapper');
-        expect(ReactDOM.findDOMNode(this.innerRef).title).toBe('inner');
-        mounted = true;
-      },
-    });
-
-    var instance = <Component />;
-    instance = ReactTestUtils.renderIntoDocument(instance);
-    expect(mounted).toBe(true);
-  });
-
-  it('should call refs at the correct time', function() {
-    var log = [];
-
-    var Inner = React.createClass({
-      render: function() {
-        log.push(`inner ${this.props.id} render`);
-        return <div />;
-      },
-      componentDidMount: function() {
-        log.push(`inner ${this.props.id} componentDidMount`);
-      },
-      componentDidUpdate: function() {
-        log.push(`inner ${this.props.id} componentDidUpdate`);
-      },
-      componentWillUnmount: function() {
-        log.push(`inner ${this.props.id} componentWillUnmount`);
-      },
-    });
-
-    var Outer = React.createClass({
-      render: function() {
-        return (
-          <div>
-            <Inner id={1} ref={(c) => {
-              log.push(`ref 1 got ${c ? `instance ${c.props.id}` : 'null'}`);
-            }}/>
-            <Inner id={2} ref={(c) => {
-              log.push(`ref 2 got ${c ? `instance ${c.props.id}` : 'null'}`);
-            }}/>
-          </div>
-        );
-      },
-      componentDidMount: function() {
-        log.push('outer componentDidMount');
-      },
-      componentDidUpdate: function() {
-        log.push('outer componentDidUpdate');
-      },
-      componentWillUnmount: function() {
-        log.push('outer componentWillUnmount');
-      },
-    });
-
-    // mount, update, unmount
-    var el = document.createElement('div');
-    log.push('start mount');
-    ReactDOM.render(<Outer />, el);
-    log.push('start update');
-    ReactDOM.render(<Outer />, el);
-    log.push('start unmount');
-    ReactDOM.unmountComponentAtNode(el);
-
-    /* eslint-disable indent */
-    expect(log).toEqual([
-      'start mount',
-        'inner 1 render',
-        'inner 2 render',
-        'inner 1 componentDidMount',
-        'ref 1 got instance 1',
-        'inner 2 componentDidMount',
-        'ref 2 got instance 2',
-        'outer componentDidMount',
-      'start update',
-        // Previous (equivalent) refs get cleared
-        'ref 1 got null',
-        'inner 1 render',
-        'ref 2 got null',
-        'inner 2 render',
-        'inner 1 componentDidUpdate',
-        'ref 1 got instance 1',
-        'inner 2 componentDidUpdate',
-        'ref 2 got instance 2',
-        'outer componentDidUpdate',
-      'start unmount',
-        'outer componentWillUnmount',
-        'ref 1 got null',
-        'inner 1 componentWillUnmount',
-        'ref 2 got null',
-        'inner 2 componentWillUnmount',
-    ]);
-    /* eslint-enable indent */
-  });
-
-  it('fires the callback after a component is rendered', function() {
-    var callback = jest.genMockFn();
-    var container = document.createElement('div');
-    ReactDOM.render(<div />, container, callback);
-    expect(callback.mock.calls.length).toBe(1);
-    ReactDOM.render(<div className="foo" />, container, callback);
-    expect(callback.mock.calls.length).toBe(2);
-    ReactDOM.render(<span />, container, callback);
-    expect(callback.mock.calls.length).toBe(3);
-  });
-
-  it('throws usefully when rendering badly-typed elements', function() {
-    spyOn(console, 'error');
-
-    var X = undefined;
-    expect(() => ReactTestUtils.renderIntoDocument(<X />)).toThrow(
-      'Element type is invalid: expected a string (for built-in components) ' +
-      'or a class/function (for composite components) but got: undefined.'
-    );
-
-    var Y = null;
-    expect(() => ReactTestUtils.renderIntoDocument(<Y />)).toThrow(
-      'Element type is invalid: expected a string (for built-in components) ' +
-      'or a class/function (for composite components) but got: null.'
-    );
-
-    var Z = {};
-    expect(() => ReactTestUtils.renderIntoDocument(<Z />)).toThrow(
-      'Element type is invalid: expected a string (for built-in components) ' +
-      'or a class/function (for composite components) but got: object.'
-    );
-
-    // One warning for each element creation
-    expect(console.error.calls.length).toBe(3);
-  });
-
-});
diff --git a/src/renderers/shared/reconciler/__tests__/ReactComponentLifeCycle-test.js b/src/renderers/shared/reconciler/__tests__/ReactComponentLifeCycle-test.js
deleted file mode 100644
index b7204eb9a9e1..000000000000
--- a/src/renderers/shared/reconciler/__tests__/ReactComponentLifeCycle-test.js
+++ /dev/null
@@ -1,582 +0,0 @@
-/**
- * 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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-var keyMirror = require('keyMirror');
-
-var React;
-var ReactDOM;
-var ReactInstanceMap;
-var ReactTestUtils;
-
-var clone = function(o) {
-  return JSON.parse(JSON.stringify(o));
-};
-
-
-var GET_INIT_STATE_RETURN_VAL = {
-  hasWillMountCompleted: false,
-  hasRenderCompleted: false,
-  hasDidMountCompleted: false,
-  hasWillUnmountCompleted: false,
-};
-
-var INIT_RENDER_STATE = {
-  hasWillMountCompleted: true,
-  hasRenderCompleted: false,
-  hasDidMountCompleted: false,
-  hasWillUnmountCompleted: false,
-};
-
-var DID_MOUNT_STATE = {
-  hasWillMountCompleted: true,
-  hasRenderCompleted: true,
-  hasDidMountCompleted: false,
-  hasWillUnmountCompleted: false,
-};
-
-var NEXT_RENDER_STATE = {
-  hasWillMountCompleted: true,
-  hasRenderCompleted: true,
-  hasDidMountCompleted: true,
-  hasWillUnmountCompleted: false,
-};
-
-var WILL_UNMOUNT_STATE = {
-  hasWillMountCompleted: true,
-  hasDidMountCompleted: true,
-  hasRenderCompleted: true,
-  hasWillUnmountCompleted: false,
-};
-
-var POST_WILL_UNMOUNT_STATE = {
-  hasWillMountCompleted: true,
-  hasDidMountCompleted: true,
-  hasRenderCompleted: true,
-  hasWillUnmountCompleted: true,
-};
-
-/**
- * Every React component is in one of these life cycles.
- */
-var ComponentLifeCycle = keyMirror({
-  /**
-   * Mounted components have a DOM node representation and are capable of
-   * receiving new props.
-   */
-  MOUNTED: null,
-  /**
-   * Unmounted components are inactive and cannot receive new props.
-   */
-  UNMOUNTED: null,
-});
-
-function getLifeCycleState(instance) {
-  var internalInstance = ReactInstanceMap.get(instance);
-  // Once a component gets mounted, it has an internal instance, once it
-  // gets unmounted, it loses that internal instance.
-  return internalInstance ?
-         ComponentLifeCycle.MOUNTED :
-         ComponentLifeCycle.UNMOUNTED;
-}
-
-/**
- * TODO: We should make any setState calls fail in
- * `getInitialState` and `componentWillMount`. They will usually fail
- * anyways because `this._renderedComponent` is empty, however, if a component
- * is *reused*, then that won't be the case and things will appear to work in
- * some cases. Better to just block all updates in initialization.
- */
-describe('ReactComponentLifeCycle', function() {
-  beforeEach(function() {
-    jest.resetModuleRegistry();
-    React = require('React');
-    ReactDOM = require('ReactDOM');
-    ReactTestUtils = require('ReactTestUtils');
-    ReactInstanceMap = require('ReactInstanceMap');
-  });
-
-  it('should not reuse an instance when it has been unmounted', function() {
-    var container = document.createElement('div');
-    var StatefulComponent = React.createClass({
-      getInitialState: function() {
-        return {};
-      },
-      render: function() {
-        return (
-          <div></div>
-        );
-      },
-    });
-    var element = <StatefulComponent />;
-    var firstInstance = ReactDOM.render(element, container);
-    ReactDOM.unmountComponentAtNode(container);
-    var secondInstance = ReactDOM.render(element, container);
-    expect(firstInstance).not.toBe(secondInstance);
-  });
-
-  /**
-   * If a state update triggers rerendering that in turn fires an onDOMReady,
-   * that second onDOMReady should not fail.
-   */
-  it('it should fire onDOMReady when already in onDOMReady', function() {
-
-    var _testJournal = [];
-
-    var Child = React.createClass({
-      componentDidMount: function() {
-        _testJournal.push('Child:onDOMReady');
-      },
-      render: function() {
-        return <div></div>;
-      },
-    });
-
-    var SwitcherParent = React.createClass({
-      getInitialState: function() {
-        _testJournal.push('SwitcherParent:getInitialState');
-        return {showHasOnDOMReadyComponent: false};
-      },
-      componentDidMount: function() {
-        _testJournal.push('SwitcherParent:onDOMReady');
-        this.switchIt();
-      },
-      switchIt: function() {
-        this.setState({showHasOnDOMReadyComponent: true});
-      },
-      render: function() {
-        return (
-          <div>{
-            this.state.showHasOnDOMReadyComponent ?
-            <Child /> :
-            <div> </div>
-          }</div>
-        );
-      },
-    });
-
-    var instance = <SwitcherParent />;
-    instance = ReactTestUtils.renderIntoDocument(instance);
-    expect(_testJournal).toEqual([
-      'SwitcherParent:getInitialState',
-      'SwitcherParent:onDOMReady',
-      'Child:onDOMReady',
-    ]);
-  });
-
-  // You could assign state here, but not access members of it, unless you
-  // had provided a getInitialState method.
-  it('throws when accessing state in componentWillMount', function() {
-    var StatefulComponent = React.createClass({
-      componentWillMount: function() {
-        void this.state.yada;
-      },
-      render: function() {
-        return (
-          <div></div>
-        );
-      },
-    });
-    var instance = <StatefulComponent />;
-    expect(function() {
-      instance = ReactTestUtils.renderIntoDocument(instance);
-    }).toThrow();
-  });
-
-  it('should allow update state inside of componentWillMount', function() {
-    var StatefulComponent = React.createClass({
-      componentWillMount: function() {
-        this.setState({stateField: 'something'});
-      },
-      render: function() {
-        return (
-          <div></div>
-        );
-      },
-    });
-    var instance = <StatefulComponent />;
-    expect(function() {
-      instance = ReactTestUtils.renderIntoDocument(instance);
-    }).not.toThrow();
-  });
-
-  it('should not allow update state inside of getInitialState', function() {
-    spyOn(console, 'error');
-    var StatefulComponent = React.createClass({
-      getInitialState: function() {
-        this.setState({stateField: 'something'});
-
-        return {stateField: 'somethingelse'};
-      },
-      render: function() {
-        return (
-          <div></div>
-        );
-      },
-    });
-    ReactTestUtils.renderIntoDocument(<StatefulComponent />);
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: setState(...): Can only update a mounted or ' +
-      'mounting component. This usually means you called setState() on an ' +
-      'unmounted component. This is a no-op. Please check the code for the ' +
-      'StatefulComponent component.'
-    );
-  });
-
-  it('should correctly determine if a component is mounted', function() {
-    spyOn(console, 'error');
-    var Component = React.createClass({
-      componentWillMount: function() {
-        expect(this.isMounted()).toBeFalsy();
-      },
-      componentDidMount: function() {
-        expect(this.isMounted()).toBeTruthy();
-      },
-      render: function() {
-        expect(this.isMounted()).toBeFalsy();
-        return <div/>;
-      },
-    });
-
-    var element = <Component />;
-
-    var instance = ReactTestUtils.renderIntoDocument(element);
-    expect(instance.isMounted()).toBeTruthy();
-
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
-      'Component is accessing isMounted inside its render()'
-    );
-  });
-
-  it('should correctly determine if a null component is mounted', function() {
-    spyOn(console, 'error');
-    var Component = React.createClass({
-      componentWillMount: function() {
-        expect(this.isMounted()).toBeFalsy();
-      },
-      componentDidMount: function() {
-        expect(this.isMounted()).toBeTruthy();
-      },
-      render: function() {
-        expect(this.isMounted()).toBeFalsy();
-        return null;
-      },
-    });
-
-    var element = <Component />;
-
-    var instance = ReactTestUtils.renderIntoDocument(element);
-    expect(instance.isMounted()).toBeTruthy();
-
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
-      'Component is accessing isMounted inside its render()'
-    );
-  });
-
-  it('isMounted should return false when unmounted', function() {
-    var Component = React.createClass({
-      render: function() {
-        return <div/>;
-      },
-    });
-
-    var container = document.createElement('div');
-    var instance = ReactDOM.render(<Component />, container);
-
-    expect(instance.isMounted()).toBe(true);
-
-    ReactDOM.unmountComponentAtNode(container);
-
-    expect(instance.isMounted()).toBe(false);
-  });
-
-  it('warns if findDOMNode is used inside render', function() {
-    spyOn(console, 'error');
-    var Component = React.createClass({
-      getInitialState: function() {
-        return {isMounted: false};
-      },
-      componentDidMount: function() {
-        this.setState({isMounted: true});
-      },
-      render: function() {
-        if (this.state.isMounted) {
-          expect(ReactDOM.findDOMNode(this).tagName).toBe('DIV');
-        }
-        return <div/>;
-      },
-    });
-
-    ReactTestUtils.renderIntoDocument(<Component />);
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
-      'Component is accessing findDOMNode inside its render()'
-    );
-  });
-
-  it('should carry through each of the phases of setup', function() {
-    var LifeCycleComponent = React.createClass({
-      getInitialState: function() {
-        this._testJournal = {};
-        var initState = {
-          hasWillMountCompleted: false,
-          hasDidMountCompleted: false,
-          hasRenderCompleted: false,
-          hasWillUnmountCompleted: false,
-        };
-        this._testJournal.returnedFromGetInitialState = clone(initState);
-        this._testJournal.lifeCycleAtStartOfGetInitialState =
-          getLifeCycleState(this);
-        return initState;
-      },
-
-      componentWillMount: function() {
-        this._testJournal.stateAtStartOfWillMount = clone(this.state);
-        this._testJournal.lifeCycleAtStartOfWillMount =
-          getLifeCycleState(this);
-        this.state.hasWillMountCompleted = true;
-      },
-
-      componentDidMount: function() {
-        this._testJournal.stateAtStartOfDidMount = clone(this.state);
-        this._testJournal.lifeCycleAtStartOfDidMount =
-          getLifeCycleState(this);
-        this.setState({hasDidMountCompleted: true});
-      },
-
-      render: function() {
-        var isInitialRender = !this.state.hasRenderCompleted;
-        if (isInitialRender) {
-          this._testJournal.stateInInitialRender = clone(this.state);
-          this._testJournal.lifeCycleInInitialRender = getLifeCycleState(this);
-        } else {
-          this._testJournal.stateInLaterRender = clone(this.state);
-          this._testJournal.lifeCycleInLaterRender = getLifeCycleState(this);
-        }
-        // you would *NEVER* do anything like this in real code!
-        this.state.hasRenderCompleted = true;
-        return (
-          <div ref="theDiv">
-            I am the inner DIV
-          </div>
-        );
-      },
-
-      componentWillUnmount: function() {
-        this._testJournal.stateAtStartOfWillUnmount = clone(this.state);
-        this._testJournal.lifeCycleAtStartOfWillUnmount =
-          getLifeCycleState(this);
-        this.state.hasWillUnmountCompleted = true;
-      },
-    });
-
-    // A component that is merely "constructed" (as in "constructor") but not
-    // yet initialized, or rendered.
-    //
-    var container = document.createElement('div');
-    var instance = ReactDOM.render(<LifeCycleComponent />, container);
-
-    // getInitialState
-    expect(instance._testJournal.returnedFromGetInitialState).toEqual(
-      GET_INIT_STATE_RETURN_VAL
-    );
-    expect(instance._testJournal.lifeCycleAtStartOfGetInitialState)
-      .toBe(ComponentLifeCycle.UNMOUNTED);
-
-    // componentWillMount
-    expect(instance._testJournal.stateAtStartOfWillMount).toEqual(
-      instance._testJournal.returnedFromGetInitialState
-    );
-    expect(instance._testJournal.lifeCycleAtStartOfWillMount)
-      .toBe(ComponentLifeCycle.MOUNTED);
-
-    // componentDidMount
-    expect(instance._testJournal.stateAtStartOfDidMount)
-      .toEqual(DID_MOUNT_STATE);
-    expect(instance._testJournal.lifeCycleAtStartOfDidMount).toBe(
-      ComponentLifeCycle.MOUNTED
-    );
-
-    // render
-    expect(instance._testJournal.stateInInitialRender)
-      .toEqual(INIT_RENDER_STATE);
-    expect(instance._testJournal.lifeCycleInInitialRender).toBe(
-      ComponentLifeCycle.MOUNTED
-    );
-
-    expect(getLifeCycleState(instance)).toBe(ComponentLifeCycle.MOUNTED);
-
-    // Now *update the component*
-    instance.forceUpdate();
-
-    // render 2nd time
-    expect(instance._testJournal.stateInLaterRender)
-      .toEqual(NEXT_RENDER_STATE);
-    expect(instance._testJournal.lifeCycleInLaterRender).toBe(
-      ComponentLifeCycle.MOUNTED
-    );
-
-    expect(getLifeCycleState(instance)).toBe(ComponentLifeCycle.MOUNTED);
-
-    ReactDOM.unmountComponentAtNode(container);
-
-    expect(instance._testJournal.stateAtStartOfWillUnmount)
-      .toEqual(WILL_UNMOUNT_STATE);
-    // componentWillUnmount called right before unmount.
-    expect(instance._testJournal.lifeCycleAtStartOfWillUnmount).toBe(
-      ComponentLifeCycle.MOUNTED
-    );
-
-    // But the current lifecycle of the component is unmounted.
-    expect(getLifeCycleState(instance)).toBe(ComponentLifeCycle.UNMOUNTED);
-    expect(instance.state).toEqual(POST_WILL_UNMOUNT_STATE);
-  });
-
-  it('should not throw when updating an auxiliary component', function() {
-    var Tooltip = React.createClass({
-      render: function() {
-        return <div>{this.props.children}</div>;
-      },
-      componentDidMount: function() {
-        this.container = document.createElement('div');
-        this.updateTooltip();
-      },
-      componentDidUpdate: function() {
-        this.updateTooltip();
-      },
-      updateTooltip: function() {
-        // Even though this.props.tooltip has an owner, updating it shouldn't
-        // throw here because it's mounted as a root component
-        ReactDOM.render(this.props.tooltip, this.container);
-      },
-    });
-    var Component = React.createClass({
-      render: function() {
-        return (
-          <Tooltip
-              ref="tooltip"
-              tooltip={<div>{this.props.tooltipText}</div>}>
-            {this.props.text}
-          </Tooltip>
-        );
-      },
-    });
-
-    var container = document.createElement('div');
-    ReactDOM.render(
-      <Component text="uno" tooltipText="one" />,
-      container
-    );
-
-    // Since `instance` is a root component, we can set its props. This also
-    // makes Tooltip rerender the tooltip component, which shouldn't throw.
-    ReactDOM.render(
-      <Component text="dos" tooltipText="two" />,
-      container
-    );
-  });
-
-  it('should allow state updates in componentDidMount', function() {
-    /**
-     * calls setState in an componentDidMount.
-     */
-    var SetStateInComponentDidMount = React.createClass({
-      getInitialState: function() {
-        return {
-          stateField: this.props.valueToUseInitially,
-        };
-      },
-      componentDidMount: function() {
-        this.setState({stateField: this.props.valueToUseInOnDOMReady});
-      },
-      render: function() {
-        return (<div></div>);
-      },
-    });
-    var instance =
-      <SetStateInComponentDidMount
-        valueToUseInitially="hello"
-        valueToUseInOnDOMReady="goodbye"
-      />;
-    instance = ReactTestUtils.renderIntoDocument(instance);
-    expect(instance.state.stateField).toBe('goodbye');
-  });
-
-  it('should call nested lifecycle methods in the right order', function() {
-    var log;
-    var logger = function(msg) {
-      return function() {
-        // return true for shouldComponentUpdate
-        log.push(msg);
-        return true;
-      };
-    };
-    var Outer = React.createClass({
-      render: function() {
-        return <div><Inner x={this.props.x} /></div>;
-      },
-      componentWillMount: logger('outer componentWillMount'),
-      componentDidMount: logger('outer componentDidMount'),
-      componentWillReceiveProps: logger('outer componentWillReceiveProps'),
-      shouldComponentUpdate: logger('outer shouldComponentUpdate'),
-      componentWillUpdate: logger('outer componentWillUpdate'),
-      componentDidUpdate: logger('outer componentDidUpdate'),
-      componentWillUnmount: logger('outer componentWillUnmount'),
-    });
-    var Inner = React.createClass({
-      render: function() {
-        return <span>{this.props.x}</span>;
-      },
-      componentWillMount: logger('inner componentWillMount'),
-      componentDidMount: logger('inner componentDidMount'),
-      componentWillReceiveProps: logger('inner componentWillReceiveProps'),
-      shouldComponentUpdate: logger('inner shouldComponentUpdate'),
-      componentWillUpdate: logger('inner componentWillUpdate'),
-      componentDidUpdate: logger('inner componentDidUpdate'),
-      componentWillUnmount: logger('inner componentWillUnmount'),
-    });
-
-
-    var container = document.createElement('div');
-    log = [];
-    ReactDOM.render(<Outer x={17} />, container);
-    expect(log).toEqual([
-      'outer componentWillMount',
-      'inner componentWillMount',
-      'inner componentDidMount',
-      'outer componentDidMount',
-    ]);
-
-    log = [];
-    ReactDOM.render(<Outer x={42} />, container);
-    expect(log).toEqual([
-      'outer componentWillReceiveProps',
-      'outer shouldComponentUpdate',
-      'outer componentWillUpdate',
-      'inner componentWillReceiveProps',
-      'inner shouldComponentUpdate',
-      'inner componentWillUpdate',
-      'inner componentDidUpdate',
-      'outer componentDidUpdate',
-    ]);
-
-    log = [];
-    ReactDOM.unmountComponentAtNode(container);
-    expect(log).toEqual([
-      'outer componentWillUnmount',
-      'inner componentWillUnmount',
-    ]);
-  });
-});
diff --git a/src/renderers/shared/reconciler/__tests__/ReactCompositeComponent-test.js b/src/renderers/shared/reconciler/__tests__/ReactCompositeComponent-test.js
deleted file mode 100644
index c33fb33b2538..000000000000
--- a/src/renderers/shared/reconciler/__tests__/ReactCompositeComponent-test.js
+++ /dev/null
@@ -1,1306 +0,0 @@
-/**
- * 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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-var ChildUpdates;
-var MorphingComponent;
-var React;
-var ReactDOM;
-var ReactCurrentOwner;
-var ReactPropTypes;
-var ReactServerRendering;
-var ReactTestUtils;
-var ReactUpdates;
-
-var reactComponentExpect;
-
-describe('ReactCompositeComponent', function() {
-
-  beforeEach(function() {
-    jest.resetModuleRegistry();
-    reactComponentExpect = require('reactComponentExpect');
-    React = require('React');
-    ReactDOM = require('ReactDOM');
-    ReactCurrentOwner = require('ReactCurrentOwner');
-    ReactPropTypes = require('ReactPropTypes');
-    ReactTestUtils = require('ReactTestUtils');
-    ReactServerRendering = require('ReactServerRendering');
-    ReactUpdates = require('ReactUpdates');
-
-    MorphingComponent = React.createClass({
-      getInitialState: function() {
-        return {activated: false};
-      },
-
-      _toggleActivatedState: function() {
-        this.setState({activated: !this.state.activated});
-      },
-
-      render: function() {
-        var toggleActivatedState = this._toggleActivatedState;
-        return !this.state.activated ?
-          <a ref="x" onClick={toggleActivatedState} /> :
-          <b ref="x" onClick={toggleActivatedState} />;
-      },
-    });
-
-    /**
-     * We'll use this to ensure that an old version is not cached when it is
-     * reallocated again.
-     */
-    ChildUpdates = React.createClass({
-      getAnchor: function() {
-        return this.refs.anch;
-      },
-      render: function() {
-        var className = this.props.anchorClassOn ? 'anchorClass' : '';
-        return this.props.renderAnchor ?
-          <a ref="anch" className={className}></a> :
-          <b></b>;
-      },
-    });
-  });
-
-  it('should support module pattern components', function() {
-    function Child({test}) {
-      return {
-        render() {
-          return <div>{test}</div>;
-        },
-      };
-    }
-
-    var el = document.createElement('div');
-    ReactDOM.render(<Child test="test" />, el);
-
-    expect(el.textContent).toBe('test');
-  });
-
-  it('should support rendering to different child types over time', function() {
-    var instance = <MorphingComponent />;
-    instance = ReactTestUtils.renderIntoDocument(instance);
-
-    reactComponentExpect(instance)
-      .expectRenderedChild()
-      .toBeDOMComponentWithTag('a');
-
-    instance._toggleActivatedState();
-    reactComponentExpect(instance)
-      .expectRenderedChild()
-      .toBeDOMComponentWithTag('b');
-
-    instance._toggleActivatedState();
-    reactComponentExpect(instance)
-      .expectRenderedChild()
-      .toBeDOMComponentWithTag('a');
-  });
-
-  it('should not thrash a server rendered layout with client side one', () => {
-    var Child = React.createClass({
-      render: function() {
-        return null;
-      },
-    });
-    var Parent = React.createClass({
-      render: function() {
-        return <div><Child /></div>;
-      },
-    });
-
-    var markup = ReactServerRendering.renderToString(<Parent />);
-    var container = document.createElement('div');
-    container.innerHTML = markup;
-
-    ReactDOM.render(<Parent />, container);
-  });
-
-  it('should react to state changes from callbacks', function() {
-    var instance = <MorphingComponent />;
-    instance = ReactTestUtils.renderIntoDocument(instance);
-
-    var renderedChild = reactComponentExpect(instance)
-      .expectRenderedChild()
-      .instance();
-
-    ReactTestUtils.Simulate.click(renderedChild);
-    reactComponentExpect(instance)
-      .expectRenderedChild()
-      .toBeDOMComponentWithTag('b');
-  });
-
-  it('should rewire refs when rendering to different child types', function() {
-    var instance = <MorphingComponent />;
-    instance = ReactTestUtils.renderIntoDocument(instance);
-
-    expect(ReactDOM.findDOMNode(instance.refs.x).tagName).toBe('A');
-    instance._toggleActivatedState();
-    expect(ReactDOM.findDOMNode(instance.refs.x).tagName).toBe('B');
-    instance._toggleActivatedState();
-    expect(ReactDOM.findDOMNode(instance.refs.x).tagName).toBe('A');
-  });
-
-  it('should not cache old DOM nodes when switching constructors', function() {
-    var container = document.createElement('div');
-    var instance = ReactDOM.render(
-      <ChildUpdates renderAnchor={true} anchorClassOn={false}/>,
-      container
-    );
-    ReactDOM.render(  // Warm any cache
-      <ChildUpdates renderAnchor={true} anchorClassOn={true}/>,
-      container
-    );
-    ReactDOM.render(  // Clear out the anchor
-      <ChildUpdates renderAnchor={false} anchorClassOn={true}/>,
-      container
-    );
-    ReactDOM.render(  // rerender
-      <ChildUpdates renderAnchor={true} anchorClassOn={false}/>,
-      container
-    );
-    expect(instance.getAnchor().className).toBe('');
-  });
-
-  it('should auto bind methods and values correctly', function() {
-    spyOn(console, 'error');
-
-    var ComponentClass = React.createClass({
-      getInitialState: function() {
-        return {valueToReturn: 'hi'};
-      },
-      methodToBeExplicitlyBound: function() {
-        return this;
-      },
-      methodAutoBound: function() {
-        return this;
-      },
-      render: function() {
-        return <div></div>;
-      },
-    });
-    var instance = <ComponentClass />;
-
-    // Next, prove that once mounted, the scope is bound correctly to the actual
-    // component.
-    var mountedInstance = ReactTestUtils.renderIntoDocument(instance);
-
-    expect(function() {
-      mountedInstance.methodToBeExplicitlyBound.bind(instance)();
-    }).not.toThrow();
-    expect(function() {
-      mountedInstance.methodAutoBound();
-    }).not.toThrow();
-
-    expect(console.error.argsForCall.length).toBe(1);
-    var explicitlyBound = mountedInstance.methodToBeExplicitlyBound.bind(
-      mountedInstance
-    );
-    expect(console.error.argsForCall.length).toBe(2);
-    var autoBound = mountedInstance.methodAutoBound;
-
-    var context = {};
-    expect(explicitlyBound.call(context)).toBe(mountedInstance);
-    expect(autoBound.call(context)).toBe(mountedInstance);
-
-    expect(explicitlyBound.call(mountedInstance)).toBe(mountedInstance);
-    expect(autoBound.call(mountedInstance)).toBe(mountedInstance);
-
-  });
-
-  it('should not pass this to getDefaultProps', function() {
-    var Component = React.createClass({
-      getDefaultProps: function() {
-        expect(this.render).not.toBeDefined();
-        return {};
-      },
-      render: function() {
-        return <div />;
-      },
-    });
-    ReactTestUtils.renderIntoDocument(<Component />);
-  });
-
-  it('should use default values for undefined props', function() {
-    var Component = React.createClass({
-      getDefaultProps: function() {
-        return {prop: 'testKey'};
-      },
-      render: function() {
-        return <span />;
-      },
-    });
-
-    var instance1 = <Component />;
-    instance1 = ReactTestUtils.renderIntoDocument(instance1);
-    reactComponentExpect(instance1).scalarPropsEqual({prop: 'testKey'});
-
-    var instance2 = <Component prop={undefined} />;
-    instance2 = ReactTestUtils.renderIntoDocument(instance2);
-    reactComponentExpect(instance2).scalarPropsEqual({prop: 'testKey'});
-
-    var instance3 = <Component prop={null} />;
-    instance3 = ReactTestUtils.renderIntoDocument(instance3);
-    reactComponentExpect(instance3).scalarPropsEqual({prop: null});
-  });
-
-  it('should not mutate passed-in props object', function() {
-    var Component = React.createClass({
-      getDefaultProps: function() {
-        return {prop: 'testKey'};
-      },
-      render: function() {
-        return <span />;
-      },
-    });
-
-    var inputProps = {};
-    var instance1 = <Component {...inputProps} />;
-    instance1 = ReactTestUtils.renderIntoDocument(instance1);
-    expect(instance1.props.prop).toBe('testKey');
-
-    // We don't mutate the input, just in case the caller wants to do something
-    // with it after using it to instantiate a component
-    expect(inputProps.prop).not.toBeDefined();
-  });
-
-  it('should warn about `forceUpdate` on unmounted components', function() {
-    spyOn(console, 'error');
-
-    var container = document.createElement('div');
-    document.body.appendChild(container);
-
-    var Component = React.createClass({
-      render: function() {
-        return <div />;
-      },
-    });
-
-    var instance = <Component />;
-    expect(instance.forceUpdate).not.toBeDefined();
-
-    instance = ReactDOM.render(instance, container);
-    instance.forceUpdate();
-
-    expect(console.error.calls.length).toBe(0);
-
-    ReactDOM.unmountComponentAtNode(container);
-
-    instance.forceUpdate();
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: forceUpdate(...): Can only update a mounted or ' +
-      'mounting component. This usually means you called forceUpdate() on an ' +
-      'unmounted component. This is a no-op. Please check the code for the ' +
-      'Component component.'
-    );
-  });
-
-  it('should warn about `setState` on unmounted components', function() {
-    spyOn(console, 'error');
-
-    var container = document.createElement('div');
-    document.body.appendChild(container);
-
-    var renders = 0;
-
-    var Component = React.createClass({
-      getInitialState: function() {
-        return {value: 0};
-      },
-      render: function() {
-        renders++;
-        return <div />;
-      },
-    });
-
-    var instance = <Component />;
-    expect(instance.setState).not.toBeDefined();
-
-    instance = ReactDOM.render(instance, container);
-
-    expect(renders).toBe(1);
-
-    instance.setState({value: 1});
-
-    expect(console.error.calls.length).toBe(0);
-
-    expect(renders).toBe(2);
-
-    ReactDOM.unmountComponentAtNode(container);
-    instance.setState({value: 2});
-
-    expect(renders).toBe(2);
-
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: setState(...): Can only update a mounted or ' +
-      'mounting component. This usually means you called setState() on an ' +
-      'unmounted component. This is a no-op. Please check the code for the ' +
-      'Component component.'
-    );
-  });
-
-  it('should silently allow `setState`, not call cb on unmounting components', function() {
-    var cbCalled = false;
-    var container = document.createElement('div');
-    document.body.appendChild(container);
-
-    var Component = React.createClass({
-      getInitialState: function() {
-        return {value: 0};
-      },
-      componentWillUnmount: function() {
-        expect(() => {
-          this.setState({value: 2}, function() {
-            cbCalled = true;
-          });
-        }).not.toThrow();
-      },
-      render: function() {
-        return <div />;
-      },
-    });
-
-    var instance = ReactDOM.render(<Component />, container);
-    instance.setState({value: 1});
-
-    ReactDOM.unmountComponentAtNode(container);
-    expect(cbCalled).toBe(false);
-  });
-
-
-  it('should warn about `setState` in render', function() {
-    spyOn(console, 'error');
-
-    var container = document.createElement('div');
-
-    var renderedState = -1;
-    var renderPasses = 0;
-
-    var Component = React.createClass({
-      getInitialState: function() {
-        return {value: 0};
-      },
-      render: function() {
-        renderPasses++;
-        renderedState = this.state.value;
-        if (this.state.value === 0) {
-          this.setState({ value: 1 });
-        }
-        return <div />;
-      },
-    });
-
-    expect(console.error.calls.length).toBe(0);
-
-    var instance = ReactDOM.render(<Component />, container);
-
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: setState(...): 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`.'
-    );
-
-    // The setState call is queued and then executed as a second pass. This
-    // behavior is undefined though so we're free to change it to suit the
-    // implementation details.
-    expect(renderPasses).toBe(2);
-    expect(renderedState).toBe(1);
-    expect(instance.state.value).toBe(1);
-
-    // Forcing a rerender anywhere will cause the update to happen.
-    var instance2 = ReactDOM.render(<Component prop={123} />, container);
-    expect(instance).toBe(instance2);
-    expect(renderedState).toBe(1);
-    expect(instance2.state.value).toBe(1);
-  });
-
-  it('should warn about `setState` in getChildContext', function() {
-    spyOn(console, 'error');
-
-    var container = document.createElement('div');
-
-    var renderPasses = 0;
-
-    var Component = React.createClass({
-      getInitialState: function() {
-        return {value: 0};
-      },
-      getChildContext: function() {
-        if (this.state.value === 0) {
-          this.setState({ value: 1 });
-        }
-      },
-      render: function() {
-        renderPasses++;
-        return <div />;
-      },
-    });
-    expect(console.error.calls.length).toBe(0);
-    var instance = ReactDOM.render(<Component />, container);
-    expect(renderPasses).toBe(2);
-    expect(instance.state.value).toBe(1);
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: setState(...): Cannot call setState() inside getChildContext()'
-    );
-  });
-
-  it('should cleanup even if render() fatals', function() {
-    var BadComponent = React.createClass({
-      render: function() {
-        throw new Error();
-      },
-    });
-    var instance = <BadComponent />;
-
-    expect(ReactCurrentOwner.current).toBe(null);
-
-    expect(function() {
-      instance = ReactTestUtils.renderIntoDocument(instance);
-    }).toThrow();
-
-    expect(ReactCurrentOwner.current).toBe(null);
-  });
-
-  it('should call componentWillUnmount before unmounting', function() {
-    var container = document.createElement('div');
-    var innerUnmounted = false;
-
-    var Component = React.createClass({
-      render: function() {
-        return (
-          <div>
-            <Inner />
-            Text
-          </div>
-        );
-      },
-    });
-    var Inner = React.createClass({
-      componentWillUnmount: function() {
-        innerUnmounted = true;
-      },
-      render: function() {
-        return <div />;
-      },
-    });
-
-    ReactDOM.render(<Component />, container);
-    ReactDOM.unmountComponentAtNode(container);
-    expect(innerUnmounted).toBe(true);
-  });
-
-  it('should warn when shouldComponentUpdate() returns undefined', function() {
-    spyOn(console, 'error');
-
-    var Component = React.createClass({
-      getInitialState: function() {
-        return {bogus: false};
-      },
-
-      shouldComponentUpdate: function() {
-        return undefined;
-      },
-
-      render: function() {
-        return <div />;
-      },
-    });
-
-    var instance = ReactTestUtils.renderIntoDocument(<Component />);
-    instance.setState({bogus: true});
-
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: Component.shouldComponentUpdate(): Returned undefined instead of a ' +
-      'boolean value. Make sure to return true or false.'
-    );
-  });
-
-  it('should warn when componentDidUnmount method is defined', function() {
-    spyOn(console, 'error');
-
-    var Component = React.createClass({
-      componentDidUnmount: function() {
-      },
-
-      render: function() {
-        return <div />;
-      },
-    });
-
-    ReactTestUtils.renderIntoDocument(<Component />);
-
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: Component has a method called ' +
-      'componentDidUnmount(). But there is no such lifecycle method. ' +
-      'Did you mean componentWillUnmount()?'
-    );
-  });
-
-  it('should pass context to children when not owner', function() {
-    var Parent = React.createClass({
-      render: function() {
-        return <Child><Grandchild /></Child>;
-      },
-    });
-
-    var Child = React.createClass({
-      childContextTypes: {
-        foo: ReactPropTypes.string,
-      },
-
-      getChildContext: function() {
-        return {
-          foo: 'bar',
-        };
-      },
-
-      render: function() {
-        return React.Children.only(this.props.children);
-      },
-    });
-
-    var Grandchild = React.createClass({
-      contextTypes: {
-        foo: ReactPropTypes.string,
-      },
-
-      render: function() {
-        return <div>{this.context.foo}</div>;
-      },
-    });
-
-    var component = ReactTestUtils.renderIntoDocument(<Parent />);
-    expect(ReactDOM.findDOMNode(component).innerHTML).toBe('bar');
-  });
-
-  it('should skip update when rerendering element in container', function() {
-    var Parent = React.createClass({
-      render: function() {
-        return <div>{this.props.children}</div>;
-      },
-    });
-
-    var childRenders = 0;
-    var Child = React.createClass({
-      render: function() {
-        childRenders++;
-        return <div />;
-      },
-    });
-
-    var container = document.createElement('div');
-    var child = <Child />;
-
-    ReactDOM.render(<Parent>{child}</Parent>, container);
-    ReactDOM.render(<Parent>{child}</Parent>, container);
-    expect(childRenders).toBe(1);
-  });
-
-  it('should pass context when re-rendered for static child', function() {
-    var parentInstance = null;
-    var childInstance = null;
-
-    var Parent = React.createClass({
-      childContextTypes: {
-        foo: ReactPropTypes.string,
-        flag: ReactPropTypes.bool,
-      },
-
-      getChildContext: function() {
-        return {
-          foo: 'bar',
-          flag: this.state.flag,
-        };
-      },
-
-      getInitialState: function() {
-        return {
-          flag: false,
-        };
-      },
-
-      render: function() {
-        return React.Children.only(this.props.children);
-      },
-    });
-
-    var Middle = React.createClass({
-      render: function() {
-        return this.props.children;
-      },
-    });
-
-    var Child = React.createClass({
-      contextTypes: {
-        foo: ReactPropTypes.string,
-        flag: ReactPropTypes.bool,
-      },
-
-      render: function() {
-        childInstance = this;
-        return <span>Child</span>;
-      },
-    });
-
-    parentInstance = ReactTestUtils.renderIntoDocument(
-      <Parent><Middle><Child /></Middle></Parent>
-    );
-
-    expect(parentInstance.state.flag).toBe(false);
-    reactComponentExpect(childInstance).scalarContextEqual({foo: 'bar', flag: false});
-
-    parentInstance.setState({flag: true});
-    expect(parentInstance.state.flag).toBe(true);
-
-    reactComponentExpect(childInstance).scalarContextEqual({foo: 'bar', flag: true});
-  });
-
-  it('should pass context when re-rendered for static child within a composite component', function() {
-    var Parent = React.createClass({
-      childContextTypes: {
-        flag: ReactPropTypes.bool,
-      },
-
-      getChildContext() {
-        return {
-          flag: this.state.flag,
-        };
-      },
-
-      getInitialState: function() {
-        return {
-          flag: true,
-        };
-      },
-
-      render() {
-        return <div>{this.props.children}</div>;
-      },
-
-    });
-
-    var Child = React.createClass({
-      contextTypes: {
-        flag: ReactPropTypes.bool,
-      },
-
-      render: function() {
-        return <div />;
-      },
-    });
-
-    var Wrapper = React.createClass({
-      render() {
-        return (
-          <Parent ref="parent">
-            <Child ref="child" />
-          </Parent>
-        );
-      },
-    });
-
-
-    var wrapper = ReactTestUtils.renderIntoDocument(
-      <Wrapper />
-    );
-
-    expect(wrapper.refs.parent.state.flag).toEqual(true);
-    reactComponentExpect(wrapper.refs.child).scalarContextEqual({flag: true});
-
-    // We update <Parent /> while <Child /> is still a static prop relative to this update
-    wrapper.refs.parent.setState({flag: false});
-
-    expect(wrapper.refs.parent.state.flag).toEqual(false);
-    reactComponentExpect(wrapper.refs.child).scalarContextEqual({flag: false});
-
-  });
-
-  it('should pass context transitively', function() {
-    var childInstance = null;
-    var grandchildInstance = null;
-
-    var Parent = React.createClass({
-      childContextTypes: {
-        foo: ReactPropTypes.string,
-        depth: ReactPropTypes.number,
-      },
-
-      getChildContext: function() {
-        return {
-          foo: 'bar',
-          depth: 0,
-        };
-      },
-
-      render: function() {
-        return <Child />;
-      },
-    });
-
-    var Child = React.createClass({
-      contextTypes: {
-        foo: ReactPropTypes.string,
-        depth: ReactPropTypes.number,
-      },
-
-      childContextTypes: {
-        depth: ReactPropTypes.number,
-      },
-
-      getChildContext: function() {
-        return {
-          depth: this.context.depth + 1,
-        };
-      },
-
-      render: function() {
-        childInstance = this;
-        return <Grandchild />;
-      },
-    });
-
-    var Grandchild = React.createClass({
-      contextTypes: {
-        foo: ReactPropTypes.string,
-        depth: ReactPropTypes.number,
-      },
-
-      render: function() {
-        grandchildInstance = this;
-        return <div />;
-      },
-    });
-
-    ReactTestUtils.renderIntoDocument(<Parent />);
-    reactComponentExpect(childInstance).scalarContextEqual({foo: 'bar', depth: 0});
-    reactComponentExpect(grandchildInstance).scalarContextEqual({foo: 'bar', depth: 1});
-  });
-
-  it('should pass context when re-rendered', function() {
-    var parentInstance = null;
-    var childInstance = null;
-
-    var Parent = React.createClass({
-      childContextTypes: {
-        foo: ReactPropTypes.string,
-        depth: ReactPropTypes.number,
-      },
-
-      getChildContext: function() {
-        return {
-          foo: 'bar',
-          depth: 0,
-        };
-      },
-
-      getInitialState: function() {
-        return {
-          flag: false,
-        };
-      },
-
-      render: function() {
-        var output = <Child />;
-        if (!this.state.flag) {
-          output = <span>Child</span>;
-        }
-        return output;
-      },
-    });
-
-    var Child = React.createClass({
-      contextTypes: {
-        foo: ReactPropTypes.string,
-        depth: ReactPropTypes.number,
-      },
-
-      render: function() {
-        childInstance = this;
-        return <span>Child</span>;
-      },
-    });
-
-    parentInstance = ReactTestUtils.renderIntoDocument(<Parent />);
-    expect(childInstance).toBeNull();
-
-    expect(parentInstance.state.flag).toBe(false);
-    ReactUpdates.batchedUpdates(function() {
-      parentInstance.setState({flag: true});
-    });
-    expect(parentInstance.state.flag).toBe(true);
-
-    reactComponentExpect(childInstance).scalarContextEqual({foo: 'bar', depth: 0});
-  });
-
-  it('unmasked context propagates through updates', function() {
-
-    var Leaf = React.createClass({
-      contextTypes: {
-        foo: ReactPropTypes.string.isRequired,
-      },
-
-      componentWillReceiveProps: function(nextProps, nextContext) {
-        expect('foo' in nextContext).toBe(true);
-      },
-
-      componentDidUpdate: function(prevProps, prevState, prevContext) {
-        expect('foo' in prevContext).toBe(true);
-      },
-
-      shouldComponentUpdate: function(nextProps, nextState, nextContext) {
-        expect('foo' in nextContext).toBe(true);
-        return true;
-      },
-
-      render: function() {
-        return <span>{this.context.foo}</span>;
-      },
-    });
-
-    var Intermediary = React.createClass({
-
-      componentWillReceiveProps: function(nextProps, nextContext) {
-        expect('foo' in nextContext).toBe(false);
-      },
-
-      componentDidUpdate: function(prevProps, prevState, prevContext) {
-        expect('foo' in prevContext).toBe(false);
-      },
-
-      shouldComponentUpdate: function(nextProps, nextState, nextContext) {
-        expect('foo' in nextContext).toBe(false);
-        return true;
-      },
-
-      render: function() {
-        return <Leaf />;
-      },
-    });
-
-    var Parent = React.createClass({
-      childContextTypes: {
-        foo: ReactPropTypes.string,
-      },
-
-      getChildContext: function() {
-        return {
-          foo: this.props.cntxt,
-        };
-      },
-
-      render: function() {
-        return <Intermediary />;
-      },
-    });
-
-    var div = document.createElement('div');
-    ReactDOM.render(<Parent cntxt="noise" />, div);
-    expect(div.children[0].innerHTML).toBe('noise');
-    div.children[0].innerHTML = 'aliens';
-    div.children[0].id = 'aliens';
-    expect(div.children[0].innerHTML).toBe('aliens');
-    expect(div.children[0].id).toBe('aliens');
-    ReactDOM.render(<Parent cntxt="bar" />, div);
-    expect(div.children[0].innerHTML).toBe('bar');
-    expect(div.children[0].id).toBe('aliens');
-  });
-
-  it('should trigger componentWillReceiveProps for context changes', function() {
-    var contextChanges = 0;
-    var propChanges = 0;
-
-    var GrandChild = React.createClass({
-      contextTypes: {
-        foo: ReactPropTypes.string.isRequired,
-      },
-
-      componentWillReceiveProps: function(nextProps, nextContext) {
-        expect('foo' in nextContext).toBe(true);
-
-        if (nextProps !== this.props) {
-          propChanges++;
-        }
-
-        if (nextContext !== this.context) {
-          contextChanges++;
-        }
-      },
-
-      render: function() {
-        return <span className="grand-child">{this.props.children}</span>;
-      },
-    });
-
-    var ChildWithContext = React.createClass({
-      contextTypes: {
-        foo: ReactPropTypes.string.isRequired,
-      },
-
-      componentWillReceiveProps: function(nextProps, nextContext) {
-        expect('foo' in nextContext).toBe(true);
-
-        if (nextProps !== this.props) {
-          propChanges++;
-        }
-
-        if (nextContext !== this.context) {
-          contextChanges++;
-        }
-      },
-
-      render: function() {
-        return <div className="child-with">{this.props.children}</div>;
-      },
-    });
-
-    var ChildWithoutContext = React.createClass({
-      componentWillReceiveProps: function(nextProps, nextContext) {
-        expect('foo' in nextContext).toBe(false);
-
-        if (nextProps !== this.props) {
-          propChanges++;
-        }
-
-        if (nextContext !== this.context) {
-          contextChanges++;
-        }
-      },
-
-      render: function() {
-        return <div className="child-without">{this.props.children}</div>;
-      },
-    });
-
-    var Parent = React.createClass({
-      childContextTypes: {
-        foo: ReactPropTypes.string,
-      },
-
-      getInitialState() {
-        return {
-          foo: 'abc',
-        };
-      },
-
-      getChildContext: function() {
-        return {
-          foo: this.state.foo,
-        };
-      },
-
-      onClick() {
-        this.setState({
-          foo: 'def',
-        });
-      },
-
-      render: function() {
-        return <div className="parent" onClick={this.onClick}>{this.props.children}</div>;
-      },
-    });
-
-    var div = document.createElement('div');
-
-    ReactDOM.render(
-      <Parent>
-        <ChildWithoutContext>
-          A1
-          <GrandChild>A2</GrandChild>
-        </ChildWithoutContext>
-
-        <ChildWithContext>
-          B1
-          <GrandChild>B2</GrandChild>
-        </ChildWithContext>
-      </Parent>,
-      div
-    );
-
-    ReactTestUtils.Simulate.click(div.childNodes[0]);
-
-    expect(propChanges).toBe(0);
-    expect(contextChanges).toBe(3); // ChildWithContext, GrandChild x 2
-  });
-
-  it('should disallow nested render calls', function() {
-    spyOn(console, 'error');
-
-    var Inner = React.createClass({
-      render: function() {
-        return <div />;
-      },
-    });
-    var Outer = React.createClass({
-      render: function() {
-        ReactTestUtils.renderIntoDocument(<Inner />);
-        return <div />;
-      },
-    });
-
-    ReactTestUtils.renderIntoDocument(<Outer />);
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: _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 Outer.'
-    );
-  });
-
-  it('only renders once if updated in componentWillReceiveProps', function() {
-    var renders = 0;
-    var Component = React.createClass({
-      getInitialState: function() {
-        return {updated: false};
-      },
-      componentWillReceiveProps: function(props) {
-        expect(props.update).toBe(1);
-        this.setState({updated: true});
-      },
-      render: function() {
-        renders++;
-        return <div />;
-      },
-    });
-
-    var container = document.createElement('div');
-    var instance = ReactDOM.render(<Component update={0} />, container);
-    expect(renders).toBe(1);
-    expect(instance.state.updated).toBe(false);
-    ReactDOM.render(<Component update={1} />, container);
-    expect(renders).toBe(2);
-    expect(instance.state.updated).toBe(true);
-  });
-
-  it('should update refs if shouldComponentUpdate gives false', function() {
-    var Static = React.createClass({
-      shouldComponentUpdate: function() {
-        return false;
-      },
-      render: function() {
-        return <div>{this.props.children}</div>;
-      },
-    });
-    var Component = React.createClass({
-      render: function() {
-        if (this.props.flipped) {
-          return (
-            <div>
-              <Static ref="static0" key="B">B (ignored)</Static>
-              <Static ref="static1" key="A">A (ignored)</Static>
-            </div>
-          );
-        } else {
-          return (
-            <div>
-              <Static ref="static0" key="A">A</Static>
-              <Static ref="static1" key="B">B</Static>
-            </div>
-          );
-        }
-      },
-    });
-
-    var container = document.createElement('div');
-    var comp = ReactDOM.render(<Component flipped={false} />, container);
-    expect(ReactDOM.findDOMNode(comp.refs.static0).textContent).toBe('A');
-    expect(ReactDOM.findDOMNode(comp.refs.static1).textContent).toBe('B');
-
-    // When flipping the order, the refs should update even though the actual
-    // contents do not
-    ReactDOM.render(<Component flipped={true} />, container);
-    expect(ReactDOM.findDOMNode(comp.refs.static0).textContent).toBe('B');
-    expect(ReactDOM.findDOMNode(comp.refs.static1).textContent).toBe('A');
-  });
-
-  it('should allow access to findDOMNode in componentWillUnmount', function() {
-    var a = null;
-    var b = null;
-    var Component = React.createClass({
-      componentDidMount: function() {
-        a = ReactDOM.findDOMNode(this);
-        expect(a).not.toBe(null);
-      },
-      componentWillUnmount: function() {
-        b = ReactDOM.findDOMNode(this);
-        expect(b).not.toBe(null);
-      },
-      render: function() {
-        return <div />;
-      },
-    });
-    var container = document.createElement('div');
-    expect(a).toBe(container.firstChild);
-    ReactDOM.render(<Component />, container);
-    ReactDOM.unmountComponentAtNode(container);
-    expect(a).toBe(b);
-  });
-
-  it('context should be passed down from the parent', function() {
-    var Parent = React.createClass({
-      childContextTypes: {
-        foo: ReactPropTypes.string,
-      },
-
-      getChildContext: function() {
-        return {
-          foo: 'bar',
-        };
-      },
-
-      render: function() {
-        return <div>{this.props.children}</div>;
-      },
-    });
-
-    var Component = React.createClass({
-      contextTypes: {
-        foo: ReactPropTypes.string.isRequired,
-      },
-
-      render: function() {
-        return <div />;
-      },
-    });
-
-    var div = document.createElement('div');
-    ReactDOM.render(<Parent><Component /></Parent>, div);
-  });
-
-  it('should replace state', function() {
-    var Moo = React.createClass({
-      getInitialState: function() {
-        return {x: 1};
-      },
-      render: function() {
-        return <div />;
-      },
-    });
-
-    var moo = ReactTestUtils.renderIntoDocument(<Moo />);
-    moo.replaceState({y: 2});
-    expect('x' in moo.state).toBe(false);
-    expect(moo.state.y).toBe(2);
-  });
-
-  it('should support objects with prototypes as state', function() {
-    var NotActuallyImmutable = function(str) {
-      this.str = str;
-    };
-    NotActuallyImmutable.prototype.amIImmutable = function() {
-      return true;
-    };
-    var Moo = React.createClass({
-      getInitialState: function() {
-        return new NotActuallyImmutable('first');
-      },
-      render: function() {
-        return <div />;
-      },
-    });
-
-    var moo = ReactTestUtils.renderIntoDocument(<Moo />);
-    expect(moo.state.str).toBe('first');
-    expect(moo.state.amIImmutable()).toBe(true);
-
-    var secondState = new NotActuallyImmutable('second');
-    moo.replaceState(secondState);
-    expect(moo.state.str).toBe('second');
-    expect(moo.state.amIImmutable()).toBe(true);
-    expect(moo.state).toBe(secondState);
-
-    moo.setState({str: 'third'});
-    expect(moo.state.str).toBe('third');
-    // Here we lose the prototype.
-    expect(moo.state.amIImmutable).toBe(undefined);
-
-    // When more than one state update is enqueued, we have the same behavior
-    var fifthState = new NotActuallyImmutable('fifth');
-    ReactUpdates.batchedUpdates(function() {
-      moo.setState({str: 'fourth'});
-      moo.replaceState(fifthState);
-    });
-    expect(moo.state).toBe(fifthState);
-
-    // When more than one state update is enqueued, we have the same behavior
-    var sixthState = new NotActuallyImmutable('sixth');
-    ReactUpdates.batchedUpdates(function() {
-      moo.replaceState(sixthState);
-      moo.setState({str: 'seventh'});
-    });
-    expect(moo.state.str).toBe('seventh');
-    expect(moo.state.amIImmutable).toBe(undefined);
-  });
-
-  it('should not warn about unmounting during unmounting', function() {
-    var container = document.createElement('div');
-    var layer = document.createElement('div');
-
-    var Component = React.createClass({
-      componentWillMount: function() {
-        ReactDOM.render(<div />, layer);
-      },
-
-      componentWillUnmount: function() {
-        ReactDOM.unmountComponentAtNode(layer);
-      },
-
-      render: function() {
-        return <div />;
-      },
-    });
-
-    var Outer = React.createClass({
-      render: function() {
-        return <div>{this.props.children}</div>;
-      },
-    });
-
-    ReactDOM.render(<Outer><Component /></Outer>, container);
-    ReactDOM.render(<Outer />, container);
-  });
-
-  it('should warn when mutated props are passed', function() {
-    spyOn(console, 'error');
-
-    var container = document.createElement('div');
-
-    class Foo extends React.Component {
-      constructor(props) {
-        var _props = { idx: props.idx + '!' };
-        super(_props);
-      }
-
-      render() {
-        return <span />;
-      }
-    }
-
-    expect(console.error.calls.length).toBe(0);
-
-    ReactDOM.render(<Foo idx="qwe" />, container);
-
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
-      'Foo(...): When calling super() in `Foo`, make sure to pass ' +
-      'up the same props that your component\'s constructor was passed.'
-    );
-
-  });
-
-});
diff --git a/src/renderers/shared/reconciler/__tests__/ReactCompositeComponentNestedState-test.js b/src/renderers/shared/reconciler/__tests__/ReactCompositeComponentNestedState-test.js
deleted file mode 100644
index d574d57b9a0a..000000000000
--- a/src/renderers/shared/reconciler/__tests__/ReactCompositeComponentNestedState-test.js
+++ /dev/null
@@ -1,119 +0,0 @@
-/**
- * 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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-var React;
-var ReactDOM;
-var ReactTestUtils;
-
-describe('ReactCompositeComponentNestedState-state', function() {
-
-  beforeEach(function() {
-    React = require('React');
-    ReactDOM = require('ReactDOM');
-    ReactTestUtils = require('ReactTestUtils');
-  });
-
-  it('should provide up to date values for props', function() {
-    var ParentComponent = React.createClass({
-      getInitialState: function() {
-        return {color: 'blue'};
-      },
-
-      handleColor: function(color) {
-        this.props.logger('parent-handleColor', this.state.color);
-        this.setState({color: color}, function() {
-          this.props.logger('parent-after-setState', this.state.color);
-        });
-      },
-
-      render: function() {
-        this.props.logger('parent-render', this.state.color);
-        return (
-          <ChildComponent
-            logger={this.props.logger}
-            color={this.state.color}
-            onSelectColor={this.handleColor}
-          />
-        );
-      },
-    });
-
-    var ChildComponent = React.createClass({
-      getInitialState: function() {
-        this.props.logger('getInitialState', this.props.color);
-        return {hue: 'dark ' + this.props.color};
-      },
-
-      handleHue: function(shade, color) {
-        this.props.logger('handleHue', this.state.hue, this.props.color);
-        this.props.onSelectColor(color);
-        this.setState(function(state, props) {
-          this.props.logger('setState-this', this.state.hue, this.props.color);
-          this.props.logger('setState-args', state.hue, props.color);
-          return {hue: shade + ' ' + props.color};
-        }, function() {
-          this.props.logger('after-setState', this.state.hue, this.props.color);
-        });
-      },
-
-      render: function() {
-        this.props.logger('render', this.state.hue, this.props.color);
-        return (
-          <div>
-            <button onClick={this.handleHue.bind(this, 'dark', 'blue')}>
-              Dark Blue
-            </button>
-            <button onClick={this.handleHue.bind(this, 'light', 'blue')}>
-              Light Blue
-            </button>
-            <button onClick={this.handleHue.bind(this, 'dark', 'green')}>
-              Dark Green
-            </button>
-            <button onClick={this.handleHue.bind(this, 'light', 'green')}>
-              Light Green
-            </button>
-          </div>
-        );
-      },
-    });
-
-    var container = document.createElement('div');
-    document.body.appendChild(container);
-
-    var logger = jest.genMockFn();
-
-    void ReactDOM.render(
-      <ParentComponent logger={logger} />,
-      container
-    );
-
-    // click "light green"
-    ReactTestUtils.Simulate.click(
-      container.childNodes[0].childNodes[3]
-    );
-
-    expect(logger.mock.calls).toEqual([
-      ['parent-render', 'blue'],
-      ['getInitialState', 'blue'],
-      ['render', 'dark blue', 'blue'],
-      ['handleHue', 'dark blue', 'blue'],
-      ['parent-handleColor', 'blue'],
-      ['parent-render', 'green'],
-      ['setState-this', 'dark blue', 'blue'],
-      ['setState-args', 'dark blue', 'green'],
-      ['render', 'light green', 'green'],
-      ['parent-after-setState', 'green'],
-      ['after-setState', 'light green', 'green'],
-    ]);
-  });
-});
diff --git a/src/renderers/shared/reconciler/__tests__/ReactCompositeComponentState-test.js b/src/renderers/shared/reconciler/__tests__/ReactCompositeComponentState-test.js
deleted file mode 100644
index 49045338dc63..000000000000
--- a/src/renderers/shared/reconciler/__tests__/ReactCompositeComponentState-test.js
+++ /dev/null
@@ -1,246 +0,0 @@
-/**
- * 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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-var React;
-var ReactDOM;
-
-var TestComponent;
-
-describe('ReactCompositeComponent-state', function() {
-
-  beforeEach(function() {
-    React = require('React');
-
-    ReactDOM = require('ReactDOM');
-
-    TestComponent = React.createClass({
-      peekAtState: function(from, state) {
-        state = state || this.state;
-        this.props.stateListener(from, state && state.color);
-      },
-
-      peekAtCallback: function(from) {
-        return () => this.peekAtState(from);
-      },
-
-      setFavoriteColor: function(nextColor) {
-        this.setState(
-          {color: nextColor},
-          this.peekAtCallback('setFavoriteColor')
-        );
-      },
-
-      getInitialState: function() {
-        this.peekAtState('getInitialState');
-        return {color: 'red'};
-      },
-
-      render: function() {
-        this.peekAtState('render');
-        return <div>{this.state.color}</div>;
-      },
-
-      componentWillMount: function() {
-        this.peekAtState('componentWillMount-start');
-        this.setState(function(state) {
-          this.peekAtState('before-setState-sunrise', state);
-        });
-        this.setState(
-          {color: 'sunrise'},
-          this.peekAtCallback('setState-sunrise')
-        );
-        this.setState(function(state) {
-          this.peekAtState('after-setState-sunrise', state);
-        });
-        this.peekAtState('componentWillMount-after-sunrise');
-        this.setState(
-          {color: 'orange'},
-          this.peekAtCallback('setState-orange')
-        );
-        this.setState(function(state) {
-          this.peekAtState('after-setState-orange', state);
-        });
-        this.peekAtState('componentWillMount-end');
-      },
-
-      componentDidMount: function() {
-        this.peekAtState('componentDidMount-start');
-        this.setState(
-          {color: 'yellow'},
-          this.peekAtCallback('setState-yellow')
-        );
-        this.peekAtState('componentDidMount-end');
-      },
-
-      componentWillReceiveProps: function(newProps) {
-        this.peekAtState('componentWillReceiveProps-start');
-        if (newProps.nextColor) {
-          this.setState(function(state) {
-            this.peekAtState('before-setState-receiveProps', state);
-            return {color: newProps.nextColor};
-          });
-          this.replaceState({color: undefined});
-          this.setState(
-            function(state) {
-              this.peekAtState('before-setState-again-receiveProps', state);
-              return {color: newProps.nextColor};
-            },
-            this.peekAtCallback('setState-receiveProps')
-          );
-          this.setState(function(state) {
-            this.peekAtState('after-setState-receiveProps', state);
-          });
-        }
-        this.peekAtState('componentWillReceiveProps-end');
-      },
-
-      shouldComponentUpdate: function(nextProps, nextState) {
-        this.peekAtState('shouldComponentUpdate-currentState');
-        this.peekAtState('shouldComponentUpdate-nextState', nextState);
-        return true;
-      },
-
-      componentWillUpdate: function(nextProps, nextState) {
-        this.peekAtState('componentWillUpdate-currentState');
-        this.peekAtState('componentWillUpdate-nextState', nextState);
-      },
-
-      componentDidUpdate: function(prevProps, prevState) {
-        this.peekAtState('componentDidUpdate-currentState');
-        this.peekAtState('componentDidUpdate-prevState', prevState);
-      },
-
-      componentWillUnmount: function() {
-        this.peekAtState('componentWillUnmount');
-      },
-    });
-  });
-
-  it('should support setting state', function() {
-    var container = document.createElement('div');
-    document.body.appendChild(container);
-
-    var stateListener = jest.genMockFn();
-    var instance = ReactDOM.render(
-      <TestComponent stateListener={stateListener} />,
-      container,
-      function peekAtInitialCallback() {
-        this.peekAtState('initial-callback');
-      }
-    );
-    ReactDOM.render(
-      <TestComponent stateListener={stateListener} nextColor="green" />,
-      container,
-      instance.peekAtCallback('setProps')
-    );
-    instance.setFavoriteColor('blue');
-    instance.forceUpdate(instance.peekAtCallback('forceUpdate'));
-
-    ReactDOM.unmountComponentAtNode(container);
-
-    expect(stateListener.mock.calls.join('\n')).toEqual([
-      // there is no state when getInitialState() is called
-      ['getInitialState', null],
-      ['componentWillMount-start', 'red'],
-      // setState()'s only enqueue pending states.
-      ['componentWillMount-after-sunrise', 'red'],
-      ['componentWillMount-end', 'red'],
-      // pending state queue is processed
-      ['before-setState-sunrise', 'red'],
-      ['after-setState-sunrise', 'sunrise'],
-      ['after-setState-orange', 'orange'],
-      // pending state has been applied
-      ['render', 'orange'],
-      ['componentDidMount-start', 'orange'],
-      // setState-sunrise and setState-orange should be called here,
-      // after the bug in #1740
-      // componentDidMount() called setState({color:'yellow'}), which is async.
-      // The update doesn't happen until the next flush.
-      ['componentDidMount-end', 'orange'],
-      ['shouldComponentUpdate-currentState', 'orange'],
-      ['shouldComponentUpdate-nextState', 'yellow'],
-      ['componentWillUpdate-currentState', 'orange'],
-      ['componentWillUpdate-nextState', 'yellow'],
-      ['render', 'yellow'],
-      ['componentDidUpdate-currentState', 'yellow'],
-      ['componentDidUpdate-prevState', 'orange'],
-      ['setState-sunrise', 'yellow'],
-      ['setState-orange', 'yellow'],
-      ['setState-yellow', 'yellow'],
-      ['initial-callback', 'yellow'],
-      ['componentWillReceiveProps-start', 'yellow'],
-      // setState({color:'green'}) only enqueues a pending state.
-      ['componentWillReceiveProps-end', 'yellow'],
-      // pending state queue is processed
-      // before-setState-receiveProps never called, due to replaceState.
-      ['before-setState-again-receiveProps', undefined],
-      ['after-setState-receiveProps', 'green'],
-      ['shouldComponentUpdate-currentState', 'yellow'],
-      ['shouldComponentUpdate-nextState', 'green'],
-      ['componentWillUpdate-currentState', 'yellow'],
-      ['componentWillUpdate-nextState', 'green'],
-      ['render', 'green'],
-      ['componentDidUpdate-currentState', 'green'],
-      ['componentDidUpdate-prevState', 'yellow'],
-      ['setState-receiveProps', 'green'],
-      ['setProps', 'green'],
-      // setFavoriteColor('blue')
-      ['shouldComponentUpdate-currentState', 'green'],
-      ['shouldComponentUpdate-nextState', 'blue'],
-      ['componentWillUpdate-currentState', 'green'],
-      ['componentWillUpdate-nextState', 'blue'],
-      ['render', 'blue'],
-      ['componentDidUpdate-currentState', 'blue'],
-      ['componentDidUpdate-prevState', 'green'],
-      ['setFavoriteColor', 'blue'],
-      // forceUpdate()
-      ['componentWillUpdate-currentState', 'blue'],
-      ['componentWillUpdate-nextState', 'blue'],
-      ['render', 'blue'],
-      ['componentDidUpdate-currentState', 'blue'],
-      ['componentDidUpdate-prevState', 'blue'],
-      ['forceUpdate', 'blue'],
-      // unmountComponent()
-      // state is available within `componentWillUnmount()`
-      ['componentWillUnmount', 'blue'],
-    ].join('\n'));
-  });
-
-  it('should batch unmounts', function() {
-    var outer;
-    var Inner = React.createClass({
-      render: function() {
-        return <div />;
-      },
-      componentWillUnmount: function() {
-        // This should get silently ignored (maybe with a warning), but it
-        // shouldn't break React.
-        outer.setState({showInner: false});
-      },
-    });
-    var Outer = React.createClass({
-      getInitialState: function() {
-        return {showInner: true};
-      },
-      render: function() {
-        return <div>{this.state.showInner && <Inner />}</div>;
-      },
-    });
-
-    var container = document.createElement('div');
-    outer = ReactDOM.render(<Outer />, container);
-    expect(() => {
-      ReactDOM.unmountComponentAtNode(container);
-    }).not.toThrow();
-  });
-});
diff --git a/src/renderers/shared/reconciler/__tests__/ReactEmptyComponent-test.js b/src/renderers/shared/reconciler/__tests__/ReactEmptyComponent-test.js
deleted file mode 100644
index 406e18e2a1cf..000000000000
--- a/src/renderers/shared/reconciler/__tests__/ReactEmptyComponent-test.js
+++ /dev/null
@@ -1,311 +0,0 @@
-/**
- * Copyright 2014-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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-var React;
-var ReactDOM;
-var ReactTestUtils;
-var TogglingComponent;
-
-var reactComponentExpect;
-
-var log;
-
-describe('ReactEmptyComponent', function() {
-  beforeEach(function() {
-    jest.resetModuleRegistry();
-
-    React = require('React');
-    ReactDOM = require('ReactDOM');
-    ReactTestUtils = require('ReactTestUtils');
-
-    reactComponentExpect = require('reactComponentExpect');
-
-    log = jasmine.createSpy();
-
-    TogglingComponent = React.createClass({
-      getInitialState: function() {
-        return {component: this.props.firstComponent};
-      },
-      componentDidMount: function() {
-        log(ReactDOM.findDOMNode(this));
-        this.setState({component: this.props.secondComponent});
-      },
-      componentDidUpdate: function() {
-        log(ReactDOM.findDOMNode(this));
-      },
-      render: function() {
-        var Component = this.state.component;
-        return Component ? <Component /> : null;
-      },
-    });
-  });
-
-  it('should render null and false as a noscript tag under the hood', () => {
-    var Component1 = React.createClass({
-      render: function() {
-        return null;
-      },
-    });
-    var Component2 = React.createClass({
-      render: function() {
-        return false;
-      },
-    });
-
-    var instance1 = ReactTestUtils.renderIntoDocument(<Component1 />);
-    var instance2 = ReactTestUtils.renderIntoDocument(<Component2 />);
-    reactComponentExpect(instance1)
-      .expectRenderedChild()
-      .toBeEmptyComponent();
-    reactComponentExpect(instance2)
-      .expectRenderedChild()
-      .toBeEmptyComponent();
-  });
-
-  it('should still throw when rendering to undefined', () => {
-    var Component = React.createClass({
-      render: function() {},
-    });
-    expect(function() {
-      ReactTestUtils.renderIntoDocument(<Component />);
-    }).toThrow(
-      'Component.render(): A valid React element (or null) must be returned. You may ' +
-      'have returned undefined, an array or some other invalid object.'
-    );
-  });
-
-  it('should be able to switch between rendering null and a normal tag', () => {
-    var instance1 =
-      <TogglingComponent
-        firstComponent={null}
-        secondComponent={'div'}
-      />;
-    var instance2 =
-      <TogglingComponent
-        firstComponent={'div'}
-        secondComponent={null}
-      />;
-
-    ReactTestUtils.renderIntoDocument(instance1);
-    ReactTestUtils.renderIntoDocument(instance2);
-
-    expect(log.argsForCall.length).toBe(4);
-    expect(log.argsForCall[0][0]).toBe(null);
-    expect(log.argsForCall[1][0].tagName).toBe('DIV');
-    expect(log.argsForCall[2][0].tagName).toBe('DIV');
-    expect(log.argsForCall[3][0]).toBe(null);
-  });
-
-  it('should be able to switch in a list of children', () => {
-    var instance1 =
-      <TogglingComponent
-        firstComponent={null}
-        secondComponent={'div'}
-      />;
-
-    ReactTestUtils.renderIntoDocument(
-      <div>
-        {instance1}
-        {instance1}
-        {instance1}
-      </div>
-    );
-
-    expect(log.argsForCall.length).toBe(6);
-    expect(log.argsForCall[0][0]).toBe(null);
-    expect(log.argsForCall[1][0]).toBe(null);
-    expect(log.argsForCall[2][0]).toBe(null);
-    expect(log.argsForCall[3][0].tagName).toBe('DIV');
-    expect(log.argsForCall[4][0].tagName).toBe('DIV');
-    expect(log.argsForCall[5][0].tagName).toBe('DIV');
-  });
-
-  it('should distinguish between a script placeholder and an actual script tag',
-    () => {
-      var instance1 =
-        <TogglingComponent
-          firstComponent={null}
-          secondComponent={'script'}
-        />;
-      var instance2 =
-        <TogglingComponent
-          firstComponent={'script'}
-          secondComponent={null}
-        />;
-
-      expect(function() {
-        ReactTestUtils.renderIntoDocument(instance1);
-      }).not.toThrow();
-      expect(function() {
-        ReactTestUtils.renderIntoDocument(instance2);
-      }).not.toThrow();
-
-      expect(log.argsForCall.length).toBe(4);
-      expect(log.argsForCall[0][0]).toBe(null);
-      expect(log.argsForCall[1][0].tagName).toBe('SCRIPT');
-      expect(log.argsForCall[2][0].tagName).toBe('SCRIPT');
-      expect(log.argsForCall[3][0]).toBe(null);
-    }
-  );
-
-  it('should have findDOMNode return null when multiple layers of composite ' +
-    'components render to the same null placeholder',
-    () => {
-      var GrandChild = React.createClass({
-        render: function() {
-          return null;
-        },
-      });
-
-      var Child = React.createClass({
-        render: function() {
-          return <GrandChild />;
-        },
-      });
-
-      var instance1 =
-        <TogglingComponent
-          firstComponent={'div'}
-          secondComponent={Child}
-        />;
-      var instance2 =
-        <TogglingComponent
-          firstComponent={Child}
-          secondComponent={'div'}
-        />;
-
-      expect(function() {
-        ReactTestUtils.renderIntoDocument(instance1);
-      }).not.toThrow();
-      expect(function() {
-        ReactTestUtils.renderIntoDocument(instance2);
-      }).not.toThrow();
-
-      expect(log.argsForCall.length).toBe(4);
-      expect(log.argsForCall[0][0].tagName).toBe('DIV');
-      expect(log.argsForCall[1][0]).toBe(null);
-      expect(log.argsForCall[2][0]).toBe(null);
-      expect(log.argsForCall[3][0].tagName).toBe('DIV');
-    }
-  );
-
-  it('works when switching components', function() {
-    var assertions = 0;
-    var Inner = React.createClass({
-      render: function() {
-        return <span />;
-      },
-      componentDidMount: function() {
-        // Make sure the DOM node resolves properly even if we're replacing a
-        // `null` component
-        expect(ReactDOM.findDOMNode(this)).not.toBe(null);
-        assertions++;
-      },
-      componentWillUnmount: function() {
-        // Even though we're getting replaced by `null`, we haven't been
-        // replaced yet!
-        expect(ReactDOM.findDOMNode(this)).not.toBe(null);
-        assertions++;
-      },
-    });
-    var Wrapper = React.createClass({
-      render: function() {
-        return this.props.showInner ? <Inner /> : null;
-      },
-    });
-
-    var el = document.createElement('div');
-    var component;
-
-    // Render the <Inner /> component...
-    component = ReactDOM.render(<Wrapper showInner={true} />, el);
-    expect(ReactDOM.findDOMNode(component)).not.toBe(null);
-
-    // Switch to null...
-    component = ReactDOM.render(<Wrapper showInner={false} />, el);
-    expect(ReactDOM.findDOMNode(component)).toBe(null);
-
-    // ...then switch back.
-    component = ReactDOM.render(<Wrapper showInner={true} />, el);
-    expect(ReactDOM.findDOMNode(component)).not.toBe(null);
-
-    expect(assertions).toBe(3);
-  });
-
-  it('throws when rendering null at the top level', function() {
-    // TODO: This should actually work since `null` is a valid ReactNode
-    var div = document.createElement('div');
-    expect(function() {
-      ReactDOM.render(null, div);
-    }).toThrow(
-      'ReactDOM.render(): Invalid component element.'
-    );
-  });
-
-  it('does not break when updating during mount', function() {
-    var Child = React.createClass({
-      componentDidMount() {
-        if (this.props.onMount) {
-          this.props.onMount();
-        }
-      },
-      render() {
-        if (!this.props.visible) {
-          return null;
-        }
-
-        return <div>hello world</div>;
-      },
-    });
-
-    var Parent = React.createClass({
-      update() {
-        this.forceUpdate();
-      },
-      render() {
-        return (
-          <div>
-            <Child key="1" visible={false} />
-            <Child key="0" visible={true} onMount={this.update} />
-            <Child key="2" visible={false} />
-          </div>
-        );
-      },
-    });
-
-    expect(function() {
-      ReactTestUtils.renderIntoDocument(<Parent />);
-    }).not.toThrow();
-  });
-
-  it('preserves the dom node during updates', function() {
-    var Empty = React.createClass({
-      render: function() {
-        return null;
-      },
-    });
-
-    var container = document.createElement('div');
-
-    ReactDOM.render(<Empty />, container);
-    var noscript1 = container.firstChild;
-    expect(noscript1.nodeName).toBe('#comment');
-
-    // This update shouldn't create a DOM node
-    ReactDOM.render(<Empty />, container);
-    var noscript2 = container.firstChild;
-    expect(noscript2.nodeName).toBe('#comment');
-
-    expect(noscript1).toBe(noscript2);
-  });
-});
diff --git a/src/renderers/shared/reconciler/__tests__/ReactIdentity-test.js b/src/renderers/shared/reconciler/__tests__/ReactIdentity-test.js
deleted file mode 100644
index 02ec4361d087..000000000000
--- a/src/renderers/shared/reconciler/__tests__/ReactIdentity-test.js
+++ /dev/null
@@ -1,289 +0,0 @@
-/**
- * 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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-var React;
-var ReactDOM;
-var ReactFragment;
-var ReactTestUtils;
-
-describe('ReactIdentity', function() {
-
-  beforeEach(function() {
-    jest.resetModuleRegistry();
-    React = require('React');
-    ReactDOM = require('ReactDOM');
-    ReactFragment = require('ReactFragment');
-    ReactTestUtils = require('ReactTestUtils');
-  });
-
-  function frag(obj) {
-    return ReactFragment.create(obj);
-  }
-
-  it('should allow key property to express identity', function() {
-    var node;
-    var Component = (props) =>
-      <div ref={(c) => node = c}>
-        <div key={props.swap ? 'banana' : 'apple'} />
-        <div key={props.swap ? 'apple' : 'banana'} />
-      </div>;
-
-    var container = document.createElement('div');
-    ReactDOM.render(<Component />, container);
-    var origChildren = Array.from(node.childNodes);
-    ReactDOM.render(<Component swap={true} />, container);
-    var newChildren = Array.from(node.childNodes);
-    expect(origChildren[0]).toBe(newChildren[1]);
-    expect(origChildren[1]).toBe(newChildren[0]);
-  });
-
-  it('should use composite identity', function() {
-
-    var Wrapper = React.createClass({
-      render: function() {
-        return <a>{this.props.children}</a>;
-      },
-    });
-
-    var container = document.createElement('div');
-    var node1;
-    var node2;
-    ReactDOM.render(
-      <Wrapper key="wrap1"><span ref={(c) => node1 = c} /></Wrapper>,
-      container
-    );
-    ReactDOM.render(
-      <Wrapper key="wrap2"><span ref={(c) => node2 = c} /></Wrapper>,
-      container
-    );
-
-    expect(node1).not.toBe(node2);
-  });
-
-  function renderAComponentWithKeyIntoContainer(key, container) {
-
-    var Wrapper = React.createClass({
-
-      render: function() {
-        var s1 = <span ref="span1" key={key} />;
-        var s2 = <span ref="span2" />;
-
-        var map = {};
-        map[key] = s2;
-        return <div>{[s1, frag(map)]}</div>;
-      },
-
-    });
-
-    var instance = ReactDOM.render(<Wrapper />, container);
-    var span1 = instance.refs.span1;
-    var span2 = instance.refs.span2;
-
-    expect(ReactDOM.findDOMNode(span1)).not.toBe(null);
-    expect(ReactDOM.findDOMNode(span2)).not.toBe(null);
-  }
-
-  it('should allow any character as a key, in a detached parent', function() {
-    var detachedContainer = document.createElement('div');
-    renderAComponentWithKeyIntoContainer(
-      "<'WEIRD/&\\key'>",
-      detachedContainer
-    );
-  });
-
-  it('should allow any character as a key, in an attached parent', function() {
-    // This test exists to protect against implementation details that
-    // incorrectly query escaped IDs using DOM tools like getElementById.
-    var attachedContainer = document.createElement('div');
-    document.body.appendChild(attachedContainer);
-
-    renderAComponentWithKeyIntoContainer(
-      "<'WEIRD/&\\key'>",
-      attachedContainer
-    );
-
-    document.body.removeChild(attachedContainer);
-  });
-
-  it('should not allow scripts in keys to execute', function() {
-    var h4x0rKey =
-      '"><script>window[\'YOUVEBEENH4X0RED\']=true;</script><div id="';
-
-    var attachedContainer = document.createElement('div');
-    document.body.appendChild(attachedContainer);
-
-    renderAComponentWithKeyIntoContainer(h4x0rKey, attachedContainer);
-
-    document.body.removeChild(attachedContainer);
-
-    // If we get this far, make sure we haven't executed the code
-    expect(window.YOUVEBEENH4X0RED).toBe(undefined);
-  });
-
-  it('should let restructured components retain their uniqueness', function() {
-    var instance0 = <span />;
-    var instance1 = <span />;
-    var instance2 = <span />;
-
-    var TestComponent = React.createClass({
-      render: function() {
-        return (
-          <div>
-            {instance2}
-            {this.props.children[0]}
-            {this.props.children[1]}
-          </div>
-        );
-      },
-    });
-
-    var TestContainer = React.createClass({
-
-      render: function() {
-        return <TestComponent>{instance0}{instance1}</TestComponent>;
-      },
-
-    });
-
-    expect(function() {
-
-      ReactTestUtils.renderIntoDocument(<TestContainer />);
-
-    }).not.toThrow();
-  });
-
-  it('should let nested restructures retain their uniqueness', function() {
-    var instance0 = <span />;
-    var instance1 = <span />;
-    var instance2 = <span />;
-
-    var TestComponent = React.createClass({
-      render: function() {
-        return (
-          <div>
-            {instance2}
-            {this.props.children[0]}
-            {this.props.children[1]}
-          </div>
-        );
-      },
-    });
-
-    var TestContainer = React.createClass({
-
-      render: function() {
-        return (
-          <div>
-            <TestComponent>{instance0}{instance1}</TestComponent>
-          </div>
-        );
-      },
-
-    });
-
-    expect(function() {
-
-      ReactTestUtils.renderIntoDocument(<TestContainer />);
-
-    }).not.toThrow();
-  });
-
-  it('should let text nodes retain their uniqueness', function() {
-    var TestComponent = React.createClass({
-      render: function() {
-        return <div>{this.props.children}<span /></div>;
-      },
-    });
-
-    var TestContainer = React.createClass({
-
-      render: function() {
-        return (
-          <TestComponent>
-            <div />
-            {'second'}
-          </TestComponent>
-        );
-      },
-
-    });
-
-    expect(function() {
-
-      ReactTestUtils.renderIntoDocument(<TestContainer />);
-
-    }).not.toThrow();
-  });
-
-  it('should retain key during updates in composite components', function() {
-
-    var TestComponent = React.createClass({
-      render: function() {
-        return <div>{this.props.children}</div>;
-      },
-    });
-
-    var TestContainer = React.createClass({
-
-      getInitialState: function() {
-        return {swapped: false};
-      },
-
-      swap: function() {
-        this.setState({swapped: true});
-      },
-
-      render: function() {
-        return (
-          <TestComponent>
-            {this.state.swapped ? this.props.second : this.props.first}
-            {this.state.swapped ? this.props.first : this.props.second}
-          </TestComponent>
-        );
-      },
-
-    });
-
-    var instance0 = <span key="A" />;
-    var instance1 = <span key="B" />;
-
-    var wrapped = <TestContainer first={instance0} second={instance1} />;
-
-    wrapped = ReactDOM.render(wrapped, document.createElement('div'));
-    var div = ReactDOM.findDOMNode(wrapped);
-
-    var beforeA = div.childNodes[0];
-    var beforeB = div.childNodes[1];
-    wrapped.swap();
-    var afterA = div.childNodes[1];
-    var afterB = div.childNodes[0];
-
-    expect(beforeA).toBe(afterA);
-    expect(beforeB).toBe(afterB);
-
-  });
-
-  it('should not allow implicit and explicit keys to collide', function() {
-    var component =
-      <div>
-        <span />
-        <span key="0" />
-      </div>;
-
-    expect(function() {
-      ReactTestUtils.renderIntoDocument(component);
-    }).not.toThrow();
-  });
-
-
-});
diff --git a/src/renderers/shared/reconciler/__tests__/ReactMockedComponent-test.js b/src/renderers/shared/reconciler/__tests__/ReactMockedComponent-test.js
deleted file mode 100644
index 761b68b05c48..000000000000
--- a/src/renderers/shared/reconciler/__tests__/ReactMockedComponent-test.js
+++ /dev/null
@@ -1,107 +0,0 @@
-/**
- * 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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-var React;
-var ReactTestUtils;
-
-var AutoMockedComponent;
-var MockedComponent;
-
-describe('ReactMockedComponent', function() {
-
-  beforeEach(function() {
-    React = require('React');
-    ReactTestUtils = require('ReactTestUtils');
-
-    AutoMockedComponent = jest.genMockFromModule('ReactMockedComponentTestComponent');
-    MockedComponent = jest.genMockFromModule('ReactMockedComponentTestComponent');
-
-    ReactTestUtils.mockComponent(MockedComponent);
-  });
-
-  it('should allow an implicitly mocked component to be rendered without warnings', () => {
-    spyOn(console, 'error');
-    ReactTestUtils.renderIntoDocument(<AutoMockedComponent />);
-    expect(console.error.calls.length).toBe(0);
-  });
-
-  it('should allow an implicitly mocked component to be updated', () => {
-    var Wrapper = React.createClass({
-
-      getInitialState: function() {
-        return {foo: 1};
-      },
-
-      update: function() {
-        this.setState({foo: 2});
-      },
-
-      render: function() {
-        return <div><AutoMockedComponent prop={this.state.foo} /></div>;
-      },
-
-    });
-
-    var instance = ReactTestUtils.renderIntoDocument(<Wrapper />);
-
-    var found = ReactTestUtils.findRenderedComponentWithType(
-      instance,
-      AutoMockedComponent
-    );
-    expect(typeof found).toBe('object');
-
-    instance.update();
-  });
-
-  it('has custom methods on the implicitly mocked component', () => {
-    var instance = ReactTestUtils.renderIntoDocument(<AutoMockedComponent />);
-    expect(typeof instance.hasCustomMethod).toBe('function');
-  });
-
-  it('should allow an explicitly mocked component to be rendered', () => {
-    ReactTestUtils.renderIntoDocument(<MockedComponent />);
-  });
-
-  it('should allow an explicitly mocked component to be updated', () => {
-    var Wrapper = React.createClass({
-
-      getInitialState: function() {
-        return {foo: 1};
-      },
-
-      update: function() {
-        this.setState({foo: 2});
-      },
-
-      render: function() {
-        return <div><MockedComponent prop={this.state.foo} /></div>;
-      },
-
-    });
-    var instance = ReactTestUtils.renderIntoDocument(<Wrapper />);
-
-    var found = ReactTestUtils.findRenderedComponentWithType(
-      instance,
-      MockedComponent
-    );
-    expect(typeof found).toBe('object');
-
-    instance.update();
-  });
-
-  it('has custom methods on the explicitly mocked component', () => {
-    var instance = ReactTestUtils.renderIntoDocument(<MockedComponent />);
-    expect(typeof instance.hasCustomMethod).toBe('function');
-  });
-
-});
diff --git a/src/renderers/shared/reconciler/__tests__/ReactMultiChild-test.js b/src/renderers/shared/reconciler/__tests__/ReactMultiChild-test.js
deleted file mode 100644
index 979b2115ad3c..000000000000
--- a/src/renderers/shared/reconciler/__tests__/ReactMultiChild-test.js
+++ /dev/null
@@ -1,152 +0,0 @@
-/**
- * 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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-describe('ReactMultiChild', function() {
-  var React;
-
-  var ReactDOM;
-
-  beforeEach(function() {
-    jest.resetModuleRegistry();
-    React = require('React');
-    ReactDOM = require('ReactDOM');
-  });
-
-  describe('reconciliation', function() {
-    it('should update children when possible', function() {
-      var container = document.createElement('div');
-
-      var mockMount = jest.genMockFn();
-      var mockUpdate = jest.genMockFn();
-      var mockUnmount = jest.genMockFn();
-
-      var MockComponent = React.createClass({
-        componentDidMount: mockMount,
-        componentDidUpdate: mockUpdate,
-        componentWillUnmount: mockUnmount,
-        render: function() {
-          return <span />;
-        },
-      });
-
-      expect(mockMount.mock.calls.length).toBe(0);
-      expect(mockUpdate.mock.calls.length).toBe(0);
-      expect(mockUnmount.mock.calls.length).toBe(0);
-
-      ReactDOM.render(<div><MockComponent /></div>, container);
-
-      expect(mockMount.mock.calls.length).toBe(1);
-      expect(mockUpdate.mock.calls.length).toBe(0);
-      expect(mockUnmount.mock.calls.length).toBe(0);
-
-      ReactDOM.render(<div><MockComponent /></div>, container);
-
-      expect(mockMount.mock.calls.length).toBe(1);
-      expect(mockUpdate.mock.calls.length).toBe(1);
-      expect(mockUnmount.mock.calls.length).toBe(0);
-    });
-
-    it('should replace children with different constructors', function() {
-      var container = document.createElement('div');
-
-      var mockMount = jest.genMockFn();
-      var mockUnmount = jest.genMockFn();
-
-      var MockComponent = React.createClass({
-        componentDidMount: mockMount,
-        componentWillUnmount: mockUnmount,
-        render: function() {
-          return <span />;
-        },
-      });
-
-      expect(mockMount.mock.calls.length).toBe(0);
-      expect(mockUnmount.mock.calls.length).toBe(0);
-
-      ReactDOM.render(<div><MockComponent /></div>, container);
-
-      expect(mockMount.mock.calls.length).toBe(1);
-      expect(mockUnmount.mock.calls.length).toBe(0);
-
-      ReactDOM.render(<div><span /></div>, container);
-
-      expect(mockMount.mock.calls.length).toBe(1);
-      expect(mockUnmount.mock.calls.length).toBe(1);
-    });
-
-    it('should NOT replace children with different owners', function() {
-      var container = document.createElement('div');
-
-      var mockMount = jest.genMockFn();
-      var mockUnmount = jest.genMockFn();
-
-      var MockComponent = React.createClass({
-        componentDidMount: mockMount,
-        componentWillUnmount: mockUnmount,
-        render: function() {
-          return <span />;
-        },
-      });
-
-      var WrapperComponent = React.createClass({
-        render: function() {
-          return this.props.children || <MockComponent />;
-        },
-      });
-
-      expect(mockMount.mock.calls.length).toBe(0);
-      expect(mockUnmount.mock.calls.length).toBe(0);
-
-      ReactDOM.render(<WrapperComponent />, container);
-
-      expect(mockMount.mock.calls.length).toBe(1);
-      expect(mockUnmount.mock.calls.length).toBe(0);
-
-      ReactDOM.render(
-        <WrapperComponent><MockComponent /></WrapperComponent>,
-        container
-      );
-
-      expect(mockMount.mock.calls.length).toBe(1);
-      expect(mockUnmount.mock.calls.length).toBe(0);
-    });
-
-    it('should replace children with different keys', function() {
-      var container = document.createElement('div');
-
-      var mockMount = jest.genMockFn();
-      var mockUnmount = jest.genMockFn();
-
-      var MockComponent = React.createClass({
-        componentDidMount: mockMount,
-        componentWillUnmount: mockUnmount,
-        render: function() {
-          return <span />;
-        },
-      });
-
-      expect(mockMount.mock.calls.length).toBe(0);
-      expect(mockUnmount.mock.calls.length).toBe(0);
-
-      ReactDOM.render(<div><MockComponent key="A" /></div>, container);
-
-      expect(mockMount.mock.calls.length).toBe(1);
-      expect(mockUnmount.mock.calls.length).toBe(0);
-
-      ReactDOM.render(<div><MockComponent key="B" /></div>, container);
-
-      expect(mockMount.mock.calls.length).toBe(2);
-      expect(mockUnmount.mock.calls.length).toBe(1);
-    });
-  });
-});
diff --git a/src/renderers/shared/reconciler/__tests__/ReactMultiChildText-test.js b/src/renderers/shared/reconciler/__tests__/ReactMultiChildText-test.js
deleted file mode 100644
index 8d8de3d90231..000000000000
--- a/src/renderers/shared/reconciler/__tests__/ReactMultiChildText-test.js
+++ /dev/null
@@ -1,249 +0,0 @@
-/**
- * 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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-var React = require('React');
-var ReactDOM = require('ReactDOM');
-var ReactTestUtils = require('ReactTestUtils');
-
-// Helpers
-var testAllPermutations = function(testCases) {
-  for (var i = 0; i < testCases.length; i += 2) {
-    var renderWithChildren = testCases[i];
-    var expectedResultAfterRender = testCases[i + 1];
-
-    for (var j = 0; j < testCases.length; j += 2) {
-      var updateWithChildren = testCases[j];
-      var expectedResultAfterUpdate = testCases[j + 1];
-
-      var container = document.createElement('div');
-      var d = ReactDOM.render(<div>{renderWithChildren}</div>, container);
-      expectChildren(d, expectedResultAfterRender);
-
-      d = ReactDOM.render(<div>{updateWithChildren}</div>, container);
-      expectChildren(d, expectedResultAfterUpdate);
-    }
-  }
-};
-
-var expectChildren = function(d, children) {
-  var outerNode = ReactDOM.findDOMNode(d);
-  var textNode;
-  if (typeof children === 'string') {
-    textNode = outerNode.firstChild;
-
-    if (children === '') {
-      expect(textNode != null).toBe(false);
-    } else {
-      expect(textNode != null).toBe(true);
-      expect(textNode.nodeType).toBe(3);
-      expect(textNode.data).toBe('' + children);
-    }
-  } else {
-    var openingCommentNode;
-    var closingCommentNode;
-    var mountIndex = 0;
-
-    for (var i = 0; i < children.length; i++) {
-      var child = children[i];
-
-      if (typeof child === 'string') {
-        openingCommentNode = outerNode.childNodes[mountIndex];
-
-        expect(openingCommentNode.nodeType).toBe(8);
-        expect(openingCommentNode.nodeValue).toMatch(' react-text: [0-9]+ ');
-
-        if (child === '') {
-          textNode = null;
-          closingCommentNode = openingCommentNode.nextSibling;
-          mountIndex += 2;
-        } else {
-          textNode = openingCommentNode.nextSibling;
-          closingCommentNode = textNode.nextSibling;
-          mountIndex += 3;
-        }
-
-        if (textNode) {
-          expect(textNode.nodeType).toBe(3);
-          expect(textNode.data).toBe('' + child);
-        }
-
-        expect(closingCommentNode.nodeType).toBe(8);
-        expect(closingCommentNode.nodeValue).toBe(' /react-text ');
-      } else {
-        var elementDOMNode = outerNode.childNodes[mountIndex];
-        expect(elementDOMNode.tagName).toBe('DIV');
-        mountIndex++;
-      }
-    }
-  }
-};
-
-
-/**
- * ReactMultiChild DOM integration test. In ReactDOM components, we make sure
- * that single children that are strings are treated as "content" which is much
- * faster to render and update.
- */
-describe('ReactMultiChildText', function() {
-  it('should correctly handle all possible children for render and update', function() {
-    spyOn(console, 'error');
-    testAllPermutations([
-      // basic values
-      undefined, [],
-      null, [],
-      false, [],
-      true, [],
-      0, '0',
-      1.2, '1.2',
-      '', '',
-      'foo', 'foo',
-
-      [], [],
-      [undefined], [],
-      [null], [],
-      [false], [],
-      [true], [],
-      [0], ['0'],
-      [1.2], ['1.2'],
-      [''], [''],
-      ['foo'], ['foo'],
-      [<div />], [<div />],
-
-      // two adjacent values
-      [true, 0], ['0'],
-      [0, 0], ['0', '0'],
-      [1.2, 0], ['1.2', '0'],
-      [0, ''], ['0', ''],
-      ['foo', 0], ['foo', '0'],
-      [0, <div />], ['0', <div />],
-
-      [true, 1.2], ['1.2'],
-      [1.2, 0], ['1.2', '0'],
-      [1.2, 1.2], ['1.2', '1.2'],
-      [1.2, ''], ['1.2', ''],
-      ['foo', 1.2], ['foo', '1.2'],
-      [1.2, <div />], ['1.2', <div />],
-
-      [true, ''], [''],
-      ['', 0], ['', '0'],
-      [1.2, ''], ['1.2', ''],
-      ['', ''], ['', ''],
-      ['foo', ''], ['foo', ''],
-      ['', <div />], ['', <div />],
-
-      [true, 'foo'], ['foo'],
-      ['foo', 0], ['foo', '0'],
-      [1.2, 'foo'], ['1.2', 'foo'],
-      ['foo', ''], ['foo', ''],
-      ['foo', 'foo'], ['foo', 'foo'],
-      ['foo', <div />], ['foo', <div />],
-
-      // values separated by an element
-      [true, <div />, true], [<div />],
-      [1.2, <div />, 1.2], ['1.2', <div />, '1.2'],
-      ['', <div />, ''], ['', <div />, ''],
-      ['foo', <div />, 'foo'], ['foo', <div />, 'foo'],
-
-      [true, 1.2, <div />, '', 'foo'], ['1.2', <div />, '', 'foo'],
-      [1.2, '', <div />, 'foo', true], ['1.2', '', <div />, 'foo'],
-      ['', 'foo', <div />, true, 1.2], ['', 'foo', <div />, '1.2'],
-
-      [true, 1.2, '', <div />, 'foo', true, 1.2], ['1.2', '', <div />, 'foo', '1.2'],
-      ['', 'foo', true, <div />, 1.2, '', 'foo'], ['', 'foo', <div />, '1.2', '', 'foo'],
-
-      // values inside arrays
-      [[true], [true]], [],
-      [[1.2], [1.2]], ['1.2', '1.2'],
-      [[''], ['']], ['', ''],
-      [['foo'], ['foo']], ['foo', 'foo'],
-      [[<div />], [<div />]], [<div />, <div />],
-
-      [[true, 1.2, <div />], '', 'foo'], ['1.2', <div />, '', 'foo'],
-      [1.2, '', [<div />, 'foo', true]], ['1.2', '', <div />, 'foo'],
-      ['', ['foo', <div />, true], 1.2], ['', 'foo', <div />, '1.2'],
-
-      [true, [1.2, '', <div />, 'foo'], true, 1.2], ['1.2', '', <div />, 'foo', '1.2'],
-      ['', 'foo', [true, <div />, 1.2, ''], 'foo'], ['', 'foo', <div />, '1.2', '', 'foo'],
-
-      // values inside elements
-      [<div>{true}{1.2}{<div />}</div>, '', 'foo'], [<div />, '', 'foo'],
-      [1.2, '', <div>{<div />}{'foo'}{true}</div>], ['1.2', '', <div />],
-      ['', <div>{'foo'}{<div />}{true}</div>, 1.2], ['', <div />, '1.2'],
-
-      [true, <div>{1.2}{''}{<div />}{'foo'}</div>, true, 1.2], [<div />, '1.2'],
-      ['', 'foo', <div>{true}{<div />}{1.2}{''}</div>, 'foo'], ['', 'foo', <div />, 'foo'],
-    ]);
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
-      'Warning: Each child in an array or iterator should have a unique "key" prop.'
-    );
-  });
-
-  it('should throw if rendering both HTML and children', function() {
-    expect(function() {
-      ReactTestUtils.renderIntoDocument(
-        <div dangerouslySetInnerHTML={{__html: 'abcdef'}}>ghjkl</div>
-      );
-    }).toThrow();
-  });
-
-  it('should render between nested components and inline children', function() {
-    ReactTestUtils.renderIntoDocument(<div><h1><span /><span /></h1></div>);
-
-    expect(function() {
-      ReactTestUtils.renderIntoDocument(<div><h1>A</h1></div>);
-    }).not.toThrow();
-
-    expect(function() {
-      ReactTestUtils.renderIntoDocument(<div><h1>{['A']}</h1></div>);
-    }).not.toThrow();
-
-    expect(function() {
-      ReactTestUtils.renderIntoDocument(<div><h1>{['A', 'B']}</h1></div>);
-    }).not.toThrow();
-  });
-
-  it('should reorder keyed text nodes', function() {
-    spyOn(console, 'error');
-
-    var container = document.createElement('div');
-    ReactDOM.render(
-      <div>{new Map([['a', 'alpha'], ['b', 'beta']])}</div>,
-      container
-    );
-
-    var childNodes = container.firstChild.childNodes;
-    var alpha1 = childNodes[0];
-    var alpha2 = childNodes[1];
-    var alpha3 = childNodes[2];
-    var beta1 = childNodes[3];
-    var beta2 = childNodes[4];
-    var beta3 = childNodes[5];
-
-    ReactDOM.render(
-      <div>{new Map([['b', 'beta'], ['a', 'alpha']])}</div>,
-      container
-    );
-
-    childNodes = container.firstChild.childNodes;
-    expect(childNodes[0]).toBe(beta1);
-    expect(childNodes[1]).toBe(beta2);
-    expect(childNodes[2]).toBe(beta3);
-    expect(childNodes[3]).toBe(alpha1);
-    expect(childNodes[4]).toBe(alpha2);
-    expect(childNodes[5]).toBe(alpha3);
-
-    // Using Maps as children gives a single warning
-    expect(console.error.calls.length).toBe(1);
-  });
-});
diff --git a/src/renderers/shared/reconciler/__tests__/ReactStateSetters-test.js b/src/renderers/shared/reconciler/__tests__/ReactStateSetters-test.js
deleted file mode 100644
index 23b0e5d86f32..000000000000
--- a/src/renderers/shared/reconciler/__tests__/ReactStateSetters-test.js
+++ /dev/null
@@ -1,154 +0,0 @@
-/**
- * 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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-var React = require('React');
-var ReactStateSetters = require('ReactStateSetters');
-var ReactTestUtils = require('ReactTestUtils');
-
-var TestComponent;
-var TestComponentWithMixin;
-
-describe('ReactStateSetters', function() {
-  beforeEach(function() {
-    jest.resetModuleRegistry();
-
-    TestComponent = React.createClass({
-      getInitialState: function() {
-        return {foo: 'foo'};
-      },
-
-      render: function() {
-        return <div />;
-      },
-    });
-
-    TestComponentWithMixin = React.createClass({
-      mixins: [ReactStateSetters.Mixin],
-
-      getInitialState: function() {
-        return {foo: 'foo'};
-      },
-
-      render: function() {
-        return <div />;
-      },
-    });
-  });
-
-  it('createStateSetter should update state', function() {
-    var instance = <TestComponent />;
-    instance = ReactTestUtils.renderIntoDocument(instance);
-    expect(instance.state).toEqual({foo: 'foo'});
-
-    var setter = ReactStateSetters.createStateSetter(
-      instance,
-      function(a, b, c) {
-        return {
-          foo: a + b + c,
-          bar: a * b * c,
-        };
-      }
-    );
-    expect(instance.state).toEqual({foo: 'foo'});
-
-    setter(1, 2, 3);
-    expect(instance.state).toEqual({foo: 6, bar: 6});
-
-    setter(10, 11, 12);
-    expect(instance.state).toEqual({foo: 33, bar: 1320});
-  });
-
-  it('createStateKeySetter should update state', function() {
-    var instance = <TestComponent />;
-    instance = ReactTestUtils.renderIntoDocument(instance);
-    expect(instance.state).toEqual({foo: 'foo'});
-
-    var setter = ReactStateSetters.createStateKeySetter(instance, 'foo');
-
-    expect(instance.state).toEqual({foo: 'foo'});
-
-    setter('bar');
-    expect(instance.state).toEqual({foo: 'bar'});
-
-    setter('baz');
-    expect(instance.state).toEqual({foo: 'baz'});
-  });
-
-  it('createStateKeySetter is memoized', function() {
-    var instance = <TestComponent />;
-    instance = ReactTestUtils.renderIntoDocument(instance);
-    expect(instance.state).toEqual({foo: 'foo'});
-
-    var foo1 = ReactStateSetters.createStateKeySetter(instance, 'foo');
-    var bar1 = ReactStateSetters.createStateKeySetter(instance, 'bar');
-
-    var foo2 = ReactStateSetters.createStateKeySetter(instance, 'foo');
-    var bar2 = ReactStateSetters.createStateKeySetter(instance, 'bar');
-
-    expect(foo2).toBe(foo1);
-    expect(bar2).toBe(bar1);
-  });
-
-  it('createStateSetter should update state from mixin', function() {
-    var instance = <TestComponentWithMixin />;
-    instance = ReactTestUtils.renderIntoDocument(instance);
-    expect(instance.state).toEqual({foo: 'foo'});
-
-    var setter = instance.createStateSetter(
-      function(a, b, c) {
-        return {
-          foo: a + b + c,
-          bar: a * b * c,
-        };
-      }
-    );
-    expect(instance.state).toEqual({foo: 'foo'});
-
-    setter(1, 2, 3);
-    expect(instance.state).toEqual({foo: 6, bar: 6});
-
-    setter(10, 11, 12);
-    expect(instance.state).toEqual({foo: 33, bar: 1320});
-  });
-
-  it('createStateKeySetter should update state with mixin', function() {
-    var instance = <TestComponentWithMixin />;
-    instance = ReactTestUtils.renderIntoDocument(instance);
-    expect(instance.state).toEqual({foo: 'foo'});
-
-    var setter = instance.createStateKeySetter('foo');
-
-    expect(instance.state).toEqual({foo: 'foo'});
-
-    setter('bar');
-    expect(instance.state).toEqual({foo: 'bar'});
-
-    setter('baz');
-    expect(instance.state).toEqual({foo: 'baz'});
-  });
-
-  it('createStateKeySetter is memoized with mixin', function() {
-    var instance = <TestComponentWithMixin />;
-    instance = ReactTestUtils.renderIntoDocument(instance);
-    expect(instance.state).toEqual({foo: 'foo'});
-
-    var foo1 = instance.createStateKeySetter('foo');
-    var bar1 = instance.createStateKeySetter('bar');
-
-    var foo2 = instance.createStateKeySetter('foo');
-    var bar2 = instance.createStateKeySetter('bar');
-
-    expect(foo2).toBe(foo1);
-    expect(bar2).toBe(bar1);
-  });
-});
diff --git a/src/renderers/shared/reconciler/__tests__/ReactStatelessComponent-test.js b/src/renderers/shared/reconciler/__tests__/ReactStatelessComponent-test.js
deleted file mode 100644
index 8e0c8ac49219..000000000000
--- a/src/renderers/shared/reconciler/__tests__/ReactStatelessComponent-test.js
+++ /dev/null
@@ -1,245 +0,0 @@
-/**
- * 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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-var React;
-var ReactDOM;
-var ReactTestUtils;
-
-function StatelessComponent(props) {
-  return <div>{props.name}</div>;
-}
-
-describe('ReactStatelessComponent', function() {
-
-  beforeEach(function() {
-    React = require('React');
-    ReactDOM = require('ReactDOM');
-    ReactTestUtils = require('ReactTestUtils');
-  });
-
-  it('should render stateless component', function() {
-    var el = document.createElement('div');
-    ReactDOM.render(<StatelessComponent name="A" />, el);
-
-    expect(el.textContent).toBe('A');
-  });
-
-  it('should update stateless component', function() {
-    var Parent = React.createClass({
-      render() {
-        return <StatelessComponent {...this.props} />;
-      },
-    });
-
-    var el = document.createElement('div');
-    ReactDOM.render(<Parent name="A" />, el);
-    expect(el.textContent).toBe('A');
-
-    ReactDOM.render(<Parent name="B" />, el);
-    expect(el.textContent).toBe('B');
-  });
-
-  it('should unmount stateless component', function() {
-    var container = document.createElement('div');
-
-    ReactDOM.render(<StatelessComponent name="A" />, container);
-    expect(container.textContent).toBe('A');
-
-    ReactDOM.unmountComponentAtNode(container);
-    expect(container.textContent).toBe('');
-  });
-
-  it('should pass context thru stateless component', function() {
-    var Child = React.createClass({
-      contextTypes: {
-        test: React.PropTypes.string.isRequired,
-      },
-
-      render: function() {
-        return <div>{this.context.test}</div>;
-      },
-    });
-
-    function Parent() {
-      return <Child />;
-    }
-
-    var GrandParent = React.createClass({
-      childContextTypes: {
-        test: React.PropTypes.string.isRequired,
-      },
-
-      getChildContext() {
-        return {test: this.props.test};
-      },
-
-      render: function() {
-        return <Parent />;
-      },
-    });
-
-    var el = document.createElement('div');
-    ReactDOM.render(<GrandParent test="test" />, el);
-
-    expect(el.textContent).toBe('test');
-
-    ReactDOM.render(<GrandParent test="mest" />, el);
-
-    expect(el.textContent).toBe('mest');
-  });
-
-  it('should warn when stateless component returns array', function() {
-    spyOn(console, 'error');
-    function NotAComponent() {
-      return [<div />, <div />];
-    }
-    expect(function() {
-      ReactTestUtils.renderIntoDocument(<div><NotAComponent /></div>);
-    }).toThrow();
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
-      'NotAComponent(...): A valid React element (or null) must be returned. '+
-      'You may have returned undefined, an array or some other invalid object.'
-    );
-  });
-
-  it('should throw on string refs in pure functions', function() {
-    function Child() {
-      return <div ref="me" />;
-    }
-
-    expect(function() {
-      ReactTestUtils.renderIntoDocument(<Child test="test" />);
-    }).toThrow(
-      'Stateless function components cannot have refs.'
-    );
-  });
-
-  it('should warn when given a ref', function() {
-    spyOn(console, 'error');
-
-    var Parent = React.createClass({
-      displayName: 'Parent',
-      render: function() {
-        return <StatelessComponent name="A" ref="stateless"/>;
-      },
-    });
-    ReactTestUtils.renderIntoDocument(<Parent/>);
-
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
-      'Stateless function components cannot be given refs ' +
-      '(See ref "stateless" in StatelessComponent created by Parent). ' +
-      'Attempts to access this ref will fail.'
-    );
-  });
-
-  it('should provide a null ref', function() {
-    function Child() {
-      return <div />;
-    }
-
-    var comp = ReactTestUtils.renderIntoDocument(<Child />);
-    expect(comp).toBe(null);
-  });
-
-  it('should use correct name in key warning', function() {
-    function Child() {
-      return <div>{[<span />]}</div>;
-    }
-
-    spyOn(console, 'error');
-    ReactTestUtils.renderIntoDocument(<Child />);
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain('a unique "key" prop');
-    expect(console.error.argsForCall[0][0]).toContain('Child');
-  });
-
-  it('should support default props and prop types', function() {
-    function Child(props) {
-      return <div>{props.test}</div>;
-    }
-    Child.defaultProps = {test: 2};
-    Child.propTypes = {test: React.PropTypes.string};
-
-    spyOn(console, 'error');
-    ReactTestUtils.renderIntoDocument(<Child />);
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toBe(
-      'Warning: Failed propType: Invalid prop `test` of type `number` ' +
-      'supplied to `Child`, expected `string`.'
-    );
-  });
-
-  it('should receive context', function() {
-    var Parent = React.createClass({
-      childContextTypes: {
-        lang: React.PropTypes.string,
-      },
-      getChildContext: function() {
-        return {lang: 'en'};
-      },
-      render: function() {
-        return <Child />;
-      },
-    });
-    function Child(props, context) {
-      return <div>{context.lang}</div>;
-    }
-    Child.contextTypes = {lang: React.PropTypes.string};
-
-    var el = document.createElement('div');
-    ReactDOM.render(<Parent />, el);
-    expect(el.textContent).toBe('en');
-  });
-
-  it('should work with arrow functions', function() {
-    var Child = function() {
-      return <div />;
-    };
-    // Will create a new bound function without a prototype, much like a native
-    // arrow function.
-    Child = Child.bind(this);
-
-    expect(() => ReactTestUtils.renderIntoDocument(<Child />)).not.toThrow();
-  });
-
-  it('should allow simple functions to return null', function() {
-    var Child = function() {
-      return null;
-    };
-    expect(() => ReactTestUtils.renderIntoDocument(<Child />)).not.toThrow();
-  });
-
-  it('should allow simple functions to return false', function() {
-    function Child() {
-      return false;
-    }
-    expect(() => ReactTestUtils.renderIntoDocument(<Child />)).not.toThrow();
-  });
-
-  it('should warn when using non-React functions in JSX', function() {
-    spyOn(console, 'error');
-    function NotAComponent() {
-      return [<div />, <div />];
-    }
-    expect(function() {
-      ReactTestUtils.renderIntoDocument(<div><NotAComponent /></div>);
-    }).toThrow();  // has no method 'render'
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
-      'NotAComponent(...): A valid React element (or null) must be returned. You may ' +
-      'have returned undefined, an array or some other invalid object.'
-    );
-  });
-});
diff --git a/src/renderers/shared/reconciler/__tests__/ReactUpdates-test.js b/src/renderers/shared/reconciler/__tests__/ReactUpdates-test.js
deleted file mode 100644
index f59193d691ca..000000000000
--- a/src/renderers/shared/reconciler/__tests__/ReactUpdates-test.js
+++ /dev/null
@@ -1,1027 +0,0 @@
-/**
- * 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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-var React;
-var ReactDOM;
-var ReactTestUtils;
-var ReactUpdates;
-
-describe('ReactUpdates', function() {
-  beforeEach(function() {
-    React = require('React');
-    ReactDOM = require('ReactDOM');
-    ReactTestUtils = require('ReactTestUtils');
-    ReactUpdates = require('ReactUpdates');
-  });
-
-  it('should batch state when updating state twice', function() {
-    var updateCount = 0;
-    var Component = React.createClass({
-      getInitialState: function() {
-        return {x: 0};
-      },
-      componentDidUpdate: function() {
-        updateCount++;
-      },
-      render: function() {
-        return <div>{this.state.x}</div>;
-      },
-    });
-
-    var instance = ReactTestUtils.renderIntoDocument(<Component />);
-    expect(instance.state.x).toBe(0);
-
-    ReactUpdates.batchedUpdates(function() {
-      instance.setState({x: 1});
-      instance.setState({x: 2});
-      expect(instance.state.x).toBe(0);
-      expect(updateCount).toBe(0);
-    });
-
-    expect(instance.state.x).toBe(2);
-    expect(updateCount).toBe(1);
-  });
-
-  it('should batch state when updating two different state keys', function() {
-    var updateCount = 0;
-    var Component = React.createClass({
-      getInitialState: function() {
-        return {x: 0, y: 0};
-      },
-      componentDidUpdate: function() {
-        updateCount++;
-      },
-      render: function() {
-        return <div>({this.state.x}, {this.state.y})</div>;
-      },
-    });
-
-    var instance = ReactTestUtils.renderIntoDocument(<Component />);
-    expect(instance.state.x).toBe(0);
-    expect(instance.state.y).toBe(0);
-
-    ReactUpdates.batchedUpdates(function() {
-      instance.setState({x: 1});
-      instance.setState({y: 2});
-      expect(instance.state.x).toBe(0);
-      expect(instance.state.y).toBe(0);
-      expect(updateCount).toBe(0);
-    });
-
-    expect(instance.state.x).toBe(1);
-    expect(instance.state.y).toBe(2);
-    expect(updateCount).toBe(1);
-  });
-
-  it('should batch state and props together', function() {
-    var updateCount = 0;
-    var Component = React.createClass({
-      getInitialState: function() {
-        return {y: 0};
-      },
-      componentDidUpdate: function() {
-        updateCount++;
-      },
-      render: function() {
-        return <div>({this.props.x}, {this.state.y})</div>;
-      },
-    });
-
-    var container = document.createElement('div');
-    var instance = ReactDOM.render(<Component x={0} />, container);
-    expect(instance.props.x).toBe(0);
-    expect(instance.state.y).toBe(0);
-
-    ReactUpdates.batchedUpdates(function() {
-      ReactDOM.render(<Component x={1} />, container);
-      instance.setState({y: 2});
-      expect(instance.props.x).toBe(0);
-      expect(instance.state.y).toBe(0);
-      expect(updateCount).toBe(0);
-    });
-
-    expect(instance.props.x).toBe(1);
-    expect(instance.state.y).toBe(2);
-    expect(updateCount).toBe(1);
-  });
-
-  it('should batch parent/child state updates together', function() {
-    var parentUpdateCount = 0;
-    var Parent = React.createClass({
-      getInitialState: function() {
-        return {x: 0};
-      },
-      componentDidUpdate: function() {
-        parentUpdateCount++;
-      },
-      render: function() {
-        return <div><Child ref="child" x={this.state.x} /></div>;
-      },
-    });
-    var childUpdateCount = 0;
-    var Child = React.createClass({
-      getInitialState: function() {
-        return {y: 0};
-      },
-      componentDidUpdate: function() {
-        childUpdateCount++;
-      },
-      render: function() {
-        return <div>{this.props.x + this.state.y}</div>;
-      },
-    });
-
-    var instance = ReactTestUtils.renderIntoDocument(<Parent />);
-    var child = instance.refs.child;
-    expect(instance.state.x).toBe(0);
-    expect(child.state.y).toBe(0);
-
-    ReactUpdates.batchedUpdates(function() {
-      instance.setState({x: 1});
-      child.setState({y: 2});
-      expect(instance.state.x).toBe(0);
-      expect(child.state.y).toBe(0);
-      expect(parentUpdateCount).toBe(0);
-      expect(childUpdateCount).toBe(0);
-    });
-
-    expect(instance.state.x).toBe(1);
-    expect(child.state.y).toBe(2);
-    expect(parentUpdateCount).toBe(1);
-    expect(childUpdateCount).toBe(1);
-  });
-
-  it('should batch child/parent state updates together', function() {
-    var parentUpdateCount = 0;
-    var Parent = React.createClass({
-      getInitialState: function() {
-        return {x: 0};
-      },
-      componentDidUpdate: function() {
-        parentUpdateCount++;
-      },
-      render: function() {
-        return <div><Child ref="child" x={this.state.x} /></div>;
-      },
-    });
-    var childUpdateCount = 0;
-    var Child = React.createClass({
-      getInitialState: function() {
-        return {y: 0};
-      },
-      componentDidUpdate: function() {
-        childUpdateCount++;
-      },
-      render: function() {
-        return <div>{this.props.x + this.state.y}</div>;
-      },
-    });
-
-    var instance = ReactTestUtils.renderIntoDocument(<Parent />);
-    var child = instance.refs.child;
-    expect(instance.state.x).toBe(0);
-    expect(child.state.y).toBe(0);
-
-    ReactUpdates.batchedUpdates(function() {
-      child.setState({y: 2});
-      instance.setState({x: 1});
-      expect(instance.state.x).toBe(0);
-      expect(child.state.y).toBe(0);
-      expect(parentUpdateCount).toBe(0);
-      expect(childUpdateCount).toBe(0);
-    });
-
-    expect(instance.state.x).toBe(1);
-    expect(child.state.y).toBe(2);
-    expect(parentUpdateCount).toBe(1);
-
-    // Batching reduces the number of updates here to 1.
-    expect(childUpdateCount).toBe(1);
-  });
-
-  it('should support chained state updates', function() {
-    var updateCount = 0;
-    var Component = React.createClass({
-      getInitialState: function() {
-        return {x: 0};
-      },
-      componentDidUpdate: function() {
-        updateCount++;
-      },
-      render: function() {
-        return <div>{this.state.x}</div>;
-      },
-    });
-
-    var instance = ReactTestUtils.renderIntoDocument(<Component />);
-    expect(instance.state.x).toBe(0);
-
-    var innerCallbackRun = false;
-    ReactUpdates.batchedUpdates(function() {
-      instance.setState({x: 1}, function() {
-        instance.setState({x: 2}, function() {
-          expect(this).toBe(instance);
-          innerCallbackRun = true;
-          expect(instance.state.x).toBe(2);
-          expect(updateCount).toBe(2);
-        });
-        expect(instance.state.x).toBe(1);
-        expect(updateCount).toBe(1);
-      });
-      expect(instance.state.x).toBe(0);
-      expect(updateCount).toBe(0);
-    });
-
-    expect(innerCallbackRun).toBeTruthy();
-    expect(instance.state.x).toBe(2);
-    expect(updateCount).toBe(2);
-  });
-
-  it('should batch forceUpdate together', function() {
-    var shouldUpdateCount = 0;
-    var updateCount = 0;
-    var Component = React.createClass({
-      getInitialState: function() {
-        return {x: 0};
-      },
-      shouldComponentUpdate: function() {
-        shouldUpdateCount++;
-      },
-      componentDidUpdate: function() {
-        updateCount++;
-      },
-      render: function() {
-        return <div>{this.state.x}</div>;
-      },
-    });
-
-    var instance = ReactTestUtils.renderIntoDocument(<Component />);
-    expect(instance.state.x).toBe(0);
-
-    var callbacksRun = 0;
-    ReactUpdates.batchedUpdates(function() {
-      instance.setState({x: 1}, function() {
-        callbacksRun++;
-      });
-      instance.forceUpdate(function() {
-        callbacksRun++;
-      });
-      expect(instance.state.x).toBe(0);
-      expect(updateCount).toBe(0);
-    });
-
-    expect(callbacksRun).toBe(2);
-    // shouldComponentUpdate shouldn't be called since we're forcing
-    expect(shouldUpdateCount).toBe(0);
-    expect(instance.state.x).toBe(1);
-    expect(updateCount).toBe(1);
-  });
-
-  it('should update children even if parent blocks updates', function() {
-    var parentRenderCount = 0;
-    var childRenderCount = 0;
-
-    var Parent = React.createClass({
-      shouldComponentUpdate: function() {
-        return false;
-      },
-
-      render: function() {
-        parentRenderCount++;
-        return <Child ref="child" />;
-      },
-    });
-
-    var Child = React.createClass({
-      render: function() {
-        childRenderCount++;
-        return <div />;
-      },
-    });
-
-    expect(parentRenderCount).toBe(0);
-    expect(childRenderCount).toBe(0);
-
-    var instance = <Parent />;
-    instance = ReactTestUtils.renderIntoDocument(instance);
-
-    expect(parentRenderCount).toBe(1);
-    expect(childRenderCount).toBe(1);
-
-    ReactUpdates.batchedUpdates(function() {
-      instance.setState({x: 1});
-    });
-
-    expect(parentRenderCount).toBe(1);
-    expect(childRenderCount).toBe(1);
-
-    ReactUpdates.batchedUpdates(function() {
-      instance.refs.child.setState({x: 1});
-    });
-
-    expect(parentRenderCount).toBe(1);
-    expect(childRenderCount).toBe(2);
-  });
-
-  it('should not reconcile children passed via props', function() {
-    var numMiddleRenders = 0;
-    var numBottomRenders = 0;
-
-    var Top = React.createClass({
-      render: function() {
-        return <Middle><Bottom /></Middle>;
-      },
-    });
-
-    var Middle = React.createClass({
-      componentDidMount: function() {
-        this.forceUpdate();
-      },
-
-      render: function() {
-        numMiddleRenders++;
-        return React.Children.only(this.props.children);
-      },
-    });
-
-    var Bottom = React.createClass({
-      render: function() {
-        numBottomRenders++;
-        return null;
-      },
-    });
-
-    ReactTestUtils.renderIntoDocument(<Top />);
-    expect(numMiddleRenders).toBe(2);
-    expect(numBottomRenders).toBe(1);
-  });
-
-  it('should flow updates correctly', function() {
-    var willUpdates = [];
-    var didUpdates = [];
-
-    var UpdateLoggingMixin = {
-      componentWillUpdate: function() {
-        willUpdates.push(this.constructor.displayName);
-      },
-      componentDidUpdate: function() {
-        didUpdates.push(this.constructor.displayName);
-      },
-    };
-
-    var Box = React.createClass({
-      mixins: [UpdateLoggingMixin],
-
-      render: function() {
-        return <div ref="boxDiv">{this.props.children}</div>;
-      },
-    });
-
-    var Child = React.createClass({
-      mixins: [UpdateLoggingMixin],
-
-      render: function() {
-        return <span ref="span">child</span>;
-      },
-    });
-
-    var Switcher = React.createClass({
-      mixins: [UpdateLoggingMixin],
-
-      getInitialState: function() {
-        return {tabKey: 'hello'};
-      },
-
-      render: function() {
-        var child = this.props.children;
-
-        return (
-          <Box ref="box">
-            <div
-              ref="switcherDiv"
-              style={{
-                display: this.state.tabKey === child.key ? '' : 'none',
-              }}>
-              {child}
-            </div>
-          </Box>
-        );
-      },
-    });
-
-    var App = React.createClass({
-      mixins: [UpdateLoggingMixin],
-
-      render: function() {
-        return (
-          <Switcher ref="switcher">
-            <Child key="hello" ref="child" />
-          </Switcher>
-        );
-      },
-    });
-
-    var root = <App />;
-    root = ReactTestUtils.renderIntoDocument(root);
-
-    function expectUpdates(desiredWillUpdates, desiredDidUpdates) {
-      var i;
-      for (i = 0; i < desiredWillUpdates; i++) {
-        expect(willUpdates).toContain(desiredWillUpdates[i]);
-      }
-      for (i = 0; i < desiredDidUpdates; i++) {
-        expect(didUpdates).toContain(desiredDidUpdates[i]);
-      }
-      willUpdates = [];
-      didUpdates = [];
-    }
-
-    function triggerUpdate(c) {
-      c.setState({x: 1});
-    }
-
-    function testUpdates(components, desiredWillUpdates, desiredDidUpdates) {
-      var i;
-
-      ReactUpdates.batchedUpdates(function() {
-        for (i = 0; i < components.length; i++) {
-          triggerUpdate(components[i]);
-        }
-      });
-
-      expectUpdates(desiredWillUpdates, desiredDidUpdates);
-
-      // Try them in reverse order
-
-      ReactUpdates.batchedUpdates(function() {
-        for (i = components.length - 1; i >= 0; i--) {
-          triggerUpdate(components[i]);
-        }
-      });
-
-      expectUpdates(desiredWillUpdates, desiredDidUpdates);
-    }
-    testUpdates(
-      [root.refs.switcher.refs.box, root.refs.switcher],
-      // Owner-child relationships have inverse will and did
-      ['Switcher', 'Box'],
-      ['Box', 'Switcher']
-    );
-
-    testUpdates(
-      [root.refs.child, root.refs.switcher.refs.box],
-      // Not owner-child so reconcile independently
-      ['Box', 'Child'],
-      ['Box', 'Child']
-    );
-
-    testUpdates(
-      [root.refs.child, root.refs.switcher],
-      // Switcher owns Box and Child, Box does not own Child
-      ['Switcher', 'Box', 'Child'],
-      ['Box', 'Switcher', 'Child']
-    );
-  });
-
-  it('should share reconcile transaction across different roots', function() {
-    var ReconcileTransaction = ReactUpdates.ReactReconcileTransaction;
-    spyOn(ReconcileTransaction, 'getPooled').andCallThrough();
-
-    var Component = React.createClass({
-      render: function() {
-        return <div>{this.props.text}</div>;
-      },
-    });
-
-    var containerA = document.createElement('div');
-    var containerB = document.createElement('div');
-
-    // Initial renders aren't batched together yet...
-    ReactUpdates.batchedUpdates(function() {
-      ReactDOM.render(<Component text="A1" />, containerA);
-      ReactDOM.render(<Component text="B1" />, containerB);
-    });
-    expect(ReconcileTransaction.getPooled.calls.length).toBe(2);
-
-    // ...but updates are! Here only one more transaction is used, which means
-    // we only have to initialize and close the wrappers once.
-    ReactUpdates.batchedUpdates(function() {
-      ReactDOM.render(<Component text="A2" />, containerA);
-      ReactDOM.render(<Component text="B2" />, containerB);
-    });
-    expect(ReconcileTransaction.getPooled.calls.length).toBe(3);
-  });
-
-  it('should queue mount-ready handlers across different roots', function() {
-    // We'll define two components A and B, then update both of them. When A's
-    // componentDidUpdate handlers is called, B's DOM should already have been
-    // updated.
-
-    var a;
-    var b;
-
-    var aUpdated = false;
-
-    var A = React.createClass({
-      getInitialState: function() {
-        return {x: 0};
-      },
-      componentDidUpdate: function() {
-        expect(ReactDOM.findDOMNode(b).textContent).toBe('B1');
-        aUpdated = true;
-      },
-      render: function() {
-        return <div>A{this.state.x}</div>;
-      },
-    });
-
-    var B = React.createClass({
-      getInitialState: function() {
-        return {x: 0};
-      },
-      render: function() {
-        return <div>B{this.state.x}</div>;
-      },
-    });
-
-    a = ReactTestUtils.renderIntoDocument(<A />);
-    b = ReactTestUtils.renderIntoDocument(<B />);
-
-    ReactUpdates.batchedUpdates(function() {
-      a.setState({x: 1});
-      b.setState({x: 1});
-    });
-
-    expect(aUpdated).toBe(true);
-  });
-
-  it('should flush updates in the correct order', function() {
-    var updates = [];
-    var Outer = React.createClass({
-      getInitialState: function() {
-        return {x: 0};
-      },
-      render: function() {
-        updates.push('Outer-render-' + this.state.x);
-        return <div><Inner x={this.state.x} ref="inner" /></div>;
-      },
-      componentDidUpdate: function() {
-        var x = this.state.x;
-        updates.push('Outer-didUpdate-' + x);
-        updates.push('Inner-setState-' + x);
-        this.refs.inner.setState({x: x}, function() {
-          updates.push('Inner-callback-' + x);
-        });
-      },
-    });
-    var Inner = React.createClass({
-      getInitialState: function() {
-        return {x: 0};
-      },
-      render: function() {
-        updates.push('Inner-render-' + this.props.x + '-' + this.state.x);
-        return <div />;
-      },
-      componentDidUpdate: function() {
-        updates.push('Inner-didUpdate-' + this.props.x + '-' + this.state.x);
-      },
-    });
-
-    var instance = ReactTestUtils.renderIntoDocument(<Outer />);
-
-    updates.push('Outer-setState-1');
-    instance.setState({x: 1}, function() {
-      updates.push('Outer-callback-1');
-      updates.push('Outer-setState-2');
-      instance.setState({x: 2}, function() {
-        updates.push('Outer-callback-2');
-      });
-    });
-
-    /* eslint-disable indent */
-    expect(updates).toEqual([
-      'Outer-render-0',
-        'Inner-render-0-0',
-
-      'Outer-setState-1',
-        'Outer-render-1',
-          'Inner-render-1-0',
-          'Inner-didUpdate-1-0',
-        'Outer-didUpdate-1',
-          'Inner-setState-1',
-            'Inner-render-1-1',
-            'Inner-didUpdate-1-1',
-          'Inner-callback-1',
-      'Outer-callback-1',
-
-      'Outer-setState-2',
-        'Outer-render-2',
-          'Inner-render-2-1',
-          'Inner-didUpdate-2-1',
-        'Outer-didUpdate-2',
-          'Inner-setState-2',
-            'Inner-render-2-2',
-            'Inner-didUpdate-2-2',
-          'Inner-callback-2',
-      'Outer-callback-2',
-    ]);
-    /* eslint-enable indent */
-  });
-
-  it('should flush updates in the correct order across roots', function() {
-    var instances = [];
-    var updates = [];
-
-    var MockComponent = React.createClass({
-      render: function() {
-        updates.push(this.props.depth);
-        return <div />;
-      },
-      componentDidMount: function() {
-        instances.push(this);
-        if (this.props.depth < this.props.count) {
-          ReactDOM.render(
-            <MockComponent
-              depth={this.props.depth + 1}
-              count={this.props.count}
-            />,
-            ReactDOM.findDOMNode(this)
-          );
-        }
-      },
-    });
-
-    ReactTestUtils.renderIntoDocument(<MockComponent depth={0} count={2} />);
-
-    expect(updates).toEqual([0, 1, 2]);
-
-    ReactUpdates.batchedUpdates(function() {
-      // Simulate update on each component from top to bottom.
-      instances.forEach(function(instance) {
-        instance.forceUpdate();
-      });
-    });
-
-    expect(updates).toEqual([0, 1, 2, 0, 1, 2]);
-  });
-
-  it('should queue nested updates', function() {
-    // See https://github.com/facebook/react/issues/1147
-
-    var X = React.createClass({
-      getInitialState: function() {
-        return {s: 0};
-      },
-      render: function() {
-        if (this.state.s === 0) {
-          return (
-            <div>
-              <span>0</span>
-            </div>
-          );
-        } else {
-          return <div>1</div>;
-        }
-      },
-      go: function() {
-        this.setState({s: 1});
-        this.setState({s: 0});
-        this.setState({s: 1});
-      },
-    });
-
-    var Y = React.createClass({
-      render: function() {
-        return (
-          <div>
-            <Z />
-          </div>
-        );
-      },
-    });
-
-    var Z = React.createClass({
-      render: function() {
-        return <div />;
-      },
-      componentWillUpdate: function() {
-        x.go();
-      },
-    });
-
-    var x;
-    var y;
-
-    x = ReactTestUtils.renderIntoDocument(<X />);
-    y = ReactTestUtils.renderIntoDocument(<Y />);
-    expect(ReactDOM.findDOMNode(x).textContent).toBe('0');
-
-    y.forceUpdate();
-    expect(ReactDOM.findDOMNode(x).textContent).toBe('1');
-  });
-
-  it('should queue updates from during mount', function() {
-    // See https://github.com/facebook/react/issues/1353
-    var a;
-
-    var A = React.createClass({
-      getInitialState: function() {
-        return {x: 0};
-      },
-      componentWillMount: function() {
-        a = this;
-      },
-      render: function() {
-        return <div>A{this.state.x}</div>;
-      },
-    });
-
-    var B = React.createClass({
-      componentWillMount: function() {
-        a.setState({x: 1});
-      },
-      render: function() {
-        return <div />;
-      },
-    });
-
-    ReactUpdates.batchedUpdates(function() {
-      ReactTestUtils.renderIntoDocument(
-        <div>
-          <A />
-          <B />
-        </div>
-      );
-    });
-
-    expect(a.state.x).toBe(1);
-    expect(ReactDOM.findDOMNode(a).textContent).toBe('A1');
-  });
-
-  it('calls componentWillReceiveProps setState callback properly', function() {
-    var callbackCount = 0;
-    var A = React.createClass({
-      getInitialState: function() {
-        return {x: this.props.x};
-      },
-      componentWillReceiveProps: function(nextProps) {
-        var newX = nextProps.x;
-        this.setState({x: newX}, function() {
-          // State should have updated by the time this callback gets called
-          expect(this.state.x).toBe(newX);
-          callbackCount++;
-        });
-      },
-      render: function() {
-        return <div>{this.state.x}</div>;
-      },
-    });
-
-    var container = document.createElement('div');
-    ReactDOM.render(<A x={1} />, container);
-    ReactDOM.render(<A x={2} />, container);
-    expect(callbackCount).toBe(1);
-  });
-
-  it('calls asap callbacks properly', function() {
-    var callbackCount = 0;
-    var A = React.createClass({
-      render: function() {
-        return <div />;
-      },
-      componentDidUpdate: function() {
-        ReactUpdates.asap(function() {
-          expect(this).toBe(component);
-          callbackCount++;
-          ReactUpdates.asap(function() {
-            callbackCount++;
-          });
-          expect(callbackCount).toBe(1);
-        }, component);
-        expect(callbackCount).toBe(0);
-      },
-    });
-
-    var component = ReactTestUtils.renderIntoDocument(<A />);
-    component.forceUpdate();
-    expect(callbackCount).toBe(2);
-  });
-
-  it('calls asap callbacks with queued updates', function() {
-    var log = [];
-    var A = React.createClass({
-      getInitialState: () => ({updates: 0}),
-      render: function() {
-        log.push('render-' + this.state.updates);
-        return <div />;
-      },
-      componentDidUpdate: function() {
-        if (this.state.updates === 1) {
-          ReactUpdates.asap(function() {
-            this.setState({updates: 2}, function() {
-              ReactUpdates.asap(function() {
-                log.push('asap-1.2');
-              });
-              log.push('setState-cb');
-            });
-            log.push('asap-1.1');
-          }, this);
-        } else if (this.state.updates === 2) {
-          ReactUpdates.asap(function() {
-            log.push('asap-2');
-          });
-        }
-        log.push('didUpdate-' + this.state.updates);
-      },
-    });
-
-    var component = ReactTestUtils.renderIntoDocument(<A />);
-    component.setState({updates: 1});
-    expect(log).toEqual([
-      'render-0',
-      // We do the first update...
-      'render-1',
-      'didUpdate-1',
-      // ...which calls asap and enqueues a second update...
-      'asap-1.1',
-      // ...which runs and enqueues the asap-2 log in its didUpdate...
-      'render-2',
-      'didUpdate-2',
-      // ...and runs the setState callback, which enqueues the log for
-      // asap-1.2.
-      'setState-cb',
-      'asap-2',
-      'asap-1.2',
-    ]);
-  });
-
-  it('does not call render after a component as been deleted', function() {
-
-    var renderCount = 0;
-    var componentB = null;
-
-    var B = React.createClass({
-      getInitialState: function() {
-        return {updates: 0};
-      },
-      componentDidMount: function() {
-        componentB = this;
-      },
-      render: function() {
-        renderCount++;
-        return <div />;
-      },
-    });
-
-    var A = React.createClass({
-      getInitialState: function() {
-        return {showB: true};
-      },
-      render: function() {
-        return this.state.showB ? <B /> : <div />;
-      },
-    });
-
-    var component = ReactTestUtils.renderIntoDocument(<A />);
-
-    ReactUpdates.batchedUpdates(function() {
-      // B will have scheduled an update but the batching should ensure that its
-      // update never fires.
-      componentB.setState({updates: 1});
-      component.setState({showB: false});
-    });
-
-    expect(renderCount).toBe(1);
-  });
-
-  it('marks top-level updates', function() {
-    var ReactFeatureFlags = require('ReactFeatureFlags');
-
-    var Foo = React.createClass({
-      render: function() {
-        return <Bar />;
-      },
-    });
-
-    var Bar = React.createClass({
-      render: function() {
-        return <div />;
-      },
-    });
-
-    var container = document.createElement('div');
-    ReactDOM.render(<Foo />, container);
-
-    try {
-      ReactFeatureFlags.logTopLevelRenders = true;
-      spyOn(console, 'time');
-      spyOn(console, 'timeEnd');
-
-      ReactDOM.render(<Foo />, container);
-
-      expect(console.time.argsForCall.length).toBe(1);
-      expect(console.time.argsForCall[0][0]).toBe('React update: Foo');
-      expect(console.timeEnd.argsForCall.length).toBe(1);
-      expect(console.timeEnd.argsForCall[0][0]).toBe('React update: Foo');
-    } finally {
-      ReactFeatureFlags.logTopLevelRenders = false;
-    }
-  });
-
-  it('throws in setState if the update callback is not a function', function() {
-    function Foo() {
-      this.a = 1;
-      this.b = 2;
-    }
-    var A = React.createClass({
-      getInitialState: function() {
-        return {};
-      },
-      render: function() {
-        return <div />;
-      },
-    });
-    var component = ReactTestUtils.renderIntoDocument(<A />);
-
-    expect(() => component.setState({}, 'no')).toThrow(
-      'setState(...): Expected the last optional `callback` argument ' +
-      'to be a function. Instead received: string.'
-    );
-    expect(() => component.setState({}, {})).toThrow(
-      'setState(...): Expected the last optional `callback` argument ' +
-      'to be a function. Instead received: Object.'
-    );
-    expect(() => component.setState({}, new Foo())).toThrow(
-      'setState(...): Expected the last optional `callback` argument ' +
-      'to be a function. Instead received: Foo (keys: a, b).'
-    );
-  });
-
-  it('throws in replaceState if the update callback is not a function', function() {
-    function Foo() {
-      this.a = 1;
-      this.b = 2;
-    }
-    var A = React.createClass({
-      getInitialState: function() {
-        return {};
-      },
-      render: function() {
-        return <div />;
-      },
-    });
-    var component = ReactTestUtils.renderIntoDocument(<A />);
-
-    expect(() => component.replaceState({}, 'no')).toThrow(
-      'replaceState(...): Expected the last optional `callback` argument ' +
-      'to be a function. Instead received: string.'
-    );
-    expect(() => component.replaceState({}, {})).toThrow(
-      'replaceState(...): Expected the last optional `callback` argument ' +
-      'to be a function. Instead received: Object.'
-    );
-    expect(() => component.replaceState({}, new Foo())).toThrow(
-      'replaceState(...): Expected the last optional `callback` argument ' +
-      'to be a function. Instead received: Foo (keys: a, b).'
-    );
-  });
-
-  it('throws in forceUpdate if the update callback is not a function', function() {
-    function Foo() {
-      this.a = 1;
-      this.b = 2;
-    }
-    var A = React.createClass({
-      getInitialState: function() {
-        return {};
-      },
-      render: function() {
-        return <div />;
-      },
-    });
-    var component = ReactTestUtils.renderIntoDocument(<A />);
-
-    expect(() => component.forceUpdate('no')).toThrow(
-      'forceUpdate(...): Expected the last optional `callback` argument ' +
-      'to be a function. Instead received: string.'
-    );
-    expect(() => component.forceUpdate({})).toThrow(
-      'forceUpdate(...): Expected the last optional `callback` argument ' +
-      'to be a function. Instead received: Object.'
-    );
-    expect(() => component.forceUpdate(new Foo())).toThrow(
-      'forceUpdate(...): Expected the last optional `callback` argument ' +
-      'to be a function. Instead received: Foo (keys: a, b).'
-    );
-  });
-});
diff --git a/src/renderers/shared/reconciler/__tests__/refs-destruction-test.js b/src/renderers/shared/reconciler/__tests__/refs-destruction-test.js
deleted file mode 100644
index 0d001c22540b..000000000000
--- a/src/renderers/shared/reconciler/__tests__/refs-destruction-test.js
+++ /dev/null
@@ -1,104 +0,0 @@
-/**
- * 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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-var React;
-var ReactDOM;
-var ReactTestUtils;
-
-var TestComponent;
-
-describe('refs-destruction', function() {
-  beforeEach(function() {
-    jest.resetModuleRegistry();
-
-    React = require('React');
-    ReactDOM = require('ReactDOM');
-    ReactTestUtils = require('ReactTestUtils');
-
-    TestComponent = React.createClass({
-      render: function() {
-        return (
-          <div>
-            {this.props.destroy ? null :
-              <div ref="theInnerDiv">
-                Lets try to destroy this.
-              </div>
-            }
-          </div>
-        );
-      },
-    });
-  });
-
-  it('should remove refs when destroying the parent', function() {
-    var container = document.createElement('div');
-    var testInstance = ReactDOM.render(<TestComponent />, container);
-    expect(ReactTestUtils.isDOMComponent(testInstance.refs.theInnerDiv))
-      .toBe(true);
-    expect(Object.keys(testInstance.refs || {}).length).toEqual(1);
-    ReactDOM.unmountComponentAtNode(container);
-    expect(Object.keys(testInstance.refs || {}).length).toEqual(0);
-  });
-
-  it('should remove refs when destroying the child', function() {
-    var container = document.createElement('div');
-    var testInstance = ReactDOM.render(<TestComponent />, container);
-    expect(ReactTestUtils.isDOMComponent(testInstance.refs.theInnerDiv))
-      .toBe(true);
-    expect(Object.keys(testInstance.refs || {}).length).toEqual(1);
-    ReactDOM.render(<TestComponent destroy={true} />, container);
-    expect(Object.keys(testInstance.refs || {}).length).toEqual(0);
-  });
-
-  it('should not error when destroying child with ref asynchronously', function() {
-    var Modal = React.createClass({
-      componentDidMount: function() {
-        this.div = document.createElement('div');
-        document.body.appendChild(this.div);
-        this.componentDidUpdate();
-      },
-      componentDidUpdate: function() {
-        ReactDOM.render(<div>{this.props.children}</div>, this.div);
-      },
-      componentWillUnmount: function() {
-        var self = this;
-        // some async animation
-        setTimeout(function() {
-          expect(function() {
-            ReactDOM.unmountComponentAtNode(self.div);
-          }).not.toThrow();
-          document.body.removeChild(self.div);
-        }, 0);
-      },
-      render() {
-        return null;
-      },
-    });
-    var AppModal = React.createClass({
-      render: function() {
-        return (<Modal>
-          <a ref="ref"/>
-        </Modal>);
-      },
-    });
-    var App = React.createClass({
-      render: function() {
-        return this.props.hidden ? null : <AppModal onClose={this.close}/>;
-      },
-    });
-    var container = document.createElement('div');
-    ReactDOM.render(<App />, container);
-    ReactDOM.render(<App hidden={true}/>, container);
-    jest.runAllTimers();
-  });
-});
diff --git a/src/renderers/shared/reconciler/__tests__/refs-test.js b/src/renderers/shared/reconciler/__tests__/refs-test.js
deleted file mode 100644
index 8e2733258a6c..000000000000
--- a/src/renderers/shared/reconciler/__tests__/refs-test.js
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * 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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-var React = require('React');
-var ReactTestUtils = require('ReactTestUtils');
-
-var reactComponentExpect = require('reactComponentExpect');
-
-
-/**
- * Counts clicks and has a renders an item for each click. Each item rendered
- * has a ref of the form "clickLogN".
- */
-var ClickCounter = React.createClass({
-  getInitialState: function() {
-    return {count: this.props.initialCount};
-  },
-  triggerReset: function() {
-    this.setState({count: this.props.initialCount});
-  },
-  handleClick: function() {
-    this.setState({count: this.state.count + 1});
-  },
-  render: function() {
-    var children = [];
-    var i;
-    for (i = 0; i < this.state.count; i++) {
-      children.push(
-        <div
-          className="clickLogDiv"
-          key={'clickLog' + i}
-          ref={'clickLog' + i}
-        />
-      );
-    }
-    return (
-      <span className="clickIncrementer" onClick={this.handleClick}>
-        {children}
-      </span>
-    );
-  },
-});
-
-/**
- * Only purpose is to test that refs are tracked even when applied to a
- * component that is injected down several layers. Ref systems are difficult to
- * build in such a way that ownership is maintained in an airtight manner.
- */
-var GeneralContainerComponent = React.createClass({
-  render: function() {
-    return <div>{this.props.children}</div>;
-  },
-});
-
-/**
- * Notice how refs ownership is maintained even when injecting a component
- * into a different parent.
- */
-var TestRefsComponent = React.createClass({
-  doReset: function() {
-    this.refs.myCounter.triggerReset();
-  },
-  render: function() {
-    return (
-      <div>
-        <div ref="resetDiv" onClick={this.doReset}>
-          Reset Me By Clicking This.
-        </div>
-        <GeneralContainerComponent ref="myContainer">
-          <ClickCounter ref="myCounter" initialCount={1}/>
-        </GeneralContainerComponent>
-      </div>
-    );
-  },
-});
-
-/**
- * Render a TestRefsComponent and ensure that the main refs are wired up.
- */
-var renderTestRefsComponent = function() {
-  var testRefsComponent =
-      ReactTestUtils.renderIntoDocument(<TestRefsComponent />);
-
-  reactComponentExpect(testRefsComponent)
-      .toBeCompositeComponentWithType(TestRefsComponent);
-
-  var generalContainer = testRefsComponent.refs.myContainer;
-  var counter = testRefsComponent.refs.myCounter;
-
-  reactComponentExpect(generalContainer)
-      .toBeCompositeComponentWithType(GeneralContainerComponent);
-  reactComponentExpect(counter)
-      .toBeCompositeComponentWithType(ClickCounter);
-
-  return testRefsComponent;
-};
-
-
-var expectClickLogsLengthToBe = function(instance, length) {
-  var clickLogs =
-    ReactTestUtils.scryRenderedDOMComponentsWithClass(instance, 'clickLogDiv');
-  expect(clickLogs.length).toBe(length);
-  expect(Object.keys(instance.refs.myCounter.refs).length).toBe(length);
-};
-
-describe('reactiverefs', function() {
-  beforeEach(function() {
-    jest.resetModuleRegistry();
-  });
-
-  /**
-   * Ensure that for every click log there is a corresponding ref (from the
-   * perspective of the injected ClickCounter component.
-   */
-  it('Should increase refs with an increase in divs', function() {
-    var testRefsComponent = renderTestRefsComponent();
-    var clickIncrementer =
-      ReactTestUtils.findRenderedDOMComponentWithClass(
-        testRefsComponent,
-        'clickIncrementer'
-      );
-
-    expectClickLogsLengthToBe(testRefsComponent, 1);
-
-    // After clicking the reset, there should still only be one click log ref.
-    ReactTestUtils.Simulate.click(testRefsComponent.refs.resetDiv);
-    expectClickLogsLengthToBe(testRefsComponent, 1);
-
-    // Begin incrementing clicks (and therefore refs).
-    ReactTestUtils.Simulate.click(clickIncrementer);
-    expectClickLogsLengthToBe(testRefsComponent, 2);
-
-    ReactTestUtils.Simulate.click(clickIncrementer);
-    expectClickLogsLengthToBe(testRefsComponent, 3);
-
-    // Now reset again
-    ReactTestUtils.Simulate.click(testRefsComponent.refs.resetDiv);
-    expectClickLogsLengthToBe(testRefsComponent, 1);
-
-  });
-
-});
-
-
-
-/**
- * Tests that when a ref hops around children, we can track that correctly.
- */
-describe('ref swapping', function() {
-  beforeEach(function() {
-    jest.resetModuleRegistry();
-  });
-
-  var RefHopsAround = React.createClass({
-    getInitialState: function() {
-      return {count: 0};
-    },
-    moveRef: function() {
-      this.setState({count: this.state.count + 1});
-    },
-    render: function() {
-      var count = this.state.count;
-      /**
-       * What we have here, is three divs with refs (div1/2/3), but a single
-       * moving cursor ref `hopRef` that "hops" around the three. We'll call the
-       * `moveRef()` function several times and make sure that the hop ref
-       * points to the correct divs.
-       */
-      return (
-        <div>
-          <div
-            className="first"
-            ref={count % 3 === 0 ? 'hopRef' : 'divOneRef'}
-          />
-          <div
-            className="second"
-            ref={count % 3 === 1 ? 'hopRef' : 'divTwoRef'}
-          />
-          <div
-            className="third"
-            ref={count % 3 === 2 ? 'hopRef' : 'divThreeRef'}
-          />
-        </div>
-      );
-    },
-  });
-
-  it('Allow refs to hop around children correctly', function() {
-    var refHopsAround = ReactTestUtils.renderIntoDocument(<RefHopsAround />);
-
-    var firstDiv =
-      ReactTestUtils.findRenderedDOMComponentWithClass(refHopsAround, 'first');
-    var secondDiv =
-      ReactTestUtils.findRenderedDOMComponentWithClass(refHopsAround, 'second');
-    var thirdDiv =
-      ReactTestUtils.findRenderedDOMComponentWithClass(refHopsAround, 'third');
-
-    expect(refHopsAround.refs.hopRef).toEqual(firstDiv);
-    expect(refHopsAround.refs.divTwoRef).toEqual(secondDiv);
-    expect(refHopsAround.refs.divThreeRef).toEqual(thirdDiv);
-
-    refHopsAround.moveRef();
-    expect(refHopsAround.refs.divOneRef).toEqual(firstDiv);
-    expect(refHopsAround.refs.hopRef).toEqual(secondDiv);
-    expect(refHopsAround.refs.divThreeRef).toEqual(thirdDiv);
-
-    refHopsAround.moveRef();
-    expect(refHopsAround.refs.divOneRef).toEqual(firstDiv);
-    expect(refHopsAround.refs.divTwoRef).toEqual(secondDiv);
-    expect(refHopsAround.refs.hopRef).toEqual(thirdDiv);
-
-    /**
-     * Make sure that after the third, we're back to where we started and the
-     * refs are completely restored.
-     */
-    refHopsAround.moveRef();
-    expect(refHopsAround.refs.hopRef).toEqual(firstDiv);
-    expect(refHopsAround.refs.divTwoRef).toEqual(secondDiv);
-    expect(refHopsAround.refs.divThreeRef).toEqual(thirdDiv);
-  });
-
-
-  it('always has a value for this.refs', function() {
-    var Component = React.createClass({
-      render: function() {
-        return <div />;
-      },
-    });
-
-    var instance = ReactTestUtils.renderIntoDocument(<Component />);
-    expect(!!instance.refs).toBe(true);
-  });
-});
-
diff --git a/src/renderers/shared/reconciler/instantiateReactComponent.js b/src/renderers/shared/reconciler/instantiateReactComponent.js
deleted file mode 100644
index 796e037b9958..000000000000
--- a/src/renderers/shared/reconciler/instantiateReactComponent.js
+++ /dev/null
@@ -1,135 +0,0 @@
-/**
- * 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 instantiateReactComponent
- */
-
-'use strict';
-
-var ReactCompositeComponent = require('ReactCompositeComponent');
-var ReactEmptyComponent = require('ReactEmptyComponent');
-var ReactNativeComponent = require('ReactNativeComponent');
-
-var invariant = require('invariant');
-var warning = require('warning');
-
-// To avoid a cyclic dependency, we create the final class in this module
-var ReactCompositeComponentWrapper = function(element) {
-  this.construct(element);
-};
-Object.assign(
-  ReactCompositeComponentWrapper.prototype,
-  ReactCompositeComponent.Mixin,
-  {
-    _instantiateReactComponent: instantiateReactComponent,
-  }
-);
-
-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
- * @return {object} A new instance of the element's constructor.
- * @protected
- */
-function instantiateReactComponent(node) {
-  var instance;
-
-  if (node === null || node === false) {
-    instance = ReactEmptyComponent.create(instantiateReactComponent);
-  } else if (typeof node === 'object') {
-    var element = node;
-    invariant(
-      element && (typeof element.type === 'function' ||
-                  typeof element.type === 'string'),
-      'Element type is invalid: expected a string (for built-in components) ' +
-      'or a class/function (for composite components) but got: %s.%s',
-      element.type == null ? element.type : typeof element.type,
-      getDeclarationErrorAddendum(element._owner)
-    );
-
-    // Special case string values
-    if (typeof element.type === 'string') {
-      instance = ReactNativeComponent.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);
-    } else {
-      instance = new ReactCompositeComponentWrapper(element);
-    }
-  } else if (typeof node === 'string' || typeof node === 'number') {
-    instance = ReactNativeComponent.createInstanceForText(node);
-  } else {
-    invariant(
-      false,
-      'Encountered invalid React node of type %s',
-      typeof node
-    );
-  }
-
-  if (__DEV__) {
-    warning(
-      typeof instance.mountComponent === 'function' &&
-      typeof instance.receiveComponent === 'function' &&
-      typeof instance.getNativeNode === 'function' &&
-      typeof instance.unmountComponent === 'function',
-      'Only React Components can be mounted.'
-    );
-  }
-
-  // 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 (__DEV__) {
-    instance._isOwnerNecessary = false;
-    instance._warnedAboutRefsInRender = false;
-  }
-
-  // Internal instances should fully constructed at this point, so they should
-  // not get any new fields added to them at this point.
-  if (__DEV__) {
-    if (Object.preventExtensions) {
-      Object.preventExtensions(instance);
-    }
-  }
-
-  return instance;
-}
-
-module.exports = instantiateReactComponent;
diff --git a/src/renderers/shared/reconciler/ReactInstanceMap.js b/src/renderers/shared/shared/ReactInstanceMap.js
similarity index 99%
rename from src/renderers/shared/reconciler/ReactInstanceMap.js
rename to src/renderers/shared/shared/ReactInstanceMap.js
index 24eeb2d74037..495c82c311b6 100644
--- a/src/renderers/shared/reconciler/ReactInstanceMap.js
+++ b/src/renderers/shared/shared/ReactInstanceMap.js
@@ -20,7 +20,6 @@
 
 // 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
@@ -41,7 +40,6 @@ var ReactInstanceMap = {
   set: function(key, value) {
     key._reactInternalInstance = value;
   },
-
 };
 
 module.exports = ReactInstanceMap;
diff --git a/src/renderers/shared/reconciler/shouldUpdateReactComponent.js b/src/renderers/shared/shared/shouldUpdateReactComponent.js
similarity index 95%
rename from src/renderers/shared/reconciler/shouldUpdateReactComponent.js
rename to src/renderers/shared/shared/shouldUpdateReactComponent.js
index 2c4a15542992..097eab1c5424 100644
--- a/src/renderers/shared/reconciler/shouldUpdateReactComponent.js
+++ b/src/renderers/shared/shared/shouldUpdateReactComponent.js
@@ -32,7 +32,7 @@ function shouldUpdateReactComponent(prevElement, nextElement) {
   var prevType = typeof prevElement;
   var nextType = typeof nextElement;
   if (prevType === 'string' || prevType === 'number') {
-    return (nextType === 'string' || nextType === 'number');
+    return nextType === 'string' || nextType === 'number';
   } else {
     return (
       nextType === 'object' &&
diff --git a/src/renderers/shared/event/EventConstants.js b/src/renderers/shared/stack/event/EventConstants.js
similarity index 90%
rename from src/renderers/shared/event/EventConstants.js
rename to src/renderers/shared/stack/event/EventConstants.js
index 84a9e9d486ff..385f353385a2 100644
--- a/src/renderers/shared/event/EventConstants.js
+++ b/src/renderers/shared/stack/event/EventConstants.js
@@ -11,14 +11,12 @@
 
 'use strict';
 
-var keyMirror = require('keyMirror');
-
-var PropagationPhases = keyMirror({bubbled: null, captured: null});
+export type PropagationPhases = 'bubbled' | 'captured';
 
 /**
  * Types of raw signals from the browser caught at the top level.
  */
-var topLevelTypes = keyMirror({
+var topLevelTypes = {
   topAbort: null,
   topAnimationEnd: null,
   topAnimationIteration: null,
@@ -87,11 +85,12 @@ var topLevelTypes = keyMirror({
   topVolumeChange: null,
   topWaiting: null,
   topWheel: null,
-});
+};
+
+export type TopLevelTypes = $Enum<typeof topLevelTypes>;
 
 var EventConstants = {
-  topLevelTypes: topLevelTypes,
-  PropagationPhases: PropagationPhases,
+  topLevelTypes,
 };
 
 module.exports = EventConstants;
diff --git a/src/renderers/shared/event/EventPluginHub.js b/src/renderers/shared/stack/event/EventPluginHub.js
similarity index 78%
rename from src/renderers/shared/event/EventPluginHub.js
rename to src/renderers/shared/stack/event/EventPluginHub.js
index 270d1665d8e4..8eb3fc8f2a7f 100644
--- a/src/renderers/shared/event/EventPluginHub.js
+++ b/src/renderers/shared/stack/event/EventPluginHub.js
@@ -53,6 +53,39 @@ 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.
  *
@@ -76,12 +109,10 @@ var executeDispatchesAndReleaseTopLevel = function(e) {
  * @public
  */
 var EventPluginHub = {
-
   /**
    * Methods for injecting dependencies.
    */
   injection: {
-
     /**
      * @param {array} InjectedEventPluginOrder
      * @public
@@ -92,11 +123,10 @@ var EventPluginHub = {
      * @param {object} injectedNamesToPlugins Map from names to plugin modules.
      */
     injectEventPluginsByName: EventPluginRegistry.injectEventPluginsByName,
-
   },
 
   /**
-   * Stores `listener` at `listenerBank[registrationName][id]`. Is idempotent.
+   * 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`).
@@ -106,12 +136,14 @@ var EventPluginHub = {
     invariant(
       typeof listener === 'function',
       'Expected %s listener to be a function, instead got type %s',
-      registrationName, typeof listener
+      registrationName,
+      typeof listener,
     );
 
+    var key = getDictionaryKey(inst);
     var bankForRegistrationName =
       listenerBank[registrationName] || (listenerBank[registrationName] = {});
-    bankForRegistrationName[inst._rootNodeID] = listener;
+    bankForRegistrationName[key] = listener;
 
     var PluginModule =
       EventPluginRegistry.registrationNameModules[registrationName];
@@ -126,8 +158,20 @@ var EventPluginHub = {
    * @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];
-    return bankForRegistrationName && bankForRegistrationName[inst._rootNodeID];
+    if (
+      shouldPreventMouseEvent(
+        registrationName,
+        inst._currentElement.type,
+        inst._currentElement.props,
+      )
+    ) {
+      return null;
+    }
+    var key = getDictionaryKey(inst);
+    return bankForRegistrationName && bankForRegistrationName[key];
   },
 
   /**
@@ -146,7 +190,8 @@ var EventPluginHub = {
     var bankForRegistrationName = listenerBank[registrationName];
     // TODO: This should never be null -- when is it?
     if (bankForRegistrationName) {
-      delete bankForRegistrationName[inst._rootNodeID];
+      var key = getDictionaryKey(inst);
+      delete bankForRegistrationName[key];
     }
   },
 
@@ -156,8 +201,13 @@ var EventPluginHub = {
    * @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[registrationName][inst._rootNodeID]) {
+      if (!listenerBank.hasOwnProperty(registrationName)) {
+        continue;
+      }
+
+      if (!listenerBank[registrationName][key]) {
         continue;
       }
 
@@ -167,7 +217,7 @@ var EventPluginHub = {
         PluginModule.willDeleteListener(inst, registrationName);
       }
 
-      delete listenerBank[registrationName][inst._rootNodeID];
+      delete listenerBank[registrationName][key];
     }
   },
 
@@ -179,10 +229,11 @@ var EventPluginHub = {
    * @internal
    */
   extractEvents: function(
-      topLevelType,
-      targetInst,
-      nativeEvent,
-      nativeEventTarget) {
+    topLevelType,
+    targetInst,
+    nativeEvent,
+    nativeEventTarget,
+  ) {
     var events;
     var plugins = EventPluginRegistry.plugins;
     for (var i = 0; i < plugins.length; i++) {
@@ -193,7 +244,7 @@ var EventPluginHub = {
           topLevelType,
           targetInst,
           nativeEvent,
-          nativeEventTarget
+          nativeEventTarget,
         );
         if (extractedEvents) {
           events = accumulateInto(events, extractedEvents);
@@ -229,18 +280,18 @@ var EventPluginHub = {
     if (simulated) {
       forEachAccumulated(
         processingEventQueue,
-        executeDispatchesAndReleaseSimulated
+        executeDispatchesAndReleaseSimulated,
       );
     } else {
       forEachAccumulated(
         processingEventQueue,
-        executeDispatchesAndReleaseTopLevel
+        executeDispatchesAndReleaseTopLevel,
       );
     }
     invariant(
       !eventQueue,
       'processEventQueue(): Additional events were enqueued while processing ' +
-      'an event queue. Support for this has not yet been implemented.'
+        'an event queue. Support for this has not yet been implemented.',
     );
     // This would be a good time to rethrow if any of the event handlers threw.
     ReactErrorUtils.rethrowCaughtError();
@@ -256,7 +307,6 @@ var EventPluginHub = {
   __getListenerBank: function() {
     return listenerBank;
   },
-
 };
 
 module.exports = EventPluginHub;
diff --git a/src/renderers/shared/stack/event/EventPluginRegistry.js b/src/renderers/shared/stack/event/EventPluginRegistry.js
new file mode 100644
index 000000000000..be2159edf6d0
--- /dev/null
+++ b/src/renderers/shared/stack/event/EventPluginRegistry.js
@@ -0,0 +1,335 @@
+/**
+ * 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 EventPluginRegistry
+ * @flow
+ */
+
+'use strict';
+
+import type {
+  DispatchConfig,
+  ReactSyntheticEvent,
+} from 'ReactSyntheticEventType';
+
+import type {AnyNativeEvent, PluginName, PluginModule} from 'PluginModuleType';
+
+type NamesToPlugins = {[key: PluginName]: PluginModule<AnyNativeEvent>};
+
+type EventPluginOrder = null | Array<PluginName>;
+
+var invariant = require('invariant');
+
+/**
+ * Injectable ordering of event plugins.
+ */
+var eventPluginOrder: EventPluginOrder = null;
+
+/**
+ * Injectable mapping from names to event plugin modules.
+ */
+var namesToPlugins: NamesToPlugins = {};
+
+/**
+ * Recomputes the plugin list using the injected plugins and plugin ordering.
+ *
+ * @private
+ */
+function recomputePluginOrdering(): void {
+  if (!eventPluginOrder) {
+    // Wait until an `eventPluginOrder` is injected.
+    return;
+  }
+  for (var pluginName in namesToPlugins) {
+    var pluginModule = namesToPlugins[pluginName];
+    var pluginIndex = eventPluginOrder.indexOf(pluginName);
+    invariant(
+      pluginIndex > -1,
+      'EventPluginRegistry: Cannot inject event plugins that do not exist in ' +
+        'the plugin ordering, `%s`.',
+      pluginName,
+    );
+    if (EventPluginRegistry.plugins[pluginIndex]) {
+      continue;
+    }
+    invariant(
+      pluginModule.extractEvents,
+      'EventPluginRegistry: Event plugins must implement an `extractEvents` ' +
+        'method, but `%s` does not.',
+      pluginName,
+    );
+    EventPluginRegistry.plugins[pluginIndex] = pluginModule;
+    var publishedEvents = pluginModule.eventTypes;
+    for (var eventName in publishedEvents) {
+      invariant(
+        publishEventForPlugin(
+          publishedEvents[eventName],
+          pluginModule,
+          eventName,
+        ),
+        'EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.',
+        eventName,
+        pluginName,
+      );
+    }
+  }
+}
+
+/**
+ * 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: DispatchConfig,
+  pluginModule: PluginModule<AnyNativeEvent>,
+  eventName: string,
+): boolean {
+  invariant(
+    !EventPluginRegistry.eventNameDispatchConfigs.hasOwnProperty(eventName),
+    'EventPluginHub: More than one plugin attempted to publish the same ' +
+      'event name, `%s`.',
+    eventName,
+  );
+  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: string,
+  pluginModule: PluginModule<AnyNativeEvent>,
+  eventName: string,
+): void {
+  invariant(
+    !EventPluginRegistry.registrationNameModules[registrationName],
+    'EventPluginHub: More than one plugin attempted to publish the same ' +
+      'registration name, `%s`.',
+    registrationName,
+  );
+  EventPluginRegistry.registrationNameModules[registrationName] = pluginModule;
+  EventPluginRegistry.registrationNameDependencies[registrationName] =
+    pluginModule.eventTypes[eventName].dependencies;
+
+  if (__DEV__) {
+    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: __DEV__ ? {} : (null: any),
+  // 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,
+  ): void {
+    invariant(
+      !eventPluginOrder,
+      'EventPluginRegistry: Cannot inject event plugin ordering more than ' +
+        'once. You are likely trying to load more than one copy of React.',
+    );
+    // 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: NamesToPlugins,
+  ): void {
+    var isOrderingDirty = false;
+    for (var pluginName in injectedNamesToPlugins) {
+      if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) {
+        continue;
+      }
+      var pluginModule = injectedNamesToPlugins[pluginName];
+      if (
+        !namesToPlugins.hasOwnProperty(pluginName) ||
+        namesToPlugins[pluginName] !== pluginModule
+      ) {
+        invariant(
+          !namesToPlugins[pluginName],
+          'EventPluginRegistry: Cannot inject two different event plugins ' +
+            'using the same name, `%s`.',
+          pluginName,
+        );
+        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: ReactSyntheticEvent,
+  ): null | PluginModule<AnyNativeEvent> {
+    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;
+      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(): void {
+    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 (__DEV__) {
+      var possibleRegistrationNames =
+        EventPluginRegistry.possibleRegistrationNames;
+      for (var lowerCasedName in possibleRegistrationNames) {
+        if (possibleRegistrationNames.hasOwnProperty(lowerCasedName)) {
+          delete possibleRegistrationNames[lowerCasedName];
+        }
+      }
+    }
+  },
+};
+
+module.exports = EventPluginRegistry;
diff --git a/src/renderers/shared/event/EventPluginUtils.js b/src/renderers/shared/stack/event/EventPluginUtils.js
similarity index 84%
rename from src/renderers/shared/event/EventPluginUtils.js
rename to src/renderers/shared/stack/event/EventPluginUtils.js
index f7e8efe12f5e..cd4531e40b7b 100644
--- a/src/renderers/shared/event/EventPluginUtils.js
+++ b/src/renderers/shared/stack/event/EventPluginUtils.js
@@ -11,7 +11,6 @@
 
 'use strict';
 
-var EventConstants = require('EventConstants');
 var ReactErrorUtils = require('ReactErrorUtils');
 
 var invariant = require('invariant');
@@ -33,10 +32,10 @@ var injection = {
     if (__DEV__) {
       warning(
         Injected &&
-        Injected.getNodeFromInstance &&
-        Injected.getInstanceFromNode,
+          Injected.getNodeFromInstance &&
+          Injected.getInstanceFromNode,
         'EventPluginUtils.injection.injectComponentTree(...): Injected ' +
-        'module is missing getNodeFromInstance or getInstanceFromNode.'
+          'module is missing getNodeFromInstance or getInstanceFromNode.',
       );
     }
   },
@@ -46,30 +45,27 @@ var injection = {
       warning(
         Injected && Injected.isAncestor && Injected.getLowestCommonAncestor,
         'EventPluginUtils.injection.injectTreeTraversal(...): Injected ' +
-        'module is missing isAncestor or getLowestCommonAncestor.'
+          'module is missing isAncestor or getLowestCommonAncestor.',
       );
     }
   },
 };
 
-var topLevelTypes = EventConstants.topLevelTypes;
-
 function isEndish(topLevelType) {
-  return topLevelType === topLevelTypes.topMouseUp ||
-         topLevelType === topLevelTypes.topTouchEnd ||
-         topLevelType === topLevelTypes.topTouchCancel;
+  return (
+    topLevelType === 'topMouseUp' ||
+    topLevelType === 'topTouchEnd' ||
+    topLevelType === 'topTouchCancel'
+  );
 }
 
 function isMoveish(topLevelType) {
-  return topLevelType === topLevelTypes.topMouseMove ||
-         topLevelType === topLevelTypes.topTouchMove;
+  return topLevelType === 'topMouseMove' || topLevelType === 'topTouchMove';
 }
 function isStartish(topLevelType) {
-  return topLevelType === topLevelTypes.topMouseDown ||
-         topLevelType === topLevelTypes.topTouchStart;
+  return topLevelType === 'topMouseDown' || topLevelType === 'topTouchStart';
 }
 
-
 var validateEventDispatches;
 if (__DEV__) {
   validateEventDispatches = function(event) {
@@ -77,18 +73,18 @@ if (__DEV__) {
     var dispatchInstances = event._dispatchInstances;
 
     var listenersIsArr = Array.isArray(dispatchListeners);
-    var listenersLen = listenersIsArr ?
-      dispatchListeners.length :
-      dispatchListeners ? 1 : 0;
+    var listenersLen = listenersIsArr
+      ? dispatchListeners.length
+      : dispatchListeners ? 1 : 0;
 
     var instancesIsArr = Array.isArray(dispatchInstances);
-    var instancesLen = instancesIsArr ?
-      dispatchInstances.length :
-      dispatchInstances ? 1 : 0;
+    var instancesLen = instancesIsArr
+      ? dispatchInstances.length
+      : dispatchInstances ? 1 : 0;
 
     warning(
       instancesIsArr === listenersIsArr && instancesLen === listenersLen,
-      'EventPluginUtils: Invalid `event`.'
+      'EventPluginUtils: Invalid `event`.',
     );
   };
 }
@@ -104,11 +100,7 @@ function executeDispatch(event, simulated, listener, inst) {
   var type = event.type || 'unknown-event';
   event.currentTarget = EventPluginUtils.getNodeFromInstance(inst);
   if (simulated) {
-    ReactErrorUtils.invokeGuardedCallbackWithCatch(
-      type,
-      listener,
-      event
-    );
+    ReactErrorUtils.invokeGuardedCallbackWithCatch(type, listener, event);
   } else {
     ReactErrorUtils.invokeGuardedCallback(type, listener, event);
   }
@@ -134,7 +126,7 @@ function executeDispatchesInOrder(event, simulated) {
         event,
         simulated,
         dispatchListeners[i],
-        dispatchInstances[i]
+        dispatchInstances[i],
       );
     }
   } else if (dispatchListeners) {
@@ -202,9 +194,11 @@ function executeDirectDispatch(event) {
   var dispatchInstance = event._dispatchInstances;
   invariant(
     !Array.isArray(dispatchListener),
-    'executeDirectDispatch(...): Invalid `event`.'
+    'executeDirectDispatch(...): Invalid `event`.',
   );
-  event.currentTarget = EventPluginUtils.getNodeFromInstance(dispatchInstance);
+  event.currentTarget = dispatchListener
+    ? EventPluginUtils.getNodeFromInstance(dispatchInstance)
+    : null;
   var res = dispatchListener ? dispatchListener(event) : null;
   event.currentTarget = null;
   event._dispatchListeners = null;
diff --git a/src/renderers/shared/event/EventPropagators.js b/src/renderers/shared/stack/event/EventPropagators.js
similarity index 87%
rename from src/renderers/shared/event/EventPropagators.js
rename to src/renderers/shared/stack/event/EventPropagators.js
index 95cc188261ec..ec0766729afe 100644
--- a/src/renderers/shared/event/EventPropagators.js
+++ b/src/renderers/shared/stack/event/EventPropagators.js
@@ -11,7 +11,6 @@
 
 'use strict';
 
-var EventConstants = require('EventConstants');
 var EventPluginHub = require('EventPluginHub');
 var EventPluginUtils = require('EventPluginUtils');
 
@@ -19,14 +18,15 @@ var accumulateInto = require('accumulateInto');
 var forEachAccumulated = require('forEachAccumulated');
 var warning = require('warning');
 
-var PropagationPhases = EventConstants.PropagationPhases;
+import type {PropagationPhases} from 'EventConstants';
+
 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) {
+function listenerAtPhase(inst, event, propagationPhase: PropagationPhases) {
   var registrationName =
     event.dispatchConfig.phasedRegistrationNames[propagationPhase];
   return getListener(inst, registrationName);
@@ -38,18 +38,16 @@ function listenerAtPhase(inst, event, propagationPhase) {
  * 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, upwards, event) {
+function accumulateDirectionalDispatches(inst, phase, event) {
   if (__DEV__) {
-    warning(
-      inst,
-      'Dispatching inst must not be null'
-    );
+    warning(inst, 'Dispatching inst must not be null');
   }
-  var phase = upwards ? PropagationPhases.bubbled : PropagationPhases.captured;
   var listener = listenerAtPhase(inst, event, phase);
   if (listener) {
-    event._dispatchListeners =
-      accumulateInto(event._dispatchListeners, listener);
+    event._dispatchListeners = accumulateInto(
+      event._dispatchListeners,
+      listener,
+    );
     event._dispatchInstances = accumulateInto(event._dispatchInstances, inst);
   }
 }
@@ -66,7 +64,7 @@ function accumulateTwoPhaseDispatchesSingle(event) {
     EventPluginUtils.traverseTwoPhase(
       event._targetInst,
       accumulateDirectionalDispatches,
-      event
+      event,
     );
   }
 }
@@ -77,17 +75,17 @@ function accumulateTwoPhaseDispatchesSingle(event) {
 function accumulateTwoPhaseDispatchesSingleSkipTarget(event) {
   if (event && event.dispatchConfig.phasedRegistrationNames) {
     var targetInst = event._targetInst;
-    var parentInst =
-      targetInst ? EventPluginUtils.getParentInstance(targetInst) : null;
+    var parentInst = targetInst
+      ? EventPluginUtils.getParentInstance(targetInst)
+      : null;
     EventPluginUtils.traverseTwoPhase(
       parentInst,
       accumulateDirectionalDispatches,
-      event
+      event,
     );
   }
 }
 
-
 /**
  * Accumulates without regard to direction, does not look for phased
  * registration names. Same as `accumulateDirectDispatchesSingle` but without
@@ -98,8 +96,10 @@ function accumulateDispatches(inst, ignoredDirection, event) {
     var registrationName = event.dispatchConfig.registrationName;
     var listener = getListener(inst, registrationName);
     if (listener) {
-      event._dispatchListeners =
-        accumulateInto(event._dispatchListeners, listener);
+      event._dispatchListeners = accumulateInto(
+        event._dispatchListeners,
+        listener,
+      );
       event._dispatchInstances = accumulateInto(event._dispatchInstances, inst);
     }
   }
@@ -130,17 +130,14 @@ function accumulateEnterLeaveDispatches(leave, enter, from, to) {
     to,
     accumulateDispatches,
     leave,
-    enter
+    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
diff --git a/src/renderers/shared/stack/event/PluginModuleType.js b/src/renderers/shared/stack/event/PluginModuleType.js
new file mode 100644
index 000000000000..bfcdbb0c1cec
--- /dev/null
+++ b/src/renderers/shared/stack/event/PluginModuleType.js
@@ -0,0 +1,42 @@
+/**
+ * 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 PluginModuleType
+ * @flow
+ */
+
+'use strict';
+
+import type {ReactInstance} from 'ReactInstanceType';
+import type {
+  DispatchConfig,
+  ReactSyntheticEvent,
+} from 'ReactSyntheticEventType';
+
+export type EventTypes = {[key: string]: DispatchConfig};
+
+export type AnyNativeEvent = Event | KeyboardEvent | MouseEvent | Touch;
+
+export type PluginName = string;
+
+export type PluginModule<NativeEvent> = {
+  eventTypes: EventTypes,
+  extractEvents: (
+    topLevelType: string,
+    targetInst: ReactInstance,
+    nativeTarget: NativeEvent,
+    nativeEventTarget: EventTarget,
+  ) => null | ReactSyntheticEvent,
+  didPutListener?: (
+    inst: ReactInstance,
+    registrationName: string,
+    listener: () => void,
+  ) => void,
+  willDeleteListener?: (inst: ReactInstance, registrationName: string) => void,
+  tapMoveThreshold?: number,
+};
diff --git a/src/renderers/shared/stack/event/ReactSyntheticEventType.js b/src/renderers/shared/stack/event/ReactSyntheticEventType.js
new file mode 100644
index 000000000000..79dd3229e91b
--- /dev/null
+++ b/src/renderers/shared/stack/event/ReactSyntheticEventType.js
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ *
+ * Flow type for SyntheticEvent class that includes private properties
+ *
+ * @providesModule ReactSyntheticEventType
+ * @flow
+ */
+
+'use strict';
+
+import type {ReactInstance} from 'ReactInstanceType';
+
+export type DispatchConfig = {
+  dependencies: Array<string>,
+  phasedRegistrationNames?: {
+    bubbled: string,
+    captured: string,
+  },
+  registrationName?: string,
+};
+
+export type ReactSyntheticEvent = {
+  dispatchConfig: DispatchConfig,
+  getPooled: (
+    dispatchConfig: DispatchConfig,
+    targetInst: ReactInstance,
+    nativeTarget: Event,
+    nativeEventTarget: EventTarget,
+  ) => ReactSyntheticEvent,
+} & SyntheticEvent;
diff --git a/src/renderers/dom/client/syntheticEvents/SyntheticEvent.js b/src/renderers/shared/stack/event/SyntheticEvent.js
similarity index 75%
rename from src/renderers/dom/client/syntheticEvents/SyntheticEvent.js
rename to src/renderers/shared/stack/event/SyntheticEvent.js
index d3cdf3c399d3..8325c734e023 100644
--- a/src/renderers/dom/client/syntheticEvents/SyntheticEvent.js
+++ b/src/renderers/shared/stack/event/SyntheticEvent.js
@@ -66,7 +66,12 @@ var EventInterface = {
  * @param {object} nativeEvent Native browser event.
  * @param {DOMEventTarget} nativeEventTarget Target node.
  */
-function SyntheticEvent(dispatchConfig, targetInst, nativeEvent, nativeEventTarget) {
+function SyntheticEvent(
+  dispatchConfig,
+  targetInst,
+  nativeEvent,
+  nativeEventTarget,
+) {
   if (__DEV__) {
     // these have a getter/setter for warnings
     delete this.nativeEvent;
@@ -98,9 +103,9 @@ function SyntheticEvent(dispatchConfig, targetInst, nativeEvent, nativeEventTarg
     }
   }
 
-  var defaultPrevented = nativeEvent.defaultPrevented != null ?
-    nativeEvent.defaultPrevented :
-    nativeEvent.returnValue === false;
+  var defaultPrevented = nativeEvent.defaultPrevented != null
+    ? nativeEvent.defaultPrevented
+    : nativeEvent.returnValue === false;
   if (defaultPrevented) {
     this.isDefaultPrevented = emptyFunction.thatReturnsTrue;
   } else {
@@ -111,7 +116,6 @@ function SyntheticEvent(dispatchConfig, targetInst, nativeEvent, nativeEventTarg
 }
 
 Object.assign(SyntheticEvent.prototype, {
-
   preventDefault: function() {
     this.defaultPrevented = true;
     var event = this.nativeEvent;
@@ -121,7 +125,8 @@ Object.assign(SyntheticEvent.prototype, {
 
     if (event.preventDefault) {
       event.preventDefault();
-    } else {
+      // eslint-disable-next-line valid-typeof
+    } else if (typeof event.returnValue !== 'unknown') {
       event.returnValue = false;
     }
     this.isDefaultPrevented = emptyFunction.thatReturnsTrue;
@@ -135,9 +140,16 @@ Object.assign(SyntheticEvent.prototype, {
 
     if (event.stopPropagation) {
       event.stopPropagation();
-    } else {
+      // 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;
   },
 
@@ -164,7 +176,11 @@ Object.assign(SyntheticEvent.prototype, {
     var Interface = this.constructor.Interface;
     for (var propName in Interface) {
       if (__DEV__) {
-        Object.defineProperty(this, propName, getPooledWarningPropertyDefinition(propName, Interface[propName]));
+        Object.defineProperty(
+          this,
+          propName,
+          getPooledWarningPropertyDefinition(propName, Interface[propName]),
+        );
       } else {
         this[propName] = null;
       }
@@ -173,13 +189,23 @@ Object.assign(SyntheticEvent.prototype, {
       this[shouldBeReleasedProperties[i]] = null;
     }
     if (__DEV__) {
-      var noop = require('emptyFunction');
-      Object.defineProperty(this, 'nativeEvent', getPooledWarningPropertyDefinition('nativeEvent', null));
-      Object.defineProperty(this, 'preventDefault', getPooledWarningPropertyDefinition('preventDefault', noop));
-      Object.defineProperty(this, 'stopPropagation', getPooledWarningPropertyDefinition('stopPropagation', noop));
+      Object.defineProperty(
+        this,
+        'nativeEvent',
+        getPooledWarningPropertyDefinition('nativeEvent', null),
+      );
+      Object.defineProperty(
+        this,
+        'preventDefault',
+        getPooledWarningPropertyDefinition('preventDefault', emptyFunction),
+      );
+      Object.defineProperty(
+        this,
+        'stopPropagation',
+        getPooledWarningPropertyDefinition('stopPropagation', emptyFunction),
+      );
     }
   },
-
 });
 
 SyntheticEvent.Interface = EventInterface;
@@ -194,15 +220,17 @@ if (__DEV__) {
       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) {
+            if (
+              prop !== 'isPersistent' &&
+              !target.constructor.Interface.hasOwnProperty(prop) &&
+              shouldBeReleasedProperties.indexOf(prop) === -1
+            ) {
               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.'
+                "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.',
               );
               didWarnForAddedNewProperty = true;
             }
@@ -265,7 +293,9 @@ function getPooledWarningPropertyDefinition(propName, getVal) {
 
   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';
+    var result = isFunction
+      ? 'This is a no-op function'
+      : 'This is set to null';
     warn(action, result);
     return getVal;
   }
@@ -274,13 +304,13 @@ function getPooledWarningPropertyDefinition(propName, getVal) {
     var warningCondition = false;
     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.',
+      "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
+      result,
     );
   }
 }
diff --git a/src/renderers/shared/event/__tests__/EventPluginHub-test.js b/src/renderers/shared/stack/event/__tests__/EventPluginHub-test.js
similarity index 77%
rename from src/renderers/shared/event/__tests__/EventPluginHub-test.js
rename to src/renderers/shared/stack/event/__tests__/EventPluginHub-test.js
index 5dc566c74b76..7f9598f2b50f 100644
--- a/src/renderers/shared/event/__tests__/EventPluginHub-test.js
+++ b/src/renderers/shared/stack/event/__tests__/EventPluginHub-test.js
@@ -11,26 +11,24 @@
 
 'use strict';
 
-jest
-  .dontMock('EventPluginHub')
-  .mock('isEventSupported');
+jest.mock('isEventSupported');
 
-describe('EventPluginHub', function() {
+describe('EventPluginHub', () => {
   var EventPluginHub;
   var isEventSupported;
 
-  beforeEach(function() {
+  beforeEach(() => {
     jest.resetModuleRegistry();
     EventPluginHub = require('EventPluginHub');
     isEventSupported = require('isEventSupported');
     isEventSupported.mockReturnValueOnce(false);
   });
 
-  it('should prevent non-function listeners', function() {
+  it('should prevent non-function listeners', () => {
     expect(function() {
       EventPluginHub.putListener(1, 'onClick', 'not a function');
-    }).toThrow(
-      'Expected onClick listener to be a function, instead got type string'
+    }).toThrowError(
+      'Expected onClick listener to be a function, instead got type string',
     );
   });
 });
diff --git a/src/renderers/shared/event/__tests__/EventPluginRegistry-test.js b/src/renderers/shared/stack/event/__tests__/EventPluginRegistry-test.js
similarity index 81%
rename from src/renderers/shared/event/__tests__/EventPluginRegistry-test.js
rename to src/renderers/shared/stack/event/__tests__/EventPluginRegistry-test.js
index 7f06e58c1302..7e068e214f6d 100644
--- a/src/renderers/shared/event/__tests__/EventPluginRegistry-test.js
+++ b/src/renderers/shared/stack/event/__tests__/EventPluginRegistry-test.js
@@ -11,12 +11,11 @@
 
 'use strict';
 
-
-describe('EventPluginRegistry', function() {
+describe('EventPluginRegistry', () => {
   var EventPluginRegistry;
   var createPlugin;
 
-  beforeEach(function() {
+  beforeEach(() => {
     EventPluginRegistry = require('EventPluginRegistry');
     EventPluginRegistry._resetEventPlugins();
 
@@ -25,7 +24,7 @@ describe('EventPluginRegistry', function() {
     };
   });
 
-  it('should be able to inject ordering before plugins', function() {
+  it('should be able to inject ordering before plugins', () => {
     var OnePlugin = createPlugin();
     var TwoPlugin = createPlugin();
     var ThreePlugin = createPlugin();
@@ -45,7 +44,7 @@ describe('EventPluginRegistry', function() {
     expect(EventPluginRegistry.plugins[2]).toBe(ThreePlugin);
   });
 
-  it('should be able to inject plugins before and after ordering', function() {
+  it('should be able to inject plugins before and after ordering', () => {
     var OnePlugin = createPlugin();
     var TwoPlugin = createPlugin();
     var ThreePlugin = createPlugin();
@@ -65,7 +64,7 @@ describe('EventPluginRegistry', function() {
     expect(EventPluginRegistry.plugins[2]).toBe(ThreePlugin);
   });
 
-  it('should be able to inject repeated plugins and out-of-order', function() {
+  it('should be able to inject repeated plugins and out-of-order', () => {
     var OnePlugin = createPlugin();
     var TwoPlugin = createPlugin();
     var ThreePlugin = createPlugin();
@@ -86,7 +85,7 @@ describe('EventPluginRegistry', function() {
     expect(EventPluginRegistry.plugins[2]).toBe(ThreePlugin);
   });
 
-  it('should throw if plugin does not implement `extractEvents`', function() {
+  it('should throw if plugin does not implement `extractEvents`', () => {
     var BadPlugin = {};
 
     EventPluginRegistry.injectEventPluginOrder(['bad']);
@@ -95,13 +94,13 @@ describe('EventPluginRegistry', function() {
       EventPluginRegistry.injectEventPluginsByName({
         bad: BadPlugin,
       });
-    }).toThrow(
+    }).toThrowError(
       'EventPluginRegistry: Event plugins must implement an `extractEvents` ' +
-      'method, but `bad` does not.'
+        'method, but `bad` does not.',
     );
   });
 
-  it('should throw if plugin does not exist in ordering', function() {
+  it('should throw if plugin does not exist in ordering', () => {
     var OnePlugin = createPlugin();
     var RandomPlugin = createPlugin();
 
@@ -112,26 +111,26 @@ describe('EventPluginRegistry', function() {
         one: OnePlugin,
         random: RandomPlugin,
       });
-    }).toThrow(
+    }).toThrowError(
       'EventPluginRegistry: Cannot inject event plugins that do not exist ' +
-      'in the plugin ordering, `random`.'
+        'in the plugin ordering, `random`.',
     );
   });
 
-  it('should throw if ordering is injected more than once', function() {
+  it('should throw if ordering is injected more than once', () => {
     var pluginOrdering = [];
 
     EventPluginRegistry.injectEventPluginOrder(pluginOrdering);
 
     expect(function() {
       EventPluginRegistry.injectEventPluginOrder(pluginOrdering);
-    }).toThrow(
+    }).toThrowError(
       'EventPluginRegistry: Cannot inject event plugin ordering more than ' +
-      'once. You are likely trying to load more than one copy of React.'
+        'once. You are likely trying to load more than one copy of React.',
     );
   });
 
-  it('should throw if different plugins injected using same name', function() {
+  it('should throw if different plugins injected using same name', () => {
     var OnePlugin = createPlugin();
     var TwoPlugin = createPlugin();
 
@@ -139,13 +138,13 @@ describe('EventPluginRegistry', function() {
 
     expect(function() {
       EventPluginRegistry.injectEventPluginsByName({same: TwoPlugin});
-    }).toThrow(
+    }).toThrowError(
       'EventPluginRegistry: Cannot inject two different event plugins using ' +
-      'the same name, `same`.'
+        'the same name, `same`.',
     );
   });
 
-  it('should publish registration names of injected plugins', function() {
+  it('should publish registration names of injected plugins', () => {
     var OnePlugin = createPlugin({
       eventTypes: {
         click: {registrationName: 'onClick'},
@@ -166,20 +165,26 @@ describe('EventPluginRegistry', function() {
     EventPluginRegistry.injectEventPluginsByName({one: OnePlugin});
     EventPluginRegistry.injectEventPluginOrder(['one', 'two']);
 
-    expect(Object.keys(EventPluginRegistry.registrationNameModules).length).toBe(2);
+    expect(
+      Object.keys(EventPluginRegistry.registrationNameModules).length,
+    ).toBe(2);
     expect(EventPluginRegistry.registrationNameModules.onClick).toBe(OnePlugin);
     expect(EventPluginRegistry.registrationNameModules.onFocus).toBe(OnePlugin);
 
     EventPluginRegistry.injectEventPluginsByName({two: TwoPlugin});
 
-    expect(Object.keys(EventPluginRegistry.registrationNameModules).length).toBe(4);
-    expect(EventPluginRegistry.registrationNameModules.onMagicBubble).toBe(TwoPlugin);
     expect(
-      EventPluginRegistry.registrationNameModules.onMagicCapture
-    ).toBe(TwoPlugin);
+      Object.keys(EventPluginRegistry.registrationNameModules).length,
+    ).toBe(4);
+    expect(EventPluginRegistry.registrationNameModules.onMagicBubble).toBe(
+      TwoPlugin,
+    );
+    expect(EventPluginRegistry.registrationNameModules.onMagicCapture).toBe(
+      TwoPlugin,
+    );
   });
 
-  it('should throw if multiple registration names collide', function() {
+  it('should throw if multiple registration names collide', () => {
     var OnePlugin = createPlugin({
       eventTypes: {
         photoCapture: {registrationName: 'onPhotoCapture'},
@@ -203,16 +208,18 @@ describe('EventPluginRegistry', function() {
 
     expect(function() {
       EventPluginRegistry.injectEventPluginOrder(['one', 'two']);
-    }).toThrow(
+    }).toThrowError(
       'EventPluginHub: More than one plugin attempted to publish the same ' +
-      'registration name, `onPhotoCapture`.'
+        'registration name, `onPhotoCapture`.',
     );
   });
 
-  it('should throw if an invalid event is published', function() {
+  it('should throw if an invalid event is published', () => {
     var OnePlugin = createPlugin({
       eventTypes: {
-        badEvent: {/* missing configuration */},
+        badEvent: {
+          /* missing configuration */
+        },
       },
     });
 
@@ -220,13 +227,13 @@ describe('EventPluginRegistry', function() {
 
     expect(function() {
       EventPluginRegistry.injectEventPluginOrder(['one']);
-    }).toThrow(
+    }).toThrowError(
       'EventPluginRegistry: Failed to publish event `badEvent` for plugin ' +
-      '`one`.'
+        '`one`.',
     );
   });
 
-  it('should be able to get the plugin from synthetic events', function() {
+  it('should be able to get the plugin from synthetic events', () => {
     var clickDispatchConfig = {
       registrationName: 'onClick',
     };
@@ -253,12 +260,11 @@ describe('EventPluginRegistry', function() {
     EventPluginRegistry.injectEventPluginsByName({one: OnePlugin});
     EventPluginRegistry.injectEventPluginOrder(['one']);
 
-    expect(
-      EventPluginRegistry.getPluginModuleForEvent(clickEvent)
-    ).toBe(OnePlugin);
-    expect(
-      EventPluginRegistry.getPluginModuleForEvent(magicEvent)
-    ).toBe(OnePlugin);
+    expect(EventPluginRegistry.getPluginModuleForEvent(clickEvent)).toBe(
+      OnePlugin,
+    );
+    expect(EventPluginRegistry.getPluginModuleForEvent(magicEvent)).toBe(
+      OnePlugin,
+    );
   });
-
 });
diff --git a/src/renderers/shared/event/eventPlugins/ResponderEventPlugin.js b/src/renderers/shared/stack/event/eventPlugins/ResponderEventPlugin.js
similarity index 85%
rename from src/renderers/shared/event/eventPlugins/ResponderEventPlugin.js
rename to src/renderers/shared/stack/event/eventPlugins/ResponderEventPlugin.js
index d673b8addf6d..15601903bde7 100644
--- a/src/renderers/shared/event/eventPlugins/ResponderEventPlugin.js
+++ b/src/renderers/shared/stack/event/eventPlugins/ResponderEventPlugin.js
@@ -11,15 +11,12 @@
 
 'use strict';
 
-var EventConstants = require('EventConstants');
 var EventPluginUtils = require('EventPluginUtils');
 var EventPropagators = require('EventPropagators');
 var ResponderSyntheticEvent = require('ResponderSyntheticEvent');
 var ResponderTouchHistoryStore = require('ResponderTouchHistoryStore');
 
 var accumulate = require('accumulate');
-var invariant = require('invariant');
-var keyOf = require('keyOf');
 
 var isStartish = EventPluginUtils.isStartish;
 var isMoveish = EventPluginUtils.isMoveish;
@@ -46,14 +43,14 @@ var trackedTouchCount = 0;
  */
 var previousActiveTouches = 0;
 
-var changeResponder = function(nextResponderInst, blockNativeResponder) {
+var changeResponder = function(nextResponderInst, blockHostResponder) {
   var oldResponderInst = responderInst;
   responderInst = nextResponderInst;
   if (ResponderEventPlugin.GlobalResponderHandler !== null) {
     ResponderEventPlugin.GlobalResponderHandler.onChange(
       oldResponderInst,
       nextResponderInst,
-      blockNativeResponder
+      blockHostResponder,
     );
   }
 };
@@ -65,8 +62,8 @@ var eventTypes = {
    */
   startShouldSetResponder: {
     phasedRegistrationNames: {
-      bubbled: keyOf({onStartShouldSetResponder: null}),
-      captured: keyOf({onStartShouldSetResponderCapture: null}),
+      bubbled: 'onStartShouldSetResponder',
+      captured: 'onStartShouldSetResponderCapture',
     },
   },
 
@@ -81,8 +78,8 @@ var eventTypes = {
    */
   scrollShouldSetResponder: {
     phasedRegistrationNames: {
-      bubbled: keyOf({onScrollShouldSetResponder: null}),
-      captured: keyOf({onScrollShouldSetResponderCapture: null}),
+      bubbled: 'onScrollShouldSetResponder',
+      captured: 'onScrollShouldSetResponderCapture',
     },
   },
 
@@ -95,8 +92,8 @@ var eventTypes = {
    */
   selectionChangeShouldSetResponder: {
     phasedRegistrationNames: {
-      bubbled: keyOf({onSelectionChangeShouldSetResponder: null}),
-      captured: keyOf({onSelectionChangeShouldSetResponderCapture: null}),
+      bubbled: 'onSelectionChangeShouldSetResponder',
+      captured: 'onSelectionChangeShouldSetResponderCapture',
     },
   },
 
@@ -106,24 +103,24 @@ var eventTypes = {
    */
   moveShouldSetResponder: {
     phasedRegistrationNames: {
-      bubbled: keyOf({onMoveShouldSetResponder: null}),
-      captured: keyOf({onMoveShouldSetResponderCapture: null}),
+      bubbled: 'onMoveShouldSetResponder',
+      captured: 'onMoveShouldSetResponderCapture',
     },
   },
 
   /**
    * Direct responder events dispatched directly to responder. Do not bubble.
    */
-  responderStart: {registrationName: keyOf({onResponderStart: null})},
-  responderMove: {registrationName: keyOf({onResponderMove: null})},
-  responderEnd: {registrationName: keyOf({onResponderEnd: null})},
-  responderRelease: {registrationName: keyOf({onResponderRelease: null})},
+  responderStart: {registrationName: 'onResponderStart'},
+  responderMove: {registrationName: 'onResponderMove'},
+  responderEnd: {registrationName: 'onResponderEnd'},
+  responderRelease: {registrationName: 'onResponderRelease'},
   responderTerminationRequest: {
-    registrationName: keyOf({onResponderTerminationRequest: null}),
+    registrationName: 'onResponderTerminationRequest',
   },
-  responderGrant: {registrationName: keyOf({onResponderGrant: null})},
-  responderReject: {registrationName: keyOf({onResponderReject: null})},
-  responderTerminate: {registrationName: keyOf({onResponderTerminate: null})},
+  responderGrant: {registrationName: 'onResponderGrant'},
+  responderReject: {registrationName: 'onResponderReject'},
+  responderTerminate: {registrationName: 'onResponderTerminate'},
 };
 
 /**
@@ -256,8 +253,6 @@ to return true:wantsResponderID|                            |
                                |                            |
                                +                            + */
 
-
-
 /**
  * A note about event ordering in the `EventPluginHub`.
  *
@@ -322,19 +317,20 @@ function setResponderAndExtractTransfer(
   topLevelType,
   targetInst,
   nativeEvent,
-  nativeEventTarget
+  nativeEventTarget,
 ) {
-  var shouldSetEventType =
-    isStartish(topLevelType) ? eventTypes.startShouldSetResponder :
-    isMoveish(topLevelType) ? eventTypes.moveShouldSetResponder :
-    topLevelType === EventConstants.topLevelTypes.topSelectionChange ?
-      eventTypes.selectionChangeShouldSetResponder :
-    eventTypes.scrollShouldSetResponder;
+  var shouldSetEventType = isStartish(topLevelType)
+    ? eventTypes.startShouldSetResponder
+    : isMoveish(topLevelType)
+      ? eventTypes.moveShouldSetResponder
+      : topLevelType === 'topSelectionChange'
+        ? eventTypes.selectionChangeShouldSetResponder
+        : eventTypes.scrollShouldSetResponder;
 
   // TODO: stop one short of the current responder.
-  var bubbleShouldSetFrom = !responderInst ?
-    targetInst :
-    EventPluginUtils.getLowestCommonAncestor(responderInst, targetInst);
+  var bubbleShouldSetFrom = !responderInst
+    ? targetInst
+    : EventPluginUtils.getLowestCommonAncestor(responderInst, targetInst);
 
   // When capturing/bubbling the "shouldSet" event, we want to skip the target
   // (deepest ID) if it happens to be the current responder. The reasoning:
@@ -345,7 +341,7 @@ function setResponderAndExtractTransfer(
     shouldSetEventType,
     bubbleShouldSetFrom,
     nativeEvent,
-    nativeEventTarget
+    nativeEventTarget,
   );
   shouldSetEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
   if (skipOverBubbleShouldSetFrom) {
@@ -366,23 +362,24 @@ function setResponderAndExtractTransfer(
     eventTypes.responderGrant,
     wantsResponderInst,
     nativeEvent,
-    nativeEventTarget
+    nativeEventTarget,
   );
   grantEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
 
   EventPropagators.accumulateDirectDispatches(grantEvent);
-  var blockNativeResponder = executeDirectDispatch(grantEvent) === true;
+  var blockHostResponder = executeDirectDispatch(grantEvent) === true;
   if (responderInst) {
-
     var terminationRequestEvent = ResponderSyntheticEvent.getPooled(
       eventTypes.responderTerminationRequest,
       responderInst,
       nativeEvent,
-      nativeEventTarget
+      nativeEventTarget,
     );
-    terminationRequestEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
+    terminationRequestEvent.touchHistory =
+      ResponderTouchHistoryStore.touchHistory;
     EventPropagators.accumulateDirectDispatches(terminationRequestEvent);
-    var shouldSwitch = !hasDispatches(terminationRequestEvent) ||
+    var shouldSwitch =
+      !hasDispatches(terminationRequestEvent) ||
       executeDirectDispatch(terminationRequestEvent);
     if (!terminationRequestEvent.isPersistent()) {
       terminationRequestEvent.constructor.release(terminationRequestEvent);
@@ -393,18 +390,18 @@ function setResponderAndExtractTransfer(
         eventTypes.responderTerminate,
         responderInst,
         nativeEvent,
-        nativeEventTarget
+        nativeEventTarget,
       );
       terminateEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
       EventPropagators.accumulateDirectDispatches(terminateEvent);
       extracted = accumulate(extracted, [grantEvent, terminateEvent]);
-      changeResponder(wantsResponderInst, blockNativeResponder);
+      changeResponder(wantsResponderInst, blockHostResponder);
     } else {
       var rejectEvent = ResponderSyntheticEvent.getPooled(
         eventTypes.responderReject,
         wantsResponderInst,
         nativeEvent,
-        nativeEventTarget
+        nativeEventTarget,
       );
       rejectEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
       EventPropagators.accumulateDirectDispatches(rejectEvent);
@@ -412,7 +409,7 @@ function setResponderAndExtractTransfer(
     }
   } else {
     extracted = accumulate(extracted, grantEvent);
-    changeResponder(wantsResponderInst, blockNativeResponder);
+    changeResponder(wantsResponderInst, blockHostResponder);
   }
   return extracted;
 }
@@ -426,16 +423,15 @@ function setResponderAndExtractTransfer(
  * @return {boolean} True if a transfer of responder could possibly occur.
  */
 function canTriggerTransfer(topLevelType, topLevelInst, nativeEvent) {
-  return topLevelInst && (
+  return (
+    topLevelInst &&
     // responderIgnoreScroll: We are trying to migrate away from specifically
     // tracking native scroll events here and responderIgnoreScroll indicates we
     // will send topTouchCancel to handle canceling touch events instead
-    (topLevelType === EventConstants.topLevelTypes.topScroll &&
-      !nativeEvent.responderIgnoreScroll) ||
-    (trackedTouchCount > 0 &&
-      topLevelType === EventConstants.topLevelTypes.topSelectionChange) ||
-    isStartish(topLevelType) ||
-    isMoveish(topLevelType)
+    ((topLevelType === 'topScroll' && !nativeEvent.responderIgnoreScroll) ||
+      (trackedTouchCount > 0 && topLevelType === 'topSelectionChange') ||
+      isStartish(topLevelType) ||
+      isMoveish(topLevelType))
   );
 }
 
@@ -465,9 +461,7 @@ function noResponderTouches(nativeEvent) {
   return true;
 }
 
-
 var ResponderEventPlugin = {
-
   /* For unit testing only */
   _getResponderID: function() {
     return responderInst ? responderInst._rootNodeID : null;
@@ -484,27 +478,31 @@ var ResponderEventPlugin = {
     topLevelType,
     targetInst,
     nativeEvent,
-    nativeEventTarget
+    nativeEventTarget,
   ) {
     if (isStartish(topLevelType)) {
       trackedTouchCount += 1;
     } else if (isEndish(topLevelType)) {
-      trackedTouchCount -= 1;
-      invariant(
-        trackedTouchCount >= 0,
-        'Ended a touch event which was not counted in trackedTouchCount.'
-      );
+      if (trackedTouchCount >= 0) {
+        trackedTouchCount -= 1;
+      } else {
+        console.error(
+          'Ended a touch event which was not counted in `trackedTouchCount`.',
+        );
+        return null;
+      }
     }
 
-    ResponderTouchHistoryStore.recordTouchTrack(topLevelType, nativeEvent, nativeEventTarget);
+    ResponderTouchHistoryStore.recordTouchTrack(topLevelType, nativeEvent);
 
-    var extracted = canTriggerTransfer(topLevelType, targetInst, nativeEvent) ?
-      setResponderAndExtractTransfer(
-        topLevelType,
-        targetInst,
-        nativeEvent,
-        nativeEventTarget) :
-      null;
+    var extracted = canTriggerTransfer(topLevelType, targetInst, nativeEvent)
+      ? setResponderAndExtractTransfer(
+          topLevelType,
+          targetInst,
+          nativeEvent,
+          nativeEventTarget,
+        )
+      : null;
     // Responder may or may not have transferred on a new touch start/move.
     // Regardless, whoever is the responder after any potential transfer, we
     // direct all touch start/move/ends to them in the form of
@@ -518,40 +516,40 @@ var ResponderEventPlugin = {
     var isResponderTouchStart = responderInst && isStartish(topLevelType);
     var isResponderTouchMove = responderInst && isMoveish(topLevelType);
     var isResponderTouchEnd = responderInst && isEndish(topLevelType);
-    var incrementalTouch =
-      isResponderTouchStart ? eventTypes.responderStart :
-      isResponderTouchMove ? eventTypes.responderMove :
-      isResponderTouchEnd ? eventTypes.responderEnd :
-      null;
+    var incrementalTouch = isResponderTouchStart
+      ? eventTypes.responderStart
+      : isResponderTouchMove
+        ? eventTypes.responderMove
+        : isResponderTouchEnd ? eventTypes.responderEnd : null;
 
     if (incrementalTouch) {
-      var gesture =
-        ResponderSyntheticEvent.getPooled(
-          incrementalTouch,
-          responderInst,
-          nativeEvent,
-          nativeEventTarget
-        );
+      var gesture = ResponderSyntheticEvent.getPooled(
+        incrementalTouch,
+        responderInst,
+        nativeEvent,
+        nativeEventTarget,
+      );
       gesture.touchHistory = ResponderTouchHistoryStore.touchHistory;
       EventPropagators.accumulateDirectDispatches(gesture);
       extracted = accumulate(extracted, gesture);
     }
 
     var isResponderTerminate =
-      responderInst &&
-      topLevelType === EventConstants.topLevelTypes.topTouchCancel;
+      responderInst && topLevelType === 'topTouchCancel';
     var isResponderRelease =
       responderInst &&
       !isResponderTerminate &&
       isEndish(topLevelType) &&
       noResponderTouches(nativeEvent);
-    var finalTouch =
-      isResponderTerminate ? eventTypes.responderTerminate :
-      isResponderRelease ? eventTypes.responderRelease :
-      null;
+    var finalTouch = isResponderTerminate
+      ? eventTypes.responderTerminate
+      : isResponderRelease ? eventTypes.responderRelease : null;
     if (finalTouch) {
       var finalEvent = ResponderSyntheticEvent.getPooled(
-        finalTouch, responderInst, nativeEvent, nativeEventTarget
+        finalTouch,
+        responderInst,
+        nativeEvent,
+        nativeEventTarget,
       );
       finalEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
       EventPropagators.accumulateDirectDispatches(finalEvent);
@@ -561,10 +559,12 @@ var ResponderEventPlugin = {
 
     var numberActiveTouches =
       ResponderTouchHistoryStore.touchHistory.numberActiveTouches;
-    if (ResponderEventPlugin.GlobalInteractionHandler &&
-      numberActiveTouches !== previousActiveTouches) {
+    if (
+      ResponderEventPlugin.GlobalInteractionHandler &&
+      numberActiveTouches !== previousActiveTouches
+    ) {
       ResponderEventPlugin.GlobalInteractionHandler.onChange(
-        numberActiveTouches
+        numberActiveTouches,
       );
     }
     previousActiveTouches = numberActiveTouches;
diff --git a/src/renderers/shared/event/eventPlugins/ResponderSyntheticEvent.js b/src/renderers/shared/stack/event/eventPlugins/ResponderSyntheticEvent.js
similarity index 82%
rename from src/renderers/shared/event/eventPlugins/ResponderSyntheticEvent.js
rename to src/renderers/shared/stack/event/eventPlugins/ResponderSyntheticEvent.js
index f1cf77feacfc..f8e2132d56af 100644
--- a/src/renderers/shared/event/eventPlugins/ResponderSyntheticEvent.js
+++ b/src/renderers/shared/stack/event/eventPlugins/ResponderSyntheticEvent.js
@@ -30,8 +30,19 @@ var ResponderEventInterface = {
  * @param {object} nativeEvent Native event.
  * @extends {SyntheticEvent}
  */
-function ResponderSyntheticEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget) {
-  return SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget);
+function ResponderSyntheticEvent(
+  dispatchConfig,
+  dispatchMarker,
+  nativeEvent,
+  nativeEventTarget,
+) {
+  return SyntheticEvent.call(
+    this,
+    dispatchConfig,
+    dispatchMarker,
+    nativeEvent,
+    nativeEventTarget,
+  );
 }
 
 SyntheticEvent.augmentClass(ResponderSyntheticEvent, ResponderEventInterface);
diff --git a/src/renderers/shared/stack/event/eventPlugins/ResponderTouchHistoryStore.js b/src/renderers/shared/stack/event/eventPlugins/ResponderTouchHistoryStore.js
new file mode 100644
index 000000000000..5bebd29d1172
--- /dev/null
+++ b/src/renderers/shared/stack/event/eventPlugins/ResponderTouchHistoryStore.js
@@ -0,0 +1,220 @@
+/**
+ * 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 ResponderTouchHistoryStore
+ * @flow
+ */
+
+'use strict';
+
+const EventPluginUtils = require('EventPluginUtils');
+
+const invariant = require('invariant');
+const warning = require('warning');
+
+const {isEndish, isMoveish, isStartish} = EventPluginUtils;
+
+/**
+ * Tracks the position and time of each active touch by `touch.identifier`. We
+ * should typically only see IDs in the range of 1-20 because IDs get recycled
+ * when touches end and start again.
+ */
+type TouchRecord = {
+  touchActive: boolean,
+  startPageX: number,
+  startPageY: number,
+  startTimeStamp: number,
+  currentPageX: number,
+  currentPageY: number,
+  currentTimeStamp: number,
+  previousPageX: number,
+  previousPageY: number,
+  previousTimeStamp: number,
+};
+
+const MAX_TOUCH_BANK = 20;
+const touchBank: Array<TouchRecord> = [];
+const touchHistory = {
+  touchBank,
+  numberActiveTouches: 0,
+  // If there is only one active touch, we remember its location. This prevents
+  // us having to loop through all of the touches all the time in the most
+  // common case.
+  indexOfSingleActiveTouch: -1,
+  mostRecentTimeStamp: 0,
+};
+
+type Touch = {
+  identifier: ?number,
+  pageX: number,
+  pageY: number,
+  timestamp: number,
+};
+type TouchEvent = {
+  changedTouches: Array<Touch>,
+  touches: Array<Touch>,
+};
+
+function timestampForTouch(touch: Touch): number {
+  // The legacy internal implementation provides "timeStamp", which has been
+  // renamed to "timestamp". Let both work for now while we iron it out
+  // TODO (evv): rename timeStamp to timestamp in internal code
+  return (touch: any).timeStamp || touch.timestamp;
+}
+
+/**
+ * TODO: Instead of making gestures recompute filtered velocity, we could
+ * include a built in velocity computation that can be reused globally.
+ */
+function createTouchRecord(touch: Touch): TouchRecord {
+  return {
+    touchActive: true,
+    startPageX: touch.pageX,
+    startPageY: touch.pageY,
+    startTimeStamp: timestampForTouch(touch),
+    currentPageX: touch.pageX,
+    currentPageY: touch.pageY,
+    currentTimeStamp: timestampForTouch(touch),
+    previousPageX: touch.pageX,
+    previousPageY: touch.pageY,
+    previousTimeStamp: timestampForTouch(touch),
+  };
+}
+
+function resetTouchRecord(touchRecord: TouchRecord, touch: Touch): void {
+  touchRecord.touchActive = true;
+  touchRecord.startPageX = touch.pageX;
+  touchRecord.startPageY = touch.pageY;
+  touchRecord.startTimeStamp = timestampForTouch(touch);
+  touchRecord.currentPageX = touch.pageX;
+  touchRecord.currentPageY = touch.pageY;
+  touchRecord.currentTimeStamp = timestampForTouch(touch);
+  touchRecord.previousPageX = touch.pageX;
+  touchRecord.previousPageY = touch.pageY;
+  touchRecord.previousTimeStamp = timestampForTouch(touch);
+}
+
+function getTouchIdentifier({identifier}: Touch): number {
+  invariant(identifier != null, 'Touch object is missing identifier.');
+  warning(
+    identifier <= MAX_TOUCH_BANK,
+    'Touch identifier %s is greater than maximum supported %s which causes ' +
+      'performance issues backfilling array locations for all of the indices.',
+    identifier,
+    MAX_TOUCH_BANK,
+  );
+  return identifier;
+}
+
+function recordTouchStart(touch: Touch): void {
+  const identifier = getTouchIdentifier(touch);
+  const touchRecord = touchBank[identifier];
+  if (touchRecord) {
+    resetTouchRecord(touchRecord, touch);
+  } else {
+    touchBank[identifier] = createTouchRecord(touch);
+  }
+  touchHistory.mostRecentTimeStamp = timestampForTouch(touch);
+}
+
+function recordTouchMove(touch: Touch): void {
+  const touchRecord = touchBank[getTouchIdentifier(touch)];
+  if (touchRecord) {
+    touchRecord.touchActive = true;
+    touchRecord.previousPageX = touchRecord.currentPageX;
+    touchRecord.previousPageY = touchRecord.currentPageY;
+    touchRecord.previousTimeStamp = touchRecord.currentTimeStamp;
+    touchRecord.currentPageX = touch.pageX;
+    touchRecord.currentPageY = touch.pageY;
+    touchRecord.currentTimeStamp = timestampForTouch(touch);
+    touchHistory.mostRecentTimeStamp = timestampForTouch(touch);
+  } else {
+    console.error(
+      'Cannot record touch move without a touch start.\n' + 'Touch Move: %s\n',
+      'Touch Bank: %s',
+      printTouch(touch),
+      printTouchBank(),
+    );
+  }
+}
+
+function recordTouchEnd(touch: Touch): void {
+  const touchRecord = touchBank[getTouchIdentifier(touch)];
+  if (touchRecord) {
+    touchRecord.touchActive = false;
+    touchRecord.previousPageX = touchRecord.currentPageX;
+    touchRecord.previousPageY = touchRecord.currentPageY;
+    touchRecord.previousTimeStamp = touchRecord.currentTimeStamp;
+    touchRecord.currentPageX = touch.pageX;
+    touchRecord.currentPageY = touch.pageY;
+    touchRecord.currentTimeStamp = timestampForTouch(touch);
+    touchHistory.mostRecentTimeStamp = timestampForTouch(touch);
+  } else {
+    console.error(
+      'Cannot record touch end without a touch start.\n' + 'Touch End: %s\n',
+      'Touch Bank: %s',
+      printTouch(touch),
+      printTouchBank(),
+    );
+  }
+}
+
+function printTouch(touch: Touch): string {
+  return JSON.stringify({
+    identifier: touch.identifier,
+    pageX: touch.pageX,
+    pageY: touch.pageY,
+    timestamp: timestampForTouch(touch),
+  });
+}
+
+function printTouchBank(): string {
+  let printed = JSON.stringify(touchBank.slice(0, MAX_TOUCH_BANK));
+  if (touchBank.length > MAX_TOUCH_BANK) {
+    printed += ' (original size: ' + touchBank.length + ')';
+  }
+  return printed;
+}
+
+const ResponderTouchHistoryStore = {
+  recordTouchTrack(topLevelType: string, nativeEvent: TouchEvent): void {
+    if (isMoveish(topLevelType)) {
+      nativeEvent.changedTouches.forEach(recordTouchMove);
+    } else if (isStartish(topLevelType)) {
+      nativeEvent.changedTouches.forEach(recordTouchStart);
+      touchHistory.numberActiveTouches = nativeEvent.touches.length;
+      if (touchHistory.numberActiveTouches === 1) {
+        touchHistory.indexOfSingleActiveTouch =
+          nativeEvent.touches[0].identifier;
+      }
+    } else if (isEndish(topLevelType)) {
+      nativeEvent.changedTouches.forEach(recordTouchEnd);
+      touchHistory.numberActiveTouches = nativeEvent.touches.length;
+      if (touchHistory.numberActiveTouches === 1) {
+        for (let i = 0; i < touchBank.length; i++) {
+          const touchTrackToCheck = touchBank[i];
+          if (touchTrackToCheck != null && touchTrackToCheck.touchActive) {
+            touchHistory.indexOfSingleActiveTouch = i;
+            break;
+          }
+        }
+        if (__DEV__) {
+          const activeRecord = touchBank[touchHistory.indexOfSingleActiveTouch];
+          warning(
+            activeRecord != null && activeRecord.touchActive,
+            'Cannot find single active touch.',
+          );
+        }
+      }
+    }
+  },
+
+  touchHistory,
+};
+
+module.exports = ResponderTouchHistoryStore;
diff --git a/src/renderers/shared/stack/event/eventPlugins/TouchHistoryMath.js b/src/renderers/shared/stack/event/eventPlugins/TouchHistoryMath.js
new file mode 100644
index 000000000000..a841e00af227
--- /dev/null
+++ b/src/renderers/shared/stack/event/eventPlugins/TouchHistoryMath.js
@@ -0,0 +1,148 @@
+/**
+ * @providesModule TouchHistoryMath
+ */
+
+'use strict';
+
+var TouchHistoryMath = {
+  /**
+   * This code is optimized and not intended to look beautiful. This allows
+   * computing of touch centroids that have moved after `touchesChangedAfter`
+   * timeStamp. You can compute the current centroid involving all touches
+   * moves after `touchesChangedAfter`, or you can compute the previous
+   * centroid of all touches that were moved after `touchesChangedAfter`.
+   *
+   * @param {TouchHistoryMath} touchHistory Standard Responder touch track
+   * data.
+   * @param {number} touchesChangedAfter timeStamp after which moved touches
+   * are considered "actively moving" - not just "active".
+   * @param {boolean} isXAxis Consider `x` dimension vs. `y` dimension.
+   * @param {boolean} ofCurrent Compute current centroid for actively moving
+   * touches vs. previous centroid of now actively moving touches.
+   * @return {number} value of centroid in specified dimension.
+   */
+  centroidDimension: function(
+    touchHistory,
+    touchesChangedAfter,
+    isXAxis,
+    ofCurrent,
+  ) {
+    var touchBank = touchHistory.touchBank;
+    var total = 0;
+    var count = 0;
+
+    var oneTouchData = touchHistory.numberActiveTouches === 1
+      ? touchHistory.touchBank[touchHistory.indexOfSingleActiveTouch]
+      : null;
+
+    if (oneTouchData !== null) {
+      if (
+        oneTouchData.touchActive &&
+        oneTouchData.currentTimeStamp > touchesChangedAfter
+      ) {
+        total += ofCurrent && isXAxis
+          ? oneTouchData.currentPageX
+          : ofCurrent && !isXAxis
+            ? oneTouchData.currentPageY
+            : !ofCurrent && isXAxis
+              ? oneTouchData.previousPageX
+              : oneTouchData.previousPageY;
+        count = 1;
+      }
+    } else {
+      for (var i = 0; i < touchBank.length; i++) {
+        var touchTrack = touchBank[i];
+        if (
+          touchTrack !== null &&
+          touchTrack !== undefined &&
+          touchTrack.touchActive &&
+          touchTrack.currentTimeStamp >= touchesChangedAfter
+        ) {
+          var toAdd; // Yuck, program temporarily in invalid state.
+          if (ofCurrent && isXAxis) {
+            toAdd = touchTrack.currentPageX;
+          } else if (ofCurrent && !isXAxis) {
+            toAdd = touchTrack.currentPageY;
+          } else if (!ofCurrent && isXAxis) {
+            toAdd = touchTrack.previousPageX;
+          } else {
+            toAdd = touchTrack.previousPageY;
+          }
+          total += toAdd;
+          count++;
+        }
+      }
+    }
+    return count > 0 ? total / count : TouchHistoryMath.noCentroid;
+  },
+
+  currentCentroidXOfTouchesChangedAfter: function(
+    touchHistory,
+    touchesChangedAfter,
+  ) {
+    return TouchHistoryMath.centroidDimension(
+      touchHistory,
+      touchesChangedAfter,
+      true, // isXAxis
+      true, // ofCurrent
+    );
+  },
+
+  currentCentroidYOfTouchesChangedAfter: function(
+    touchHistory,
+    touchesChangedAfter,
+  ) {
+    return TouchHistoryMath.centroidDimension(
+      touchHistory,
+      touchesChangedAfter,
+      false, // isXAxis
+      true, // ofCurrent
+    );
+  },
+
+  previousCentroidXOfTouchesChangedAfter: function(
+    touchHistory,
+    touchesChangedAfter,
+  ) {
+    return TouchHistoryMath.centroidDimension(
+      touchHistory,
+      touchesChangedAfter,
+      true, // isXAxis
+      false, // ofCurrent
+    );
+  },
+
+  previousCentroidYOfTouchesChangedAfter: function(
+    touchHistory,
+    touchesChangedAfter,
+  ) {
+    return TouchHistoryMath.centroidDimension(
+      touchHistory,
+      touchesChangedAfter,
+      false, // isXAxis
+      false, // ofCurrent
+    );
+  },
+
+  currentCentroidX: function(touchHistory) {
+    return TouchHistoryMath.centroidDimension(
+      touchHistory,
+      0, // touchesChangedAfter
+      true, // isXAxis
+      true, // ofCurrent
+    );
+  },
+
+  currentCentroidY: function(touchHistory) {
+    return TouchHistoryMath.centroidDimension(
+      touchHistory,
+      0, // touchesChangedAfter
+      false, // isXAxis
+      true, // ofCurrent
+    );
+  },
+
+  noCentroid: -1,
+};
+
+module.exports = TouchHistoryMath;
diff --git a/src/renderers/shared/stack/event/eventPlugins/__tests__/ResponderEventPlugin-test.js b/src/renderers/shared/stack/event/eventPlugins/__tests__/ResponderEventPlugin-test.js
new file mode 100644
index 000000000000..e6689decdc5a
--- /dev/null
+++ b/src/renderers/shared/stack/event/eventPlugins/__tests__/ResponderEventPlugin-test.js
@@ -0,0 +1,1342 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var EventPluginHub;
+var ResponderEventPlugin;
+var EventPluginUtils;
+
+var touch = function(nodeHandle, i) {
+  return {target: nodeHandle, identifier: i};
+};
+
+/**
+ * @param {NodeHandle} nodeHandle @see NodeHandle. Handle of target.
+ * @param {Array<Touch>} touches All active touches.
+ * @param {Array<Touch>} changedTouches Only the touches that have changed.
+ * @return {TouchEvent} Model of a touch event that is compliant with responder
+ * system plugin.
+ */
+var touchEvent = function(nodeHandle, touches, changedTouches) {
+  return {
+    target: nodeHandle,
+    changedTouches: changedTouches,
+    touches: touches,
+  };
+};
+
+var subsequence = function(arr, indices) {
+  var ret = [];
+  for (var i = 0; i < indices.length; i++) {
+    var index = indices[i];
+    ret.push(arr[index]);
+  }
+  return ret;
+};
+
+var antiSubsequence = function(arr, indices) {
+  var ret = [];
+  for (var i = 0; i < arr.length; i++) {
+    if (indices.indexOf(i) === -1) {
+      ret.push(arr[i]);
+    }
+  }
+  return ret;
+};
+
+/**
+ * Helper for creating touch test config data.
+ * @param allTouchHandles
+ */
+var _touchConfig = function(
+  topType,
+  targetNodeHandle,
+  allTouchHandles,
+  changedIndices,
+  eventTarget,
+) {
+  var allTouchObjects = allTouchHandles.map(touch);
+  var changedTouchObjects = subsequence(allTouchObjects, changedIndices);
+  var activeTouchObjects = topType === 'topTouchStart'
+    ? allTouchObjects
+    : topType === 'topTouchMove'
+      ? allTouchObjects
+      : topType === 'topTouchEnd'
+        ? antiSubsequence(allTouchObjects, changedIndices)
+        : topType === 'topTouchCancel'
+          ? antiSubsequence(allTouchObjects, changedIndices)
+          : null;
+
+  return {
+    nativeEvent: touchEvent(
+      targetNodeHandle,
+      activeTouchObjects,
+      changedTouchObjects,
+    ),
+    topLevelType: topType,
+    targetInst: idToInstance[targetNodeHandle],
+  };
+};
+
+/**
+ * Creates test data for touch events using environment agnostic "node
+ * handles".
+ *
+ * @param {NodeHandle} nodeHandle Environment agnostic handle to DOM node.
+ * @param {Array<NodeHandle>} allTouchHandles Encoding of all "touches" in the
+ * form of a mapping from integer (touch `identifier`) to touch target. This is
+ * encoded in array form. Because of this, it is possible for two separate
+ * touches (meaning two separate indices) to have the same touch target ID -
+ * this corresponds to real world cases where two separate unique touches have
+ * the same target. These touches don't just represent all active touches,
+ * rather it also includes any touches that are not active, but are in the
+ * process of being removed.
+ * @param {Array<NodeHandle>} changedIndices Indices of `allTouchHandles` that
+ * have changed.
+ * @return {object} Config data used by test cases for extracting responder
+ * events.
+ */
+var startConfig = function(nodeHandle, allTouchHandles, changedIndices) {
+  return _touchConfig(
+    'topTouchStart',
+    nodeHandle,
+    allTouchHandles,
+    changedIndices,
+    nodeHandle,
+  );
+};
+
+/**
+ * @see `startConfig`
+ */
+var moveConfig = function(nodeHandle, allTouchHandles, changedIndices) {
+  return _touchConfig(
+    'topTouchMove',
+    nodeHandle,
+    allTouchHandles,
+    changedIndices,
+    nodeHandle,
+  );
+};
+
+/**
+ * @see `startConfig`
+ */
+var endConfig = function(nodeHandle, allTouchHandles, changedIndices) {
+  return _touchConfig(
+    'topTouchEnd',
+    nodeHandle,
+    allTouchHandles,
+    changedIndices,
+    nodeHandle,
+  );
+};
+
+/**
+ * Test config for events that aren't negotiation related, but rather result of
+ * a negotiation.
+ *
+ * Returns object of the form:
+ *
+ *     {
+ *       responderReject: {
+ *         // Whatever "readableIDToID" was passed in.
+ *         grandParent: {order: NA, assertEvent: null, returnVal: blah},
+ *         ...
+ *         child: {order: NA, assertEvent: null, returnVal: blah},
+ *       }
+ *       responderGrant: {
+ *         grandParent: {order: NA, assertEvent: null, returnVal: blah},
+ *         ...
+ *         child: {order: NA, assertEvent: null, returnVal: blah}
+ *       }
+ *       ...
+ *     }
+ *
+ * After this is created, a test case would configure specific event orderings
+ * and optional assertions. Anything left with an `order` of `NA` will be
+ * required to never be invoked (the test runner will make sure it throws if
+ * ever invoked).
+ *
+ */
+var NA = -1;
+var oneEventLoopTestConfig = function(readableIDToID) {
+  var ret = {
+    // Negotiation
+    scrollShouldSetResponder: {bubbled: {}, captured: {}},
+    startShouldSetResponder: {bubbled: {}, captured: {}},
+    moveShouldSetResponder: {bubbled: {}, captured: {}},
+    responderTerminationRequest: {},
+
+    // Non-negotiation
+    responderReject: {}, // These do not bubble capture.
+    responderGrant: {},
+    responderStart: {},
+    responderMove: {},
+    responderTerminate: {},
+    responderEnd: {},
+    responderRelease: {},
+  };
+  for (var eventName in ret) {
+    for (var readableNodeName in readableIDToID) {
+      if (ret[eventName].bubbled) {
+        // Two phase
+        ret[eventName].bubbled[readableNodeName] = {
+          order: NA,
+          assertEvent: null,
+          returnVal: undefined,
+        };
+        ret[eventName].captured[readableNodeName] = {
+          order: NA,
+          assertEvent: null,
+          returnVal: undefined,
+        };
+      } else {
+        ret[eventName][readableNodeName] = {
+          order: NA,
+          assertEvent: null,
+          returnVal: undefined,
+        };
+      }
+    }
+  }
+  return ret;
+};
+
+/**
+ * @param {object} eventTestConfig
+ * @param {object} readableIDToID
+ */
+var registerTestHandlers = function(eventTestConfig, readableIDToID) {
+  var runs = {dispatchCount: 0};
+  var neverFire = function(readableID, registrationName) {
+    runs.dispatchCount++;
+    expect('').toBe(
+      'Event type: ' +
+        registrationName +
+        '\nShould never occur on:' +
+        readableID +
+        '\nFor event test config:\n' +
+        JSON.stringify(eventTestConfig) +
+        '\n',
+    );
+  };
+
+  var registerOneEventType = function(registrationName, eventTypeTestConfig) {
+    for (var readableID in eventTypeTestConfig) {
+      var nodeConfig = eventTypeTestConfig[readableID];
+      var id = readableIDToID[readableID];
+      var handler = nodeConfig.order === NA
+        ? neverFire.bind(null, readableID, registrationName)
+        : // We partially apply readableID and nodeConfig, as they change in the
+          // parent closure across iterations.
+          function(rID, config, e) {
+            expect(
+              rID + '->' + registrationName + ' index:' + runs.dispatchCount++,
+            ).toBe(rID + '->' + registrationName + ' index:' + config.order);
+            if (config.assertEvent) {
+              config.assertEvent(e);
+            }
+            return config.returnVal;
+          }.bind(null, readableID, nodeConfig);
+      EventPluginHub.putListener(idToInstance[id], registrationName, handler);
+    }
+  };
+  for (var eventName in eventTestConfig) {
+    var oneEventTypeTestConfig = eventTestConfig[eventName];
+    var hasTwoPhase = !!oneEventTypeTestConfig.bubbled;
+    if (hasTwoPhase) {
+      registerOneEventType(
+        ResponderEventPlugin.eventTypes[eventName].phasedRegistrationNames
+          .bubbled,
+        oneEventTypeTestConfig.bubbled,
+      );
+      registerOneEventType(
+        ResponderEventPlugin.eventTypes[eventName].phasedRegistrationNames
+          .captured,
+        oneEventTypeTestConfig.captured,
+      );
+    } else {
+      registerOneEventType(
+        ResponderEventPlugin.eventTypes[eventName].registrationName,
+        oneEventTypeTestConfig,
+      );
+    }
+  }
+  return runs;
+};
+
+var run = function(config, hierarchyConfig, nativeEventConfig) {
+  var max = NA;
+  var searchForMax = function(nodeConfig) {
+    for (var readableID in nodeConfig) {
+      var order = nodeConfig[readableID].order;
+      max = order > max ? order : max;
+    }
+  };
+  for (var eventName in config) {
+    var eventConfig = config[eventName];
+    if (eventConfig.bubbled) {
+      searchForMax(eventConfig.bubbled);
+      searchForMax(eventConfig.captured);
+    } else {
+      searchForMax(eventConfig);
+    }
+  }
+
+  // Register the handlers
+  var runData = registerTestHandlers(config, hierarchyConfig);
+
+  // Trigger the event
+  var extractedEvents = ResponderEventPlugin.extractEvents(
+    nativeEventConfig.topLevelType,
+    nativeEventConfig.targetInst,
+    nativeEventConfig.nativeEvent,
+    nativeEventConfig.target,
+  );
+
+  // At this point the negotiation events have been dispatched as part of the
+  // extraction process, but not the side effectful events. Below, we dispatch
+  // side effectful events.
+  EventPluginHub.enqueueEvents(extractedEvents);
+  EventPluginHub.processEventQueue(true);
+
+  // Ensure that every event that declared an `order`, was actually dispatched.
+  expect('number of events dispatched:' + runData.dispatchCount).toBe(
+    'number of events dispatched:' + (max + 1),
+  ); // +1 for extra ++
+};
+
+var GRANDPARENT_ID = '.0';
+var PARENT_ID = '.0.0';
+var CHILD_ID = '.0.0.0';
+var CHILD_ID2 = '.0.0.1';
+
+var idToInstance = {};
+[GRANDPARENT_ID, PARENT_ID, CHILD_ID, CHILD_ID2].forEach(function(id) {
+  idToInstance[id] = {_rootNodeID: id, _currentElement: {}};
+});
+
+var three = {
+  grandParent: GRANDPARENT_ID,
+  parent: PARENT_ID,
+  child: CHILD_ID,
+};
+
+var siblings = {
+  parent: PARENT_ID,
+  childOne: CHILD_ID,
+  childTwo: CHILD_ID2,
+};
+
+describe('ResponderEventPlugin', () => {
+  // This test is written against React IDs such as 'root.a.b[10]' but we
+  // removed those. In order to make those tests still pass with minimum
+  // surgery, we are inlining the implementation of those IDs here as it
+  // is the only remaining call site.
+
+  var SEPARATOR = '.';
+
+  function isBoundary(id, index) {
+    return id.charAt(index) === SEPARATOR || index === id.length;
+  }
+
+  function isAncestorIDOf(ancestorID, descendantID) {
+    return (
+      descendantID.indexOf(ancestorID) === 0 &&
+      isBoundary(descendantID, ancestorID.length)
+    );
+  }
+
+  function getParentID(id) {
+    return id ? id.substr(0, id.lastIndexOf(SEPARATOR)) : '';
+  }
+
+  function getNextDescendantID(ancestorID, destinationID) {
+    if (ancestorID === destinationID) {
+      return ancestorID;
+    }
+    // Skip over the ancestor and the immediate separator. Traverse until we hit
+    // another separator or we reach the end of `destinationID`.
+    var start = ancestorID.length + SEPARATOR.length;
+    var i;
+    for (i = start; i < destinationID.length; i++) {
+      if (isBoundary(destinationID, i)) {
+        break;
+      }
+    }
+    return destinationID.substr(0, i);
+  }
+
+  function getFirstCommonAncestorID(oneID, twoID) {
+    var minLength = Math.min(oneID.length, twoID.length);
+    if (minLength === 0) {
+      return '';
+    }
+    var lastCommonMarkerIndex = 0;
+    // Use `<=` to traverse until the "EOL" of the shorter string.
+    for (var i = 0; i <= minLength; i++) {
+      if (isBoundary(oneID, i) && isBoundary(twoID, i)) {
+        lastCommonMarkerIndex = i;
+      } else if (oneID.charAt(i) !== twoID.charAt(i)) {
+        break;
+      }
+    }
+    return oneID.substr(0, lastCommonMarkerIndex);
+  }
+
+  function traverseParentPath(start, stop, cb, arg, skipFirst, skipLast) {
+    var traverseUp = isAncestorIDOf(stop, start);
+    var traverse = traverseUp ? getParentID : getNextDescendantID;
+    for (var id = start /* until break */; ; id = traverse(id, stop)) {
+      var ret;
+      if ((!skipFirst || id !== start) && (!skipLast || id !== stop)) {
+        ret = cb(id, traverseUp ? 'bubbled' : 'captured', arg);
+      }
+      if (ret === false || id === stop) {
+        // Only break //after// visiting `stop`.
+        break;
+      }
+    }
+  }
+
+  function traverseTwoPhase(targetID, cb, arg) {
+    traverseParentPath('', targetID, cb, arg, true, false);
+    traverseParentPath(targetID, '', cb, arg, false, true);
+  }
+
+  // -- end of the React ID implementation
+
+  beforeEach(() => {
+    jest.resetModuleRegistry();
+
+    EventPluginHub = require('EventPluginHub');
+    EventPluginUtils = require('EventPluginUtils');
+    ResponderEventPlugin = require('ResponderEventPlugin');
+
+    EventPluginUtils.injection.injectComponentTree({
+      getInstanceFromNode: function(id) {
+        return idToInstance[id];
+      },
+      getNodeFromInstance: function(inst) {
+        return inst._rootNodeID;
+      },
+    });
+
+    EventPluginUtils.injection.injectTreeTraversal({
+      isAncestor: function(a, b) {
+        return isAncestorIDOf(a._rootNodeID, b._rootNodeID);
+      },
+      getLowestCommonAncestor: function(a, b) {
+        var commonID = getFirstCommonAncestorID(a._rootNodeID, b._rootNodeID);
+        return idToInstance[commonID] || null;
+      },
+      getParentInstance: function(inst) {
+        var id = inst._rootNodeID;
+        var parentID = id.substr(0, id.lastIndexOf(SEPARATOR));
+        return idToInstance[parentID] || null;
+      },
+      traverseTwoPhase: function(target, fn, arg) {
+        traverseTwoPhase(target._rootNodeID, function(id, phase) {
+          fn(idToInstance[id], phase, arg);
+        });
+      },
+    });
+  });
+
+  it('should do nothing when no one wants to respond', () => {
+    var config = oneEventLoopTestConfig(three);
+    config.startShouldSetResponder.captured.grandParent = {
+      order: 0,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.captured.parent = {
+      order: 1,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.captured.child = {
+      order: 2,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: false};
+    config.startShouldSetResponder.bubbled.parent = {
+      order: 4,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.bubbled.grandParent = {
+      order: 5,
+      returnVal: false,
+    };
+    run(config, three, startConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(null);
+
+    // Now no handlers should be called on `touchEnd`.
+    config = oneEventLoopTestConfig(three);
+    run(config, three, endConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(null);
+  });
+
+  /**
+   * Simple Start Granting
+   * --------------------
+   */
+
+  it('should grant responder grandParent while capturing', () => {
+    var config = oneEventLoopTestConfig(three);
+    config.startShouldSetResponder.captured.grandParent = {
+      order: 0,
+      returnVal: true,
+    };
+    config.responderGrant.grandParent = {order: 1};
+    config.responderStart.grandParent = {order: 2};
+    run(config, three, startConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(three.grandParent);
+
+    config = oneEventLoopTestConfig(three);
+    config.responderEnd.grandParent = {order: 0};
+    config.responderRelease.grandParent = {order: 1};
+    run(config, three, endConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(null);
+  });
+
+  it('should grant responder parent while capturing', () => {
+    var config = oneEventLoopTestConfig(three);
+    config.startShouldSetResponder.captured.grandParent = {
+      order: 0,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.captured.parent = {
+      order: 1,
+      returnVal: true,
+    };
+    config.responderGrant.parent = {order: 2};
+    config.responderStart.parent = {order: 3};
+    run(config, three, startConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(three.parent);
+
+    config = oneEventLoopTestConfig(three);
+    config.responderEnd.parent = {order: 0};
+    config.responderRelease.parent = {order: 1};
+    run(config, three, endConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(null);
+  });
+
+  it('should grant responder child while capturing', () => {
+    var config = oneEventLoopTestConfig(three);
+    config.startShouldSetResponder.captured.grandParent = {
+      order: 0,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.captured.parent = {
+      order: 1,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.captured.child = {order: 2, returnVal: true};
+    config.responderGrant.child = {order: 3};
+    config.responderStart.child = {order: 4};
+    run(config, three, startConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
+
+    config = oneEventLoopTestConfig(three);
+    config.responderEnd.child = {order: 0};
+    config.responderRelease.child = {order: 1};
+    run(config, three, endConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(null);
+  });
+
+  it('should grant responder child while bubbling', () => {
+    var config = oneEventLoopTestConfig(three);
+    config.startShouldSetResponder.captured.grandParent = {
+      order: 0,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.captured.parent = {
+      order: 1,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.captured.child = {
+      order: 2,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: true};
+    config.responderGrant.child = {order: 4};
+    config.responderStart.child = {order: 5};
+    run(config, three, startConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
+
+    config = oneEventLoopTestConfig(three);
+    config.responderEnd.child = {order: 0};
+    config.responderRelease.child = {order: 1};
+    run(config, three, endConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(null);
+  });
+
+  it('should grant responder parent while bubbling', () => {
+    var config = oneEventLoopTestConfig(three);
+    config.startShouldSetResponder.captured.grandParent = {
+      order: 0,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.captured.parent = {
+      order: 1,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.captured.child = {
+      order: 2,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: false};
+    config.startShouldSetResponder.bubbled.parent = {order: 4, returnVal: true};
+    config.responderGrant.parent = {order: 5};
+    config.responderStart.parent = {order: 6};
+    run(config, three, startConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(three.parent);
+
+    config = oneEventLoopTestConfig(three);
+    config.responderEnd.parent = {order: 0};
+    config.responderRelease.parent = {order: 1};
+    run(config, three, endConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(null);
+  });
+
+  it('should grant responder grandParent while bubbling', () => {
+    var config = oneEventLoopTestConfig(three);
+    config.startShouldSetResponder.captured.grandParent = {
+      order: 0,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.captured.parent = {
+      order: 1,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.captured.child = {
+      order: 2,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: false};
+    config.startShouldSetResponder.bubbled.parent = {
+      order: 4,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.bubbled.grandParent = {
+      order: 5,
+      returnVal: true,
+    };
+    config.responderGrant.grandParent = {order: 6};
+    config.responderStart.grandParent = {order: 7};
+    run(config, three, startConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(three.grandParent);
+
+    config = oneEventLoopTestConfig(three);
+    config.responderEnd.grandParent = {order: 0};
+    config.responderRelease.grandParent = {order: 1};
+    run(config, three, endConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(null);
+  });
+
+  /**
+   * Simple Move Granting
+   * --------------------
+   */
+
+  it('should grant responder grandParent while capturing move', () => {
+    var config = oneEventLoopTestConfig(three);
+
+    config.startShouldSetResponder.captured.grandParent = {order: 0};
+    config.startShouldSetResponder.captured.parent = {order: 1};
+    config.startShouldSetResponder.captured.child = {order: 2};
+    config.startShouldSetResponder.bubbled.child = {order: 3};
+    config.startShouldSetResponder.bubbled.parent = {order: 4};
+    config.startShouldSetResponder.bubbled.grandParent = {order: 5};
+    run(config, three, startConfig(three.child, [three.child], [0]));
+
+    config = oneEventLoopTestConfig(three);
+    config.moveShouldSetResponder.captured.grandParent = {
+      order: 0,
+      returnVal: true,
+    };
+    config.responderGrant.grandParent = {order: 1};
+    config.responderMove.grandParent = {order: 2};
+    run(config, three, moveConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(three.grandParent);
+
+    config = oneEventLoopTestConfig(three);
+    config.responderEnd.grandParent = {order: 0};
+    config.responderRelease.grandParent = {order: 1};
+    run(config, three, endConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(null);
+  });
+
+  it('should grant responder parent while capturing move', () => {
+    var config = oneEventLoopTestConfig(three);
+
+    config.startShouldSetResponder.captured.grandParent = {order: 0};
+    config.startShouldSetResponder.captured.parent = {order: 1};
+    config.startShouldSetResponder.captured.child = {order: 2};
+    config.startShouldSetResponder.bubbled.child = {order: 3};
+    config.startShouldSetResponder.bubbled.parent = {order: 4};
+    config.startShouldSetResponder.bubbled.grandParent = {order: 5};
+    run(config, three, startConfig(three.child, [three.child], [0]));
+
+    config = oneEventLoopTestConfig(three);
+    config.moveShouldSetResponder.captured.grandParent = {
+      order: 0,
+      returnVal: false,
+    };
+    config.moveShouldSetResponder.captured.parent = {order: 1, returnVal: true};
+    config.responderGrant.parent = {order: 2};
+    config.responderMove.parent = {order: 3};
+    run(config, three, moveConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(three.parent);
+
+    config = oneEventLoopTestConfig(three);
+    config.responderEnd.parent = {order: 0};
+    config.responderRelease.parent = {order: 1};
+    run(config, three, endConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(null);
+  });
+
+  it('should grant responder child while capturing move', () => {
+    var config = oneEventLoopTestConfig(three);
+
+    config.startShouldSetResponder.captured.grandParent = {order: 0};
+    config.startShouldSetResponder.captured.parent = {order: 1};
+    config.startShouldSetResponder.captured.child = {order: 2};
+    config.startShouldSetResponder.bubbled.child = {order: 3};
+    config.startShouldSetResponder.bubbled.parent = {order: 4};
+    config.startShouldSetResponder.bubbled.grandParent = {order: 5};
+    run(config, three, startConfig(three.child, [three.child], [0]));
+
+    config = oneEventLoopTestConfig(three);
+    config.moveShouldSetResponder.captured.grandParent = {
+      order: 0,
+      returnVal: false,
+    };
+    config.moveShouldSetResponder.captured.parent = {
+      order: 1,
+      returnVal: false,
+    };
+    config.moveShouldSetResponder.captured.child = {order: 2, returnVal: true};
+    config.responderGrant.child = {order: 3};
+    config.responderMove.child = {order: 4};
+    run(config, three, moveConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
+
+    config = oneEventLoopTestConfig(three);
+    config.responderEnd.child = {order: 0};
+    config.responderRelease.child = {order: 1};
+    run(config, three, endConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(null);
+  });
+
+  it('should grant responder child while bubbling move', () => {
+    var config = oneEventLoopTestConfig(three);
+
+    config.startShouldSetResponder.captured.grandParent = {order: 0};
+    config.startShouldSetResponder.captured.parent = {order: 1};
+    config.startShouldSetResponder.captured.child = {order: 2};
+    config.startShouldSetResponder.bubbled.child = {order: 3};
+    config.startShouldSetResponder.bubbled.parent = {order: 4};
+    config.startShouldSetResponder.bubbled.grandParent = {order: 5};
+    run(config, three, startConfig(three.child, [three.child], [0]));
+
+    config = oneEventLoopTestConfig(three);
+    config.moveShouldSetResponder.captured.grandParent = {
+      order: 0,
+      returnVal: false,
+    };
+    config.moveShouldSetResponder.captured.parent = {
+      order: 1,
+      returnVal: false,
+    };
+    config.moveShouldSetResponder.captured.child = {order: 2, returnVal: false};
+    config.moveShouldSetResponder.bubbled.child = {order: 3, returnVal: true};
+    config.responderGrant.child = {order: 4};
+    config.responderMove.child = {order: 5};
+    run(config, three, moveConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
+
+    config = oneEventLoopTestConfig(three);
+    config.responderEnd.child = {order: 0};
+    config.responderRelease.child = {order: 1};
+    run(config, three, endConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(null);
+  });
+
+  it('should grant responder parent while bubbling move', () => {
+    var config = oneEventLoopTestConfig(three);
+
+    config.startShouldSetResponder.captured.grandParent = {order: 0};
+    config.startShouldSetResponder.captured.parent = {order: 1};
+    config.startShouldSetResponder.captured.child = {order: 2};
+    config.startShouldSetResponder.bubbled.child = {order: 3};
+    config.startShouldSetResponder.bubbled.parent = {order: 4};
+    config.startShouldSetResponder.bubbled.grandParent = {order: 5};
+    run(config, three, startConfig(three.child, [three.child], [0]));
+
+    config = oneEventLoopTestConfig(three);
+    config.moveShouldSetResponder.captured.grandParent = {
+      order: 0,
+      returnVal: false,
+    };
+    config.moveShouldSetResponder.captured.parent = {
+      order: 1,
+      returnVal: false,
+    };
+    config.moveShouldSetResponder.captured.child = {order: 2, returnVal: false};
+    config.moveShouldSetResponder.bubbled.child = {order: 3, returnVal: false};
+    config.moveShouldSetResponder.bubbled.parent = {order: 4, returnVal: true};
+    config.responderGrant.parent = {order: 5};
+    config.responderMove.parent = {order: 6};
+    run(config, three, moveConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(three.parent);
+
+    config = oneEventLoopTestConfig(three);
+    config.responderEnd.parent = {order: 0};
+    config.responderRelease.parent = {order: 1};
+    run(config, three, endConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(null);
+  });
+
+  it('should grant responder grandParent while bubbling move', () => {
+    var config = oneEventLoopTestConfig(three);
+
+    config.startShouldSetResponder.captured.grandParent = {order: 0};
+    config.startShouldSetResponder.captured.parent = {order: 1};
+    config.startShouldSetResponder.captured.child = {order: 2};
+    config.startShouldSetResponder.bubbled.child = {order: 3};
+    config.startShouldSetResponder.bubbled.parent = {order: 4};
+    config.startShouldSetResponder.bubbled.grandParent = {order: 5};
+    run(config, three, startConfig(three.child, [three.child], [0]));
+
+    config = oneEventLoopTestConfig(three);
+    config.moveShouldSetResponder.captured.grandParent = {
+      order: 0,
+      returnVal: false,
+    };
+    config.moveShouldSetResponder.captured.parent = {
+      order: 1,
+      returnVal: false,
+    };
+    config.moveShouldSetResponder.captured.child = {order: 2, returnVal: false};
+    config.moveShouldSetResponder.bubbled.child = {order: 3, returnVal: false};
+    config.moveShouldSetResponder.bubbled.parent = {order: 4, returnVal: false};
+    config.moveShouldSetResponder.bubbled.grandParent = {
+      order: 5,
+      returnVal: true,
+    };
+    config.responderGrant.grandParent = {order: 6};
+    config.responderMove.grandParent = {order: 7};
+    run(config, three, moveConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(three.grandParent);
+
+    config = oneEventLoopTestConfig(three);
+    config.responderEnd.grandParent = {order: 0};
+    config.responderRelease.grandParent = {order: 1};
+    run(config, three, endConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(null);
+  });
+
+  /**
+   * Common ancestor tests
+   * ---------------------
+   */
+
+  it('should bubble negotiation to first common ancestor of responder', () => {
+    var config = oneEventLoopTestConfig(three);
+    config.startShouldSetResponder.captured.grandParent = {
+      order: 0,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.captured.parent = {
+      order: 1,
+      returnVal: true,
+    };
+    config.responderGrant.parent = {order: 2};
+    config.responderStart.parent = {order: 3};
+    run(config, three, startConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(three.parent);
+
+    // While `parent` is still responder, we create new handlers that verify
+    // the ordering of propagation, restarting the count at `0`.
+    config = oneEventLoopTestConfig(three);
+    config.startShouldSetResponder.captured.grandParent = {
+      order: 0,
+      returnVal: false,
+    };
+
+    config.startShouldSetResponder.bubbled.grandParent = {
+      order: 1,
+      returnVal: false,
+    };
+    config.responderStart.parent = {order: 2};
+    run(config, three, startConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(three.parent);
+
+    config = oneEventLoopTestConfig(three);
+    config.responderEnd.parent = {order: 0};
+    config.responderRelease.parent = {order: 1};
+    run(config, three, endConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(null);
+  });
+
+  it('should bubble negotiation to first common ancestor of responder then transfer', () => {
+    var config = oneEventLoopTestConfig(three);
+    config.startShouldSetResponder.captured.grandParent = {
+      order: 0,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.captured.parent = {
+      order: 1,
+      returnVal: true,
+    };
+    config.responderGrant.parent = {order: 2};
+    config.responderStart.parent = {order: 3};
+    run(config, three, startConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(three.parent);
+
+    config = oneEventLoopTestConfig(three);
+
+    // Parent is responder, and responder is transferred by a second touch start
+    config.startShouldSetResponder.captured.grandParent = {
+      order: 0,
+      returnVal: true,
+    };
+    config.responderGrant.grandParent = {order: 1};
+    config.responderTerminationRequest.parent = {order: 2, returnVal: true};
+    config.responderTerminate.parent = {order: 3};
+    config.responderStart.grandParent = {order: 4};
+    run(
+      config,
+      three,
+      startConfig(three.child, [three.child, three.child], [1]),
+    );
+    expect(ResponderEventPlugin._getResponderID()).toBe(three.grandParent);
+
+    config = oneEventLoopTestConfig(three);
+    config.responderEnd.grandParent = {order: 0};
+    // one remains\ /one ended \
+    run(config, three, endConfig(three.child, [three.child, three.child], [1]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(three.grandParent);
+
+    config = oneEventLoopTestConfig(three);
+    config.responderEnd.grandParent = {order: 0};
+    config.responderRelease.grandParent = {order: 1};
+    run(config, three, endConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(null);
+  });
+
+  /**
+   * If nothing is responder, then the negotiation should propagate directly to
+   * the deepest target in the second touch.
+   */
+  it('should negotiate with deepest target on second touch if nothing is responder', () => {
+    // Initially nothing wants to become the responder
+    var config = oneEventLoopTestConfig(three);
+    config.startShouldSetResponder.captured.grandParent = {
+      order: 0,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.captured.parent = {
+      order: 1,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.bubbled.parent = {
+      order: 2,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.bubbled.grandParent = {
+      order: 3,
+      returnVal: false,
+    };
+
+    run(config, three, startConfig(three.parent, [three.parent], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(null);
+
+    config = oneEventLoopTestConfig(three);
+
+    // Now child wants to become responder. Negotiation should bubble as deep
+    // as the target is because we don't find first common ancestor (with
+    // current responder) because there is no current responder.
+    // (Even if this is the second active touch).
+    config.startShouldSetResponder.captured.grandParent = {
+      order: 0,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.captured.parent = {
+      order: 1,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.captured.child = {
+      order: 2,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: true};
+    config.responderGrant.child = {order: 4};
+    config.responderStart.child = {order: 5};
+    //                                     /  Two active touches  \  /one of them new\
+    run(
+      config,
+      three,
+      startConfig(three.child, [three.parent, three.child], [1]),
+    );
+    expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
+
+    // Now we remove the original first touch, keeping the second touch that
+    // started within the current responder (child). Nothing changes because
+    // there's still touches that started inside of the current responder.
+    config = oneEventLoopTestConfig(three);
+    config.responderEnd.child = {order: 0};
+    //                                      / one ended\  /one remains \
+    run(
+      config,
+      three,
+      endConfig(three.child, [three.parent, three.child], [0]),
+    );
+    expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
+
+    // Okay, now let's add back that first touch (nothing should change) and
+    // then we'll try peeling back the touches in the opposite order to make
+    // sure that first removing the second touch instantly causes responder to
+    // be released.
+    config = oneEventLoopTestConfig(three);
+    config.startShouldSetResponder.captured.grandParent = {
+      order: 0,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.captured.parent = {
+      order: 1,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.bubbled.parent = {
+      order: 2,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.bubbled.grandParent = {
+      order: 3,
+      returnVal: false,
+    };
+    // Interesting: child still gets moves even though touch target is parent!
+    // Current responder gets a `responderStart` for any touch while responder.
+    config.responderStart.child = {order: 4};
+    //                                           /  Two active touches  \  /one of them new\
+    run(
+      config,
+      three,
+      startConfig(three.parent, [three.child, three.parent], [1]),
+    );
+    expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
+
+    // Now, move that new touch that had no effect, and did not start within
+    // the current responder.
+    config = oneEventLoopTestConfig(three);
+    config.moveShouldSetResponder.captured.grandParent = {
+      order: 0,
+      returnVal: false,
+    };
+    config.moveShouldSetResponder.captured.parent = {
+      order: 1,
+      returnVal: false,
+    };
+    config.moveShouldSetResponder.bubbled.parent = {order: 2, returnVal: false};
+    config.moveShouldSetResponder.bubbled.grandParent = {
+      order: 3,
+      returnVal: false,
+    };
+    // Interesting: child still gets moves even though touch target is parent!
+    // Current responder gets a `responderMove` for any touch while responder.
+    config.responderMove.child = {order: 4};
+    //                                     /  Two active touches  \  /one of them moved\
+    run(
+      config,
+      three,
+      moveConfig(three.parent, [three.child, three.parent], [1]),
+    );
+    expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
+
+    config = oneEventLoopTestConfig(three);
+    config.responderEnd.child = {order: 0};
+    config.responderRelease.child = {order: 1};
+    //                                        /child end \ /parent remain\
+    run(
+      config,
+      three,
+      endConfig(three.child, [three.child, three.parent], [0]),
+    );
+    expect(ResponderEventPlugin._getResponderID()).toBe(null);
+  });
+
+  /**
+   * If nothing is responder, then the negotiation should propagate directly to
+   * the deepest target in the second touch.
+   */
+  it('should negotiate until first common ancestor when there are siblings', () => {
+    // Initially nothing wants to become the responder
+    var config = oneEventLoopTestConfig(siblings);
+    config.startShouldSetResponder.captured.parent = {
+      order: 0,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.captured.childOne = {
+      order: 1,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.bubbled.childOne = {
+      order: 2,
+      returnVal: true,
+    };
+    config.responderGrant.childOne = {order: 3};
+    config.responderStart.childOne = {order: 4};
+
+    run(
+      config,
+      siblings,
+      startConfig(siblings.childOne, [siblings.childOne], [0]),
+    );
+    expect(ResponderEventPlugin._getResponderID()).toBe(siblings.childOne);
+
+    // If the touch target is the sibling item, the negotiation should only
+    // propagate to first common ancestor of current responder and sibling (so
+    // the parent).
+    config = oneEventLoopTestConfig(siblings);
+    config.startShouldSetResponder.captured.parent = {
+      order: 0,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.bubbled.parent = {
+      order: 1,
+      returnVal: false,
+    };
+    config.responderStart.childOne = {order: 2};
+
+    var touchConfig = startConfig(
+      siblings.childTwo,
+      [siblings.childOne, siblings.childTwo],
+      [1],
+    );
+    run(config, siblings, touchConfig);
+    expect(ResponderEventPlugin._getResponderID()).toBe(siblings.childOne);
+
+    // move childOne
+    config = oneEventLoopTestConfig(siblings);
+    config.moveShouldSetResponder.captured.parent = {
+      order: 0,
+      returnVal: false,
+    };
+    config.moveShouldSetResponder.bubbled.parent = {order: 1, returnVal: false};
+    config.responderMove.childOne = {order: 2};
+    run(
+      config,
+      siblings,
+      moveConfig(
+        siblings.childOne,
+        [siblings.childOne, siblings.childTwo],
+        [0],
+      ),
+    );
+    expect(ResponderEventPlugin._getResponderID()).toBe(siblings.childOne);
+
+    // move childTwo: Only negotiates to `parent`.
+    config = oneEventLoopTestConfig(siblings);
+    config.moveShouldSetResponder.captured.parent = {
+      order: 0,
+      returnVal: false,
+    };
+    config.moveShouldSetResponder.bubbled.parent = {order: 1, returnVal: false};
+    config.responderMove.childOne = {order: 2};
+    run(
+      config,
+      siblings,
+      moveConfig(
+        siblings.childTwo,
+        [siblings.childOne, siblings.childTwo],
+        [1],
+      ),
+    );
+    expect(ResponderEventPlugin._getResponderID()).toBe(siblings.childOne);
+  });
+
+  it('should notify of being rejected. responderStart/Move happens on current responder', () => {
+    // Initially nothing wants to become the responder
+    var config = oneEventLoopTestConfig(three);
+    config.startShouldSetResponder.captured.grandParent = {
+      order: 0,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.captured.parent = {
+      order: 1,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.captured.child = {
+      order: 2,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: true};
+    config.responderGrant.child = {order: 4};
+    config.responderStart.child = {order: 5};
+
+    run(config, three, startConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
+
+    // Suppose parent wants to become responder on move, and is rejected
+    config = oneEventLoopTestConfig(three);
+    config.moveShouldSetResponder.captured.grandParent = {
+      order: 0,
+      returnVal: false,
+    };
+    config.moveShouldSetResponder.captured.parent = {
+      order: 1,
+      returnVal: false,
+    };
+    config.moveShouldSetResponder.bubbled.parent = {order: 2, returnVal: true};
+    config.responderGrant.parent = {order: 3};
+    config.responderTerminationRequest.child = {order: 4, returnVal: false};
+    config.responderReject.parent = {order: 5};
+    // The start/move should occur on the original responder if new one is rejected
+    config.responderMove.child = {order: 6};
+
+    var touchConfig = moveConfig(three.child, [three.child], [0]);
+    run(config, three, touchConfig);
+    expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
+
+    config = oneEventLoopTestConfig(three);
+    config.startShouldSetResponder.captured.grandParent = {
+      order: 0,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.captured.parent = {
+      order: 1,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.bubbled.parent = {order: 2, returnVal: true};
+    config.responderGrant.parent = {order: 3};
+    config.responderTerminationRequest.child = {order: 4, returnVal: false};
+    config.responderReject.parent = {order: 5};
+    // The start/move should occur on the original responder if new one is rejected
+    config.responderStart.child = {order: 6};
+
+    touchConfig = startConfig(three.child, [three.child, three.child], [1]);
+    run(config, three, touchConfig);
+    expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
+  });
+
+  it('should negotiate scroll', () => {
+    // Initially nothing wants to become the responder
+    var config = oneEventLoopTestConfig(three);
+    config.startShouldSetResponder.captured.grandParent = {
+      order: 0,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.captured.parent = {
+      order: 1,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.captured.child = {
+      order: 2,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: true};
+    config.responderGrant.child = {order: 4};
+    config.responderStart.child = {order: 5};
+
+    run(config, three, startConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
+
+    // If the touch target is the sibling item, the negotiation should only
+    // propagate to first common ancestor of current responder and sibling (so
+    // the parent).
+    config = oneEventLoopTestConfig(three);
+    config.scrollShouldSetResponder.captured.grandParent = {
+      order: 0,
+      returnVal: false,
+    };
+    config.scrollShouldSetResponder.captured.parent = {
+      order: 1,
+      returnVal: false,
+    };
+    config.scrollShouldSetResponder.bubbled.parent = {
+      order: 2,
+      returnVal: true,
+    };
+    config.responderGrant.parent = {order: 3};
+    config.responderTerminationRequest.child = {order: 4, returnVal: false};
+    config.responderReject.parent = {order: 5};
+
+    run(config, three, {
+      topLevelType: 'topScroll',
+      targetInst: idToInstance[three.parent],
+      nativeEvent: {},
+    });
+    expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
+
+    // Now lets let the scroll take control this time.
+    config = oneEventLoopTestConfig(three);
+    config.scrollShouldSetResponder.captured.grandParent = {
+      order: 0,
+      returnVal: false,
+    };
+    config.scrollShouldSetResponder.captured.parent = {
+      order: 1,
+      returnVal: false,
+    };
+    config.scrollShouldSetResponder.bubbled.parent = {
+      order: 2,
+      returnVal: true,
+    };
+    config.responderGrant.parent = {order: 3};
+    config.responderTerminationRequest.child = {order: 4, returnVal: true};
+    config.responderTerminate.child = {order: 5};
+
+    run(config, three, {
+      topLevelType: 'topScroll',
+      targetInst: idToInstance[three.parent],
+      nativeEvent: {},
+    });
+    expect(ResponderEventPlugin._getResponderID()).toBe(three.parent);
+  });
+
+  it('should cancel correctly', () => {
+    // Initially our child becomes responder
+    var config = oneEventLoopTestConfig(three);
+    config.startShouldSetResponder.captured.grandParent = {
+      order: 0,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.captured.parent = {
+      order: 1,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.captured.child = {
+      order: 2,
+      returnVal: false,
+    };
+    config.startShouldSetResponder.bubbled.child = {order: 3, returnVal: true};
+    config.responderGrant.child = {order: 4};
+    config.responderStart.child = {order: 5};
+
+    run(config, three, startConfig(three.child, [three.child], [0]));
+    expect(ResponderEventPlugin._getResponderID()).toBe(three.child);
+
+    config = oneEventLoopTestConfig(three);
+    config.responderEnd.child = {order: 0};
+    config.responderTerminate.child = {order: 1};
+
+    var nativeEvent = _touchConfig(
+      'topTouchCancel',
+      three.child,
+      [three.child],
+      [0],
+    );
+    run(config, three, nativeEvent);
+    expect(ResponderEventPlugin._getResponderID()).toBe(null);
+  });
+});
diff --git a/src/renderers/shared/stack/reconciler/ReactChildReconciler.js b/src/renderers/shared/stack/reconciler/ReactChildReconciler.js
new file mode 100644
index 000000000000..1a1aa9a61fa8
--- /dev/null
+++ b/src/renderers/shared/stack/reconciler/ReactChildReconciler.js
@@ -0,0 +1,198 @@
+/**
+ * Copyright 2014-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 ReactChildReconciler
+ */
+
+'use strict';
+
+var ReactReconciler = require('ReactReconciler');
+
+var instantiateReactComponent = require('instantiateReactComponent');
+var KeyEscapeUtils = require('KeyEscapeUtils');
+var shouldUpdateReactComponent = require('shouldUpdateReactComponent');
+var traverseAllChildren = require('traverseAllChildren');
+var warning = require('warning');
+
+var ReactComponentTreeHook;
+
+if (
+  typeof process !== 'undefined' &&
+  process.env &&
+  process.env.NODE_ENV === '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 = require('ReactComponentTreeHook');
+}
+
+function instantiateChild(childInstances, child, name, selfDebugID) {
+  // We found a component instance.
+  var keyUnique = childInstances[name] === undefined;
+  if (__DEV__) {
+    if (!ReactComponentTreeHook) {
+      ReactComponentTreeHook = require('ReactComponentTreeHook');
+    }
+    if (!keyUnique) {
+      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),
+      );
+    }
+  }
+  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 (__DEV__) {
+      traverseAllChildren(
+        nestedChildNodes,
+        (childInsts, child, name) =>
+          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;
diff --git a/src/renderers/shared/stack/reconciler/ReactComponentEnvironment.js b/src/renderers/shared/stack/reconciler/ReactComponentEnvironment.js
new file mode 100644
index 000000000000..cbba0c55c210
--- /dev/null
+++ b/src/renderers/shared/stack/reconciler/ReactComponentEnvironment.js
@@ -0,0 +1,55 @@
+/**
+ * Copyright 2014-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 ReactComponentEnvironment
+ * @flow
+ */
+
+'use strict';
+
+var invariant = require('invariant');
+
+type ReplaceNodeWithMarkup = (node: HTMLElement, markup: string) => void;
+type ProcessChildrenUpdates = (instance: mixed, updates: mixed) => void;
+
+type Environment = {
+  replaceNodeWithMarkup: ReplaceNodeWithMarkup,
+  processChildrenUpdates: ProcessChildrenUpdates,
+};
+
+var injected = false;
+
+var ReactComponentEnvironment = {
+  /**
+   * Optionally injectable hook for swapping out mount images in the middle of
+   * the tree.
+   */
+  replaceNodeWithMarkup: (null: ?ReplaceNodeWithMarkup),
+
+  /**
+   * Optionally injectable hook for processing a queue of child updates. Will
+   * later move into MultiChildComponents.
+   */
+  processChildrenUpdates: (null: ?ReplaceNodeWithMarkup),
+
+  injection: {
+    injectEnvironment: function(environment: Environment) {
+      invariant(
+        !injected,
+        'ReactCompositeComponent: injectEnvironment() can only be called once.',
+      );
+      ReactComponentEnvironment.replaceNodeWithMarkup =
+        environment.replaceNodeWithMarkup;
+      ReactComponentEnvironment.processChildrenUpdates =
+        environment.processChildrenUpdates;
+      injected = true;
+    },
+  },
+};
+
+module.exports = ReactComponentEnvironment;
diff --git a/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js b/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js
new file mode 100644
index 000000000000..ec90a21068dc
--- /dev/null
+++ b/src/renderers/shared/stack/reconciler/ReactCompositeComponent.js
@@ -0,0 +1,1217 @@
+/**
+ * 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 ReactCompositeComponent
+ */
+
+'use strict';
+
+var React = require('React');
+var ReactComponentEnvironment = require('ReactComponentEnvironment');
+var ReactCurrentOwner = require('ReactCurrentOwner');
+var ReactErrorUtils = require('ReactErrorUtils');
+var ReactInstanceMap = require('ReactInstanceMap');
+var ReactInstrumentation = require('ReactInstrumentation');
+var ReactNodeTypes = require('ReactNodeTypes');
+var ReactReconciler = require('ReactReconciler');
+
+if (__DEV__) {
+  var checkReactTypeSpec = require('checkReactTypeSpec');
+}
+
+var emptyObject = require('emptyObject');
+var invariant = require('invariant');
+var shallowEqual = require('shallowEqual');
+var shouldUpdateReactComponent = require('shouldUpdateReactComponent');
+var warning = require('warning');
+
+import type {ReactPropTypeLocations} from 'ReactPropTypeLocations';
+
+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 (__DEV__) {
+    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',
+    );
+    warning(
+      !Component.childContextTypes,
+      '%s(...): childContextTypes cannot be defined on a functional component.',
+      Component.displayName || Component.name || 'Component',
+    );
+  }
+}
+
+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 (__DEV__) {
+      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,
+  ) {
+    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);
+      invariant(
+        inst === null || inst === false || React.isValidElement(inst),
+        '%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',
+      );
+      inst = new StatelessComponent(Component);
+      this._compositeType = CompositeTypes.StatelessFunctional;
+    } else {
+      if (isPureComponent(Component)) {
+        this._compositeType = CompositeTypes.PureClass;
+      } else {
+        this._compositeType = CompositeTypes.ImpureClass;
+      }
+    }
+
+    if (__DEV__) {
+      // This will throw later in _renderValidatedComponent, but add an early
+      // warning now to help debugging
+      if (inst.render == null) {
+        warning(
+          false,
+          '%s(...): No `render` method found on the returned component ' +
+            'instance: you may have forgotten to define `render`.',
+          Component.displayName || Component.name || 'Component',
+        );
+      }
+
+      var propsMutated = inst.props !== publicProps;
+      var componentName =
+        Component.displayName || Component.name || 'Component';
+
+      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,
+      );
+    }
+
+    // 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 (__DEV__) {
+      // 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.
+      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',
+      );
+      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',
+      );
+      warning(
+        !inst.propTypes,
+        'propTypes was defined as an instance property on %s. Use a static ' +
+          'property to define propTypes instead.',
+        this.getName() || 'a component',
+      );
+      warning(
+        !inst.contextTypes,
+        'contextTypes was defined as an instance property on %s. Use a ' +
+          'static property to define contextTypes instead.',
+        this.getName() || 'a component',
+      );
+      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',
+      );
+      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',
+      );
+      warning(
+        typeof inst.componentWillRecieveProps !== 'function',
+        '%s has a method called ' +
+          'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?',
+        this.getName() || 'A component',
+      );
+    }
+
+    var initialState = inst.state;
+    if (initialState === undefined) {
+      inst.state = initialState = null;
+    }
+    invariant(
+      typeof initialState === 'object' && !Array.isArray(initialState),
+      '%s.state: must be set to an object or null',
+      this.getName() || 'ReactCompositeComponent',
+    );
+
+    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 (__DEV__) {
+        transaction.getReactMountReady().enqueue(() => {
+          measureLifeCyclePerf(
+            () => inst.componentDidMount(),
+            this._debugID,
+            'componentDidMount',
+          );
+        });
+      } else {
+        transaction.getReactMountReady().enqueue(inst.componentDidMount, inst);
+      }
+    }
+
+    return markup;
+  },
+
+  _constructComponent: function(
+    doConstruct,
+    publicProps,
+    publicContext,
+    updateQueue,
+  ) {
+    if (__DEV__) {
+      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 (__DEV__) {
+        return measureLifeCyclePerf(
+          () => 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 (__DEV__) {
+      return measureLifeCyclePerf(
+        () => 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 (__DEV__) {
+      debugID = this._debugID;
+    }
+
+    if (inst.componentWillMount) {
+      if (__DEV__) {
+        measureLifeCyclePerf(
+          () => 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 (__DEV__) {
+      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 (__DEV__) {
+          measureLifeCyclePerf(
+            () => 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 (__DEV__) {
+      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 (__DEV__) {
+        ReactInstrumentation.debugTool.onBeginProcessingChildContext();
+        try {
+          childContext = inst.getChildContext();
+        } finally {
+          ReactInstrumentation.debugTool.onEndProcessingChildContext();
+        }
+      } else {
+        childContext = inst.getChildContext();
+      }
+    }
+
+    if (childContext) {
+      invariant(
+        typeof Component.childContextTypes === 'object',
+        '%s.getChildContext(): childContextTypes must be defined in order to ' +
+          'use getChildContext().',
+        this.getName() || 'ReactCompositeComponent',
+      );
+      if (__DEV__) {
+        this._checkContextTypes(
+          Component.childContextTypes,
+          childContext,
+          'child context',
+        );
+      }
+      for (var name in childContext) {
+        invariant(
+          name in Component.childContextTypes,
+          '%s.getChildContext(): key "%s" is not defined in childContextTypes.',
+          this.getName() || 'ReactCompositeComponent',
+          name,
+        );
+      }
+      return Object.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: ReactPropTypeLocations,
+  ) {
+    if (__DEV__) {
+      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;
+    invariant(
+      inst != null,
+      'Attempted to update component `%s` that has already been unmounted ' +
+        '(or failed to mount).',
+      this.getName() || 'ReactCompositeComponent',
+    );
+
+    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 (__DEV__) {
+        measureLifeCyclePerf(
+          () => 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 (__DEV__) {
+          shouldUpdate = measureLifeCyclePerf(
+            () => 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 (__DEV__) {
+      warning(
+        shouldUpdate !== undefined,
+        '%s.shouldComponentUpdate(): Returned undefined instead of a ' +
+          'boolean value. Make sure to return true or false.',
+        this.getName() || 'ReactCompositeComponent',
+      );
+    }
+
+    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 = Object.assign({}, replace ? queue[0] : inst.state);
+    for (var i = replace ? 1 : 0; i < queue.length; i++) {
+      var partial = queue[i];
+      Object.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 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 (__DEV__) {
+        measureLifeCyclePerf(
+          () => 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 (__DEV__) {
+        transaction.getReactMountReady().enqueue(() => {
+          measureLifeCyclePerf(
+            inst.componentDidUpdate.bind(
+              inst,
+              prevProps,
+              prevState,
+              prevContext,
+            ),
+            this._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 (__DEV__) {
+      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 (__DEV__) {
+        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 (__DEV__) {
+      renderedElement = measureLifeCyclePerf(
+        () => inst.render(),
+        this._debugID,
+        'render',
+      );
+    } else {
+      renderedElement = inst.render();
+    }
+
+    if (__DEV__) {
+      // 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 (__DEV__ || this._compositeType !== CompositeTypes.StatelessFunctional) {
+      ReactCurrentOwner.current = this;
+      try {
+        renderedElement = this._renderValidatedComponentWithoutOwnerOrContext();
+      } finally {
+        ReactCurrentOwner.current = null;
+      }
+    } else {
+      renderedElement = this._renderValidatedComponentWithoutOwnerOrContext();
+    }
+    invariant(
+      // TODO: An `isValidNode` function would probably be more appropriate
+      renderedElement === null ||
+        renderedElement === false ||
+        React.isValidElement(renderedElement),
+      '%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',
+    );
+
+    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();
+    invariant(inst != null, 'Stateless function components cannot have refs.');
+    var publicComponentInstance = component.getPublicInstance();
+    if (__DEV__) {
+      var componentName = component && component.getName
+        ? component.getName()
+        : 'a component';
+      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(),
+      );
+    }
+    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;
diff --git a/src/renderers/shared/reconciler/ReactDefaultBatchingStrategy.js b/src/renderers/shared/stack/reconciler/ReactDefaultBatchingStrategy.js
similarity index 85%
rename from src/renderers/shared/reconciler/ReactDefaultBatchingStrategy.js
rename to src/renderers/shared/stack/reconciler/ReactDefaultBatchingStrategy.js
index 904dc1f803c1..b23847d72288 100644
--- a/src/renderers/shared/reconciler/ReactDefaultBatchingStrategy.js
+++ b/src/renderers/shared/stack/reconciler/ReactDefaultBatchingStrategy.js
@@ -34,15 +34,11 @@ function ReactDefaultBatchingStrategyTransaction() {
   this.reinitializeTransaction();
 }
 
-Object.assign(
-  ReactDefaultBatchingStrategyTransaction.prototype,
-  Transaction.Mixin,
-  {
-    getTransactionWrappers: function() {
-      return TRANSACTION_WRAPPERS;
-    },
-  }
-);
+Object.assign(ReactDefaultBatchingStrategyTransaction.prototype, Transaction, {
+  getTransactionWrappers: function() {
+    return TRANSACTION_WRAPPERS;
+  },
+});
 
 var transaction = new ReactDefaultBatchingStrategyTransaction();
 
@@ -60,9 +56,9 @@ var ReactDefaultBatchingStrategy = {
 
     // The code is written this way to avoid extra allocations
     if (alreadyBatchingUpdates) {
-      callback(a, b, c, d, e);
+      return callback(a, b, c, d, e);
     } else {
-      transaction.perform(callback, null, a, b, c, d, e);
+      return transaction.perform(callback, null, a, b, c, d, e);
     }
   },
 };
diff --git a/src/renderers/shared/reconciler/ReactEmptyComponent.js b/src/renderers/shared/stack/reconciler/ReactEmptyComponent.js
similarity index 100%
rename from src/renderers/shared/reconciler/ReactEmptyComponent.js
rename to src/renderers/shared/stack/reconciler/ReactEmptyComponent.js
diff --git a/src/renderers/shared/reconciler/ReactEventEmitterMixin.js b/src/renderers/shared/stack/reconciler/ReactEventEmitterMixin.js
similarity index 89%
rename from src/renderers/shared/reconciler/ReactEventEmitterMixin.js
rename to src/renderers/shared/stack/reconciler/ReactEventEmitterMixin.js
index 94461f88024e..63134a57e1be 100644
--- a/src/renderers/shared/reconciler/ReactEventEmitterMixin.js
+++ b/src/renderers/shared/stack/reconciler/ReactEventEmitterMixin.js
@@ -19,21 +19,21 @@ function runEventQueueInBatch(events) {
 }
 
 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) {
+    topLevelType,
+    targetInst,
+    nativeEvent,
+    nativeEventTarget,
+  ) {
     var events = EventPluginHub.extractEvents(
       topLevelType,
       targetInst,
       nativeEvent,
-      nativeEventTarget
+      nativeEventTarget,
     );
     runEventQueueInBatch(events);
   },
diff --git a/src/renderers/shared/stack/reconciler/ReactHostComponent.js b/src/renderers/shared/stack/reconciler/ReactHostComponent.js
new file mode 100644
index 000000000000..c6c06b8b7b14
--- /dev/null
+++ b/src/renderers/shared/stack/reconciler/ReactHostComponent.js
@@ -0,0 +1,70 @@
+/**
+ * Copyright 2014-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 ReactHostComponent
+ */
+
+'use strict';
+
+var invariant = require('invariant');
+
+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) {
+  invariant(
+    genericComponentClass,
+    'There is no registered component for the tag %s',
+    element.type,
+  );
+  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;
diff --git a/src/renderers/shared/stack/reconciler/ReactInstanceType.js b/src/renderers/shared/stack/reconciler/ReactInstanceType.js
new file mode 100644
index 000000000000..bb213281b913
--- /dev/null
+++ b/src/renderers/shared/stack/reconciler/ReactInstanceType.js
@@ -0,0 +1,42 @@
+/**
+ * Copyright 2016-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 ReactInstanceType
+ * @flow
+ */
+
+'use strict';
+
+export type DebugID = number;
+
+export type ReactInstance = {
+  // ReactCompositeComponent
+  mountComponent: any,
+  performInitialMountWithErrorHandling: any,
+  performInitialMount: any,
+  getHostNode: any,
+  unmountComponent: any,
+  receiveComponent: any,
+  performUpdateIfNecessary: any,
+  updateComponent: any,
+  attachRef: (ref: string, component: ReactInstance) => void,
+  detachRef: (ref: string) => void,
+  getName: () => string,
+  getPublicInstance: any,
+  _rootNodeID: number,
+
+  // ReactDOMComponent
+  _tag: string,
+
+  // instantiateReactComponent
+  _mountIndex: number,
+  _mountImage: any,
+  // __DEV__
+  _debugID: DebugID,
+  _warnedAboutRefsInRender: boolean,
+};
diff --git a/src/renderers/shared/reconciler/ReactMultiChild.js b/src/renderers/shared/stack/reconciler/ReactMultiChild.js
similarity index 79%
rename from src/renderers/shared/reconciler/ReactMultiChild.js
rename to src/renderers/shared/stack/reconciler/ReactMultiChild.js
index 66f38613218b..d1821eadee37 100644
--- a/src/renderers/shared/reconciler/ReactMultiChild.js
+++ b/src/renderers/shared/stack/reconciler/ReactMultiChild.js
@@ -12,12 +12,14 @@
 'use strict';
 
 var ReactComponentEnvironment = require('ReactComponentEnvironment');
-var ReactMultiChildUpdateTypes = require('ReactMultiChildUpdateTypes');
+var ReactInstanceMap = require('ReactInstanceMap');
+var ReactInstrumentation = require('ReactInstrumentation');
 
 var ReactCurrentOwner = require('ReactCurrentOwner');
 var ReactReconciler = require('ReactReconciler');
 var ReactChildReconciler = require('ReactChildReconciler');
 
+var emptyFunction = require('emptyFunction');
 var flattenChildren = require('flattenChildren');
 var invariant = require('invariant');
 
@@ -31,7 +33,7 @@ var invariant = require('invariant');
 function makeInsertMarkup(markup, afterNode, toIndex) {
   // NOTE: Null values reduce hidden classes.
   return {
-    type: ReactMultiChildUpdateTypes.INSERT_MARKUP,
+    type: 'INSERT_MARKUP',
     content: markup,
     fromIndex: null,
     fromNode: null,
@@ -50,10 +52,10 @@ function makeInsertMarkup(markup, afterNode, toIndex) {
 function makeMove(child, afterNode, toIndex) {
   // NOTE: Null values reduce hidden classes.
   return {
-    type: ReactMultiChildUpdateTypes.MOVE_EXISTING,
+    type: 'MOVE_EXISTING',
     content: null,
     fromIndex: child._mountIndex,
-    fromNode: ReactReconciler.getNativeNode(child),
+    fromNode: ReactReconciler.getHostNode(child),
     toIndex: toIndex,
     afterNode: afterNode,
   };
@@ -68,7 +70,7 @@ function makeMove(child, afterNode, toIndex) {
 function makeRemove(child, node) {
   // NOTE: Null values reduce hidden classes.
   return {
-    type: ReactMultiChildUpdateTypes.REMOVE_NODE,
+    type: 'REMOVE_NODE',
     content: null,
     fromIndex: child._mountIndex,
     fromNode: node,
@@ -86,7 +88,7 @@ function makeRemove(child, node) {
 function makeSetMarkup(markup) {
   // NOTE: Null values reduce hidden classes.
   return {
-    type: ReactMultiChildUpdateTypes.SET_MARKUP,
+    type: 'SET_MARKUP',
     content: markup,
     fromIndex: null,
     fromNode: null,
@@ -104,7 +106,7 @@ function makeSetMarkup(markup) {
 function makeTextContent(textContent) {
   // NOTE: Null values reduce hidden classes.
   return {
-    type: ReactMultiChildUpdateTypes.TEXT_CONTENT,
+    type: 'TEXT_CONTENT',
     content: textContent,
     fromIndex: null,
     fromNode: null,
@@ -131,10 +133,34 @@ function enqueue(queue, update) {
  * @private
  */
 function processQueue(inst, updateQueue) {
-  ReactComponentEnvironment.processChildrenUpdates(
-    inst,
-    updateQueue,
-  );
+  ReactComponentEnvironment.processChildrenUpdates(inst, updateQueue);
+}
+
+var setChildrenForInstrumentation = emptyFunction;
+if (__DEV__) {
+  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(key => children[key]._debugID)
+          : [],
+      );
+    }
+  };
 }
 
 /**
@@ -144,7 +170,6 @@ function processQueue(inst, updateQueue) {
  * @internal
  */
 var ReactMultiChild = {
-
   /**
    * Provides common functionality for components that must reconcile multiple
    * children. This is used by `ReactDOMComponent` to mount, update, and
@@ -153,14 +178,21 @@ var ReactMultiChild = {
    * @lends {ReactMultiChild.prototype}
    */
   Mixin: {
-
-    _reconcilerInstantiateChildren: function(nestedChildren, transaction, context) {
+    _reconcilerInstantiateChildren: function(
+      nestedChildren,
+      transaction,
+      context,
+    ) {
       if (__DEV__) {
+        var selfDebugID = getDebugID(this);
         if (this._currentElement) {
           try {
             ReactCurrentOwner.current = this._currentElement._owner;
             return ReactChildReconciler.instantiateChildren(
-              nestedChildren, transaction, context
+              nestedChildren,
+              transaction,
+              context,
+              selfDebugID,
             );
           } finally {
             ReactCurrentOwner.current = null;
@@ -168,35 +200,59 @@ var ReactMultiChild = {
         }
       }
       return ReactChildReconciler.instantiateChildren(
-        nestedChildren, transaction, context
+        nestedChildren,
+        transaction,
+        context,
       );
     },
 
     _reconcilerUpdateChildren: function(
       prevChildren,
       nextNestedChildrenElements,
+      mountImages,
       removedNodes,
       transaction,
-      context
+      context,
     ) {
       var nextChildren;
+      var selfDebugID = 0;
       if (__DEV__) {
+        selfDebugID = getDebugID(this);
         if (this._currentElement) {
           try {
             ReactCurrentOwner.current = this._currentElement._owner;
-            nextChildren = flattenChildren(nextNestedChildrenElements);
+            nextChildren = flattenChildren(
+              nextNestedChildrenElements,
+              selfDebugID,
+            );
           } finally {
             ReactCurrentOwner.current = null;
           }
           ReactChildReconciler.updateChildren(
-            prevChildren, nextChildren, removedNodes, transaction, context
+            prevChildren,
+            nextChildren,
+            mountImages,
+            removedNodes,
+            transaction,
+            this,
+            this._hostContainerInfo,
+            context,
+            selfDebugID,
           );
           return nextChildren;
         }
       }
-      nextChildren = flattenChildren(nextNestedChildrenElements);
+      nextChildren = flattenChildren(nextNestedChildrenElements, selfDebugID);
       ReactChildReconciler.updateChildren(
-        prevChildren, nextChildren, removedNodes, transaction, context
+        prevChildren,
+        nextChildren,
+        mountImages,
+        removedNodes,
+        transaction,
+        this,
+        this._hostContainerInfo,
+        context,
+        selfDebugID,
       );
       return nextChildren;
     },
@@ -211,25 +267,38 @@ var ReactMultiChild = {
      */
     mountChildren: function(nestedChildren, transaction, context) {
       var children = this._reconcilerInstantiateChildren(
-        nestedChildren, transaction, context
+        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 (__DEV__) {
+            selfDebugID = getDebugID(this);
+          }
           var mountImage = ReactReconciler.mountComponent(
             child,
             transaction,
             this,
-            this._nativeContainerInfo,
-            context
+            this._hostContainerInfo,
+            context,
+            selfDebugID,
           );
           child._mountIndex = index++;
           mountImages.push(mountImage);
         }
       }
+
+      if (__DEV__) {
+        setChildrenForInstrumentation.call(this, children);
+      }
+
       return mountImages;
     },
 
@@ -290,15 +359,21 @@ var ReactMultiChild = {
      * @final
      * @protected
      */
-    _updateChildren: function(nextNestedChildrenElements, transaction, context) {
+    _updateChildren: function(
+      nextNestedChildrenElements,
+      transaction,
+      context,
+    ) {
       var prevChildren = this._renderedChildren;
       var removedNodes = {};
+      var mountImages = [];
       var nextChildren = this._reconcilerUpdateChildren(
         prevChildren,
         nextNestedChildrenElements,
+        mountImages,
         removedNodes,
         transaction,
-        context
+        context,
       );
       if (!nextChildren && !prevChildren) {
         return;
@@ -307,8 +382,10 @@ var ReactMultiChild = {
       var name;
       // `nextIndex` will increment for each child in `nextChildren`, but
       // `lastIndex` will be the last index visited in `prevChildren`.
-      var lastIndex = 0;
       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)) {
@@ -319,7 +396,7 @@ var ReactMultiChild = {
         if (prevChild === nextChild) {
           updates = enqueue(
             updates,
-            this.moveChild(prevChild, lastPlacedNode, nextIndex, lastIndex)
+            this.moveChild(prevChild, lastPlacedNode, nextIndex, lastIndex),
           );
           lastIndex = Math.max(prevChild._mountIndex, lastIndex);
           prevChild._mountIndex = nextIndex;
@@ -334,22 +411,24 @@ var ReactMultiChild = {
             updates,
             this._mountChildAtIndex(
               nextChild,
+              mountImages[nextMountIndex],
               lastPlacedNode,
               nextIndex,
               transaction,
-              context
-            )
+              context,
+            ),
           );
+          nextMountIndex++;
         }
         nextIndex++;
-        lastPlacedNode = ReactReconciler.getNativeNode(nextChild);
+        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])
+            this._unmountChild(prevChildren[name], removedNodes[name]),
           );
         }
       }
@@ -357,6 +436,10 @@ var ReactMultiChild = {
         processQueue(this, updates);
       }
       this._renderedChildren = nextChildren;
+
+      if (__DEV__) {
+        setChildrenForInstrumentation.call(this, nextChildren);
+      }
     },
 
     /**
@@ -423,17 +506,12 @@ var ReactMultiChild = {
      */
     _mountChildAtIndex: function(
       child,
+      mountImage,
       afterNode,
       index,
       transaction,
-      context) {
-      var mountImage = ReactReconciler.mountComponent(
-        child,
-        transaction,
-        this,
-        this._nativeContainerInfo,
-        context
-      );
+      context,
+    ) {
       child._mountIndex = index;
       return this.createChild(child, afterNode, mountImage);
     },
@@ -451,9 +529,7 @@ var ReactMultiChild = {
       child._mountIndex = null;
       return update;
     },
-
   },
-
 };
 
 module.exports = ReactMultiChild;
diff --git a/src/renderers/shared/stack/reconciler/ReactMultiChildUpdateTypes.js b/src/renderers/shared/stack/reconciler/ReactMultiChildUpdateTypes.js
new file mode 100644
index 000000000000..1319db50fae5
--- /dev/null
+++ b/src/renderers/shared/stack/reconciler/ReactMultiChildUpdateTypes.js
@@ -0,0 +1,25 @@
+/**
+ * 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 ReactMultiChildUpdateTypes
+ */
+
+'use strict';
+
+/**
+ * When a component's children are updated, a series of update configuration
+ * objects are created in order to batch and serialize the required changes.
+ *
+ * Enumerates all the possible types of update configurations.
+ */
+export type ReactMultiChildUpdateTypes =
+  | 'INSERT_MARKUP'
+  | 'MOVE_EXISTING'
+  | 'REMOVE_NODE'
+  | 'SET_MARKUP'
+  | 'TEXT_CONTENT';
diff --git a/src/shared/utils/ReactNodeTypes.js b/src/renderers/shared/stack/reconciler/ReactNodeTypes.js
similarity index 76%
rename from src/shared/utils/ReactNodeTypes.js
rename to src/renderers/shared/stack/reconciler/ReactNodeTypes.js
index 75bd75d139cf..7b8d6f2094cc 100644
--- a/src/shared/utils/ReactNodeTypes.js
+++ b/src/renderers/shared/stack/reconciler/ReactNodeTypes.js
@@ -7,27 +7,30 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule ReactNodeTypes
+ * @flow
  */
 
 'use strict';
 
-var ReactElement = require('ReactElement');
+type ReactNodeType = 0 | 1 | 2;
+
+var React = require('React');
 
 var invariant = require('invariant');
 
 var ReactNodeTypes = {
-  NATIVE: 0,
+  HOST: 0,
   COMPOSITE: 1,
   EMPTY: 2,
 
-  getType: function(node) {
+  getType: function(node: ReactElement<any>): ReactNodeType {
     if (node === null || node === false) {
       return ReactNodeTypes.EMPTY;
-    } else if (ReactElement.isValidElement(node)) {
+    } else if (React.isValidElement(node)) {
       if (typeof node.type === 'function') {
         return ReactNodeTypes.COMPOSITE;
       } else {
-        return ReactNodeTypes.NATIVE;
+        return ReactNodeTypes.HOST;
       }
     }
     invariant(false, 'Unexpected node: %s', node);
diff --git a/src/renderers/shared/stack/reconciler/ReactOwner.js b/src/renderers/shared/stack/reconciler/ReactOwner.js
new file mode 100644
index 000000000000..a25e987d8942
--- /dev/null
+++ b/src/renderers/shared/stack/reconciler/ReactOwner.js
@@ -0,0 +1,120 @@
+/**
+ * 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 ReactOwner
+ * @flow
+ */
+
+'use strict';
+
+var invariant = require('invariant');
+
+import type {ReactInstance} from 'ReactInstanceType';
+
+/**
+ * @param {?object} object
+ * @return {boolean} True if `object` is a valid owner.
+ * @final
+ */
+function isValidOwner(object: any): boolean {
+  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: ReactInstance,
+    ref: string,
+    owner: ReactInstance,
+  ): void {
+    invariant(
+      isValidOwner(owner),
+      '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).',
+    );
+    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: ReactInstance,
+    ref: string,
+    owner: ReactInstance,
+  ): void {
+    invariant(
+      isValidOwner(owner),
+      '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).',
+    );
+    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;
diff --git a/src/renderers/shared/stack/reconciler/ReactReconciler.js b/src/renderers/shared/stack/reconciler/ReactReconciler.js
new file mode 100644
index 000000000000..12c1b60ef66e
--- /dev/null
+++ b/src/renderers/shared/stack/reconciler/ReactReconciler.js
@@ -0,0 +1,221 @@
+/**
+ * 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 ReactReconciler
+ */
+
+'use strict';
+
+var ReactRef = require('ReactRef');
+var ReactInstrumentation = require('ReactInstrumentation');
+
+var warning = require('warning');
+
+/**
+ * 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 (__DEV__) {
+      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 (__DEV__) {
+      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 (__DEV__) {
+      if (internalInstance._debugID !== 0) {
+        ReactInstrumentation.debugTool.onBeforeUnmountComponent(
+          internalInstance._debugID,
+        );
+      }
+    }
+    ReactRef.detachRefs(internalInstance, internalInstance._currentElement);
+    internalInstance.unmountComponent(safely);
+    if (__DEV__) {
+      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 (__DEV__) {
+      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 (__DEV__) {
+      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.
+      warning(
+        internalInstance._updateBatchNumber == null ||
+          internalInstance._updateBatchNumber === updateBatchNumber + 1,
+        'performUpdateIfNecessary: Unexpected batch number (current %s, ' +
+          'pending %s)',
+        updateBatchNumber,
+        internalInstance._updateBatchNumber,
+      );
+      return;
+    }
+    if (__DEV__) {
+      if (internalInstance._debugID !== 0) {
+        ReactInstrumentation.debugTool.onBeforeUpdateComponent(
+          internalInstance._debugID,
+          internalInstance._currentElement,
+        );
+      }
+    }
+    internalInstance.performUpdateIfNecessary(transaction);
+    if (__DEV__) {
+      if (internalInstance._debugID !== 0) {
+        ReactInstrumentation.debugTool.onUpdateComponent(
+          internalInstance._debugID,
+        );
+      }
+    }
+  },
+};
+
+module.exports = ReactReconciler;
diff --git a/src/renderers/shared/stack/reconciler/ReactRef.js b/src/renderers/shared/stack/reconciler/ReactRef.js
new file mode 100644
index 000000000000..e5c497223e2c
--- /dev/null
+++ b/src/renderers/shared/stack/reconciler/ReactRef.js
@@ -0,0 +1,103 @@
+/**
+ * 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 ReactRef
+ * @flow
+ */
+
+'use strict';
+
+var ReactOwner = require('ReactOwner');
+
+import type {ReactInstance} from 'ReactInstanceType';
+import type {ReactElement} from 'ReactElementType';
+
+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: ReactInstance,
+  element: ReactElement | string | number | null | false,
+): void {
+  if (element === null || typeof element !== 'object') {
+    return;
+  }
+  var ref = element.ref;
+  if (ref != null) {
+    attachRef(ref, instance, element._owner);
+  }
+};
+
+ReactRef.shouldUpdateRefs = function(
+  prevElement: ReactElement | string | number | null | false,
+  nextElement: ReactElement | string | number | null | false,
+): boolean {
+  // 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: ReactInstance,
+  element: ReactElement | string | number | null | false,
+): void {
+  if (element === null || typeof element !== 'object') {
+    return;
+  }
+  var ref = element.ref;
+  if (ref != null) {
+    detachRef(ref, instance, element._owner);
+  }
+};
+
+module.exports = ReactRef;
diff --git a/src/renderers/shared/reconciler/ReactSimpleEmptyComponent.js b/src/renderers/shared/stack/reconciler/ReactSimpleEmptyComponent.js
similarity index 76%
rename from src/renderers/shared/reconciler/ReactSimpleEmptyComponent.js
rename to src/renderers/shared/stack/reconciler/ReactSimpleEmptyComponent.js
index 0565a0164418..fe009b0c4485 100644
--- a/src/renderers/shared/reconciler/ReactSimpleEmptyComponent.js
+++ b/src/renderers/shared/stack/reconciler/ReactSimpleEmptyComponent.js
@@ -13,7 +13,6 @@
 
 var ReactReconciler = require('ReactReconciler');
 
-
 var ReactSimpleEmptyComponent = function(placeholderElement, instantiate) {
   this._currentElement = null;
   this._renderedComponent = instantiate(placeholderElement);
@@ -21,22 +20,23 @@ var ReactSimpleEmptyComponent = function(placeholderElement, instantiate) {
 Object.assign(ReactSimpleEmptyComponent.prototype, {
   mountComponent: function(
     transaction,
-    nativeParent,
-    nativeContainerInfo,
-    context
+    hostParent,
+    hostContainerInfo,
+    context,
+    parentDebugID, // 0 in production and for roots
   ) {
     return ReactReconciler.mountComponent(
       this._renderedComponent,
       transaction,
-      nativeParent,
-      nativeContainerInfo,
-      context
+      hostParent,
+      hostContainerInfo,
+      context,
+      parentDebugID,
     );
   },
-  receiveComponent: function() {
-  },
-  getNativeNode: function() {
-    return ReactReconciler.getNativeNode(this._renderedComponent);
+  receiveComponent: function() {},
+  getHostNode: function() {
+    return ReactReconciler.getHostNode(this._renderedComponent);
   },
   unmountComponent: function() {
     ReactReconciler.unmountComponent(this._renderedComponent);
diff --git a/src/renderers/shared/reconciler/ReactUpdateQueue.js b/src/renderers/shared/stack/reconciler/ReactUpdateQueue.js
similarity index 77%
rename from src/renderers/shared/reconciler/ReactUpdateQueue.js
rename to src/renderers/shared/stack/reconciler/ReactUpdateQueue.js
index 65bdd490525a..c5474d67fe36 100644
--- a/src/renderers/shared/reconciler/ReactUpdateQueue.js
+++ b/src/renderers/shared/stack/reconciler/ReactUpdateQueue.js
@@ -13,6 +13,7 @@
 
 var ReactCurrentOwner = require('ReactCurrentOwner');
 var ReactInstanceMap = require('ReactInstanceMap');
+var ReactInstrumentation = require('ReactInstrumentation');
 var ReactUpdates = require('ReactUpdates');
 
 var invariant = require('invariant');
@@ -27,7 +28,7 @@ function formatUnexpectedArgument(arg) {
   if (type !== 'object') {
     return type;
   }
-  var displayName = arg.constructor && arg.constructor.name || 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(', ')})`;
@@ -39,17 +40,18 @@ function getInternalInstanceReadyForUpdate(publicInstance, callerName) {
   var internalInstance = ReactInstanceMap.get(publicInstance);
   if (!internalInstance) {
     if (__DEV__) {
+      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.
       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.',
+          '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,
-        publicInstance.constructor.displayName
+        (ctor && (ctor.displayName || ctor.name)) || 'ReactClass',
       );
     }
     return null;
@@ -59,11 +61,11 @@ function getInternalInstanceReadyForUpdate(publicInstance, callerName) {
     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
+        "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,
     );
   }
 
@@ -75,7 +77,6 @@ function getInternalInstanceReadyForUpdate(publicInstance, callerName) {
  * reconciliation step.
  */
 var ReactUpdateQueue = {
-
   /**
    * Checks whether or not this composite component is mounted.
    * @param {ReactClass} publicInstance The instance we want to test.
@@ -90,11 +91,11 @@ var ReactUpdateQueue = {
         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'
+            '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',
         );
         owner._warnedAboutRefsInRender = true;
       }
@@ -169,7 +170,7 @@ var ReactUpdateQueue = {
   enqueueForceUpdate: function(publicInstance) {
     var internalInstance = getInternalInstanceReadyForUpdate(
       publicInstance,
-      'forceUpdate'
+      'forceUpdate',
     );
 
     if (!internalInstance) {
@@ -192,10 +193,10 @@ var ReactUpdateQueue = {
    * @param {object} completeState Next state.
    * @internal
    */
-  enqueueReplaceState: function(publicInstance, completeState) {
+  enqueueReplaceState: function(publicInstance, completeState, callback) {
     var internalInstance = getInternalInstanceReadyForUpdate(
       publicInstance,
-      'replaceState'
+      'replaceState',
     );
 
     if (!internalInstance) {
@@ -205,6 +206,16 @@ var ReactUpdateQueue = {
     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);
   },
 
@@ -219,9 +230,18 @@ var ReactUpdateQueue = {
    * @internal
    */
   enqueueSetState: function(publicInstance, partialState) {
+    if (__DEV__) {
+      ReactInstrumentation.debugTool.onSetState();
+      warning(
+        partialState != null,
+        'setState(...): You passed an undefined or null state object; ' +
+          'instead, use forceUpdate().',
+      );
+    }
+
     var internalInstance = getInternalInstanceReadyForUpdate(
       publicInstance,
-      'setState'
+      'setState',
     );
 
     if (!internalInstance) {
@@ -236,8 +256,10 @@ var ReactUpdateQueue = {
     enqueueUpdate(internalInstance);
   },
 
-  enqueueElementInternal: function(internalInstance, newElement) {
-    internalInstance._pendingElement = newElement;
+  enqueueElementInternal: function(internalInstance, nextElement, nextContext) {
+    internalInstance._pendingElement = nextElement;
+    // TODO: introduce _pendingContext instead of setting it directly.
+    internalInstance._context = nextContext;
     enqueueUpdate(internalInstance);
   },
 
@@ -245,12 +267,11 @@ var ReactUpdateQueue = {
     invariant(
       !callback || typeof callback === 'function',
       '%s(...): Expected the last optional `callback` argument to be a ' +
-      'function. Instead received: %s.',
+        'function. Instead received: %s.',
       callerName,
-      formatUnexpectedArgument(callback)
+      formatUnexpectedArgument(callback),
     );
   },
-
 };
 
 module.exports = ReactUpdateQueue;
diff --git a/src/renderers/shared/reconciler/ReactUpdates.js b/src/renderers/shared/stack/reconciler/ReactUpdates.js
similarity index 77%
rename from src/renderers/shared/reconciler/ReactUpdates.js
rename to src/renderers/shared/stack/reconciler/ReactUpdates.js
index 6fd1d2f3b528..782af8a2a48c 100644
--- a/src/renderers/shared/reconciler/ReactUpdates.js
+++ b/src/renderers/shared/stack/reconciler/ReactUpdates.js
@@ -14,13 +14,13 @@
 var CallbackQueue = require('CallbackQueue');
 var PooledClass = require('PooledClass');
 var ReactFeatureFlags = require('ReactFeatureFlags');
-var ReactPerf = require('ReactPerf');
 var ReactReconciler = require('ReactReconciler');
 var Transaction = require('Transaction');
 
 var invariant = require('invariant');
 
 var dirtyComponents = [];
+var updateBatchNumber = 0;
 var asapCallbackQueue = CallbackQueue.getPooled();
 var asapEnqueued = false;
 
@@ -30,7 +30,7 @@ function ensureInjected() {
   invariant(
     ReactUpdates.ReactReconcileTransaction && batchingStrategy,
     'ReactUpdates: must inject a reconcile transaction class and batching ' +
-    'strategy'
+      'strategy',
   );
 }
 
@@ -69,46 +69,42 @@ function ReactUpdatesFlushTransaction() {
   this.dirtyComponentsLength = null;
   this.callbackQueue = CallbackQueue.getPooled();
   this.reconcileTransaction = ReactUpdates.ReactReconcileTransaction.getPooled(
-    /* useCreateElement */ true
+    /* useCreateElement */ true,
   );
 }
 
-Object.assign(
-  ReactUpdatesFlushTransaction.prototype,
-  Transaction.Mixin,
-  {
-    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.Mixin.perform.call(
-        this,
-        this.reconcileTransaction.perform,
-        this.reconcileTransaction,
-        method,
-        scope,
-        a
-      );
-    },
-  }
-);
+Object.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();
-  batchingStrategy.batchedUpdates(callback, a, b, c, d, e);
+  return batchingStrategy.batchedUpdates(callback, a, b, c, d, e);
 }
 
 /**
@@ -126,10 +122,10 @@ function runBatchedUpdates(transaction) {
   var len = transaction.dirtyComponentsLength;
   invariant(
     len === dirtyComponents.length,
-    'Expected flush transaction\'s stored dirty-components length (%s) to ' +
-    'match dirty-components array length (%s).',
+    "Expected flush transaction's stored dirty-components length (%s) to " +
+      'match dirty-components array length (%s).',
     len,
-    dirtyComponents.length
+    dirtyComponents.length,
   );
 
   // Since reconciling a component higher in the owner hierarchy usually (not
@@ -137,6 +133,13 @@ function runBatchedUpdates(transaction) {
   // 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
@@ -153,10 +156,7 @@ function runBatchedUpdates(transaction) {
     if (ReactFeatureFlags.logTopLevelRenders) {
       var namedComponent = component;
       // Duck type TopLevelWrapper. This is probably always true.
-      if (
-        component._currentElement.props ===
-        component._renderedComponent._currentElement
-      ) {
+      if (component._currentElement.type.isReactTopLevelWrapper) {
         namedComponent = component._renderedComponent;
       }
       markerName = 'React update: ' + namedComponent.getName();
@@ -165,7 +165,8 @@ function runBatchedUpdates(transaction) {
 
     ReactReconciler.performUpdateIfNecessary(
       component,
-      transaction.reconcileTransaction
+      transaction.reconcileTransaction,
+      updateBatchNumber,
     );
 
     if (markerName) {
@@ -176,7 +177,7 @@ function runBatchedUpdates(transaction) {
       for (var j = 0; j < callbacks.length; j++) {
         transaction.callbackQueue.enqueue(
           callbacks[j],
-          component.getPublicInstance()
+          component.getPublicInstance(),
         );
       }
     }
@@ -204,11 +205,6 @@ var flushBatchedUpdates = function() {
     }
   }
 };
-flushBatchedUpdates = ReactPerf.measure(
-  'ReactUpdates',
-  'flushBatchedUpdates',
-  flushBatchedUpdates
-);
 
 /**
  * Mark a component as needing a rerender, adding an optional callback to a
@@ -220,7 +216,7 @@ function enqueueUpdate(component) {
   // 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 setProps, setState, forceUpdate, etc.; creation and
+  // function, like setState, forceUpdate, etc.; creation and
   // destruction of top-level components is guarded in ReactMount.)
 
   if (!batchingStrategy.isBatchingUpdates) {
@@ -229,6 +225,9 @@ function enqueueUpdate(component) {
   }
 
   dirtyComponents.push(component);
+  if (component._updateBatchNumber == null) {
+    component._updateBatchNumber = updateBatchNumber + 1;
+  }
 }
 
 /**
@@ -238,8 +237,8 @@ function enqueueUpdate(component) {
 function asap(callback, context) {
   invariant(
     batchingStrategy.isBatchingUpdates,
-    'ReactUpdates.asap: Can\'t enqueue an asap callback in a context where' +
-    'updates are not being batched.'
+    "ReactUpdates.asap: Can't enqueue an asap callback in a context where" +
+      'updates are not being batched.',
   );
   asapCallbackQueue.enqueue(callback, context);
   asapEnqueued = true;
@@ -249,7 +248,7 @@ var ReactUpdatesInjection = {
   injectReconcileTransaction: function(ReconcileTransaction) {
     invariant(
       ReconcileTransaction,
-      'ReactUpdates: must provide a reconcile transaction class'
+      'ReactUpdates: must provide a reconcile transaction class',
     );
     ReactUpdates.ReactReconcileTransaction = ReconcileTransaction;
   },
@@ -257,15 +256,15 @@ var ReactUpdatesInjection = {
   injectBatchingStrategy: function(_batchingStrategy) {
     invariant(
       _batchingStrategy,
-      'ReactUpdates: must provide a batching strategy'
+      'ReactUpdates: must provide a batching strategy',
     );
     invariant(
       typeof _batchingStrategy.batchedUpdates === 'function',
-      'ReactUpdates: must provide a batchedUpdates() function'
+      'ReactUpdates: must provide a batchedUpdates() function',
     );
     invariant(
       typeof _batchingStrategy.isBatchingUpdates === 'boolean',
-      'ReactUpdates: must provide an isBatchingUpdates boolean attribute'
+      'ReactUpdates: must provide an isBatchingUpdates boolean attribute',
     );
     batchingStrategy = _batchingStrategy;
   },
diff --git a/src/renderers/shared/stack/reconciler/__tests__/ReactChildReconciler-test.js b/src/renderers/shared/stack/reconciler/__tests__/ReactChildReconciler-test.js
new file mode 100644
index 000000000000..aa591f916fd4
--- /dev/null
+++ b/src/renderers/shared/stack/reconciler/__tests__/ReactChildReconciler-test.js
@@ -0,0 +1,84 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+// NOTE: We're explicitly not using JSX here. This is intended to test
+// the current stack addendum without having source location added by babel.
+
+'use strict';
+
+var React;
+var ReactTestUtils;
+
+describe('ReactChildReconciler', () => {
+  function normalizeCodeLocInfo(str) {
+    return str.replace(/\(at .+?:\d+\)/g, '(at **)');
+  }
+
+  beforeEach(() => {
+    jest.resetModuleRegistry();
+
+    React = require('React');
+    ReactTestUtils = require('ReactTestUtils');
+  });
+
+  it('warns for duplicated keys', () => {
+    spyOn(console, 'error');
+
+    class Component extends React.Component {
+      render() {
+        return <div>{[<div key="1" />, <div key="1" />]}</div>;
+      }
+    }
+
+    ReactTestUtils.renderIntoDocument(<Component />);
+
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'Child keys must be unique; when two children share a key, only the first child will be used.',
+    );
+  });
+
+  it('warns for duplicated keys with component stack info', () => {
+    spyOn(console, 'error');
+
+    class Component extends React.Component {
+      render() {
+        return <div>{[<div key="1" />, <div key="1" />]}</div>;
+      }
+    }
+
+    class Parent extends React.Component {
+      render() {
+        return React.cloneElement(this.props.child);
+      }
+    }
+
+    class GrandParent extends React.Component {
+      render() {
+        return <Parent child={<Component />} />;
+      }
+    }
+
+    ReactTestUtils.renderIntoDocument(<GrandParent />);
+
+    expect(console.error.calls.count()).toBe(1);
+    expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
+      'Warning: flattenChildren(...): ' +
+        'Encountered two children with the same key, `1`. ' +
+        'Child keys must be unique; when two children share a key, ' +
+        'only the first child will be used.\n' +
+        '    in div (at **)\n' +
+        '    in Component (at **)\n' +
+        '    in Parent (at **)\n' +
+        '    in GrandParent (at **)',
+    );
+  });
+});
diff --git a/src/renderers/shared/stack/reconciler/__tests__/ReactComponent-test.js b/src/renderers/shared/stack/reconciler/__tests__/ReactComponent-test.js
new file mode 100644
index 000000000000..aebbc34b5dd8
--- /dev/null
+++ b/src/renderers/shared/stack/reconciler/__tests__/ReactComponent-test.js
@@ -0,0 +1,371 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var React;
+var ReactDOM;
+var ReactTestUtils;
+
+describe('ReactComponent', () => {
+  beforeEach(() => {
+    React = require('React');
+    ReactDOM = require('ReactDOM');
+    ReactTestUtils = require('ReactTestUtils');
+  });
+
+  it('should throw on invalid render targets', () => {
+    var container = document.createElement('div');
+    // jQuery objects are basically arrays; people often pass them in by mistake
+    expect(function() {
+      ReactDOM.render(<div />, [container]);
+    }).toThrowError(
+      '_registerComponent(...): Target container is not a DOM element.',
+    );
+
+    expect(function() {
+      ReactDOM.render(<div />, null);
+    }).toThrowError(
+      '_registerComponent(...): Target container is not a DOM element.',
+    );
+  });
+
+  it('should throw when supplying a ref outside of render method', () => {
+    var instance = <div ref="badDiv" />;
+    expect(function() {
+      instance = ReactTestUtils.renderIntoDocument(instance);
+    }).toThrow();
+  });
+
+  it('should warn when children are mutated during render', () => {
+    spyOn(console, 'error');
+    function Wrapper(props) {
+      props.children[1] = <p key={1} />; // Mutation is illegal
+      return <div>{props.children}</div>;
+    }
+    expect(() => {
+      ReactTestUtils.renderIntoDocument(
+        <Wrapper>
+          <span key={0} />
+          <span key={1} />
+          <span key={2} />
+        </Wrapper>,
+      );
+    }).toThrowError(/Cannot assign to read only property.*/);
+  });
+
+  it('should warn when children are mutated during update', () => {
+    spyOn(console, 'error');
+
+    class Wrapper extends React.Component {
+      componentDidMount() {
+        this.props.children[1] = <p key={1} />; // Mutation is illegal
+        this.forceUpdate();
+      }
+
+      render() {
+        return <div>{this.props.children}</div>;
+      }
+    }
+
+    expect(() => {
+      ReactTestUtils.renderIntoDocument(
+        <Wrapper>
+          <span key={0} />
+          <span key={1} />
+          <span key={2} />
+        </Wrapper>,
+      );
+    }).toThrowError(/Cannot assign to read only property.*/);
+  });
+
+  it('should support refs on owned components', () => {
+    var innerObj = {};
+    var outerObj = {};
+
+    class Wrapper extends React.Component {
+      getObject = () => {
+        return this.props.object;
+      };
+
+      render() {
+        return <div>{this.props.children}</div>;
+      }
+    }
+
+    class Component extends React.Component {
+      render() {
+        var inner = <Wrapper object={innerObj} ref="inner" />;
+        var outer = <Wrapper object={outerObj} ref="outer">{inner}</Wrapper>;
+        return outer;
+      }
+
+      componentDidMount() {
+        expect(this.refs.inner.getObject()).toEqual(innerObj);
+        expect(this.refs.outer.getObject()).toEqual(outerObj);
+      }
+    }
+
+    var instance = <Component />;
+    ReactTestUtils.renderIntoDocument(instance);
+  });
+
+  it('should not have refs on unmounted components', () => {
+    class Parent extends React.Component {
+      render() {
+        return <Child><div ref="test" /></Child>;
+      }
+
+      componentDidMount() {
+        expect(this.refs && this.refs.test).toEqual(undefined);
+      }
+    }
+
+    class Child extends React.Component {
+      render() {
+        return <div />;
+      }
+    }
+
+    var instance = <Parent child={<span />} />;
+    ReactTestUtils.renderIntoDocument(instance);
+  });
+
+  it('should support new-style refs', () => {
+    var innerObj = {};
+    var outerObj = {};
+
+    class Wrapper extends React.Component {
+      getObject = () => {
+        return this.props.object;
+      };
+
+      render() {
+        return <div>{this.props.children}</div>;
+      }
+    }
+
+    var mounted = false;
+
+    class Component extends React.Component {
+      render() {
+        var inner = (
+          <Wrapper object={innerObj} ref={c => (this.innerRef = c)} />
+        );
+        var outer = (
+          <Wrapper object={outerObj} ref={c => (this.outerRef = c)}>
+            {inner}
+          </Wrapper>
+        );
+        return outer;
+      }
+
+      componentDidMount() {
+        expect(this.innerRef.getObject()).toEqual(innerObj);
+        expect(this.outerRef.getObject()).toEqual(outerObj);
+        mounted = true;
+      }
+    }
+
+    var instance = <Component />;
+    ReactTestUtils.renderIntoDocument(instance);
+    expect(mounted).toBe(true);
+  });
+
+  it('should support new-style refs with mixed-up owners', () => {
+    class Wrapper extends React.Component {
+      getTitle = () => {
+        return this.props.title;
+      };
+
+      render() {
+        return this.props.getContent();
+      }
+    }
+
+    var mounted = false;
+
+    class Component extends React.Component {
+      getInner = () => {
+        // (With old-style refs, it's impossible to get a ref to this div
+        // because Wrapper is the current owner when this function is called.)
+        return <div title="inner" ref={c => (this.innerRef = c)} />;
+      };
+
+      render() {
+        return (
+          <Wrapper
+            title="wrapper"
+            ref={c => (this.wrapperRef = c)}
+            getContent={this.getInner}
+          />
+        );
+      }
+
+      componentDidMount() {
+        // Check .props.title to make sure we got the right elements back
+        expect(this.wrapperRef.getTitle()).toBe('wrapper');
+        expect(ReactDOM.findDOMNode(this.innerRef).title).toBe('inner');
+        mounted = true;
+      }
+    }
+
+    var instance = <Component />;
+    ReactTestUtils.renderIntoDocument(instance);
+    expect(mounted).toBe(true);
+  });
+
+  it('should call refs at the correct time', () => {
+    var log = [];
+
+    class Inner extends React.Component {
+      render() {
+        log.push(`inner ${this.props.id} render`);
+        return <div />;
+      }
+
+      componentDidMount() {
+        log.push(`inner ${this.props.id} componentDidMount`);
+      }
+
+      componentDidUpdate() {
+        log.push(`inner ${this.props.id} componentDidUpdate`);
+      }
+
+      componentWillUnmount() {
+        log.push(`inner ${this.props.id} componentWillUnmount`);
+      }
+    }
+
+    class Outer extends React.Component {
+      render() {
+        return (
+          <div>
+            <Inner
+              id={1}
+              ref={c => {
+                log.push(`ref 1 got ${c ? `instance ${c.props.id}` : 'null'}`);
+              }}
+            />
+            <Inner
+              id={2}
+              ref={c => {
+                log.push(`ref 2 got ${c ? `instance ${c.props.id}` : 'null'}`);
+              }}
+            />
+          </div>
+        );
+      }
+
+      componentDidMount() {
+        log.push('outer componentDidMount');
+      }
+
+      componentDidUpdate() {
+        log.push('outer componentDidUpdate');
+      }
+
+      componentWillUnmount() {
+        log.push('outer componentWillUnmount');
+      }
+    }
+
+    // mount, update, unmount
+    var el = document.createElement('div');
+    log.push('start mount');
+    ReactDOM.render(<Outer />, el);
+    log.push('start update');
+    ReactDOM.render(<Outer />, el);
+    log.push('start unmount');
+    ReactDOM.unmountComponentAtNode(el);
+
+    /* eslint-disable indent */
+    expect(log).toEqual([
+      'start mount',
+      'inner 1 render',
+      'inner 2 render',
+      'inner 1 componentDidMount',
+      'ref 1 got instance 1',
+      'inner 2 componentDidMount',
+      'ref 2 got instance 2',
+      'outer componentDidMount',
+      'start update',
+      // Previous (equivalent) refs get cleared
+      'ref 1 got null',
+      'inner 1 render',
+      'ref 2 got null',
+      'inner 2 render',
+      'inner 1 componentDidUpdate',
+      'ref 1 got instance 1',
+      'inner 2 componentDidUpdate',
+      'ref 2 got instance 2',
+      'outer componentDidUpdate',
+      'start unmount',
+      'outer componentWillUnmount',
+      'ref 1 got null',
+      'inner 1 componentWillUnmount',
+      'ref 2 got null',
+      'inner 2 componentWillUnmount',
+    ]);
+    /* eslint-enable indent */
+  });
+
+  it('fires the callback after a component is rendered', () => {
+    var callback = jest.fn();
+    var container = document.createElement('div');
+    ReactDOM.render(<div />, container, callback);
+    expect(callback.mock.calls.length).toBe(1);
+    ReactDOM.render(<div className="foo" />, container, callback);
+    expect(callback.mock.calls.length).toBe(2);
+    ReactDOM.render(<span />, container, callback);
+    expect(callback.mock.calls.length).toBe(3);
+  });
+
+  it('throws usefully when rendering badly-typed elements', () => {
+    spyOn(console, 'error');
+
+    var X = undefined;
+    expect(() => ReactTestUtils.renderIntoDocument(<X />)).toThrowError(
+      'Element type is invalid: expected a string (for built-in components) ' +
+        'or a class/function (for composite components) but got: undefined. ' +
+        "You likely forgot to export your component from the file it's " +
+        'defined in.',
+    );
+
+    var Y = null;
+    expect(() => ReactTestUtils.renderIntoDocument(<Y />)).toThrowError(
+      'Element type is invalid: expected a string (for built-in components) ' +
+        'or a class/function (for composite components) but got: null.',
+    );
+
+    // One warning for each element creation
+    expect(console.error.calls.count()).toBe(2);
+  });
+
+  it('includes owner name in the error about badly-typed elements', () => {
+    spyOn(console, 'error');
+
+    function Foo() {
+      var X = undefined;
+      return <X />;
+    }
+
+    expect(() => ReactTestUtils.renderIntoDocument(<Foo />)).toThrowError(
+      'Element type is invalid: expected a string (for built-in components) ' +
+        'or a class/function (for composite components) but got: undefined. ' +
+        "You likely forgot to export your component from the file it's " +
+        'defined in. Check the render method of `Foo`.',
+    );
+
+    // One warning for each element creation
+    expect(console.error.calls.count()).toBe(1);
+  });
+});
diff --git a/src/renderers/shared/stack/reconciler/__tests__/ReactComponentLifeCycle-test.js b/src/renderers/shared/stack/reconciler/__tests__/ReactComponentLifeCycle-test.js
new file mode 100644
index 000000000000..a4a696695a41
--- /dev/null
+++ b/src/renderers/shared/stack/reconciler/__tests__/ReactComponentLifeCycle-test.js
@@ -0,0 +1,581 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var React;
+var ReactDOM;
+var ReactInstanceMap;
+var ReactTestUtils;
+
+var clone = function(o) {
+  return JSON.parse(JSON.stringify(o));
+};
+
+var GET_INIT_STATE_RETURN_VAL = {
+  hasWillMountCompleted: false,
+  hasRenderCompleted: false,
+  hasDidMountCompleted: false,
+  hasWillUnmountCompleted: false,
+};
+
+var INIT_RENDER_STATE = {
+  hasWillMountCompleted: true,
+  hasRenderCompleted: false,
+  hasDidMountCompleted: false,
+  hasWillUnmountCompleted: false,
+};
+
+var DID_MOUNT_STATE = {
+  hasWillMountCompleted: true,
+  hasRenderCompleted: true,
+  hasDidMountCompleted: false,
+  hasWillUnmountCompleted: false,
+};
+
+var NEXT_RENDER_STATE = {
+  hasWillMountCompleted: true,
+  hasRenderCompleted: true,
+  hasDidMountCompleted: true,
+  hasWillUnmountCompleted: false,
+};
+
+var WILL_UNMOUNT_STATE = {
+  hasWillMountCompleted: true,
+  hasDidMountCompleted: true,
+  hasRenderCompleted: true,
+  hasWillUnmountCompleted: false,
+};
+
+var POST_WILL_UNMOUNT_STATE = {
+  hasWillMountCompleted: true,
+  hasDidMountCompleted: true,
+  hasRenderCompleted: true,
+  hasWillUnmountCompleted: true,
+};
+
+/**
+ * Every React component is in one of these life cycles.
+ */
+type ComponentLifeCycle =
+  /**
+   * Mounted components have a DOM node representation and are capable of
+   * receiving new props.
+   */
+  | 'MOUNTED' /**
+   * Unmounted components are inactive and cannot receive new props.
+   */
+  | 'UNMOUNTED';
+
+function getLifeCycleState(instance): ComponentLifeCycle {
+  var internalInstance = ReactInstanceMap.get(instance);
+  // Once a component gets mounted, it has an internal instance, once it
+  // gets unmounted, it loses that internal instance.
+  return internalInstance ? 'MOUNTED' : 'UNMOUNTED';
+}
+
+/**
+ * TODO: We should make any setState calls fail in
+ * `getInitialState` and `componentWillMount`. They will usually fail
+ * anyways because `this._renderedComponent` is empty, however, if a component
+ * is *reused*, then that won't be the case and things will appear to work in
+ * some cases. Better to just block all updates in initialization.
+ */
+describe('ReactComponentLifeCycle', () => {
+  beforeEach(() => {
+    jest.resetModuleRegistry();
+    React = require('React');
+    ReactDOM = require('ReactDOM');
+    ReactTestUtils = require('ReactTestUtils');
+    ReactInstanceMap = require('ReactInstanceMap');
+  });
+
+  it('should not reuse an instance when it has been unmounted', () => {
+    var container = document.createElement('div');
+
+    class StatefulComponent extends React.Component {
+      state = {};
+
+      render() {
+        return <div />;
+      }
+    }
+
+    var element = <StatefulComponent />;
+    var firstInstance = ReactDOM.render(element, container);
+    ReactDOM.unmountComponentAtNode(container);
+    var secondInstance = ReactDOM.render(element, container);
+    expect(firstInstance).not.toBe(secondInstance);
+  });
+
+  /**
+   * If a state update triggers rerendering that in turn fires an onDOMReady,
+   * that second onDOMReady should not fail.
+   */
+  it('it should fire onDOMReady when already in onDOMReady', () => {
+    var _testJournal = [];
+
+    class Child extends React.Component {
+      componentDidMount() {
+        _testJournal.push('Child:onDOMReady');
+      }
+
+      render() {
+        return <div />;
+      }
+    }
+
+    class SwitcherParent extends React.Component {
+      constructor(props) {
+        super(props);
+        _testJournal.push('SwitcherParent:getInitialState');
+        this.state = {showHasOnDOMReadyComponent: false};
+      }
+
+      componentDidMount() {
+        _testJournal.push('SwitcherParent:onDOMReady');
+        this.switchIt();
+      }
+
+      switchIt = () => {
+        this.setState({showHasOnDOMReadyComponent: true});
+      };
+
+      render() {
+        return (
+          <div>
+            {this.state.showHasOnDOMReadyComponent ? <Child /> : <div />}
+          </div>
+        );
+      }
+    }
+
+    var instance = <SwitcherParent />;
+    ReactTestUtils.renderIntoDocument(instance);
+    expect(_testJournal).toEqual([
+      'SwitcherParent:getInitialState',
+      'SwitcherParent:onDOMReady',
+      'Child:onDOMReady',
+    ]);
+  });
+
+  // You could assign state here, but not access members of it, unless you
+  // had provided a getInitialState method.
+  it('throws when accessing state in componentWillMount', () => {
+    class StatefulComponent extends React.Component {
+      componentWillMount() {
+        void this.state.yada;
+      }
+
+      render() {
+        return <div />;
+      }
+    }
+
+    var instance = <StatefulComponent />;
+    expect(function() {
+      instance = ReactTestUtils.renderIntoDocument(instance);
+    }).toThrow();
+  });
+
+  it('should allow update state inside of componentWillMount', () => {
+    class StatefulComponent extends React.Component {
+      componentWillMount() {
+        this.setState({stateField: 'something'});
+      }
+
+      render() {
+        return <div />;
+      }
+    }
+
+    var instance = <StatefulComponent />;
+    expect(function() {
+      instance = ReactTestUtils.renderIntoDocument(instance);
+    }).not.toThrow();
+  });
+
+  it('should not allow update state inside of getInitialState', () => {
+    spyOn(console, 'error');
+
+    class StatefulComponent extends React.Component {
+      constructor(props, context) {
+        super(props, context);
+        this.setState({stateField: 'something'});
+
+        this.state = {stateField: 'somethingelse'};
+      }
+
+      render() {
+        return <div />;
+      }
+    }
+
+    ReactTestUtils.renderIntoDocument(<StatefulComponent />);
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: setState(...): Can only update a mounted or ' +
+        'mounting component. This usually means you called setState() on an ' +
+        'unmounted component. This is a no-op. Please check the code for the ' +
+        'StatefulComponent component.',
+    );
+  });
+
+  it('should correctly determine if a component is mounted', () => {
+    spyOn(console, 'error');
+    class Component extends React.Component {
+      _isMounted() {
+        // No longer a public API, but we can test that it works internally by
+        // reaching into the updater.
+        return this.updater.isMounted(this);
+      }
+      componentWillMount() {
+        expect(this._isMounted()).toBeFalsy();
+      }
+      componentDidMount() {
+        expect(this._isMounted()).toBeTruthy();
+      }
+      render() {
+        expect(this._isMounted()).toBeFalsy();
+        return <div />;
+      }
+    }
+
+    var element = <Component />;
+
+    var instance = ReactTestUtils.renderIntoDocument(element);
+    expect(instance._isMounted()).toBeTruthy();
+
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'Component is accessing isMounted inside its render()',
+    );
+  });
+
+  it('should correctly determine if a null component is mounted', () => {
+    spyOn(console, 'error');
+    class Component extends React.Component {
+      _isMounted() {
+        // No longer a public API, but we can test that it works internally by
+        // reaching into the updater.
+        return this.updater.isMounted(this);
+      }
+      componentWillMount() {
+        expect(this._isMounted()).toBeFalsy();
+      }
+      componentDidMount() {
+        expect(this._isMounted()).toBeTruthy();
+      }
+      render() {
+        expect(this._isMounted()).toBeFalsy();
+        return null;
+      }
+    }
+
+    var element = <Component />;
+
+    var instance = ReactTestUtils.renderIntoDocument(element);
+    expect(instance._isMounted()).toBeTruthy();
+
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'Component is accessing isMounted inside its render()',
+    );
+  });
+
+  it('isMounted should return false when unmounted', () => {
+    class Component extends React.Component {
+      render() {
+        return <div />;
+      }
+    }
+
+    var container = document.createElement('div');
+    var instance = ReactDOM.render(<Component />, container);
+
+    // No longer a public API, but we can test that it works internally by
+    // reaching into the updater.
+    expect(instance.updater.isMounted(instance)).toBe(true);
+
+    ReactDOM.unmountComponentAtNode(container);
+
+    expect(instance.updater.isMounted(instance)).toBe(false);
+  });
+
+  it('warns if findDOMNode is used inside render', () => {
+    spyOn(console, 'error');
+    class Component extends React.Component {
+      state = {isMounted: false};
+      componentDidMount() {
+        this.setState({isMounted: true});
+      }
+      render() {
+        if (this.state.isMounted) {
+          expect(ReactDOM.findDOMNode(this).tagName).toBe('DIV');
+        }
+        return <div />;
+      }
+    }
+
+    ReactTestUtils.renderIntoDocument(<Component />);
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'Component is accessing findDOMNode inside its render()',
+    );
+  });
+
+  it('should carry through each of the phases of setup', () => {
+    class LifeCycleComponent extends React.Component {
+      constructor(props, context) {
+        super(props, context);
+        this._testJournal = {};
+        var initState = {
+          hasWillMountCompleted: false,
+          hasDidMountCompleted: false,
+          hasRenderCompleted: false,
+          hasWillUnmountCompleted: false,
+        };
+        this._testJournal.returnedFromGetInitialState = clone(initState);
+        this._testJournal.lifeCycleAtStartOfGetInitialState = getLifeCycleState(
+          this,
+        );
+        this.state = initState;
+      }
+
+      componentWillMount() {
+        this._testJournal.stateAtStartOfWillMount = clone(this.state);
+        this._testJournal.lifeCycleAtStartOfWillMount = getLifeCycleState(this);
+        this.state.hasWillMountCompleted = true;
+      }
+
+      componentDidMount() {
+        this._testJournal.stateAtStartOfDidMount = clone(this.state);
+        this._testJournal.lifeCycleAtStartOfDidMount = getLifeCycleState(this);
+        this.setState({hasDidMountCompleted: true});
+      }
+
+      render() {
+        var isInitialRender = !this.state.hasRenderCompleted;
+        if (isInitialRender) {
+          this._testJournal.stateInInitialRender = clone(this.state);
+          this._testJournal.lifeCycleInInitialRender = getLifeCycleState(this);
+        } else {
+          this._testJournal.stateInLaterRender = clone(this.state);
+          this._testJournal.lifeCycleInLaterRender = getLifeCycleState(this);
+        }
+        // you would *NEVER* do anything like this in real code!
+        this.state.hasRenderCompleted = true;
+        return (
+          <div ref="theDiv">
+            I am the inner DIV
+          </div>
+        );
+      }
+
+      componentWillUnmount() {
+        this._testJournal.stateAtStartOfWillUnmount = clone(this.state);
+        this._testJournal.lifeCycleAtStartOfWillUnmount = getLifeCycleState(
+          this,
+        );
+        this.state.hasWillUnmountCompleted = true;
+      }
+    }
+
+    // A component that is merely "constructed" (as in "constructor") but not
+    // yet initialized, or rendered.
+    //
+    var container = document.createElement('div');
+    var instance = ReactDOM.render(<LifeCycleComponent />, container);
+
+    // getInitialState
+    expect(instance._testJournal.returnedFromGetInitialState).toEqual(
+      GET_INIT_STATE_RETURN_VAL,
+    );
+    expect(instance._testJournal.lifeCycleAtStartOfGetInitialState).toBe(
+      'UNMOUNTED',
+    );
+
+    // componentWillMount
+    expect(instance._testJournal.stateAtStartOfWillMount).toEqual(
+      instance._testJournal.returnedFromGetInitialState,
+    );
+    expect(instance._testJournal.lifeCycleAtStartOfWillMount).toBe('MOUNTED');
+
+    // componentDidMount
+    expect(instance._testJournal.stateAtStartOfDidMount).toEqual(
+      DID_MOUNT_STATE,
+    );
+    expect(instance._testJournal.lifeCycleAtStartOfDidMount).toBe('MOUNTED');
+
+    // render
+    expect(instance._testJournal.stateInInitialRender).toEqual(
+      INIT_RENDER_STATE,
+    );
+    expect(instance._testJournal.lifeCycleInInitialRender).toBe('MOUNTED');
+
+    expect(getLifeCycleState(instance)).toBe('MOUNTED');
+
+    // Now *update the component*
+    instance.forceUpdate();
+
+    // render 2nd time
+    expect(instance._testJournal.stateInLaterRender).toEqual(NEXT_RENDER_STATE);
+    expect(instance._testJournal.lifeCycleInLaterRender).toBe('MOUNTED');
+
+    expect(getLifeCycleState(instance)).toBe('MOUNTED');
+
+    ReactDOM.unmountComponentAtNode(container);
+
+    expect(instance._testJournal.stateAtStartOfWillUnmount).toEqual(
+      WILL_UNMOUNT_STATE,
+    );
+    // componentWillUnmount called right before unmount.
+    expect(instance._testJournal.lifeCycleAtStartOfWillUnmount).toBe('MOUNTED');
+
+    // But the current lifecycle of the component is unmounted.
+    expect(getLifeCycleState(instance)).toBe('UNMOUNTED');
+    expect(instance.state).toEqual(POST_WILL_UNMOUNT_STATE);
+  });
+
+  it('should not throw when updating an auxiliary component', () => {
+    class Tooltip extends React.Component {
+      render() {
+        return <div>{this.props.children}</div>;
+      }
+
+      componentDidMount() {
+        this.container = document.createElement('div');
+        this.updateTooltip();
+      }
+
+      componentDidUpdate() {
+        this.updateTooltip();
+      }
+
+      updateTooltip = () => {
+        // Even though this.props.tooltip has an owner, updating it shouldn't
+        // throw here because it's mounted as a root component
+        ReactDOM.render(this.props.tooltip, this.container);
+      };
+    }
+
+    class Component extends React.Component {
+      render() {
+        return (
+          <Tooltip ref="tooltip" tooltip={<div>{this.props.tooltipText}</div>}>
+            {this.props.text}
+          </Tooltip>
+        );
+      }
+    }
+
+    var container = document.createElement('div');
+    ReactDOM.render(<Component text="uno" tooltipText="one" />, container);
+
+    // Since `instance` is a root component, we can set its props. This also
+    // makes Tooltip rerender the tooltip component, which shouldn't throw.
+    ReactDOM.render(<Component text="dos" tooltipText="two" />, container);
+  });
+
+  it('should allow state updates in componentDidMount', () => {
+    /**
+     * calls setState in an componentDidMount.
+     */
+    class SetStateInComponentDidMount extends React.Component {
+      state = {
+        stateField: this.props.valueToUseInitially,
+      };
+
+      componentDidMount() {
+        this.setState({stateField: this.props.valueToUseInOnDOMReady});
+      }
+
+      render() {
+        return <div />;
+      }
+    }
+
+    var instance = (
+      <SetStateInComponentDidMount
+        valueToUseInitially="hello"
+        valueToUseInOnDOMReady="goodbye"
+      />
+    );
+    instance = ReactTestUtils.renderIntoDocument(instance);
+    expect(instance.state.stateField).toBe('goodbye');
+  });
+
+  it('should call nested lifecycle methods in the right order', () => {
+    var log;
+    var logger = function(msg) {
+      return function() {
+        // return true for shouldComponentUpdate
+        log.push(msg);
+        return true;
+      };
+    };
+    class Outer extends React.Component {
+      componentWillMount = logger('outer componentWillMount');
+      componentDidMount = logger('outer componentDidMount');
+      componentWillReceiveProps = logger('outer componentWillReceiveProps');
+      shouldComponentUpdate = logger('outer shouldComponentUpdate');
+      componentWillUpdate = logger('outer componentWillUpdate');
+      componentDidUpdate = logger('outer componentDidUpdate');
+      componentWillUnmount = logger('outer componentWillUnmount');
+      render() {
+        return <div><Inner x={this.props.x} /></div>;
+      }
+    }
+
+    class Inner extends React.Component {
+      componentWillMount = logger('inner componentWillMount');
+      componentDidMount = logger('inner componentDidMount');
+      componentWillReceiveProps = logger('inner componentWillReceiveProps');
+      shouldComponentUpdate = logger('inner shouldComponentUpdate');
+      componentWillUpdate = logger('inner componentWillUpdate');
+      componentDidUpdate = logger('inner componentDidUpdate');
+      componentWillUnmount = logger('inner componentWillUnmount');
+      render() {
+        return <span>{this.props.x}</span>;
+      }
+    }
+
+    var container = document.createElement('div');
+    log = [];
+    ReactDOM.render(<Outer x={17} />, container);
+    expect(log).toEqual([
+      'outer componentWillMount',
+      'inner componentWillMount',
+      'inner componentDidMount',
+      'outer componentDidMount',
+    ]);
+
+    log = [];
+    ReactDOM.render(<Outer x={42} />, container);
+    expect(log).toEqual([
+      'outer componentWillReceiveProps',
+      'outer shouldComponentUpdate',
+      'outer componentWillUpdate',
+      'inner componentWillReceiveProps',
+      'inner shouldComponentUpdate',
+      'inner componentWillUpdate',
+      'inner componentDidUpdate',
+      'outer componentDidUpdate',
+    ]);
+
+    log = [];
+    ReactDOM.unmountComponentAtNode(container);
+    expect(log).toEqual([
+      'outer componentWillUnmount',
+      'inner componentWillUnmount',
+    ]);
+  });
+});
diff --git a/src/renderers/shared/stack/reconciler/__tests__/ReactCompositeComponent-test.js b/src/renderers/shared/stack/reconciler/__tests__/ReactCompositeComponent-test.js
new file mode 100644
index 000000000000..3a50776420c2
--- /dev/null
+++ b/src/renderers/shared/stack/reconciler/__tests__/ReactCompositeComponent-test.js
@@ -0,0 +1,1298 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var ChildUpdates;
+var MorphingComponent;
+var React;
+var ReactDOM;
+var ReactCurrentOwner;
+var ReactPropTypes;
+var ReactServerRendering;
+var ReactTestUtils;
+var ReactUpdates;
+
+var reactComponentExpect;
+
+describe('ReactCompositeComponent', () => {
+  beforeEach(() => {
+    jest.resetModuleRegistry();
+    reactComponentExpect = require('reactComponentExpect');
+    React = require('React');
+    ReactDOM = require('ReactDOM');
+    ReactCurrentOwner = require('ReactCurrentOwner');
+    ReactPropTypes = require('ReactPropTypes');
+    ReactTestUtils = require('ReactTestUtils');
+    ReactServerRendering = require('ReactServerRendering');
+    ReactUpdates = require('ReactUpdates');
+
+    MorphingComponent = class extends React.Component {
+      state = {activated: false};
+
+      _toggleActivatedState = () => {
+        this.setState({activated: !this.state.activated});
+      };
+
+      render() {
+        var toggleActivatedState = this._toggleActivatedState;
+        return !this.state.activated
+          ? <a ref="x" onClick={toggleActivatedState} />
+          : <b ref="x" onClick={toggleActivatedState} />;
+      }
+    };
+
+    /**
+     * We'll use this to ensure that an old version is not cached when it is
+     * reallocated again.
+     */
+    ChildUpdates = class extends React.Component {
+      getAnchor = () => {
+        return this.refs.anch;
+      };
+
+      render() {
+        var className = this.props.anchorClassOn ? 'anchorClass' : '';
+        return this.props.renderAnchor
+          ? <a ref="anch" className={className} />
+          : <b />;
+      }
+    };
+  });
+
+  it('should support module pattern components', () => {
+    function Child({test}) {
+      return {
+        render() {
+          return <div>{test}</div>;
+        },
+      };
+    }
+
+    var el = document.createElement('div');
+    ReactDOM.render(<Child test="test" />, el);
+
+    expect(el.textContent).toBe('test');
+  });
+
+  it('should support rendering to different child types over time', () => {
+    var instance = <MorphingComponent />;
+    instance = ReactTestUtils.renderIntoDocument(instance);
+
+    reactComponentExpect(instance)
+      .expectRenderedChild()
+      .toBeDOMComponentWithTag('a');
+
+    instance._toggleActivatedState();
+    reactComponentExpect(instance)
+      .expectRenderedChild()
+      .toBeDOMComponentWithTag('b');
+
+    instance._toggleActivatedState();
+    reactComponentExpect(instance)
+      .expectRenderedChild()
+      .toBeDOMComponentWithTag('a');
+  });
+
+  it('should not thrash a server rendered layout with client side one', () => {
+    class Child extends React.Component {
+      render() {
+        return null;
+      }
+    }
+
+    class Parent extends React.Component {
+      render() {
+        return <div><Child /></div>;
+      }
+    }
+
+    var markup = ReactServerRendering.renderToString(<Parent />);
+    var container = document.createElement('div');
+    container.innerHTML = markup;
+
+    ReactDOM.render(<Parent />, container);
+  });
+
+  it('should react to state changes from callbacks', () => {
+    var instance = <MorphingComponent />;
+    instance = ReactTestUtils.renderIntoDocument(instance);
+
+    var renderedChild = reactComponentExpect(instance)
+      .expectRenderedChild()
+      .instance();
+
+    ReactTestUtils.Simulate.click(renderedChild);
+    reactComponentExpect(instance)
+      .expectRenderedChild()
+      .toBeDOMComponentWithTag('b');
+  });
+
+  it('should rewire refs when rendering to different child types', () => {
+    var instance = <MorphingComponent />;
+    instance = ReactTestUtils.renderIntoDocument(instance);
+
+    expect(ReactDOM.findDOMNode(instance.refs.x).tagName).toBe('A');
+    instance._toggleActivatedState();
+    expect(ReactDOM.findDOMNode(instance.refs.x).tagName).toBe('B');
+    instance._toggleActivatedState();
+    expect(ReactDOM.findDOMNode(instance.refs.x).tagName).toBe('A');
+  });
+
+  it('should not cache old DOM nodes when switching constructors', () => {
+    var container = document.createElement('div');
+    var instance = ReactDOM.render(
+      <ChildUpdates renderAnchor={true} anchorClassOn={false} />,
+      container,
+    );
+    ReactDOM.render(
+      // Warm any cache
+      <ChildUpdates renderAnchor={true} anchorClassOn={true} />,
+      container,
+    );
+    ReactDOM.render(
+      // Clear out the anchor
+      <ChildUpdates renderAnchor={false} anchorClassOn={true} />,
+      container,
+    );
+    ReactDOM.render(
+      // rerender
+      <ChildUpdates renderAnchor={true} anchorClassOn={false} />,
+      container,
+    );
+    expect(instance.getAnchor().className).toBe('');
+  });
+
+  it('should use default values for undefined props', () => {
+    class Component extends React.Component {
+      static defaultProps = {prop: 'testKey'};
+
+      render() {
+        return <span />;
+      }
+    }
+
+    var instance1 = <Component />;
+    instance1 = ReactTestUtils.renderIntoDocument(instance1);
+    reactComponentExpect(instance1).scalarPropsEqual({prop: 'testKey'});
+
+    var instance2 = <Component prop={undefined} />;
+    instance2 = ReactTestUtils.renderIntoDocument(instance2);
+    reactComponentExpect(instance2).scalarPropsEqual({prop: 'testKey'});
+
+    var instance3 = <Component prop={null} />;
+    instance3 = ReactTestUtils.renderIntoDocument(instance3);
+    reactComponentExpect(instance3).scalarPropsEqual({prop: null});
+  });
+
+  it('should not mutate passed-in props object', () => {
+    class Component extends React.Component {
+      static defaultProps = {prop: 'testKey'};
+
+      render() {
+        return <span />;
+      }
+    }
+
+    var inputProps = {};
+    var instance1 = <Component {...inputProps} />;
+    instance1 = ReactTestUtils.renderIntoDocument(instance1);
+    expect(instance1.props.prop).toBe('testKey');
+
+    // We don't mutate the input, just in case the caller wants to do something
+    // with it after using it to instantiate a component
+    expect(inputProps.prop).not.toBeDefined();
+  });
+
+  it('should warn about `forceUpdate` on unmounted components', () => {
+    spyOn(console, 'error');
+
+    var container = document.createElement('div');
+    document.body.appendChild(container);
+
+    class Component extends React.Component {
+      render() {
+        return <div />;
+      }
+    }
+
+    var instance = <Component />;
+    expect(instance.forceUpdate).not.toBeDefined();
+
+    instance = ReactDOM.render(instance, container);
+    instance.forceUpdate();
+
+    expect(console.error.calls.count()).toBe(0);
+
+    ReactDOM.unmountComponentAtNode(container);
+
+    instance.forceUpdate();
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: forceUpdate(...): Can only update a mounted or ' +
+        'mounting component. This usually means you called forceUpdate() on an ' +
+        'unmounted component. This is a no-op. Please check the code for the ' +
+        'Component component.',
+    );
+  });
+
+  it('should warn about `setState` on unmounted components', () => {
+    spyOn(console, 'error');
+
+    var container = document.createElement('div');
+    document.body.appendChild(container);
+
+    var renders = 0;
+
+    class Component extends React.Component {
+      state = {value: 0};
+
+      render() {
+        renders++;
+        return <div />;
+      }
+    }
+
+    var instance = <Component />;
+    expect(instance.setState).not.toBeDefined();
+
+    instance = ReactDOM.render(instance, container);
+
+    expect(renders).toBe(1);
+
+    instance.setState({value: 1});
+
+    expect(console.error.calls.count()).toBe(0);
+
+    expect(renders).toBe(2);
+
+    ReactDOM.unmountComponentAtNode(container);
+    instance.setState({value: 2});
+
+    expect(renders).toBe(2);
+
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: setState(...): Can only update a mounted or ' +
+        'mounting component. This usually means you called setState() on an ' +
+        'unmounted component. This is a no-op. Please check the code for the ' +
+        'Component component.',
+    );
+  });
+
+  it('should silently allow `setState`, not call cb on unmounting components', () => {
+    var cbCalled = false;
+    var container = document.createElement('div');
+    document.body.appendChild(container);
+
+    class Component extends React.Component {
+      state = {value: 0};
+
+      componentWillUnmount() {
+        expect(() => {
+          this.setState({value: 2}, function() {
+            cbCalled = true;
+          });
+        }).not.toThrow();
+      }
+
+      render() {
+        return <div />;
+      }
+    }
+
+    var instance = ReactDOM.render(<Component />, container);
+    instance.setState({value: 1});
+
+    ReactDOM.unmountComponentAtNode(container);
+    expect(cbCalled).toBe(false);
+  });
+
+  it('should warn about `setState` in render', () => {
+    spyOn(console, 'error');
+
+    var container = document.createElement('div');
+
+    var renderedState = -1;
+    var renderPasses = 0;
+
+    class Component extends React.Component {
+      state = {value: 0};
+
+      render() {
+        renderPasses++;
+        renderedState = this.state.value;
+        if (this.state.value === 0) {
+          this.setState({value: 1});
+        }
+        return <div />;
+      }
+    }
+
+    expect(console.error.calls.count()).toBe(0);
+
+    var instance = ReactDOM.render(<Component />, container);
+
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: setState(...): 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`.',
+    );
+
+    // The setState call is queued and then executed as a second pass. This
+    // behavior is undefined though so we're free to change it to suit the
+    // implementation details.
+    expect(renderPasses).toBe(2);
+    expect(renderedState).toBe(1);
+    expect(instance.state.value).toBe(1);
+
+    // Forcing a rerender anywhere will cause the update to happen.
+    var instance2 = ReactDOM.render(<Component prop={123} />, container);
+    expect(instance).toBe(instance2);
+    expect(renderedState).toBe(1);
+    expect(instance2.state.value).toBe(1);
+  });
+
+  it('should warn about `setState` in getChildContext', () => {
+    spyOn(console, 'error');
+
+    var container = document.createElement('div');
+
+    var renderPasses = 0;
+
+    class Component extends React.Component {
+      state = {value: 0};
+
+      getChildContext() {
+        if (this.state.value === 0) {
+          this.setState({value: 1});
+        }
+      }
+
+      render() {
+        renderPasses++;
+        return <div />;
+      }
+    }
+
+    expect(console.error.calls.count()).toBe(0);
+    var instance = ReactDOM.render(<Component />, container);
+    expect(renderPasses).toBe(2);
+    expect(instance.state.value).toBe(1);
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: setState(...): Cannot call setState() inside getChildContext()',
+    );
+  });
+
+  it('should cleanup even if render() fatals', () => {
+    class BadComponent extends React.Component {
+      render() {
+        throw new Error();
+      }
+    }
+
+    var instance = <BadComponent />;
+
+    expect(ReactCurrentOwner.current).toBe(null);
+
+    expect(function() {
+      instance = ReactTestUtils.renderIntoDocument(instance);
+    }).toThrow();
+
+    expect(ReactCurrentOwner.current).toBe(null);
+  });
+
+  it('should call componentWillUnmount before unmounting', () => {
+    var container = document.createElement('div');
+    var innerUnmounted = false;
+
+    class Component extends React.Component {
+      render() {
+        return (
+          <div>
+            <Inner />
+            Text
+          </div>
+        );
+      }
+    }
+
+    class Inner extends React.Component {
+      componentWillUnmount() {
+        innerUnmounted = true;
+      }
+
+      render() {
+        return <div />;
+      }
+    }
+
+    ReactDOM.render(<Component />, container);
+    ReactDOM.unmountComponentAtNode(container);
+    expect(innerUnmounted).toBe(true);
+  });
+
+  it('should warn when shouldComponentUpdate() returns undefined', () => {
+    spyOn(console, 'error');
+
+    class Component extends React.Component {
+      state = {bogus: false};
+
+      shouldComponentUpdate() {
+        return undefined;
+      }
+
+      render() {
+        return <div />;
+      }
+    }
+
+    var instance = ReactTestUtils.renderIntoDocument(<Component />);
+    instance.setState({bogus: true});
+
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: Component.shouldComponentUpdate(): Returned undefined instead of a ' +
+        'boolean value. Make sure to return true or false.',
+    );
+  });
+
+  it('should warn when componentDidUnmount method is defined', () => {
+    spyOn(console, 'error');
+
+    class Component extends React.Component {
+      componentDidUnmount = () => {};
+
+      render() {
+        return <div />;
+      }
+    }
+
+    ReactTestUtils.renderIntoDocument(<Component />);
+
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: Component has a method called ' +
+        'componentDidUnmount(). But there is no such lifecycle method. ' +
+        'Did you mean componentWillUnmount()?',
+    );
+  });
+
+  it('should pass context to children when not owner', () => {
+    class Parent extends React.Component {
+      render() {
+        return <Child><Grandchild /></Child>;
+      }
+    }
+
+    class Child extends React.Component {
+      static childContextTypes = {
+        foo: ReactPropTypes.string,
+      };
+
+      getChildContext() {
+        return {
+          foo: 'bar',
+        };
+      }
+
+      render() {
+        return React.Children.only(this.props.children);
+      }
+    }
+
+    class Grandchild extends React.Component {
+      static contextTypes = {
+        foo: ReactPropTypes.string,
+      };
+
+      render() {
+        return <div>{this.context.foo}</div>;
+      }
+    }
+
+    var component = ReactTestUtils.renderIntoDocument(<Parent />);
+    expect(ReactDOM.findDOMNode(component).innerHTML).toBe('bar');
+  });
+
+  it('should skip update when rerendering element in container', () => {
+    class Parent extends React.Component {
+      render() {
+        return <div>{this.props.children}</div>;
+      }
+    }
+
+    var childRenders = 0;
+
+    class Child extends React.Component {
+      render() {
+        childRenders++;
+        return <div />;
+      }
+    }
+
+    var container = document.createElement('div');
+    var child = <Child />;
+
+    ReactDOM.render(<Parent>{child}</Parent>, container);
+    ReactDOM.render(<Parent>{child}</Parent>, container);
+    expect(childRenders).toBe(1);
+  });
+
+  it('should pass context when re-rendered for static child', () => {
+    var parentInstance = null;
+    var childInstance = null;
+
+    class Parent extends React.Component {
+      static childContextTypes = {
+        foo: ReactPropTypes.string,
+        flag: ReactPropTypes.bool,
+      };
+
+      state = {
+        flag: false,
+      };
+
+      getChildContext() {
+        return {
+          foo: 'bar',
+          flag: this.state.flag,
+        };
+      }
+
+      render() {
+        return React.Children.only(this.props.children);
+      }
+    }
+
+    class Middle extends React.Component {
+      render() {
+        return this.props.children;
+      }
+    }
+
+    class Child extends React.Component {
+      static contextTypes = {
+        foo: ReactPropTypes.string,
+        flag: ReactPropTypes.bool,
+      };
+
+      render() {
+        childInstance = this;
+        return <span>Child</span>;
+      }
+    }
+
+    parentInstance = ReactTestUtils.renderIntoDocument(
+      <Parent><Middle><Child /></Middle></Parent>,
+    );
+
+    expect(parentInstance.state.flag).toBe(false);
+    reactComponentExpect(childInstance).scalarContextEqual({
+      foo: 'bar',
+      flag: false,
+    });
+
+    parentInstance.setState({flag: true});
+    expect(parentInstance.state.flag).toBe(true);
+
+    reactComponentExpect(childInstance).scalarContextEqual({
+      foo: 'bar',
+      flag: true,
+    });
+  });
+
+  it('should pass context when re-rendered for static child within a composite component', () => {
+    class Parent extends React.Component {
+      static childContextTypes = {
+        flag: ReactPropTypes.bool,
+      };
+
+      state = {
+        flag: true,
+      };
+
+      getChildContext() {
+        return {
+          flag: this.state.flag,
+        };
+      }
+
+      render() {
+        return <div>{this.props.children}</div>;
+      }
+    }
+
+    class Child extends React.Component {
+      static contextTypes = {
+        flag: ReactPropTypes.bool,
+      };
+
+      render() {
+        return <div />;
+      }
+    }
+
+    class Wrapper extends React.Component {
+      render() {
+        return (
+          <Parent ref="parent">
+            <Child ref="child" />
+          </Parent>
+        );
+      }
+    }
+
+    var wrapper = ReactTestUtils.renderIntoDocument(<Wrapper />);
+
+    expect(wrapper.refs.parent.state.flag).toEqual(true);
+    reactComponentExpect(wrapper.refs.child).scalarContextEqual({flag: true});
+
+    // We update <Parent /> while <Child /> is still a static prop relative to this update
+    wrapper.refs.parent.setState({flag: false});
+
+    expect(wrapper.refs.parent.state.flag).toEqual(false);
+    reactComponentExpect(wrapper.refs.child).scalarContextEqual({flag: false});
+  });
+
+  it('should pass context transitively', () => {
+    var childInstance = null;
+    var grandchildInstance = null;
+
+    class Parent extends React.Component {
+      static childContextTypes = {
+        foo: ReactPropTypes.string,
+        depth: ReactPropTypes.number,
+      };
+
+      getChildContext() {
+        return {
+          foo: 'bar',
+          depth: 0,
+        };
+      }
+
+      render() {
+        return <Child />;
+      }
+    }
+
+    class Child extends React.Component {
+      static contextTypes = {
+        foo: ReactPropTypes.string,
+        depth: ReactPropTypes.number,
+      };
+
+      static childContextTypes = {
+        depth: ReactPropTypes.number,
+      };
+
+      getChildContext() {
+        return {
+          depth: this.context.depth + 1,
+        };
+      }
+
+      render() {
+        childInstance = this;
+        return <Grandchild />;
+      }
+    }
+
+    class Grandchild extends React.Component {
+      static contextTypes = {
+        foo: ReactPropTypes.string,
+        depth: ReactPropTypes.number,
+      };
+
+      render() {
+        grandchildInstance = this;
+        return <div />;
+      }
+    }
+
+    ReactTestUtils.renderIntoDocument(<Parent />);
+    reactComponentExpect(childInstance).scalarContextEqual({
+      foo: 'bar',
+      depth: 0,
+    });
+    reactComponentExpect(grandchildInstance).scalarContextEqual({
+      foo: 'bar',
+      depth: 1,
+    });
+  });
+
+  it('should pass context when re-rendered', () => {
+    var parentInstance = null;
+    var childInstance = null;
+
+    class Parent extends React.Component {
+      static childContextTypes = {
+        foo: ReactPropTypes.string,
+        depth: ReactPropTypes.number,
+      };
+
+      state = {
+        flag: false,
+      };
+
+      getChildContext() {
+        return {
+          foo: 'bar',
+          depth: 0,
+        };
+      }
+
+      render() {
+        var output = <Child />;
+        if (!this.state.flag) {
+          output = <span>Child</span>;
+        }
+        return output;
+      }
+    }
+
+    class Child extends React.Component {
+      static contextTypes = {
+        foo: ReactPropTypes.string,
+        depth: ReactPropTypes.number,
+      };
+
+      render() {
+        childInstance = this;
+        return <span>Child</span>;
+      }
+    }
+
+    parentInstance = ReactTestUtils.renderIntoDocument(<Parent />);
+    expect(childInstance).toBeNull();
+
+    expect(parentInstance.state.flag).toBe(false);
+    ReactUpdates.batchedUpdates(function() {
+      parentInstance.setState({flag: true});
+    });
+    expect(parentInstance.state.flag).toBe(true);
+
+    reactComponentExpect(childInstance).scalarContextEqual({
+      foo: 'bar',
+      depth: 0,
+    });
+  });
+
+  it('unmasked context propagates through updates', () => {
+    class Leaf extends React.Component {
+      static contextTypes = {
+        foo: ReactPropTypes.string.isRequired,
+      };
+
+      componentWillReceiveProps(nextProps, nextContext) {
+        expect('foo' in nextContext).toBe(true);
+      }
+
+      componentDidUpdate(prevProps, prevState, prevContext) {
+        expect('foo' in prevContext).toBe(true);
+      }
+
+      shouldComponentUpdate(nextProps, nextState, nextContext) {
+        expect('foo' in nextContext).toBe(true);
+        return true;
+      }
+
+      render() {
+        return <span>{this.context.foo}</span>;
+      }
+    }
+
+    class Intermediary extends React.Component {
+      componentWillReceiveProps(nextProps, nextContext) {
+        expect('foo' in nextContext).toBe(false);
+      }
+
+      componentDidUpdate(prevProps, prevState, prevContext) {
+        expect('foo' in prevContext).toBe(false);
+      }
+
+      shouldComponentUpdate(nextProps, nextState, nextContext) {
+        expect('foo' in nextContext).toBe(false);
+        return true;
+      }
+
+      render() {
+        return <Leaf />;
+      }
+    }
+
+    class Parent extends React.Component {
+      static childContextTypes = {
+        foo: ReactPropTypes.string,
+      };
+
+      getChildContext() {
+        return {
+          foo: this.props.cntxt,
+        };
+      }
+
+      render() {
+        return <Intermediary />;
+      }
+    }
+
+    var div = document.createElement('div');
+    ReactDOM.render(<Parent cntxt="noise" />, div);
+    expect(div.children[0].innerHTML).toBe('noise');
+    div.children[0].innerHTML = 'aliens';
+    div.children[0].id = 'aliens';
+    expect(div.children[0].innerHTML).toBe('aliens');
+    expect(div.children[0].id).toBe('aliens');
+    ReactDOM.render(<Parent cntxt="bar" />, div);
+    expect(div.children[0].innerHTML).toBe('bar');
+    expect(div.children[0].id).toBe('aliens');
+  });
+
+  it('should trigger componentWillReceiveProps for context changes', () => {
+    var contextChanges = 0;
+    var propChanges = 0;
+
+    class GrandChild extends React.Component {
+      static contextTypes = {
+        foo: ReactPropTypes.string.isRequired,
+      };
+
+      componentWillReceiveProps(nextProps, nextContext) {
+        expect('foo' in nextContext).toBe(true);
+
+        if (nextProps !== this.props) {
+          propChanges++;
+        }
+
+        if (nextContext !== this.context) {
+          contextChanges++;
+        }
+      }
+
+      render() {
+        return <span className="grand-child">{this.props.children}</span>;
+      }
+    }
+
+    class ChildWithContext extends React.Component {
+      static contextTypes = {
+        foo: ReactPropTypes.string.isRequired,
+      };
+
+      componentWillReceiveProps(nextProps, nextContext) {
+        expect('foo' in nextContext).toBe(true);
+
+        if (nextProps !== this.props) {
+          propChanges++;
+        }
+
+        if (nextContext !== this.context) {
+          contextChanges++;
+        }
+      }
+
+      render() {
+        return <div className="child-with">{this.props.children}</div>;
+      }
+    }
+
+    class ChildWithoutContext extends React.Component {
+      componentWillReceiveProps(nextProps, nextContext) {
+        expect('foo' in nextContext).toBe(false);
+
+        if (nextProps !== this.props) {
+          propChanges++;
+        }
+
+        if (nextContext !== this.context) {
+          contextChanges++;
+        }
+      }
+
+      render() {
+        return <div className="child-without">{this.props.children}</div>;
+      }
+    }
+
+    class Parent extends React.Component {
+      static childContextTypes = {
+        foo: ReactPropTypes.string,
+      };
+
+      state = {
+        foo: 'abc',
+      };
+
+      getChildContext() {
+        return {
+          foo: this.state.foo,
+        };
+      }
+
+      onClick = () => {
+        this.setState({
+          foo: 'def',
+        });
+      };
+
+      render() {
+        return (
+          <div className="parent" onClick={this.onClick}>
+            {this.props.children}
+          </div>
+        );
+      }
+    }
+
+    var div = document.createElement('div');
+
+    ReactDOM.render(
+      <Parent>
+        <ChildWithoutContext>
+          A1
+          <GrandChild>A2</GrandChild>
+        </ChildWithoutContext>
+
+        <ChildWithContext>
+          B1
+          <GrandChild>B2</GrandChild>
+        </ChildWithContext>
+      </Parent>,
+      div,
+    );
+
+    ReactTestUtils.Simulate.click(div.childNodes[0]);
+
+    expect(propChanges).toBe(0);
+    expect(contextChanges).toBe(3); // ChildWithContext, GrandChild x 2
+  });
+
+  it('should disallow nested render calls', () => {
+    spyOn(console, 'error');
+
+    class Inner extends React.Component {
+      render() {
+        return <div />;
+      }
+    }
+
+    class Outer extends React.Component {
+      render() {
+        ReactTestUtils.renderIntoDocument(<Inner />);
+        return <div />;
+      }
+    }
+
+    ReactTestUtils.renderIntoDocument(<Outer />);
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: _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 Outer.',
+    );
+  });
+
+  it('only renders once if updated in componentWillReceiveProps', () => {
+    var renders = 0;
+
+    class Component extends React.Component {
+      state = {updated: false};
+
+      componentWillReceiveProps(props) {
+        expect(props.update).toBe(1);
+        this.setState({updated: true});
+      }
+
+      render() {
+        renders++;
+        return <div />;
+      }
+    }
+
+    var container = document.createElement('div');
+    var instance = ReactDOM.render(<Component update={0} />, container);
+    expect(renders).toBe(1);
+    expect(instance.state.updated).toBe(false);
+    ReactDOM.render(<Component update={1} />, container);
+    expect(renders).toBe(2);
+    expect(instance.state.updated).toBe(true);
+  });
+
+  it('should update refs if shouldComponentUpdate gives false', () => {
+    class Static extends React.Component {
+      shouldComponentUpdate() {
+        return false;
+      }
+
+      render() {
+        return <div>{this.props.children}</div>;
+      }
+    }
+
+    class Component extends React.Component {
+      render() {
+        if (this.props.flipped) {
+          return (
+            <div>
+              <Static ref="static0" key="B">B (ignored)</Static>
+              <Static ref="static1" key="A">A (ignored)</Static>
+            </div>
+          );
+        } else {
+          return (
+            <div>
+              <Static ref="static0" key="A">A</Static>
+              <Static ref="static1" key="B">B</Static>
+            </div>
+          );
+        }
+      }
+    }
+
+    var container = document.createElement('div');
+    var comp = ReactDOM.render(<Component flipped={false} />, container);
+    expect(ReactDOM.findDOMNode(comp.refs.static0).textContent).toBe('A');
+    expect(ReactDOM.findDOMNode(comp.refs.static1).textContent).toBe('B');
+
+    // When flipping the order, the refs should update even though the actual
+    // contents do not
+    ReactDOM.render(<Component flipped={true} />, container);
+    expect(ReactDOM.findDOMNode(comp.refs.static0).textContent).toBe('B');
+    expect(ReactDOM.findDOMNode(comp.refs.static1).textContent).toBe('A');
+  });
+
+  it('should allow access to findDOMNode in componentWillUnmount', () => {
+    var a = null;
+    var b = null;
+
+    class Component extends React.Component {
+      componentDidMount() {
+        a = ReactDOM.findDOMNode(this);
+        expect(a).not.toBe(null);
+      }
+
+      componentWillUnmount() {
+        b = ReactDOM.findDOMNode(this);
+        expect(b).not.toBe(null);
+      }
+
+      render() {
+        return <div />;
+      }
+    }
+
+    var container = document.createElement('div');
+    expect(a).toBe(container.firstChild);
+    ReactDOM.render(<Component />, container);
+    ReactDOM.unmountComponentAtNode(container);
+    expect(a).toBe(b);
+  });
+
+  it('context should be passed down from the parent', () => {
+    class Parent extends React.Component {
+      static childContextTypes = {
+        foo: ReactPropTypes.string,
+      };
+
+      getChildContext() {
+        return {
+          foo: 'bar',
+        };
+      }
+
+      render() {
+        return <div>{this.props.children}</div>;
+      }
+    }
+
+    class Component extends React.Component {
+      static contextTypes = {
+        foo: ReactPropTypes.string.isRequired,
+      };
+
+      render() {
+        return <div />;
+      }
+    }
+
+    var div = document.createElement('div');
+    ReactDOM.render(<Parent><Component /></Parent>, div);
+  });
+
+  it('should replace state', () => {
+    class Moo extends React.Component {
+      state = {x: 1};
+      render() {
+        return <div />;
+      }
+    }
+
+    var moo = ReactTestUtils.renderIntoDocument(<Moo />);
+    // No longer a public API, but we can test that it works internally by
+    // reaching into the updater.
+    moo.updater.enqueueReplaceState(moo, {y: 2});
+    expect('x' in moo.state).toBe(false);
+    expect(moo.state.y).toBe(2);
+  });
+
+  it('should support objects with prototypes as state', () => {
+    var NotActuallyImmutable = function(str) {
+      this.str = str;
+    };
+    NotActuallyImmutable.prototype.amIImmutable = function() {
+      return true;
+    };
+    class Moo extends React.Component {
+      state = new NotActuallyImmutable('first');
+      // No longer a public API, but we can test that it works internally by
+      // reaching into the updater.
+      _replaceState = update => this.updater.enqueueReplaceState(this, update);
+      render() {
+        return <div />;
+      }
+    }
+
+    var moo = ReactTestUtils.renderIntoDocument(<Moo />);
+    expect(moo.state.str).toBe('first');
+    expect(moo.state.amIImmutable()).toBe(true);
+
+    var secondState = new NotActuallyImmutable('second');
+    moo._replaceState(secondState);
+    expect(moo.state.str).toBe('second');
+    expect(moo.state.amIImmutable()).toBe(true);
+    expect(moo.state).toBe(secondState);
+
+    moo.setState({str: 'third'});
+    expect(moo.state.str).toBe('third');
+    // Here we lose the prototype.
+    expect(moo.state.amIImmutable).toBe(undefined);
+
+    // When more than one state update is enqueued, we have the same behavior
+    var fifthState = new NotActuallyImmutable('fifth');
+    ReactUpdates.batchedUpdates(function() {
+      moo.setState({str: 'fourth'});
+      moo._replaceState(fifthState);
+    });
+    expect(moo.state).toBe(fifthState);
+
+    // When more than one state update is enqueued, we have the same behavior
+    var sixthState = new NotActuallyImmutable('sixth');
+    ReactUpdates.batchedUpdates(function() {
+      moo._replaceState(sixthState);
+      moo.setState({str: 'seventh'});
+    });
+    expect(moo.state.str).toBe('seventh');
+    expect(moo.state.amIImmutable).toBe(undefined);
+  });
+
+  it('should not warn about unmounting during unmounting', () => {
+    var container = document.createElement('div');
+    var layer = document.createElement('div');
+
+    class Component extends React.Component {
+      componentWillMount() {
+        ReactDOM.render(<div />, layer);
+      }
+
+      componentWillUnmount() {
+        ReactDOM.unmountComponentAtNode(layer);
+      }
+
+      render() {
+        return <div />;
+      }
+    }
+
+    class Outer extends React.Component {
+      render() {
+        return <div>{this.props.children}</div>;
+      }
+    }
+
+    ReactDOM.render(<Outer><Component /></Outer>, container);
+    ReactDOM.render(<Outer />, container);
+  });
+
+  it('should warn when mutated props are passed', () => {
+    spyOn(console, 'error');
+
+    var container = document.createElement('div');
+
+    class Foo extends React.Component {
+      constructor(props) {
+        var _props = {idx: props.idx + '!'};
+        super(_props);
+      }
+
+      render() {
+        return <span />;
+      }
+    }
+
+    expect(console.error.calls.count()).toBe(0);
+
+    ReactDOM.render(<Foo idx="qwe" />, container);
+
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'Foo(...): When calling super() in `Foo`, make sure to pass ' +
+        "up the same props that your component's constructor was passed.",
+    );
+  });
+
+  it('should only call componentWillUnmount once', () => {
+    var app;
+    var count = 0;
+
+    class App extends React.Component {
+      render() {
+        if (this.props.stage === 1) {
+          return <UnunmountableComponent />;
+        } else {
+          return null;
+        }
+      }
+    }
+
+    class UnunmountableComponent extends React.Component {
+      componentWillUnmount() {
+        app.setState({});
+        count++;
+        throw Error('always fails');
+      }
+
+      render() {
+        return <div>Hello {this.props.name}</div>;
+      }
+    }
+
+    var container = document.createElement('div');
+
+    var setRef = ref => {
+      if (ref) {
+        app = ref;
+      }
+    };
+
+    expect(function() {
+      ReactDOM.render(<App ref={setRef} stage={1} />, container);
+      ReactDOM.render(<App ref={setRef} stage={2} />, container);
+    }).toThrow();
+    expect(count).toBe(1);
+  });
+});
diff --git a/src/renderers/shared/reconciler/__tests__/ReactCompositeComponentDOMMinimalism-test.js b/src/renderers/shared/stack/reconciler/__tests__/ReactCompositeComponentDOMMinimalism-test.js
similarity index 79%
rename from src/renderers/shared/reconciler/__tests__/ReactCompositeComponentDOMMinimalism-test.js
rename to src/renderers/shared/stack/reconciler/__tests__/ReactCompositeComponentDOMMinimalism-test.js
index 2c5f0a71a226..ee226c93a691 100644
--- a/src/renderers/shared/reconciler/__tests__/ReactCompositeComponentDOMMinimalism-test.js
+++ b/src/renderers/shared/stack/reconciler/__tests__/ReactCompositeComponentDOMMinimalism-test.js
@@ -27,44 +27,43 @@ var expectSingleChildlessDiv;
  * abstraction, `ReactCompositeComponent` does not ever add superfluous DOM
  * nodes.
  */
-describe('ReactCompositeComponentDOMMinimalism', function() {
-
-  beforeEach(function() {
+describe('ReactCompositeComponentDOMMinimalism', () => {
+  beforeEach(() => {
     reactComponentExpect = require('reactComponentExpect');
     React = require('React');
     ReactTestUtils = require('ReactTestUtils');
 
-    LowerLevelComposite = React.createClass({
-      render: function() {
+    LowerLevelComposite = class extends React.Component {
+      render() {
         return (
           <div>
             {this.props.children}
           </div>
         );
-      },
-    });
+      }
+    };
 
-    MyCompositeComponent = React.createClass({
-      render: function() {
+    MyCompositeComponent = class extends React.Component {
+      render() {
         return (
           <LowerLevelComposite>
             {this.props.children}
           </LowerLevelComposite>
         );
-      },
-    });
+      }
+    };
 
     expectSingleChildlessDiv = function(instance) {
       reactComponentExpect(instance)
         .expectRenderedChild()
         .toBeCompositeComponentWithType(LowerLevelComposite)
-          .expectRenderedChild()
-          .toBeDOMComponentWithTag('div')
-          .toBeDOMComponentWithNoChildren();
+        .expectRenderedChild()
+        .toBeDOMComponentWithTag('div')
+        .toBeDOMComponentWithNoChildren();
     };
   });
 
-  it('should not render extra nodes for non-interpolated text', function() {
+  it('should not render extra nodes for non-interpolated text', () => {
     var instance = (
       <MyCompositeComponent>
         A string child
@@ -74,7 +73,7 @@ describe('ReactCompositeComponentDOMMinimalism', function() {
     expectSingleChildlessDiv(instance);
   });
 
-  it('should not render extra nodes for non-interpolated text', function() {
+  it('should not render extra nodes for non-interpolated text', () => {
     var instance = (
       <MyCompositeComponent>
         {'Interpolated String Child'}
@@ -84,7 +83,7 @@ describe('ReactCompositeComponentDOMMinimalism', function() {
     expectSingleChildlessDiv(instance);
   });
 
-  it('should not render extra nodes for non-interpolated text', function() {
+  it('should not render extra nodes for non-interpolated text', () => {
     var instance = (
       <MyCompositeComponent>
         <ul>
@@ -96,12 +95,11 @@ describe('ReactCompositeComponentDOMMinimalism', function() {
     reactComponentExpect(instance)
       .expectRenderedChild()
       .toBeCompositeComponentWithType(LowerLevelComposite)
-        .expectRenderedChild()
-        .toBeDOMComponentWithTag('div')
-        .toBeDOMComponentWithChildCount(1)
-        .expectRenderedChildAt(0)
-          .toBeDOMComponentWithTag('ul')
-          .toBeDOMComponentWithNoChildren();
+      .expectRenderedChild()
+      .toBeDOMComponentWithTag('div')
+      .toBeDOMComponentWithChildCount(1)
+      .expectRenderedChildAt(0)
+      .toBeDOMComponentWithTag('ul')
+      .toBeDOMComponentWithNoChildren();
   });
-
 });
diff --git a/src/renderers/shared/stack/reconciler/__tests__/ReactCompositeComponentNestedState-test.js b/src/renderers/shared/stack/reconciler/__tests__/ReactCompositeComponentNestedState-test.js
new file mode 100644
index 000000000000..f8e7f4af2ab6
--- /dev/null
+++ b/src/renderers/shared/stack/reconciler/__tests__/ReactCompositeComponentNestedState-test.js
@@ -0,0 +1,123 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var React;
+var ReactDOM;
+var ReactTestUtils;
+
+describe('ReactCompositeComponentNestedState-state', () => {
+  beforeEach(() => {
+    React = require('React');
+    ReactDOM = require('ReactDOM');
+    ReactTestUtils = require('ReactTestUtils');
+  });
+
+  it('should provide up to date values for props', () => {
+    class ParentComponent extends React.Component {
+      state = {color: 'blue'};
+
+      handleColor = color => {
+        this.props.logger('parent-handleColor', this.state.color);
+        this.setState({color: color}, function() {
+          this.props.logger('parent-after-setState', this.state.color);
+        });
+      };
+
+      render() {
+        this.props.logger('parent-render', this.state.color);
+        return (
+          <ChildComponent
+            logger={this.props.logger}
+            color={this.state.color}
+            onSelectColor={this.handleColor}
+          />
+        );
+      }
+    }
+
+    class ChildComponent extends React.Component {
+      constructor(props) {
+        super(props);
+        props.logger('getInitialState', props.color);
+        this.state = {hue: 'dark ' + props.color};
+      }
+
+      handleHue = (shade, color) => {
+        this.props.logger('handleHue', this.state.hue, this.props.color);
+        this.props.onSelectColor(color);
+        this.setState(
+          function(state, props) {
+            this.props.logger(
+              'setState-this',
+              this.state.hue,
+              this.props.color,
+            );
+            this.props.logger('setState-args', state.hue, props.color);
+            return {hue: shade + ' ' + props.color};
+          },
+          function() {
+            this.props.logger(
+              'after-setState',
+              this.state.hue,
+              this.props.color,
+            );
+          },
+        );
+      };
+
+      render() {
+        this.props.logger('render', this.state.hue, this.props.color);
+        return (
+          <div>
+            <button onClick={this.handleHue.bind(this, 'dark', 'blue')}>
+              Dark Blue
+            </button>
+            <button onClick={this.handleHue.bind(this, 'light', 'blue')}>
+              Light Blue
+            </button>
+            <button onClick={this.handleHue.bind(this, 'dark', 'green')}>
+              Dark Green
+            </button>
+            <button onClick={this.handleHue.bind(this, 'light', 'green')}>
+              Light Green
+            </button>
+          </div>
+        );
+      }
+    }
+
+    var container = document.createElement('div');
+    document.body.appendChild(container);
+
+    var logger = jest.fn();
+
+    void ReactDOM.render(<ParentComponent logger={logger} />, container);
+
+    // click "light green"
+    ReactTestUtils.Simulate.click(container.childNodes[0].childNodes[3]);
+
+    expect(logger.mock.calls).toEqual([
+      ['parent-render', 'blue'],
+      ['getInitialState', 'blue'],
+      ['render', 'dark blue', 'blue'],
+      ['handleHue', 'dark blue', 'blue'],
+      ['parent-handleColor', 'blue'],
+      ['parent-render', 'green'],
+      ['setState-this', 'dark blue', 'blue'],
+      ['setState-args', 'dark blue', 'green'],
+      ['render', 'light green', 'green'],
+      ['parent-after-setState', 'green'],
+      ['after-setState', 'light green', 'green'],
+    ]);
+  });
+});
diff --git a/src/renderers/shared/stack/reconciler/__tests__/ReactCompositeComponentState-test.js b/src/renderers/shared/stack/reconciler/__tests__/ReactCompositeComponentState-test.js
new file mode 100644
index 000000000000..bd3d4120a3bc
--- /dev/null
+++ b/src/renderers/shared/stack/reconciler/__tests__/ReactCompositeComponentState-test.js
@@ -0,0 +1,248 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var React;
+var ReactDOM;
+
+var TestComponent;
+
+describe('ReactCompositeComponent-state', () => {
+  beforeEach(() => {
+    React = require('React');
+
+    ReactDOM = require('ReactDOM');
+
+    TestComponent = class extends React.Component {
+      constructor(props) {
+        super(props);
+        this.peekAtState('getInitialState', undefined, props);
+        this.state = {color: 'red'};
+      }
+
+      peekAtState = (from, state = this.state, props = this.props) => {
+        props.stateListener(from, state && state.color);
+      };
+
+      peekAtCallback = from => {
+        return () => this.peekAtState(from);
+      };
+
+      setFavoriteColor(nextColor) {
+        this.setState(
+          {color: nextColor},
+          this.peekAtCallback('setFavoriteColor'),
+        );
+      }
+
+      render() {
+        this.peekAtState('render');
+        return <div>{this.state.color}</div>;
+      }
+
+      componentWillMount() {
+        this.peekAtState('componentWillMount-start');
+        this.setState(function(state) {
+          this.peekAtState('before-setState-sunrise', state);
+        });
+        this.setState(
+          {color: 'sunrise'},
+          this.peekAtCallback('setState-sunrise'),
+        );
+        this.setState(function(state) {
+          this.peekAtState('after-setState-sunrise', state);
+        });
+        this.peekAtState('componentWillMount-after-sunrise');
+        this.setState(
+          {color: 'orange'},
+          this.peekAtCallback('setState-orange'),
+        );
+        this.setState(function(state) {
+          this.peekAtState('after-setState-orange', state);
+        });
+        this.peekAtState('componentWillMount-end');
+      }
+
+      componentDidMount() {
+        this.peekAtState('componentDidMount-start');
+        this.setState(
+          {color: 'yellow'},
+          this.peekAtCallback('setState-yellow'),
+        );
+        this.peekAtState('componentDidMount-end');
+      }
+
+      componentWillReceiveProps(newProps) {
+        this.peekAtState('componentWillReceiveProps-start');
+        if (newProps.nextColor) {
+          this.setState(function(state) {
+            this.peekAtState('before-setState-receiveProps', state);
+            return {color: newProps.nextColor};
+          });
+          // No longer a public API, but we can test that it works internally by
+          // reaching into the updater.
+          this.updater.enqueueReplaceState(this, {color: undefined});
+          this.setState(function(state) {
+            this.peekAtState('before-setState-again-receiveProps', state);
+            return {color: newProps.nextColor};
+          }, this.peekAtCallback('setState-receiveProps'));
+          this.setState(function(state) {
+            this.peekAtState('after-setState-receiveProps', state);
+          });
+        }
+        this.peekAtState('componentWillReceiveProps-end');
+      }
+
+      shouldComponentUpdate(nextProps, nextState) {
+        this.peekAtState('shouldComponentUpdate-currentState');
+        this.peekAtState('shouldComponentUpdate-nextState', nextState);
+        return true;
+      }
+
+      componentWillUpdate(nextProps, nextState) {
+        this.peekAtState('componentWillUpdate-currentState');
+        this.peekAtState('componentWillUpdate-nextState', nextState);
+      }
+
+      componentDidUpdate(prevProps, prevState) {
+        this.peekAtState('componentDidUpdate-currentState');
+        this.peekAtState('componentDidUpdate-prevState', prevState);
+      }
+
+      componentWillUnmount() {
+        this.peekAtState('componentWillUnmount');
+      }
+    };
+  });
+
+  it('should support setting state', () => {
+    var container = document.createElement('div');
+    document.body.appendChild(container);
+
+    var stateListener = jest.fn();
+    var instance = ReactDOM.render(
+      <TestComponent stateListener={stateListener} />,
+      container,
+      function peekAtInitialCallback() {
+        this.peekAtState('initial-callback');
+      },
+    );
+    ReactDOM.render(
+      <TestComponent stateListener={stateListener} nextColor="green" />,
+      container,
+      instance.peekAtCallback('setProps'),
+    );
+    instance.setFavoriteColor('blue');
+    instance.forceUpdate(instance.peekAtCallback('forceUpdate'));
+
+    ReactDOM.unmountComponentAtNode(container);
+
+    expect(stateListener.mock.calls.join('\n')).toEqual(
+      [
+        // there is no state when getInitialState() is called
+        ['getInitialState', null],
+        ['componentWillMount-start', 'red'],
+        // setState()'s only enqueue pending states.
+        ['componentWillMount-after-sunrise', 'red'],
+        ['componentWillMount-end', 'red'],
+        // pending state queue is processed
+        ['before-setState-sunrise', 'red'],
+        ['after-setState-sunrise', 'sunrise'],
+        ['after-setState-orange', 'orange'],
+        // pending state has been applied
+        ['render', 'orange'],
+        ['componentDidMount-start', 'orange'],
+        // setState-sunrise and setState-orange should be called here,
+        // after the bug in #1740
+        // componentDidMount() called setState({color:'yellow'}), which is async.
+        // The update doesn't happen until the next flush.
+        ['componentDidMount-end', 'orange'],
+        ['shouldComponentUpdate-currentState', 'orange'],
+        ['shouldComponentUpdate-nextState', 'yellow'],
+        ['componentWillUpdate-currentState', 'orange'],
+        ['componentWillUpdate-nextState', 'yellow'],
+        ['render', 'yellow'],
+        ['componentDidUpdate-currentState', 'yellow'],
+        ['componentDidUpdate-prevState', 'orange'],
+        ['setState-sunrise', 'yellow'],
+        ['setState-orange', 'yellow'],
+        ['setState-yellow', 'yellow'],
+        ['initial-callback', 'yellow'],
+        ['componentWillReceiveProps-start', 'yellow'],
+        // setState({color:'green'}) only enqueues a pending state.
+        ['componentWillReceiveProps-end', 'yellow'],
+        // pending state queue is processed
+        // before-setState-receiveProps never called, due to replaceState.
+        ['before-setState-again-receiveProps', undefined],
+        ['after-setState-receiveProps', 'green'],
+        ['shouldComponentUpdate-currentState', 'yellow'],
+        ['shouldComponentUpdate-nextState', 'green'],
+        ['componentWillUpdate-currentState', 'yellow'],
+        ['componentWillUpdate-nextState', 'green'],
+        ['render', 'green'],
+        ['componentDidUpdate-currentState', 'green'],
+        ['componentDidUpdate-prevState', 'yellow'],
+        ['setState-receiveProps', 'green'],
+        ['setProps', 'green'],
+        // setFavoriteColor('blue')
+        ['shouldComponentUpdate-currentState', 'green'],
+        ['shouldComponentUpdate-nextState', 'blue'],
+        ['componentWillUpdate-currentState', 'green'],
+        ['componentWillUpdate-nextState', 'blue'],
+        ['render', 'blue'],
+        ['componentDidUpdate-currentState', 'blue'],
+        ['componentDidUpdate-prevState', 'green'],
+        ['setFavoriteColor', 'blue'],
+        // forceUpdate()
+        ['componentWillUpdate-currentState', 'blue'],
+        ['componentWillUpdate-nextState', 'blue'],
+        ['render', 'blue'],
+        ['componentDidUpdate-currentState', 'blue'],
+        ['componentDidUpdate-prevState', 'blue'],
+        ['forceUpdate', 'blue'],
+        // unmountComponent()
+        // state is available within `componentWillUnmount()`
+        ['componentWillUnmount', 'blue'],
+      ].join('\n'),
+    );
+  });
+
+  it('should batch unmounts', () => {
+    var outer;
+
+    class Inner extends React.Component {
+      render() {
+        return <div />;
+      }
+
+      componentWillUnmount() {
+        // This should get silently ignored (maybe with a warning), but it
+        // shouldn't break React.
+        outer.setState({showInner: false});
+      }
+    }
+
+    class Outer extends React.Component {
+      state = {showInner: true};
+
+      render() {
+        return <div>{this.state.showInner && <Inner />}</div>;
+      }
+    }
+
+    var container = document.createElement('div');
+    outer = ReactDOM.render(<Outer />, container);
+    expect(() => {
+      ReactDOM.unmountComponentAtNode(container);
+    }).not.toThrow();
+  });
+});
diff --git a/src/renderers/shared/stack/reconciler/__tests__/ReactEmptyComponent-test.js b/src/renderers/shared/stack/reconciler/__tests__/ReactEmptyComponent-test.js
new file mode 100644
index 000000000000..a6b4cfaafa0c
--- /dev/null
+++ b/src/renderers/shared/stack/reconciler/__tests__/ReactEmptyComponent-test.js
@@ -0,0 +1,299 @@
+/**
+ * Copyright 2014-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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var React;
+var ReactDOM;
+var ReactTestUtils;
+var TogglingComponent;
+
+var reactComponentExpect;
+
+var log;
+
+describe('ReactEmptyComponent', () => {
+  beforeEach(() => {
+    jest.resetModuleRegistry();
+
+    React = require('React');
+    ReactDOM = require('ReactDOM');
+    ReactTestUtils = require('ReactTestUtils');
+
+    reactComponentExpect = require('reactComponentExpect');
+
+    log = jasmine.createSpy();
+
+    TogglingComponent = class extends React.Component {
+      state = {component: this.props.firstComponent};
+
+      componentDidMount() {
+        log(ReactDOM.findDOMNode(this));
+        this.setState({component: this.props.secondComponent});
+      }
+
+      componentDidUpdate() {
+        log(ReactDOM.findDOMNode(this));
+      }
+
+      render() {
+        var Component = this.state.component;
+        return Component ? <Component /> : null;
+      }
+    };
+  });
+
+  it('should render null and false as a noscript tag under the hood', () => {
+    class Component1 extends React.Component {
+      render() {
+        return null;
+      }
+    }
+
+    class Component2 extends React.Component {
+      render() {
+        return false;
+      }
+    }
+
+    var instance1 = ReactTestUtils.renderIntoDocument(<Component1 />);
+    var instance2 = ReactTestUtils.renderIntoDocument(<Component2 />);
+    reactComponentExpect(instance1).expectRenderedChild().toBeEmptyComponent();
+    reactComponentExpect(instance2).expectRenderedChild().toBeEmptyComponent();
+  });
+
+  it('should still throw when rendering to undefined', () => {
+    class Component extends React.Component {
+      render() {}
+    }
+
+    expect(function() {
+      ReactTestUtils.renderIntoDocument(<Component />);
+    }).toThrowError(
+      'Component.render(): A valid React element (or null) must be returned. You may ' +
+        'have returned undefined, an array or some other invalid object.',
+    );
+  });
+
+  it('should be able to switch between rendering null and a normal tag', () => {
+    var instance1 = (
+      <TogglingComponent firstComponent={null} secondComponent={'div'} />
+    );
+    var instance2 = (
+      <TogglingComponent firstComponent={'div'} secondComponent={null} />
+    );
+
+    ReactTestUtils.renderIntoDocument(instance1);
+    ReactTestUtils.renderIntoDocument(instance2);
+
+    expect(log.calls.count()).toBe(4);
+    expect(log.calls.argsFor(0)[0]).toBe(null);
+    expect(log.calls.argsFor(1)[0].tagName).toBe('DIV');
+    expect(log.calls.argsFor(2)[0].tagName).toBe('DIV');
+    expect(log.calls.argsFor(3)[0]).toBe(null);
+  });
+
+  it('should be able to switch in a list of children', () => {
+    var instance1 = (
+      <TogglingComponent firstComponent={null} secondComponent={'div'} />
+    );
+
+    ReactTestUtils.renderIntoDocument(
+      <div>
+        {instance1}
+        {instance1}
+        {instance1}
+      </div>,
+    );
+
+    expect(log.calls.count()).toBe(6);
+    expect(log.calls.argsFor(0)[0]).toBe(null);
+    expect(log.calls.argsFor(1)[0]).toBe(null);
+    expect(log.calls.argsFor(2)[0]).toBe(null);
+    expect(log.calls.argsFor(3)[0].tagName).toBe('DIV');
+    expect(log.calls.argsFor(4)[0].tagName).toBe('DIV');
+    expect(log.calls.argsFor(5)[0].tagName).toBe('DIV');
+  });
+
+  it('should distinguish between a script placeholder and an actual script tag', () => {
+    var instance1 = (
+      <TogglingComponent firstComponent={null} secondComponent={'script'} />
+    );
+    var instance2 = (
+      <TogglingComponent firstComponent={'script'} secondComponent={null} />
+    );
+
+    expect(function() {
+      ReactTestUtils.renderIntoDocument(instance1);
+    }).not.toThrow();
+    expect(function() {
+      ReactTestUtils.renderIntoDocument(instance2);
+    }).not.toThrow();
+
+    expect(log.calls.count()).toBe(4);
+    expect(log.calls.argsFor(0)[0]).toBe(null);
+    expect(log.calls.argsFor(1)[0].tagName).toBe('SCRIPT');
+    expect(log.calls.argsFor(2)[0].tagName).toBe('SCRIPT');
+    expect(log.calls.argsFor(3)[0]).toBe(null);
+  });
+
+  it(
+    'should have findDOMNode return null when multiple layers of composite ' +
+      'components render to the same null placeholder',
+    () => {
+      class GrandChild extends React.Component {
+        render() {
+          return null;
+        }
+      }
+
+      class Child extends React.Component {
+        render() {
+          return <GrandChild />;
+        }
+      }
+
+      var instance1 = (
+        <TogglingComponent firstComponent={'div'} secondComponent={Child} />
+      );
+      var instance2 = (
+        <TogglingComponent firstComponent={Child} secondComponent={'div'} />
+      );
+
+      expect(function() {
+        ReactTestUtils.renderIntoDocument(instance1);
+      }).not.toThrow();
+      expect(function() {
+        ReactTestUtils.renderIntoDocument(instance2);
+      }).not.toThrow();
+
+      expect(log.calls.count()).toBe(4);
+      expect(log.calls.argsFor(0)[0].tagName).toBe('DIV');
+      expect(log.calls.argsFor(1)[0]).toBe(null);
+      expect(log.calls.argsFor(2)[0]).toBe(null);
+      expect(log.calls.argsFor(3)[0].tagName).toBe('DIV');
+    },
+  );
+
+  it('works when switching components', () => {
+    var assertions = 0;
+
+    class Inner extends React.Component {
+      render() {
+        return <span />;
+      }
+
+      componentDidMount() {
+        // Make sure the DOM node resolves properly even if we're replacing a
+        // `null` component
+        expect(ReactDOM.findDOMNode(this)).not.toBe(null);
+        assertions++;
+      }
+
+      componentWillUnmount() {
+        // Even though we're getting replaced by `null`, we haven't been
+        // replaced yet!
+        expect(ReactDOM.findDOMNode(this)).not.toBe(null);
+        assertions++;
+      }
+    }
+
+    class Wrapper extends React.Component {
+      render() {
+        return this.props.showInner ? <Inner /> : null;
+      }
+    }
+
+    var el = document.createElement('div');
+    var component;
+
+    // Render the <Inner /> component...
+    component = ReactDOM.render(<Wrapper showInner={true} />, el);
+    expect(ReactDOM.findDOMNode(component)).not.toBe(null);
+
+    // Switch to null...
+    component = ReactDOM.render(<Wrapper showInner={false} />, el);
+    expect(ReactDOM.findDOMNode(component)).toBe(null);
+
+    // ...then switch back.
+    component = ReactDOM.render(<Wrapper showInner={true} />, el);
+    expect(ReactDOM.findDOMNode(component)).not.toBe(null);
+
+    expect(assertions).toBe(3);
+  });
+
+  it('throws when rendering null at the top level', () => {
+    // TODO: This should actually work since `null` is a valid ReactNode
+    var div = document.createElement('div');
+    expect(function() {
+      ReactDOM.render(null, div);
+    }).toThrowError('ReactDOM.render(): Invalid component element.');
+  });
+
+  it('does not break when updating during mount', () => {
+    class Child extends React.Component {
+      componentDidMount() {
+        if (this.props.onMount) {
+          this.props.onMount();
+        }
+      }
+
+      render() {
+        if (!this.props.visible) {
+          return null;
+        }
+
+        return <div>hello world</div>;
+      }
+    }
+
+    class Parent extends React.Component {
+      update = () => {
+        this.forceUpdate();
+      };
+
+      render() {
+        return (
+          <div>
+            <Child key="1" visible={false} />
+            <Child key="0" visible={true} onMount={this.update} />
+            <Child key="2" visible={false} />
+          </div>
+        );
+      }
+    }
+
+    expect(function() {
+      ReactTestUtils.renderIntoDocument(<Parent />);
+    }).not.toThrow();
+  });
+
+  it('preserves the dom node during updates', () => {
+    class Empty extends React.Component {
+      render() {
+        return null;
+      }
+    }
+
+    var container = document.createElement('div');
+
+    ReactDOM.render(<Empty />, container);
+    var noscript1 = container.firstChild;
+    expect(noscript1.nodeName).toBe('#comment');
+
+    // This update shouldn't create a DOM node
+    ReactDOM.render(<Empty />, container);
+    var noscript2 = container.firstChild;
+    expect(noscript2.nodeName).toBe('#comment');
+
+    expect(noscript1).toBe(noscript2);
+  });
+});
diff --git a/src/renderers/shared/stack/reconciler/__tests__/ReactErrorBoundaries-test.js b/src/renderers/shared/stack/reconciler/__tests__/ReactErrorBoundaries-test.js
new file mode 100644
index 000000000000..b1f3f2f120b8
--- /dev/null
+++ b/src/renderers/shared/stack/reconciler/__tests__/ReactErrorBoundaries-test.js
@@ -0,0 +1,301 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var React;
+var ReactDOM;
+
+describe('ReactErrorBoundaries', () => {
+  beforeEach(() => {
+    ReactDOM = require('ReactDOM');
+    React = require('React');
+  });
+
+  it('does not register event handlers for unmounted children', () => {
+    class Angry extends React.Component {
+      render() {
+        throw new Error('Please, do not render me.');
+      }
+    }
+
+    class Boundary extends React.Component {
+      constructor(props) {
+        super(props);
+        this.state = {error: false};
+      }
+      render() {
+        if (!this.state.error) {
+          return (
+            <div><button onClick={this.onClick}>ClickMe</button><Angry /></div>
+          );
+        } else {
+          return <div>Happy Birthday!</div>;
+        }
+      }
+      onClick() {
+        /* do nothing */
+      }
+      unstable_handleError() {
+        this.setState({error: true});
+      }
+    }
+
+    var EventPluginHub = require('EventPluginHub');
+    var container = document.createElement('div');
+    EventPluginHub.putListener = jest.fn();
+    ReactDOM.render(<Boundary />, container);
+    expect(EventPluginHub.putListener).not.toBeCalled();
+  });
+
+  it('renders an error state', () => {
+    var log = [];
+    class Angry extends React.Component {
+      render() {
+        log.push('Angry render');
+        throw new Error('Please, do not render me.');
+      }
+      componentDidMount() {
+        log.push('Angry componentDidMount');
+      }
+      componentWillUnmount() {
+        log.push('Angry componentWillUnmount');
+      }
+    }
+
+    class Boundary extends React.Component {
+      constructor(props) {
+        super(props);
+        this.state = {error: false};
+      }
+      render() {
+        log.push('Boundary render');
+        if (!this.state.error) {
+          return (
+            <div><button onClick={this.onClick}>ClickMe</button><Angry /></div>
+          );
+        } else {
+          return <div>Happy Birthday!</div>;
+        }
+      }
+      componentDidMount() {
+        log.push('Boundary componentDidMount');
+      }
+      componentWillUnmount() {
+        log.push('Boundary componentWillUnmount');
+      }
+      onClick() {
+        /* do nothing */
+      }
+      unstable_handleError() {
+        this.setState({error: true});
+      }
+    }
+
+    var container = document.createElement('div');
+    ReactDOM.render(<Boundary />, container);
+    expect(container.firstChild.innerHTML).toBe('Happy Birthday!');
+    expect(log).toEqual([
+      'Boundary render',
+      'Angry render',
+      'Boundary render',
+      'Boundary componentDidMount',
+    ]);
+  });
+
+  it('will catch exceptions in componentWillUnmount', () => {
+    class ErrorBoundary extends React.Component {
+      constructor() {
+        super();
+        this.state = {error: false};
+      }
+
+      render() {
+        if (!this.state.error) {
+          return <div>{this.props.children}</div>;
+        }
+        return <div>Error has been caught</div>;
+      }
+
+      unstable_handleError() {
+        this.setState({error: true});
+      }
+    }
+
+    class BrokenRender extends React.Component {
+      render() {
+        throw new Error('Always broken.');
+      }
+    }
+
+    class BrokenUnmount extends React.Component {
+      render() {
+        return <div />;
+      }
+      componentWillUnmount() {
+        throw new Error('Always broken.');
+      }
+    }
+
+    var container = document.createElement('div');
+    ReactDOM.render(
+      <ErrorBoundary>
+        <BrokenUnmount />
+        <BrokenRender />
+        <BrokenUnmount />
+      </ErrorBoundary>,
+      container,
+    );
+    ReactDOM.unmountComponentAtNode(container);
+  });
+
+  it('expect uneventful render to succeed', () => {
+    var log = [];
+    class Boundary extends React.Component {
+      constructor(props) {
+        super(props);
+        this.state = {error: false};
+      }
+      render() {
+        log.push('Boundary render');
+        return <div><button onClick={this.onClick}>ClickMe</button></div>;
+      }
+      onClick() {
+        /* do nothing */
+      }
+      componentDidMount() {
+        log.push('Boundary componentDidMount');
+      }
+      componentWillUnmount() {
+        log.push('Boundary componentWillUnmount');
+      }
+      unstable_handleError() {
+        this.setState({error: true});
+      }
+    }
+
+    var container = document.createElement('div');
+    ReactDOM.render(<Boundary />, container);
+    expect(log).toEqual(['Boundary render', 'Boundary componentDidMount']);
+  });
+
+  it('correctly handles composite siblings', () => {
+    class ErrorBoundary extends React.Component {
+      constructor() {
+        super();
+        this.state = {error: false};
+      }
+
+      render() {
+        if (!this.state.error) {
+          return <div>{this.props.children}</div>;
+        }
+        return <div>Error has been caught</div>;
+      }
+
+      unstable_handleError() {
+        this.setState({error: true});
+      }
+    }
+
+    function Broken() {
+      throw new Error('Always broken.');
+    }
+
+    function Composite() {
+      return <div />;
+    }
+
+    var container = document.createElement('div');
+    ReactDOM.render(
+      <ErrorBoundary><Broken /><Composite /></ErrorBoundary>,
+      container,
+    );
+    ReactDOM.unmountComponentAtNode(container);
+  });
+
+  it('catches errors from children', () => {
+    var log = [];
+
+    class Box extends React.Component {
+      constructor(props) {
+        super(props);
+        this.state = {errorMessage: null};
+      }
+      render() {
+        if (this.state.errorMessage != null) {
+          log.push('Box renderError');
+          return <div>Error: {this.state.errorMessage}</div>;
+        }
+        log.push('Box render');
+        var ref = function(x) {
+          log.push('Inquisitive ref ' + x);
+        };
+        return (
+          <div>
+            <Inquisitive ref={ref} />
+            <Angry />
+          </div>
+        );
+      }
+      unstable_handleError(e) {
+        this.setState({errorMessage: e.message});
+      }
+      componentDidMount() {
+        log.push('Box componentDidMount');
+      }
+      componentWillUnmount() {
+        log.push('Box componentWillUnmount');
+      }
+    }
+
+    class Inquisitive extends React.Component {
+      render() {
+        log.push('Inquisitive render');
+        return <div>What is love?</div>;
+      }
+      componentDidMount() {
+        log.push('Inquisitive componentDidMount');
+      }
+      componentWillUnmount() {
+        log.push('Inquisitive componentWillUnmount');
+      }
+    }
+
+    class Angry extends React.Component {
+      render() {
+        log.push('Angry render');
+        throw new Error('Please, do not render me.');
+      }
+      componentDidMount() {
+        log.push('Angry componentDidMount');
+      }
+      componentWillUnmount() {
+        log.push('Angry componentWillUnmount');
+      }
+    }
+
+    var container = document.createElement('div');
+    ReactDOM.render(<Box />, container);
+    expect(container.textContent).toBe('Error: Please, do not render me.');
+    ReactDOM.unmountComponentAtNode(container);
+    expect(log).toEqual([
+      'Box render',
+      'Inquisitive render',
+      'Angry render',
+      'Inquisitive ref null',
+      'Inquisitive componentWillUnmount',
+      'Box renderError',
+      'Box componentDidMount',
+      'Box componentWillUnmount',
+    ]);
+  });
+});
diff --git a/src/renderers/shared/stack/reconciler/__tests__/ReactIdentity-test.js b/src/renderers/shared/stack/reconciler/__tests__/ReactIdentity-test.js
new file mode 100644
index 000000000000..254fc50e6d95
--- /dev/null
+++ b/src/renderers/shared/stack/reconciler/__tests__/ReactIdentity-test.js
@@ -0,0 +1,259 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var React;
+var ReactDOM;
+var ReactFragment;
+var ReactTestUtils;
+
+describe('ReactIdentity', () => {
+  beforeEach(() => {
+    jest.resetModuleRegistry();
+    React = require('React');
+    ReactDOM = require('ReactDOM');
+    ReactFragment = require('ReactFragment');
+    ReactTestUtils = require('ReactTestUtils');
+  });
+
+  function frag(obj) {
+    return ReactFragment.create(obj);
+  }
+
+  it('should allow key property to express identity', () => {
+    var node;
+    var Component = props =>
+      <div ref={c => (node = c)}>
+        <div key={props.swap ? 'banana' : 'apple'} />
+        <div key={props.swap ? 'apple' : 'banana'} />
+      </div>;
+
+    var container = document.createElement('div');
+    ReactDOM.render(<Component />, container);
+    var origChildren = Array.from(node.childNodes);
+    ReactDOM.render(<Component swap={true} />, container);
+    var newChildren = Array.from(node.childNodes);
+    expect(origChildren[0]).toBe(newChildren[1]);
+    expect(origChildren[1]).toBe(newChildren[0]);
+  });
+
+  it('should use composite identity', () => {
+    class Wrapper extends React.Component {
+      render() {
+        return <a>{this.props.children}</a>;
+      }
+    }
+
+    var container = document.createElement('div');
+    var node1;
+    var node2;
+    ReactDOM.render(
+      <Wrapper key="wrap1"><span ref={c => (node1 = c)} /></Wrapper>,
+      container,
+    );
+    ReactDOM.render(
+      <Wrapper key="wrap2"><span ref={c => (node2 = c)} /></Wrapper>,
+      container,
+    );
+
+    expect(node1).not.toBe(node2);
+  });
+
+  function renderAComponentWithKeyIntoContainer(key, container) {
+    class Wrapper extends React.Component {
+      render() {
+        var s1 = <span ref="span1" key={key} />;
+        var s2 = <span ref="span2" />;
+
+        var map = {};
+        map[key] = s2;
+        return <div>{[s1, frag(map)]}</div>;
+      }
+    }
+
+    var instance = ReactDOM.render(<Wrapper />, container);
+    var span1 = instance.refs.span1;
+    var span2 = instance.refs.span2;
+
+    expect(ReactDOM.findDOMNode(span1)).not.toBe(null);
+    expect(ReactDOM.findDOMNode(span2)).not.toBe(null);
+  }
+
+  it('should allow any character as a key, in a detached parent', () => {
+    var detachedContainer = document.createElement('div');
+    renderAComponentWithKeyIntoContainer("<'WEIRD/&\\key'>", detachedContainer);
+  });
+
+  it('should allow any character as a key, in an attached parent', () => {
+    // This test exists to protect against implementation details that
+    // incorrectly query escaped IDs using DOM tools like getElementById.
+    var attachedContainer = document.createElement('div');
+    document.body.appendChild(attachedContainer);
+
+    renderAComponentWithKeyIntoContainer("<'WEIRD/&\\key'>", attachedContainer);
+
+    document.body.removeChild(attachedContainer);
+  });
+
+  it('should not allow scripts in keys to execute', () => {
+    var h4x0rKey =
+      '"><script>window[\'YOUVEBEENH4X0RED\']=true;</script><div id="';
+
+    var attachedContainer = document.createElement('div');
+    document.body.appendChild(attachedContainer);
+
+    renderAComponentWithKeyIntoContainer(h4x0rKey, attachedContainer);
+
+    document.body.removeChild(attachedContainer);
+
+    // If we get this far, make sure we haven't executed the code
+    expect(window.YOUVEBEENH4X0RED).toBe(undefined);
+  });
+
+  it('should let restructured components retain their uniqueness', () => {
+    var instance0 = <span />;
+    var instance1 = <span />;
+    var instance2 = <span />;
+
+    class TestComponent extends React.Component {
+      render() {
+        return (
+          <div>
+            {instance2}
+            {this.props.children[0]}
+            {this.props.children[1]}
+          </div>
+        );
+      }
+    }
+
+    class TestContainer extends React.Component {
+      render() {
+        return <TestComponent>{instance0}{instance1}</TestComponent>;
+      }
+    }
+
+    expect(function() {
+      ReactTestUtils.renderIntoDocument(<TestContainer />);
+    }).not.toThrow();
+  });
+
+  it('should let nested restructures retain their uniqueness', () => {
+    var instance0 = <span />;
+    var instance1 = <span />;
+    var instance2 = <span />;
+
+    class TestComponent extends React.Component {
+      render() {
+        return (
+          <div>
+            {instance2}
+            {this.props.children[0]}
+            {this.props.children[1]}
+          </div>
+        );
+      }
+    }
+
+    class TestContainer extends React.Component {
+      render() {
+        return (
+          <div>
+            <TestComponent>{instance0}{instance1}</TestComponent>
+          </div>
+        );
+      }
+    }
+
+    expect(function() {
+      ReactTestUtils.renderIntoDocument(<TestContainer />);
+    }).not.toThrow();
+  });
+
+  it('should let text nodes retain their uniqueness', () => {
+    class TestComponent extends React.Component {
+      render() {
+        return <div>{this.props.children}<span /></div>;
+      }
+    }
+
+    class TestContainer extends React.Component {
+      render() {
+        return (
+          <TestComponent>
+            <div />
+            {'second'}
+          </TestComponent>
+        );
+      }
+    }
+
+    expect(function() {
+      ReactTestUtils.renderIntoDocument(<TestContainer />);
+    }).not.toThrow();
+  });
+
+  it('should retain key during updates in composite components', () => {
+    class TestComponent extends React.Component {
+      render() {
+        return <div>{this.props.children}</div>;
+      }
+    }
+
+    class TestContainer extends React.Component {
+      state = {swapped: false};
+
+      swap = () => {
+        this.setState({swapped: true});
+      };
+
+      render() {
+        return (
+          <TestComponent>
+            {this.state.swapped ? this.props.second : this.props.first}
+            {this.state.swapped ? this.props.first : this.props.second}
+          </TestComponent>
+        );
+      }
+    }
+
+    var instance0 = <span key="A" />;
+    var instance1 = <span key="B" />;
+
+    var wrapped = <TestContainer first={instance0} second={instance1} />;
+
+    wrapped = ReactDOM.render(wrapped, document.createElement('div'));
+    var div = ReactDOM.findDOMNode(wrapped);
+
+    var beforeA = div.childNodes[0];
+    var beforeB = div.childNodes[1];
+    wrapped.swap();
+    var afterA = div.childNodes[1];
+    var afterB = div.childNodes[0];
+
+    expect(beforeA).toBe(afterA);
+    expect(beforeB).toBe(afterB);
+  });
+
+  it('should not allow implicit and explicit keys to collide', () => {
+    var component = (
+      <div>
+        <span />
+        <span key="0" />
+      </div>
+    );
+
+    expect(function() {
+      ReactTestUtils.renderIntoDocument(component);
+    }).not.toThrow();
+  });
+});
diff --git a/src/renderers/shared/stack/reconciler/__tests__/ReactMockedComponent-test.js b/src/renderers/shared/stack/reconciler/__tests__/ReactMockedComponent-test.js
new file mode 100644
index 000000000000..185bd076241f
--- /dev/null
+++ b/src/renderers/shared/stack/reconciler/__tests__/ReactMockedComponent-test.js
@@ -0,0 +1,102 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var React;
+var ReactTestUtils;
+
+var AutoMockedComponent;
+var MockedComponent;
+
+describe('ReactMockedComponent', () => {
+  beforeEach(() => {
+    React = require('React');
+    ReactTestUtils = require('ReactTestUtils');
+
+    AutoMockedComponent = jest.genMockFromModule(
+      'ReactMockedComponentTestComponent',
+    );
+    MockedComponent = jest.genMockFromModule(
+      'ReactMockedComponentTestComponent',
+    );
+
+    ReactTestUtils.mockComponent(MockedComponent);
+  });
+
+  it('should allow an implicitly mocked component to be rendered without warnings', () => {
+    spyOn(console, 'error');
+    ReactTestUtils.renderIntoDocument(<AutoMockedComponent />);
+    expect(console.error.calls.count()).toBe(0);
+  });
+
+  it('should allow an implicitly mocked component to be updated', () => {
+    class Wrapper extends React.Component {
+      state = {foo: 1};
+
+      update = () => {
+        this.setState({foo: 2});
+      };
+
+      render() {
+        return <div><AutoMockedComponent prop={this.state.foo} /></div>;
+      }
+    }
+
+    var instance = ReactTestUtils.renderIntoDocument(<Wrapper />);
+
+    var found = ReactTestUtils.findRenderedComponentWithType(
+      instance,
+      AutoMockedComponent,
+    );
+    expect(typeof found).toBe('object');
+
+    instance.update();
+  });
+
+  it('has custom methods on the implicitly mocked component', () => {
+    var instance = ReactTestUtils.renderIntoDocument(<AutoMockedComponent />);
+    expect(typeof instance.hasCustomMethod).toBe('function');
+  });
+
+  it('should allow an explicitly mocked component to be rendered', () => {
+    ReactTestUtils.renderIntoDocument(<MockedComponent />);
+  });
+
+  it('should allow an explicitly mocked component to be updated', () => {
+    class Wrapper extends React.Component {
+      state = {foo: 1};
+
+      update = () => {
+        this.setState({foo: 2});
+      };
+
+      render() {
+        return <div><MockedComponent prop={this.state.foo} /></div>;
+      }
+    }
+
+    var instance = ReactTestUtils.renderIntoDocument(<Wrapper />);
+
+    var found = ReactTestUtils.findRenderedComponentWithType(
+      instance,
+      MockedComponent,
+    );
+    expect(typeof found).toBe('object');
+
+    instance.update();
+  });
+
+  it('has custom methods on the explicitly mocked component', () => {
+    var instance = ReactTestUtils.renderIntoDocument(<MockedComponent />);
+    expect(typeof instance.hasCustomMethod).toBe('function');
+  });
+});
diff --git a/src/renderers/shared/stack/reconciler/__tests__/ReactMultiChild-test.js b/src/renderers/shared/stack/reconciler/__tests__/ReactMultiChild-test.js
new file mode 100644
index 000000000000..e11c3ba000c7
--- /dev/null
+++ b/src/renderers/shared/stack/reconciler/__tests__/ReactMultiChild-test.js
@@ -0,0 +1,198 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+describe('ReactMultiChild', () => {
+  function normalizeCodeLocInfo(str) {
+    return str.replace(/\(at .+?:\d+\)/g, '(at **)');
+  }
+
+  var React;
+  var ReactDOM;
+
+  beforeEach(() => {
+    jest.resetModuleRegistry();
+    React = require('React');
+    ReactDOM = require('ReactDOM');
+  });
+
+  describe('reconciliation', () => {
+    it('should update children when possible', () => {
+      var container = document.createElement('div');
+
+      var mockMount = jest.fn();
+      var mockUpdate = jest.fn();
+      var mockUnmount = jest.fn();
+
+      class MockComponent extends React.Component {
+        componentDidMount = mockMount;
+        componentDidUpdate = mockUpdate;
+        componentWillUnmount = mockUnmount;
+        render() {
+          return <span />;
+        }
+      }
+
+      expect(mockMount.mock.calls.length).toBe(0);
+      expect(mockUpdate.mock.calls.length).toBe(0);
+      expect(mockUnmount.mock.calls.length).toBe(0);
+
+      ReactDOM.render(<div><MockComponent /></div>, container);
+
+      expect(mockMount.mock.calls.length).toBe(1);
+      expect(mockUpdate.mock.calls.length).toBe(0);
+      expect(mockUnmount.mock.calls.length).toBe(0);
+
+      ReactDOM.render(<div><MockComponent /></div>, container);
+
+      expect(mockMount.mock.calls.length).toBe(1);
+      expect(mockUpdate.mock.calls.length).toBe(1);
+      expect(mockUnmount.mock.calls.length).toBe(0);
+    });
+
+    it('should replace children with different constructors', () => {
+      var container = document.createElement('div');
+
+      var mockMount = jest.fn();
+      var mockUnmount = jest.fn();
+
+      class MockComponent extends React.Component {
+        componentDidMount = mockMount;
+        componentWillUnmount = mockUnmount;
+        render() {
+          return <span />;
+        }
+      }
+
+      expect(mockMount.mock.calls.length).toBe(0);
+      expect(mockUnmount.mock.calls.length).toBe(0);
+
+      ReactDOM.render(<div><MockComponent /></div>, container);
+
+      expect(mockMount.mock.calls.length).toBe(1);
+      expect(mockUnmount.mock.calls.length).toBe(0);
+
+      ReactDOM.render(<div><span /></div>, container);
+
+      expect(mockMount.mock.calls.length).toBe(1);
+      expect(mockUnmount.mock.calls.length).toBe(1);
+    });
+
+    it('should NOT replace children with different owners', () => {
+      var container = document.createElement('div');
+
+      var mockMount = jest.fn();
+      var mockUnmount = jest.fn();
+
+      class MockComponent extends React.Component {
+        componentDidMount = mockMount;
+        componentWillUnmount = mockUnmount;
+        render() {
+          return <span />;
+        }
+      }
+
+      class WrapperComponent extends React.Component {
+        render() {
+          return this.props.children || <MockComponent />;
+        }
+      }
+
+      expect(mockMount.mock.calls.length).toBe(0);
+      expect(mockUnmount.mock.calls.length).toBe(0);
+
+      ReactDOM.render(<WrapperComponent />, container);
+
+      expect(mockMount.mock.calls.length).toBe(1);
+      expect(mockUnmount.mock.calls.length).toBe(0);
+
+      ReactDOM.render(
+        <WrapperComponent><MockComponent /></WrapperComponent>,
+        container,
+      );
+
+      expect(mockMount.mock.calls.length).toBe(1);
+      expect(mockUnmount.mock.calls.length).toBe(0);
+    });
+
+    it('should replace children with different keys', () => {
+      var container = document.createElement('div');
+
+      var mockMount = jest.fn();
+      var mockUnmount = jest.fn();
+
+      class MockComponent extends React.Component {
+        componentDidMount = mockMount;
+        componentWillUnmount = mockUnmount;
+        render() {
+          return <span />;
+        }
+      }
+
+      expect(mockMount.mock.calls.length).toBe(0);
+      expect(mockUnmount.mock.calls.length).toBe(0);
+
+      ReactDOM.render(<div><MockComponent key="A" /></div>, container);
+
+      expect(mockMount.mock.calls.length).toBe(1);
+      expect(mockUnmount.mock.calls.length).toBe(0);
+
+      ReactDOM.render(<div><MockComponent key="B" /></div>, container);
+
+      expect(mockMount.mock.calls.length).toBe(2);
+      expect(mockUnmount.mock.calls.length).toBe(1);
+    });
+
+    it('should warn for duplicated keys with component stack info', () => {
+      spyOn(console, 'error');
+
+      var container = document.createElement('div');
+
+      class WrapperComponent extends React.Component {
+        render() {
+          return <div>{this.props.children}</div>;
+        }
+      }
+
+      class Parent extends React.Component {
+        render() {
+          return (
+            <div>
+              <WrapperComponent>
+                {this.props.children}
+              </WrapperComponent>
+            </div>
+          );
+        }
+      }
+
+      ReactDOM.render(<Parent>{[<div key="1" />]}</Parent>, container);
+
+      ReactDOM.render(
+        <Parent>{[<div key="1" />, <div key="1" />]}</Parent>,
+        container,
+      );
+
+      expect(console.error.calls.count()).toBe(1);
+      expect(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
+        'Warning: flattenChildren(...): ' +
+          'Encountered two children with the same key, `1`. ' +
+          'Child keys must be unique; when two children share a key, ' +
+          'only the first child will be used.\n' +
+          '    in div (at **)\n' +
+          '    in WrapperComponent (at **)\n' +
+          '    in div (at **)\n' +
+          '    in Parent (at **)',
+      );
+    });
+  });
+});
diff --git a/src/renderers/shared/reconciler/__tests__/ReactMultiChildReconcile-test.js b/src/renderers/shared/stack/reconciler/__tests__/ReactMultiChildReconcile-test.js
similarity index 78%
rename from src/renderers/shared/reconciler/__tests__/ReactMultiChildReconcile-test.js
rename to src/renderers/shared/stack/reconciler/__tests__/ReactMultiChildReconcile-test.js
index 93ef77bebe63..644e614a1841 100644
--- a/src/renderers/shared/reconciler/__tests__/ReactMultiChildReconcile-test.js
+++ b/src/renderers/shared/stack/reconciler/__tests__/ReactMultiChildReconcile-test.js
@@ -16,8 +16,6 @@ var ReactDOM = require('ReactDOM');
 var ReactDOMComponentTree = require('ReactDOMComponentTree');
 var ReactInstanceMap = require('ReactInstanceMap');
 
-var mapObject = require('mapObject');
-
 var stripEmptyValues = function(obj) {
   var ret = {};
   var name;
@@ -47,70 +45,109 @@ var getOriginalKey = function(childName) {
  * existing children won't reinitialize components, when moving children -
  * reusing existing DOM/memory resources.
  */
-var StatusDisplay = React.createClass({
-  getInitialState: function() {
-    return {internalState: Math.random()};
-  },
+class StatusDisplay extends React.Component {
+  state = {internalState: Math.random()};
 
-  getStatus: function() {
+  getStatus = () => {
     return this.props.status;
-  },
+  };
 
-  getInternalState: function() {
+  getInternalState = () => {
     return this.state.internalState;
-  },
+  };
+
+  componentDidMount() {
+    this.props.onFlush();
+  }
 
-  render: function() {
+  componentDidUpdate() {
+    this.props.onFlush();
+  }
+
+  render() {
     return (
       <div>
         {this.state.internalState}
       </div>
     );
-  },
-});
+  }
+}
 
 /**
  * Displays friends statuses.
  */
-var FriendsStatusDisplay = React.createClass({
+class FriendsStatusDisplay extends React.Component {
   /**
-   * Retrieves the rendered children in a nice format for comparing to the input
-   * `this.props.usernameToStatus`. Gets the order directly from each rendered
-   * child's `index` field. Refs are not maintained in the rendered order, and
-   * neither is `this._renderedChildren` (surprisingly).
-   */
-  getStatusDisplays: function() {
-    var name;
-    var orderOfUsernames = [];
+  * Gets the order directly from each rendered child's `index` field.
+  * Refs are not maintained in the rendered order, and neither is
+  * `this._renderedChildren` (surprisingly).
+  */
+  getOriginalKeys = () => {
+    var originalKeys = [];
     // TODO: Update this to a better test that doesn't rely so much on internal
     // implementation details.
-    var statusDisplays =
-      ReactInstanceMap.get(this)
-      ._renderedComponent
+    var statusDisplays = ReactInstanceMap.get(this)._renderedComponent
       ._renderedChildren;
+    var name;
     for (name in statusDisplays) {
       var child = statusDisplays[name];
       var isPresent = !!child;
       if (isPresent) {
-        orderOfUsernames[child._mountIndex] = getOriginalKey(name);
+        originalKeys[child._mountIndex] = getOriginalKey(name);
       }
     }
+    return originalKeys;
+  };
+
+  /**
+   * Retrieves the rendered children in a nice format for comparing to the input
+   * `this.props.usernameToStatus`.
+   */
+  getStatusDisplays = () => {
     var res = {};
     var i;
-    for (i = 0; i < orderOfUsernames.length; i++) {
-      var key = orderOfUsernames[i];
+    var originalKeys = this.getOriginalKeys();
+    for (i = 0; i < originalKeys.length; i++) {
+      var key = originalKeys[i];
       res[key] = this.refs[key];
     }
     return res;
-  },
-  render: function() {
+  };
+
+  /**
+   * Verifies that by the time a child is flushed, the refs that appeared
+   * earlier have already been resolved.
+   * TODO: This assumption will likely break with incremental reconciler
+   * but our internal layer API depends on this assumption. We need to change
+   * it to be more declarative before making ref resolution indeterministic.
+   */
+  verifyPreviousRefsResolved = flushedKey => {
+    var i;
+    var originalKeys = this.getOriginalKeys();
+    for (i = 0; i < originalKeys.length; i++) {
+      var key = originalKeys[i];
+      if (key === flushedKey) {
+        // We are only interested in children up to the current key.
+        return;
+      }
+      expect(this.refs[key]).toBeTruthy();
+    }
+  };
+
+  render() {
     var children = [];
     var key;
     for (key in this.props.usernameToStatus) {
       var status = this.props.usernameToStatus[key];
       children.push(
-        !status ? null :
-        <StatusDisplay key={key} ref={key} status={status} />
+        !status
+          ? null
+          : <StatusDisplay
+              key={key}
+              ref={key}
+              onFlush={this.verifyPreviousRefsResolved.bind(this, key)}
+              status={status}
+            />,
       );
     }
     return (
@@ -118,14 +155,14 @@ var FriendsStatusDisplay = React.createClass({
         {children}
       </div>
     );
-  },
-});
-
+  }
+}
 
 function getInternalStateByUserName(statusDisplays) {
-  return mapObject(statusDisplays, function(statusDisplay, key) {
-    return statusDisplay.getInternalState();
-  });
+  return Object.keys(statusDisplays).reduce((acc, key) => {
+    acc[key] = statusDisplays[key].getInternalState();
+    return acc;
+  }, {});
 }
 
 /**
@@ -137,14 +174,16 @@ function verifyStatuses(statusDisplays, props) {
   var nonEmptyStatusDisplays = stripEmptyValues(statusDisplays);
   var nonEmptyStatusProps = stripEmptyValues(props.usernameToStatus);
   var username;
-  expect(Object.keys(nonEmptyStatusDisplays).length)
-    .toEqual(Object.keys(nonEmptyStatusProps).length);
+  expect(Object.keys(nonEmptyStatusDisplays).length).toEqual(
+    Object.keys(nonEmptyStatusProps).length,
+  );
   for (username in nonEmptyStatusDisplays) {
     if (!nonEmptyStatusDisplays.hasOwnProperty(username)) {
       continue;
     }
-    expect(nonEmptyStatusDisplays[username].getStatus())
-      .toEqual(nonEmptyStatusProps[username]);
+    expect(nonEmptyStatusDisplays[username].getStatus()).toEqual(
+      nonEmptyStatusProps[username],
+    );
   }
 
   // now go the other way to make sure we got them all.
@@ -152,12 +191,14 @@ function verifyStatuses(statusDisplays, props) {
     if (!nonEmptyStatusProps.hasOwnProperty(username)) {
       continue;
     }
-    expect(nonEmptyStatusDisplays[username].getStatus())
-      .toEqual(nonEmptyStatusProps[username]);
+    expect(nonEmptyStatusDisplays[username].getStatus()).toEqual(
+      nonEmptyStatusProps[username],
+    );
   }
 
-  expect(Object.keys(nonEmptyStatusDisplays))
-      .toEqual(Object.keys(nonEmptyStatusProps));
+  expect(Object.keys(nonEmptyStatusDisplays)).toEqual(
+    Object.keys(nonEmptyStatusProps),
+  );
 }
 
 /**
@@ -173,13 +214,13 @@ function verifyStatesPreserved(lastInternalStates, statusDisplays) {
       continue;
     }
     if (lastInternalStates[key]) {
-      expect(lastInternalStates[key])
-        .toEqual(statusDisplays[key].getInternalState());
+      expect(lastInternalStates[key]).toEqual(
+        statusDisplays[key].getInternalState(),
+      );
     }
   }
 }
 
-
 /**
  * Verifies that the internal representation of a set of `renderedChildren`
  * accurately reflects what is in the DOM.
@@ -202,7 +243,7 @@ function verifyDomOrderingAccurate(parentInstance, statusDisplays) {
     }
     var statusDisplay = statusDisplays[username];
     orderedLogicalIDs.push(
-      ReactInstanceMap.get(statusDisplay)._renderedComponent._rootNodeID
+      ReactInstanceMap.get(statusDisplay)._renderedComponent._rootNodeID,
     );
   }
   expect(orderedDomIDs).toEqual(orderedLogicalIDs);
@@ -216,17 +257,14 @@ function testPropsSequence(sequence) {
   var container = document.createElement('div');
   var parentInstance = ReactDOM.render(
     <FriendsStatusDisplay {...sequence[0]} />,
-    container
+    container,
   );
   var statusDisplays = parentInstance.getStatusDisplays();
   var lastInternalStates = getInternalStateByUserName(statusDisplays);
   verifyStatuses(statusDisplays, sequence[0]);
 
   for (i = 1; i < sequence.length; i++) {
-    ReactDOM.render(
-      <FriendsStatusDisplay {...sequence[i]} />,
-      container
-    );
+    ReactDOM.render(<FriendsStatusDisplay {...sequence[i]} />, container);
     statusDisplays = parentInstance.getStatusDisplays();
     verifyStatuses(statusDisplays, sequence[i]);
     verifyStatesPreserved(lastInternalStates, statusDisplays);
@@ -236,12 +274,12 @@ function testPropsSequence(sequence) {
   }
 }
 
-describe('ReactMultiChildReconcile', function() {
-  beforeEach(function() {
+describe('ReactMultiChildReconcile', () => {
+  beforeEach(() => {
     jest.resetModuleRegistry();
   });
 
-  it('should reset internal state if removed then readded', function() {
+  it('should reset internal state if removed then readded', () => {
     // Test basics.
     var props = {
       usernameToStatus: {
@@ -252,31 +290,26 @@ describe('ReactMultiChildReconcile', function() {
     var container = document.createElement('div');
     var parentInstance = ReactDOM.render(
       <FriendsStatusDisplay {...props} />,
-      container
+      container,
     );
     var statusDisplays = parentInstance.getStatusDisplays();
     var startingInternalState = statusDisplays.jcw.getInternalState();
 
     // Now remove the child.
-    ReactDOM.render(
-      <FriendsStatusDisplay />,
-      container
-    );
+    ReactDOM.render(<FriendsStatusDisplay />, container);
     statusDisplays = parentInstance.getStatusDisplays();
     expect(statusDisplays.jcw).toBeFalsy();
 
     // Now reset the props that cause there to be a child
-    ReactDOM.render(
-      <FriendsStatusDisplay {...props} />,
-      container
-    );
+    ReactDOM.render(<FriendsStatusDisplay {...props} />, container);
     statusDisplays = parentInstance.getStatusDisplays();
     expect(statusDisplays.jcw).toBeTruthy();
-    expect(statusDisplays.jcw.getInternalState())
-        .toNotBe(startingInternalState);
+    expect(statusDisplays.jcw.getInternalState()).not.toBe(
+      startingInternalState,
+    );
   });
 
-  it('should create unique identity', function() {
+  it('should create unique identity', () => {
     // Test basics.
     var usernameToStatus = {
       jcw: 'jcwStatus',
@@ -287,7 +320,7 @@ describe('ReactMultiChildReconcile', function() {
     testPropsSequence([{usernameToStatus: usernameToStatus}]);
   });
 
-  it('should preserve order if children order has not changed', function() {
+  it('should preserve order if children order has not changed', () => {
     var PROPS_SEQUENCE = [
       {
         usernameToStatus: {
@@ -305,9 +338,9 @@ describe('ReactMultiChildReconcile', function() {
     testPropsSequence(PROPS_SEQUENCE);
   });
 
-  it('should transition from zero to one children correctly', function() {
+  it('should transition from zero to one children correctly', () => {
     var PROPS_SEQUENCE = [
-      {usernameToStatus: {} },
+      {usernameToStatus: {}},
       {
         usernameToStatus: {
           first: 'firstStatus',
@@ -317,19 +350,19 @@ describe('ReactMultiChildReconcile', function() {
     testPropsSequence(PROPS_SEQUENCE);
   });
 
-  it('should transition from one to zero children correctly', function() {
+  it('should transition from one to zero children correctly', () => {
     var PROPS_SEQUENCE = [
       {
         usernameToStatus: {
           first: 'firstStatus',
         },
       },
-      {usernameToStatus: {} },
+      {usernameToStatus: {}},
     ];
     testPropsSequence(PROPS_SEQUENCE);
   });
 
-  it('should transition from one child to null children', function() {
+  it('should transition from one child to null children', () => {
     testPropsSequence([
       {
         usernameToStatus: {
@@ -340,7 +373,7 @@ describe('ReactMultiChildReconcile', function() {
     ]);
   });
 
-  it('should transition from null children to one child', function() {
+  it('should transition from null children to one child', () => {
     testPropsSequence([
       {},
       {
@@ -351,7 +384,7 @@ describe('ReactMultiChildReconcile', function() {
     ]);
   });
 
-  it('should transition from zero children to null children', function() {
+  it('should transition from zero children to null children', () => {
     testPropsSequence([
       {
         usernameToStatus: {},
@@ -360,7 +393,7 @@ describe('ReactMultiChildReconcile', function() {
     ]);
   });
 
-  it('should transition from null children to zero children', function() {
+  it('should transition from null children to zero children', () => {
     testPropsSequence([
       {},
       {
@@ -369,13 +402,11 @@ describe('ReactMultiChildReconcile', function() {
     ]);
   });
 
-
-
   /**
    * `FriendsStatusDisplay` renders nulls as empty children (it's a convention
    * of `FriendsStatusDisplay`, nothing related to React or these test cases.
    */
-  it('should remove nulled out children at the beginning', function() {
+  it('should remove nulled out children at the beginning', () => {
     var PROPS_SEQUENCE = [
       {
         usernameToStatus: {
@@ -393,7 +424,7 @@ describe('ReactMultiChildReconcile', function() {
     testPropsSequence(PROPS_SEQUENCE);
   });
 
-  it('should remove nulled out children at the end', function() {
+  it('should remove nulled out children at the end', () => {
     var PROPS_SEQUENCE = [
       {
         usernameToStatus: {
@@ -411,7 +442,7 @@ describe('ReactMultiChildReconcile', function() {
     testPropsSequence(PROPS_SEQUENCE);
   });
 
-  it('should reverse the order of two children', function() {
+  it('should reverse the order of two children', () => {
     var PROPS_SEQUENCE = [
       {
         usernameToStatus: {
@@ -429,7 +460,7 @@ describe('ReactMultiChildReconcile', function() {
     testPropsSequence(PROPS_SEQUENCE);
   });
 
-  it('should reverse the order of more than two children', function() {
+  it('should reverse the order of more than two children', () => {
     var PROPS_SEQUENCE = [
       {
         usernameToStatus: {
@@ -449,7 +480,7 @@ describe('ReactMultiChildReconcile', function() {
     testPropsSequence(PROPS_SEQUENCE);
   });
 
-  it('should cycle order correctly', function() {
+  it('should cycle order correctly', () => {
     var PROPS_SEQUENCE = [
       {
         usernameToStatus: {
@@ -484,7 +515,8 @@ describe('ReactMultiChildReconcile', function() {
         },
       },
       {
-        usernameToStatus: {               // Full circle!
+        usernameToStatus: {
+          // Full circle!
           userOne: 'userOneStatus',
           userTwo: 'userTwoStatus',
           userThree: 'userThreeStatus',
@@ -495,7 +527,7 @@ describe('ReactMultiChildReconcile', function() {
     testPropsSequence(PROPS_SEQUENCE);
   });
 
-  it('should cycle order correctly in the other direction', function() {
+  it('should cycle order correctly in the other direction', () => {
     var PROPS_SEQUENCE = [
       {
         usernameToStatus: {
@@ -530,7 +562,8 @@ describe('ReactMultiChildReconcile', function() {
         },
       },
       {
-        usernameToStatus: {               // Full circle!
+        usernameToStatus: {
+          // Full circle!
           userOne: 'userOneStatus',
           userTwo: 'userTwoStatus',
           userThree: 'userThreeStatus',
@@ -541,8 +574,7 @@ describe('ReactMultiChildReconcile', function() {
     testPropsSequence(PROPS_SEQUENCE);
   });
 
-
-  it('should remove nulled out children and ignore new null children', function() {
+  it('should remove nulled out children and ignore new null children', () => {
     var PROPS_SEQUENCE = [
       {
         usernameToStatus: {
@@ -561,13 +593,13 @@ describe('ReactMultiChildReconcile', function() {
     testPropsSequence(PROPS_SEQUENCE);
   });
 
-  it('should remove nulled out children and reorder remaining', function() {
+  it('should remove nulled out children and reorder remaining', () => {
     var PROPS_SEQUENCE = [
       {
         usernameToStatus: {
           jcw: 'jcwStatus',
           jordanjcw: 'jordanjcwStatus',
-          john: 'johnStatus',  // john will go away
+          john: 'johnStatus', // john will go away
           joe: 'joeStatus',
         },
       },
@@ -582,7 +614,7 @@ describe('ReactMultiChildReconcile', function() {
     testPropsSequence(PROPS_SEQUENCE);
   });
 
-  it('should append children to the end', function() {
+  it('should append children to the end', () => {
     var PROPS_SEQUENCE = [
       {
         usernameToStatus: {
@@ -601,7 +633,7 @@ describe('ReactMultiChildReconcile', function() {
     testPropsSequence(PROPS_SEQUENCE);
   });
 
-  it('should append multiple children to the end', function() {
+  it('should append multiple children to the end', () => {
     var PROPS_SEQUENCE = [
       {
         usernameToStatus: {
@@ -621,7 +653,7 @@ describe('ReactMultiChildReconcile', function() {
     testPropsSequence(PROPS_SEQUENCE);
   });
 
-  it('should prepend children to the beginning', function() {
+  it('should prepend children to the beginning', () => {
     var PROPS_SEQUENCE = [
       {
         usernameToStatus: {
@@ -640,7 +672,7 @@ describe('ReactMultiChildReconcile', function() {
     testPropsSequence(PROPS_SEQUENCE);
   });
 
-  it('should prepend multiple children to the beginning', function() {
+  it('should prepend multiple children to the beginning', () => {
     var PROPS_SEQUENCE = [
       {
         usernameToStatus: {
@@ -660,7 +692,7 @@ describe('ReactMultiChildReconcile', function() {
     testPropsSequence(PROPS_SEQUENCE);
   });
 
-  it('should not prepend an empty child to the beginning', function() {
+  it('should not prepend an empty child to the beginning', () => {
     var PROPS_SEQUENCE = [
       {
         usernameToStatus: {
@@ -679,7 +711,7 @@ describe('ReactMultiChildReconcile', function() {
     testPropsSequence(PROPS_SEQUENCE);
   });
 
-  it('should not append an empty child to the end', function() {
+  it('should not append an empty child to the end', () => {
     var PROPS_SEQUENCE = [
       {
         usernameToStatus: {
@@ -698,7 +730,7 @@ describe('ReactMultiChildReconcile', function() {
     testPropsSequence(PROPS_SEQUENCE);
   });
 
-  it('should not insert empty children in the middle', function() {
+  it('should not insert empty children in the middle', () => {
     var PROPS_SEQUENCE = [
       {
         usernameToStatus: {
@@ -719,7 +751,7 @@ describe('ReactMultiChildReconcile', function() {
     testPropsSequence(PROPS_SEQUENCE);
   });
 
-  it('should insert one new child in the middle', function() {
+  it('should insert one new child in the middle', () => {
     var PROPS_SEQUENCE = [
       {
         usernameToStatus: {
@@ -738,7 +770,7 @@ describe('ReactMultiChildReconcile', function() {
     testPropsSequence(PROPS_SEQUENCE);
   });
 
-  it('should insert multiple new truthy children in the middle', function() {
+  it('should insert multiple new truthy children in the middle', () => {
     var PROPS_SEQUENCE = [
       {
         usernameToStatus: {
@@ -759,7 +791,7 @@ describe('ReactMultiChildReconcile', function() {
     testPropsSequence(PROPS_SEQUENCE);
   });
 
-  it('should insert non-empty children in middle where nulls were', function() {
+  it('should insert non-empty children in middle where nulls were', () => {
     var PROPS_SEQUENCE = [
       {
         usernameToStatus: {
diff --git a/src/renderers/shared/stack/reconciler/__tests__/ReactMultiChildText-test.js b/src/renderers/shared/stack/reconciler/__tests__/ReactMultiChildText-test.js
new file mode 100644
index 000000000000..549b0d259e28
--- /dev/null
+++ b/src/renderers/shared/stack/reconciler/__tests__/ReactMultiChildText-test.js
@@ -0,0 +1,314 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var React = require('React');
+var ReactDOM = require('ReactDOM');
+var ReactTestUtils = require('ReactTestUtils');
+
+// Helpers
+var testAllPermutations = function(testCases) {
+  for (var i = 0; i < testCases.length; i += 2) {
+    var renderWithChildren = testCases[i];
+    var expectedResultAfterRender = testCases[i + 1];
+
+    for (var j = 0; j < testCases.length; j += 2) {
+      var updateWithChildren = testCases[j];
+      var expectedResultAfterUpdate = testCases[j + 1];
+
+      var container = document.createElement('div');
+      var d = ReactDOM.render(<div>{renderWithChildren}</div>, container);
+      expectChildren(d, expectedResultAfterRender);
+
+      d = ReactDOM.render(<div>{updateWithChildren}</div>, container);
+      expectChildren(d, expectedResultAfterUpdate);
+    }
+  }
+};
+
+var expectChildren = function(d, children) {
+  var outerNode = ReactDOM.findDOMNode(d);
+  var textNode;
+  if (typeof children === 'string') {
+    textNode = outerNode.firstChild;
+
+    if (children === '') {
+      expect(textNode != null).toBe(false);
+    } else {
+      expect(textNode != null).toBe(true);
+      expect(textNode.nodeType).toBe(3);
+      expect(textNode.data).toBe('' + children);
+    }
+  } else {
+    var openingCommentNode;
+    var closingCommentNode;
+    var mountIndex = 0;
+
+    for (var i = 0; i < children.length; i++) {
+      var child = children[i];
+
+      if (typeof child === 'string') {
+        openingCommentNode = outerNode.childNodes[mountIndex];
+
+        expect(openingCommentNode.nodeType).toBe(8);
+        expect(openingCommentNode.nodeValue).toMatch(/ react-text: [0-9]+ /);
+
+        if (child === '') {
+          textNode = null;
+          closingCommentNode = openingCommentNode.nextSibling;
+          mountIndex += 2;
+        } else {
+          textNode = openingCommentNode.nextSibling;
+          closingCommentNode = textNode.nextSibling;
+          mountIndex += 3;
+        }
+
+        if (textNode) {
+          expect(textNode.nodeType).toBe(3);
+          expect(textNode.data).toBe('' + child);
+        }
+
+        expect(closingCommentNode.nodeType).toBe(8);
+        expect(closingCommentNode.nodeValue).toBe(' /react-text ');
+      } else {
+        var elementDOMNode = outerNode.childNodes[mountIndex];
+        expect(elementDOMNode.tagName).toBe('DIV');
+        mountIndex++;
+      }
+    }
+  }
+};
+
+/**
+ * ReactMultiChild DOM integration test. In ReactDOM components, we make sure
+ * that single children that are strings are treated as "content" which is much
+ * faster to render and update.
+ */
+describe('ReactMultiChildText', () => {
+  it('should correctly handle all possible children for render and update', () => {
+    spyOn(console, 'error');
+    testAllPermutations([
+      // basic values
+      undefined,
+      [],
+      null,
+      [],
+      false,
+      [],
+      true,
+      [],
+      0,
+      '0',
+      1.2,
+      '1.2',
+      '',
+      '',
+      'foo',
+      'foo',
+
+      [],
+      [],
+      [undefined],
+      [],
+      [null],
+      [],
+      [false],
+      [],
+      [true],
+      [],
+      [0],
+      ['0'],
+      [1.2],
+      ['1.2'],
+      [''],
+      [''],
+      ['foo'],
+      ['foo'],
+      [<div />],
+      [<div />],
+
+      // two adjacent values
+      [true, 0],
+      ['0'],
+      [0, 0],
+      ['0', '0'],
+      [1.2, 0],
+      ['1.2', '0'],
+      [0, ''],
+      ['0', ''],
+      ['foo', 0],
+      ['foo', '0'],
+      [0, <div />],
+      ['0', <div />],
+
+      [true, 1.2],
+      ['1.2'],
+      [1.2, 0],
+      ['1.2', '0'],
+      [1.2, 1.2],
+      ['1.2', '1.2'],
+      [1.2, ''],
+      ['1.2', ''],
+      ['foo', 1.2],
+      ['foo', '1.2'],
+      [1.2, <div />],
+      ['1.2', <div />],
+
+      [true, ''],
+      [''],
+      ['', 0],
+      ['', '0'],
+      [1.2, ''],
+      ['1.2', ''],
+      ['', ''],
+      ['', ''],
+      ['foo', ''],
+      ['foo', ''],
+      ['', <div />],
+      ['', <div />],
+
+      [true, 'foo'],
+      ['foo'],
+      ['foo', 0],
+      ['foo', '0'],
+      [1.2, 'foo'],
+      ['1.2', 'foo'],
+      ['foo', ''],
+      ['foo', ''],
+      ['foo', 'foo'],
+      ['foo', 'foo'],
+      ['foo', <div />],
+      ['foo', <div />],
+
+      // values separated by an element
+      [true, <div />, true],
+      [<div />],
+      [1.2, <div />, 1.2],
+      ['1.2', <div />, '1.2'],
+      ['', <div />, ''],
+      ['', <div />, ''],
+      ['foo', <div />, 'foo'],
+      ['foo', <div />, 'foo'],
+
+      [true, 1.2, <div />, '', 'foo'],
+      ['1.2', <div />, '', 'foo'],
+      [1.2, '', <div />, 'foo', true],
+      ['1.2', '', <div />, 'foo'],
+      ['', 'foo', <div />, true, 1.2],
+      ['', 'foo', <div />, '1.2'],
+
+      [true, 1.2, '', <div />, 'foo', true, 1.2],
+      ['1.2', '', <div />, 'foo', '1.2'],
+      ['', 'foo', true, <div />, 1.2, '', 'foo'],
+      ['', 'foo', <div />, '1.2', '', 'foo'],
+
+      // values inside arrays
+      [[true], [true]],
+      [],
+      [[1.2], [1.2]],
+      ['1.2', '1.2'],
+      [[''], ['']],
+      ['', ''],
+      [['foo'], ['foo']],
+      ['foo', 'foo'],
+      [[<div />], [<div />]],
+      [<div />, <div />],
+
+      [[true, 1.2, <div />], '', 'foo'],
+      ['1.2', <div />, '', 'foo'],
+      [1.2, '', [<div />, 'foo', true]],
+      ['1.2', '', <div />, 'foo'],
+      ['', ['foo', <div />, true], 1.2],
+      ['', 'foo', <div />, '1.2'],
+
+      [true, [1.2, '', <div />, 'foo'], true, 1.2],
+      ['1.2', '', <div />, 'foo', '1.2'],
+      ['', 'foo', [true, <div />, 1.2, ''], 'foo'],
+      ['', 'foo', <div />, '1.2', '', 'foo'],
+
+      // values inside elements
+      [<div>{true}{1.2}{<div />}</div>, '', 'foo'],
+      [<div />, '', 'foo'],
+      [1.2, '', <div>{<div />}{'foo'}{true}</div>],
+      ['1.2', '', <div />],
+      ['', <div>{'foo'}{<div />}{true}</div>, 1.2],
+      ['', <div />, '1.2'],
+
+      [true, <div>{1.2}{''}{<div />}{'foo'}</div>, true, 1.2],
+      [<div />, '1.2'],
+      ['', 'foo', <div>{true}{<div />}{1.2}{''}</div>, 'foo'],
+      ['', 'foo', <div />, 'foo'],
+    ]);
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'Warning: Each child in an array or iterator should have a unique "key" prop.',
+    );
+  });
+
+  it('should throw if rendering both HTML and children', () => {
+    expect(function() {
+      ReactTestUtils.renderIntoDocument(
+        <div dangerouslySetInnerHTML={{__html: 'abcdef'}}>ghjkl</div>,
+      );
+    }).toThrow();
+  });
+
+  it('should render between nested components and inline children', () => {
+    ReactTestUtils.renderIntoDocument(<div><h1><span /><span /></h1></div>);
+
+    expect(function() {
+      ReactTestUtils.renderIntoDocument(<div><h1>A</h1></div>);
+    }).not.toThrow();
+
+    expect(function() {
+      ReactTestUtils.renderIntoDocument(<div><h1>{['A']}</h1></div>);
+    }).not.toThrow();
+
+    expect(function() {
+      ReactTestUtils.renderIntoDocument(<div><h1>{['A', 'B']}</h1></div>);
+    }).not.toThrow();
+  });
+
+  it('should reorder keyed text nodes', () => {
+    spyOn(console, 'error');
+
+    var container = document.createElement('div');
+    ReactDOM.render(
+      <div>{new Map([['a', 'alpha'], ['b', 'beta']])}</div>,
+      container,
+    );
+
+    var childNodes = container.firstChild.childNodes;
+    var alpha1 = childNodes[0];
+    var alpha2 = childNodes[1];
+    var alpha3 = childNodes[2];
+    var beta1 = childNodes[3];
+    var beta2 = childNodes[4];
+    var beta3 = childNodes[5];
+
+    ReactDOM.render(
+      <div>{new Map([['b', 'beta'], ['a', 'alpha']])}</div>,
+      container,
+    );
+
+    childNodes = container.firstChild.childNodes;
+    expect(childNodes[0]).toBe(beta1);
+    expect(childNodes[1]).toBe(beta2);
+    expect(childNodes[2]).toBe(beta3);
+    expect(childNodes[3]).toBe(alpha1);
+    expect(childNodes[4]).toBe(alpha2);
+    expect(childNodes[5]).toBe(alpha3);
+
+    // Using Maps as children gives a single warning
+    expect(console.error.calls.count()).toBe(1);
+  });
+});
diff --git a/src/renderers/shared/stack/reconciler/__tests__/ReactStatelessComponent-test.js b/src/renderers/shared/stack/reconciler/__tests__/ReactStatelessComponent-test.js
new file mode 100644
index 000000000000..e55850beda9d
--- /dev/null
+++ b/src/renderers/shared/stack/reconciler/__tests__/ReactStatelessComponent-test.js
@@ -0,0 +1,273 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var PropTypes;
+var React;
+var ReactDOM;
+var ReactTestUtils;
+
+function StatelessComponent(props) {
+  return <div>{props.name}</div>;
+}
+
+describe('ReactStatelessComponent', () => {
+  beforeEach(() => {
+    React = require('React');
+    ReactDOM = require('ReactDOM');
+    ReactTestUtils = require('ReactTestUtils');
+    PropTypes = require('prop-types');
+  });
+
+  it('should render stateless component', () => {
+    var el = document.createElement('div');
+    ReactDOM.render(<StatelessComponent name="A" />, el);
+
+    expect(el.textContent).toBe('A');
+  });
+
+  it('should update stateless component', () => {
+    class Parent extends React.Component {
+      render() {
+        return <StatelessComponent {...this.props} />;
+      }
+    }
+
+    var el = document.createElement('div');
+    ReactDOM.render(<Parent name="A" />, el);
+    expect(el.textContent).toBe('A');
+
+    ReactDOM.render(<Parent name="B" />, el);
+    expect(el.textContent).toBe('B');
+  });
+
+  it('should unmount stateless component', () => {
+    var container = document.createElement('div');
+
+    ReactDOM.render(<StatelessComponent name="A" />, container);
+    expect(container.textContent).toBe('A');
+
+    ReactDOM.unmountComponentAtNode(container);
+    expect(container.textContent).toBe('');
+  });
+
+  it('should pass context thru stateless component', () => {
+    class Child extends React.Component {
+      static contextTypes = {
+        test: PropTypes.string.isRequired,
+      };
+
+      render() {
+        return <div>{this.context.test}</div>;
+      }
+    }
+
+    function Parent() {
+      return <Child />;
+    }
+
+    class GrandParent extends React.Component {
+      static childContextTypes = {
+        test: PropTypes.string.isRequired,
+      };
+
+      getChildContext() {
+        return {test: this.props.test};
+      }
+
+      render() {
+        return <Parent />;
+      }
+    }
+
+    var el = document.createElement('div');
+    ReactDOM.render(<GrandParent test="test" />, el);
+
+    expect(el.textContent).toBe('test');
+
+    ReactDOM.render(<GrandParent test="mest" />, el);
+
+    expect(el.textContent).toBe('mest');
+  });
+
+  it('should warn for childContextTypes on a functional component', () => {
+    spyOn(console, 'error');
+    function StatelessComponentWithChildContext(props) {
+      return <div>{props.name}</div>;
+    }
+
+    StatelessComponentWithChildContext.childContextTypes = {
+      foo: PropTypes.string,
+    };
+
+    var container = document.createElement('div');
+
+    ReactDOM.render(<StatelessComponentWithChildContext name="A" />, container);
+
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'StatelessComponentWithChildContext(...): childContextTypes cannot ' +
+        'be defined on a functional component.',
+    );
+  });
+
+  it('should warn when stateless component returns array', () => {
+    spyOn(console, 'error');
+    function NotAComponent() {
+      return [<div />, <div />];
+    }
+    expect(function() {
+      ReactTestUtils.renderIntoDocument(<div><NotAComponent /></div>);
+    }).toThrow();
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'NotAComponent(...): A valid React element (or null) must be returned. ' +
+        'You may have returned undefined, an array or some other invalid object.',
+    );
+  });
+
+  it('should throw on string refs in pure functions', () => {
+    function Child() {
+      return <div ref="me" />;
+    }
+
+    expect(function() {
+      ReactTestUtils.renderIntoDocument(<Child test="test" />);
+    }).toThrowError('Stateless function components cannot have refs.');
+  });
+
+  it('should warn when given a ref', () => {
+    spyOn(console, 'error');
+
+    class Parent extends React.Component {
+      static displayName = 'Parent';
+
+      render() {
+        return <StatelessComponent name="A" ref="stateless" />;
+      }
+    }
+
+    ReactTestUtils.renderIntoDocument(<Parent />);
+
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'Stateless function components cannot be given refs ' +
+        '(See ref "stateless" in StatelessComponent created by Parent). ' +
+        'Attempts to access this ref will fail.',
+    );
+  });
+
+  it('should provide a null ref', () => {
+    function Child() {
+      return <div />;
+    }
+
+    var comp = ReactTestUtils.renderIntoDocument(<Child />);
+    expect(comp).toBe(null);
+  });
+
+  it('should use correct name in key warning', () => {
+    function Child() {
+      return <div>{[<span />]}</div>;
+    }
+
+    spyOn(console, 'error');
+    ReactTestUtils.renderIntoDocument(<Child />);
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain('a unique "key" prop');
+    expect(console.error.calls.argsFor(0)[0]).toContain('Child');
+  });
+
+  it('should support default props and prop types', () => {
+    function Child(props) {
+      return <div>{props.test}</div>;
+    }
+    Child.defaultProps = {test: 2};
+    Child.propTypes = {test: PropTypes.string};
+
+    spyOn(console, 'error');
+    ReactTestUtils.renderIntoDocument(<Child />);
+    expect(console.error.calls.count()).toBe(1);
+    expect(
+      console.error.calls.argsFor(0)[0].replace(/\(at .+?:\d+\)/g, '(at **)'),
+    ).toBe(
+      'Warning: Failed prop type: Invalid prop `test` of type `number` ' +
+        'supplied to `Child`, expected `string`.\n' +
+        '    in Child (at **)',
+    );
+  });
+
+  it('should receive context', () => {
+    class Parent extends React.Component {
+      static childContextTypes = {
+        lang: PropTypes.string,
+      };
+
+      getChildContext() {
+        return {lang: 'en'};
+      }
+
+      render() {
+        return <Child />;
+      }
+    }
+
+    function Child(props, context) {
+      return <div>{context.lang}</div>;
+    }
+    Child.contextTypes = {lang: PropTypes.string};
+
+    var el = document.createElement('div');
+    ReactDOM.render(<Parent />, el);
+    expect(el.textContent).toBe('en');
+  });
+
+  it('should work with arrow functions', () => {
+    var Child = function() {
+      return <div />;
+    };
+    // Will create a new bound function without a prototype, much like a native
+    // arrow function.
+    Child = Child.bind(this);
+
+    expect(() => ReactTestUtils.renderIntoDocument(<Child />)).not.toThrow();
+  });
+
+  it('should allow simple functions to return null', () => {
+    var Child = function() {
+      return null;
+    };
+    expect(() => ReactTestUtils.renderIntoDocument(<Child />)).not.toThrow();
+  });
+
+  it('should allow simple functions to return false', () => {
+    function Child() {
+      return false;
+    }
+    expect(() => ReactTestUtils.renderIntoDocument(<Child />)).not.toThrow();
+  });
+
+  it('should warn when using non-React functions in JSX', () => {
+    spyOn(console, 'error');
+    function NotAComponent() {
+      return [<div />, <div />];
+    }
+    expect(function() {
+      ReactTestUtils.renderIntoDocument(<div><NotAComponent /></div>);
+    }).toThrow(); // has no method 'render'
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'NotAComponent(...): A valid React element (or null) must be returned. You may ' +
+        'have returned undefined, an array or some other invalid object.',
+    );
+  });
+});
diff --git a/src/renderers/shared/stack/reconciler/__tests__/ReactUpdates-test.js b/src/renderers/shared/stack/reconciler/__tests__/ReactUpdates-test.js
new file mode 100644
index 000000000000..e676e87a2a75
--- /dev/null
+++ b/src/renderers/shared/stack/reconciler/__tests__/ReactUpdates-test.js
@@ -0,0 +1,1120 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var React;
+var ReactDOM;
+var ReactTestUtils;
+var ReactUpdates;
+
+describe('ReactUpdates', () => {
+  beforeEach(() => {
+    React = require('React');
+    ReactDOM = require('ReactDOM');
+    ReactTestUtils = require('ReactTestUtils');
+    ReactUpdates = require('ReactUpdates');
+  });
+
+  it('should batch state when updating state twice', () => {
+    var updateCount = 0;
+
+    class Component extends React.Component {
+      state = {x: 0};
+
+      componentDidUpdate() {
+        updateCount++;
+      }
+
+      render() {
+        return <div>{this.state.x}</div>;
+      }
+    }
+
+    var instance = ReactTestUtils.renderIntoDocument(<Component />);
+    expect(instance.state.x).toBe(0);
+
+    ReactUpdates.batchedUpdates(function() {
+      instance.setState({x: 1});
+      instance.setState({x: 2});
+      expect(instance.state.x).toBe(0);
+      expect(updateCount).toBe(0);
+    });
+
+    expect(instance.state.x).toBe(2);
+    expect(updateCount).toBe(1);
+  });
+
+  it('should batch state when updating two different state keys', () => {
+    var updateCount = 0;
+
+    class Component extends React.Component {
+      state = {x: 0, y: 0};
+
+      componentDidUpdate() {
+        updateCount++;
+      }
+
+      render() {
+        return <div>({this.state.x}, {this.state.y})</div>;
+      }
+    }
+
+    var instance = ReactTestUtils.renderIntoDocument(<Component />);
+    expect(instance.state.x).toBe(0);
+    expect(instance.state.y).toBe(0);
+
+    ReactUpdates.batchedUpdates(function() {
+      instance.setState({x: 1});
+      instance.setState({y: 2});
+      expect(instance.state.x).toBe(0);
+      expect(instance.state.y).toBe(0);
+      expect(updateCount).toBe(0);
+    });
+
+    expect(instance.state.x).toBe(1);
+    expect(instance.state.y).toBe(2);
+    expect(updateCount).toBe(1);
+  });
+
+  it('should batch state and props together', () => {
+    var updateCount = 0;
+
+    class Component extends React.Component {
+      state = {y: 0};
+
+      componentDidUpdate() {
+        updateCount++;
+      }
+
+      render() {
+        return <div>({this.props.x}, {this.state.y})</div>;
+      }
+    }
+
+    var container = document.createElement('div');
+    var instance = ReactDOM.render(<Component x={0} />, container);
+    expect(instance.props.x).toBe(0);
+    expect(instance.state.y).toBe(0);
+
+    ReactUpdates.batchedUpdates(function() {
+      ReactDOM.render(<Component x={1} />, container);
+      instance.setState({y: 2});
+      expect(instance.props.x).toBe(0);
+      expect(instance.state.y).toBe(0);
+      expect(updateCount).toBe(0);
+    });
+
+    expect(instance.props.x).toBe(1);
+    expect(instance.state.y).toBe(2);
+    expect(updateCount).toBe(1);
+  });
+
+  it('should batch parent/child state updates together', () => {
+    var parentUpdateCount = 0;
+
+    class Parent extends React.Component {
+      state = {x: 0};
+
+      componentDidUpdate() {
+        parentUpdateCount++;
+      }
+
+      render() {
+        return <div><Child ref="child" x={this.state.x} /></div>;
+      }
+    }
+
+    var childUpdateCount = 0;
+
+    class Child extends React.Component {
+      state = {y: 0};
+
+      componentDidUpdate() {
+        childUpdateCount++;
+      }
+
+      render() {
+        return <div>{this.props.x + this.state.y}</div>;
+      }
+    }
+
+    var instance = ReactTestUtils.renderIntoDocument(<Parent />);
+    var child = instance.refs.child;
+    expect(instance.state.x).toBe(0);
+    expect(child.state.y).toBe(0);
+
+    ReactUpdates.batchedUpdates(function() {
+      instance.setState({x: 1});
+      child.setState({y: 2});
+      expect(instance.state.x).toBe(0);
+      expect(child.state.y).toBe(0);
+      expect(parentUpdateCount).toBe(0);
+      expect(childUpdateCount).toBe(0);
+    });
+
+    expect(instance.state.x).toBe(1);
+    expect(child.state.y).toBe(2);
+    expect(parentUpdateCount).toBe(1);
+    expect(childUpdateCount).toBe(1);
+  });
+
+  it('should batch child/parent state updates together', () => {
+    var parentUpdateCount = 0;
+
+    class Parent extends React.Component {
+      state = {x: 0};
+
+      componentDidUpdate() {
+        parentUpdateCount++;
+      }
+
+      render() {
+        return <div><Child ref="child" x={this.state.x} /></div>;
+      }
+    }
+
+    var childUpdateCount = 0;
+
+    class Child extends React.Component {
+      state = {y: 0};
+
+      componentDidUpdate() {
+        childUpdateCount++;
+      }
+
+      render() {
+        return <div>{this.props.x + this.state.y}</div>;
+      }
+    }
+
+    var instance = ReactTestUtils.renderIntoDocument(<Parent />);
+    var child = instance.refs.child;
+    expect(instance.state.x).toBe(0);
+    expect(child.state.y).toBe(0);
+
+    ReactUpdates.batchedUpdates(function() {
+      child.setState({y: 2});
+      instance.setState({x: 1});
+      expect(instance.state.x).toBe(0);
+      expect(child.state.y).toBe(0);
+      expect(parentUpdateCount).toBe(0);
+      expect(childUpdateCount).toBe(0);
+    });
+
+    expect(instance.state.x).toBe(1);
+    expect(child.state.y).toBe(2);
+    expect(parentUpdateCount).toBe(1);
+
+    // Batching reduces the number of updates here to 1.
+    expect(childUpdateCount).toBe(1);
+  });
+
+  it('should support chained state updates', () => {
+    var updateCount = 0;
+
+    class Component extends React.Component {
+      state = {x: 0};
+
+      componentDidUpdate() {
+        updateCount++;
+      }
+
+      render() {
+        return <div>{this.state.x}</div>;
+      }
+    }
+
+    var instance = ReactTestUtils.renderIntoDocument(<Component />);
+    expect(instance.state.x).toBe(0);
+
+    var innerCallbackRun = false;
+    ReactUpdates.batchedUpdates(function() {
+      instance.setState({x: 1}, function() {
+        instance.setState({x: 2}, function() {
+          expect(this).toBe(instance);
+          innerCallbackRun = true;
+          expect(instance.state.x).toBe(2);
+          expect(updateCount).toBe(2);
+        });
+        expect(instance.state.x).toBe(1);
+        expect(updateCount).toBe(1);
+      });
+      expect(instance.state.x).toBe(0);
+      expect(updateCount).toBe(0);
+    });
+
+    expect(innerCallbackRun).toBeTruthy();
+    expect(instance.state.x).toBe(2);
+    expect(updateCount).toBe(2);
+  });
+
+  it('should batch forceUpdate together', () => {
+    var shouldUpdateCount = 0;
+    var updateCount = 0;
+
+    class Component extends React.Component {
+      state = {x: 0};
+
+      shouldComponentUpdate() {
+        shouldUpdateCount++;
+      }
+
+      componentDidUpdate() {
+        updateCount++;
+      }
+
+      render() {
+        return <div>{this.state.x}</div>;
+      }
+    }
+
+    var instance = ReactTestUtils.renderIntoDocument(<Component />);
+    expect(instance.state.x).toBe(0);
+
+    var callbacksRun = 0;
+    ReactUpdates.batchedUpdates(function() {
+      instance.setState({x: 1}, function() {
+        callbacksRun++;
+      });
+      instance.forceUpdate(function() {
+        callbacksRun++;
+      });
+      expect(instance.state.x).toBe(0);
+      expect(updateCount).toBe(0);
+    });
+
+    expect(callbacksRun).toBe(2);
+    // shouldComponentUpdate shouldn't be called since we're forcing
+    expect(shouldUpdateCount).toBe(0);
+    expect(instance.state.x).toBe(1);
+    expect(updateCount).toBe(1);
+  });
+
+  it('should update children even if parent blocks updates', () => {
+    var parentRenderCount = 0;
+    var childRenderCount = 0;
+
+    class Parent extends React.Component {
+      shouldComponentUpdate() {
+        return false;
+      }
+
+      render() {
+        parentRenderCount++;
+        return <Child ref="child" />;
+      }
+    }
+
+    class Child extends React.Component {
+      render() {
+        childRenderCount++;
+        return <div />;
+      }
+    }
+
+    expect(parentRenderCount).toBe(0);
+    expect(childRenderCount).toBe(0);
+
+    var instance = <Parent />;
+    instance = ReactTestUtils.renderIntoDocument(instance);
+
+    expect(parentRenderCount).toBe(1);
+    expect(childRenderCount).toBe(1);
+
+    ReactUpdates.batchedUpdates(function() {
+      instance.setState({x: 1});
+    });
+
+    expect(parentRenderCount).toBe(1);
+    expect(childRenderCount).toBe(1);
+
+    ReactUpdates.batchedUpdates(function() {
+      instance.refs.child.setState({x: 1});
+    });
+
+    expect(parentRenderCount).toBe(1);
+    expect(childRenderCount).toBe(2);
+  });
+
+  it('should not reconcile children passed via props', () => {
+    var numMiddleRenders = 0;
+    var numBottomRenders = 0;
+
+    class Top extends React.Component {
+      render() {
+        return <Middle><Bottom /></Middle>;
+      }
+    }
+
+    class Middle extends React.Component {
+      componentDidMount() {
+        this.forceUpdate();
+      }
+
+      render() {
+        numMiddleRenders++;
+        return React.Children.only(this.props.children);
+      }
+    }
+
+    class Bottom extends React.Component {
+      render() {
+        numBottomRenders++;
+        return null;
+      }
+    }
+
+    ReactTestUtils.renderIntoDocument(<Top />);
+    expect(numMiddleRenders).toBe(2);
+    expect(numBottomRenders).toBe(1);
+  });
+
+  it('should flow updates correctly', () => {
+    var willUpdates = [];
+    var didUpdates = [];
+
+    var UpdateLoggingMixin = {
+      componentWillUpdate: function() {
+        willUpdates.push(this.constructor.displayName);
+      },
+      componentDidUpdate: function() {
+        didUpdates.push(this.constructor.displayName);
+      },
+    };
+
+    class Box extends React.Component {
+      render() {
+        return <div ref="boxDiv">{this.props.children}</div>;
+      }
+    }
+    Object.assign(Box.prototype, UpdateLoggingMixin);
+
+    class Child extends React.Component {
+      render() {
+        return <span ref="span">child</span>;
+      }
+    }
+    Object.assign(Child.prototype, UpdateLoggingMixin);
+
+    class Switcher extends React.Component {
+      state = {tabKey: 'hello'};
+      render() {
+        var child = this.props.children;
+
+        return (
+          <Box ref="box">
+            <div
+              ref="switcherDiv"
+              style={{
+                display: this.state.tabKey === child.key ? '' : 'none',
+              }}>
+              {child}
+            </div>
+          </Box>
+        );
+      }
+    }
+    Object.assign(Switcher.prototype, UpdateLoggingMixin);
+
+    class App extends React.Component {
+      render() {
+        return (
+          <Switcher ref="switcher">
+            <Child key="hello" ref="child" />
+          </Switcher>
+        );
+      }
+    }
+    Object.assign(App.prototype, UpdateLoggingMixin);
+
+    var root = <App />;
+    root = ReactTestUtils.renderIntoDocument(root);
+
+    function expectUpdates(desiredWillUpdates, desiredDidUpdates) {
+      var i;
+      for (i = 0; i < desiredWillUpdates; i++) {
+        expect(willUpdates).toContain(desiredWillUpdates[i]);
+      }
+      for (i = 0; i < desiredDidUpdates; i++) {
+        expect(didUpdates).toContain(desiredDidUpdates[i]);
+      }
+      willUpdates = [];
+      didUpdates = [];
+    }
+
+    function triggerUpdate(c) {
+      c.setState({x: 1});
+    }
+
+    function testUpdates(components, desiredWillUpdates, desiredDidUpdates) {
+      var i;
+
+      ReactUpdates.batchedUpdates(function() {
+        for (i = 0; i < components.length; i++) {
+          triggerUpdate(components[i]);
+        }
+      });
+
+      expectUpdates(desiredWillUpdates, desiredDidUpdates);
+
+      // Try them in reverse order
+
+      ReactUpdates.batchedUpdates(function() {
+        for (i = components.length - 1; i >= 0; i--) {
+          triggerUpdate(components[i]);
+        }
+      });
+
+      expectUpdates(desiredWillUpdates, desiredDidUpdates);
+    }
+    testUpdates(
+      [root.refs.switcher.refs.box, root.refs.switcher],
+      // Owner-child relationships have inverse will and did
+      ['Switcher', 'Box'],
+      ['Box', 'Switcher'],
+    );
+
+    testUpdates(
+      [root.refs.child, root.refs.switcher.refs.box],
+      // Not owner-child so reconcile independently
+      ['Box', 'Child'],
+      ['Box', 'Child'],
+    );
+
+    testUpdates(
+      [root.refs.child, root.refs.switcher],
+      // Switcher owns Box and Child, Box does not own Child
+      ['Switcher', 'Box', 'Child'],
+      ['Box', 'Switcher', 'Child'],
+    );
+  });
+
+  it('should share reconcile transaction across different roots', () => {
+    var ReconcileTransaction = ReactUpdates.ReactReconcileTransaction;
+    spyOn(ReconcileTransaction, 'getPooled').and.callThrough();
+
+    class Component extends React.Component {
+      render() {
+        return <div>{this.props.text}</div>;
+      }
+    }
+
+    var containerA = document.createElement('div');
+    var containerB = document.createElement('div');
+
+    // Initial renders aren't batched together yet...
+    ReactUpdates.batchedUpdates(function() {
+      ReactDOM.render(<Component text="A1" />, containerA);
+      ReactDOM.render(<Component text="B1" />, containerB);
+    });
+    expect(ReconcileTransaction.getPooled.calls.count()).toBe(2);
+
+    // ...but updates are! Here only one more transaction is used, which means
+    // we only have to initialize and close the wrappers once.
+    ReactUpdates.batchedUpdates(function() {
+      ReactDOM.render(<Component text="A2" />, containerA);
+      ReactDOM.render(<Component text="B2" />, containerB);
+    });
+    expect(ReconcileTransaction.getPooled.calls.count()).toBe(3);
+  });
+
+  it('should queue mount-ready handlers across different roots', () => {
+    // We'll define two components A and B, then update both of them. When A's
+    // componentDidUpdate handlers is called, B's DOM should already have been
+    // updated.
+
+    var a;
+    var b;
+
+    var aUpdated = false;
+
+    class A extends React.Component {
+      state = {x: 0};
+
+      componentDidUpdate() {
+        expect(ReactDOM.findDOMNode(b).textContent).toBe('B1');
+        aUpdated = true;
+      }
+
+      render() {
+        return <div>A{this.state.x}</div>;
+      }
+    }
+
+    class B extends React.Component {
+      state = {x: 0};
+
+      render() {
+        return <div>B{this.state.x}</div>;
+      }
+    }
+
+    a = ReactTestUtils.renderIntoDocument(<A />);
+    b = ReactTestUtils.renderIntoDocument(<B />);
+
+    ReactUpdates.batchedUpdates(function() {
+      a.setState({x: 1});
+      b.setState({x: 1});
+    });
+
+    expect(aUpdated).toBe(true);
+  });
+
+  it('should flush updates in the correct order', () => {
+    var updates = [];
+
+    class Outer extends React.Component {
+      state = {x: 0};
+
+      render() {
+        updates.push('Outer-render-' + this.state.x);
+        return <div><Inner x={this.state.x} ref="inner" /></div>;
+      }
+
+      componentDidUpdate() {
+        var x = this.state.x;
+        updates.push('Outer-didUpdate-' + x);
+        updates.push('Inner-setState-' + x);
+        this.refs.inner.setState({x: x}, function() {
+          updates.push('Inner-callback-' + x);
+        });
+      }
+    }
+
+    class Inner extends React.Component {
+      state = {x: 0};
+
+      render() {
+        updates.push('Inner-render-' + this.props.x + '-' + this.state.x);
+        return <div />;
+      }
+
+      componentDidUpdate() {
+        updates.push('Inner-didUpdate-' + this.props.x + '-' + this.state.x);
+      }
+    }
+
+    var instance = ReactTestUtils.renderIntoDocument(<Outer />);
+
+    updates.push('Outer-setState-1');
+    instance.setState({x: 1}, function() {
+      updates.push('Outer-callback-1');
+      updates.push('Outer-setState-2');
+      instance.setState({x: 2}, function() {
+        updates.push('Outer-callback-2');
+      });
+    });
+
+    /* eslint-disable indent */
+    expect(updates).toEqual([
+      'Outer-render-0',
+      'Inner-render-0-0',
+
+      'Outer-setState-1',
+      'Outer-render-1',
+      'Inner-render-1-0',
+      'Inner-didUpdate-1-0',
+      'Outer-didUpdate-1',
+      'Inner-setState-1',
+      'Inner-render-1-1',
+      'Inner-didUpdate-1-1',
+      'Inner-callback-1',
+      'Outer-callback-1',
+
+      'Outer-setState-2',
+      'Outer-render-2',
+      'Inner-render-2-1',
+      'Inner-didUpdate-2-1',
+      'Outer-didUpdate-2',
+      'Inner-setState-2',
+      'Inner-render-2-2',
+      'Inner-didUpdate-2-2',
+      'Inner-callback-2',
+      'Outer-callback-2',
+    ]);
+    /* eslint-enable indent */
+  });
+
+  it('should flush updates in the correct order across roots', () => {
+    var instances = [];
+    var updates = [];
+
+    class MockComponent extends React.Component {
+      render() {
+        updates.push(this.props.depth);
+        return <div />;
+      }
+
+      componentDidMount() {
+        instances.push(this);
+        if (this.props.depth < this.props.count) {
+          ReactDOM.render(
+            <MockComponent
+              depth={this.props.depth + 1}
+              count={this.props.count}
+            />,
+            ReactDOM.findDOMNode(this),
+          );
+        }
+      }
+    }
+
+    ReactTestUtils.renderIntoDocument(<MockComponent depth={0} count={2} />);
+
+    expect(updates).toEqual([0, 1, 2]);
+
+    ReactUpdates.batchedUpdates(function() {
+      // Simulate update on each component from top to bottom.
+      instances.forEach(function(instance) {
+        instance.forceUpdate();
+      });
+    });
+
+    expect(updates).toEqual([0, 1, 2, 0, 1, 2]);
+  });
+
+  it('should queue nested updates', () => {
+    // See https://github.com/facebook/react/issues/1147
+
+    class X extends React.Component {
+      state = {s: 0};
+
+      render() {
+        if (this.state.s === 0) {
+          return (
+            <div>
+              <span>0</span>
+            </div>
+          );
+        } else {
+          return <div>1</div>;
+        }
+      }
+
+      go = () => {
+        this.setState({s: 1});
+        this.setState({s: 0});
+        this.setState({s: 1});
+      };
+    }
+
+    class Y extends React.Component {
+      render() {
+        return (
+          <div>
+            <Z />
+          </div>
+        );
+      }
+    }
+
+    class Z extends React.Component {
+      render() {
+        return <div />;
+      }
+
+      componentWillUpdate() {
+        x.go();
+      }
+    }
+
+    var x;
+    var y;
+
+    x = ReactTestUtils.renderIntoDocument(<X />);
+    y = ReactTestUtils.renderIntoDocument(<Y />);
+    expect(ReactDOM.findDOMNode(x).textContent).toBe('0');
+
+    y.forceUpdate();
+    expect(ReactDOM.findDOMNode(x).textContent).toBe('1');
+  });
+
+  it('should queue updates from during mount', () => {
+    // See https://github.com/facebook/react/issues/1353
+    var a;
+
+    class A extends React.Component {
+      state = {x: 0};
+
+      componentWillMount() {
+        a = this;
+      }
+
+      render() {
+        return <div>A{this.state.x}</div>;
+      }
+    }
+
+    class B extends React.Component {
+      componentWillMount() {
+        a.setState({x: 1});
+      }
+
+      render() {
+        return <div />;
+      }
+    }
+
+    ReactUpdates.batchedUpdates(function() {
+      ReactTestUtils.renderIntoDocument(
+        <div>
+          <A />
+          <B />
+        </div>,
+      );
+    });
+
+    expect(a.state.x).toBe(1);
+    expect(ReactDOM.findDOMNode(a).textContent).toBe('A1');
+  });
+
+  it('calls componentWillReceiveProps setState callback properly', () => {
+    var callbackCount = 0;
+
+    class A extends React.Component {
+      state = {x: this.props.x};
+
+      componentWillReceiveProps(nextProps) {
+        var newX = nextProps.x;
+        this.setState({x: newX}, function() {
+          // State should have updated by the time this callback gets called
+          expect(this.state.x).toBe(newX);
+          callbackCount++;
+        });
+      }
+
+      render() {
+        return <div>{this.state.x}</div>;
+      }
+    }
+
+    var container = document.createElement('div');
+    ReactDOM.render(<A x={1} />, container);
+    ReactDOM.render(<A x={2} />, container);
+    expect(callbackCount).toBe(1);
+  });
+
+  it('calls asap callbacks properly', () => {
+    var callbackCount = 0;
+
+    class A extends React.Component {
+      render() {
+        return <div />;
+      }
+
+      componentDidUpdate() {
+        ReactUpdates.asap(function() {
+          expect(this).toBe(component);
+          callbackCount++;
+          ReactUpdates.asap(function() {
+            callbackCount++;
+          });
+          expect(callbackCount).toBe(1);
+        }, component);
+        expect(callbackCount).toBe(0);
+      }
+    }
+
+    var component = ReactTestUtils.renderIntoDocument(<A />);
+    component.forceUpdate();
+    expect(callbackCount).toBe(2);
+  });
+
+  it('calls asap callbacks with queued updates', () => {
+    var log = [];
+
+    class A extends React.Component {
+      state = {updates: 0};
+
+      render() {
+        log.push('render-' + this.state.updates);
+        return <div />;
+      }
+
+      componentDidUpdate() {
+        if (this.state.updates === 1) {
+          ReactUpdates.asap(function() {
+            this.setState({updates: 2}, function() {
+              ReactUpdates.asap(function() {
+                log.push('asap-1.2');
+              });
+              log.push('setState-cb');
+            });
+            log.push('asap-1.1');
+          }, this);
+        } else if (this.state.updates === 2) {
+          ReactUpdates.asap(function() {
+            log.push('asap-2');
+          });
+        }
+        log.push('didUpdate-' + this.state.updates);
+      }
+    }
+
+    var component = ReactTestUtils.renderIntoDocument(<A />);
+    component.setState({updates: 1});
+    expect(log).toEqual([
+      'render-0',
+      // We do the first update...
+      'render-1',
+      'didUpdate-1',
+      // ...which calls asap and enqueues a second update...
+      'asap-1.1',
+      // ...which runs and enqueues the asap-2 log in its didUpdate...
+      'render-2',
+      'didUpdate-2',
+      // ...and runs the setState callback, which enqueues the log for
+      // asap-1.2.
+      'setState-cb',
+      'asap-2',
+      'asap-1.2',
+    ]);
+  });
+
+  it('does not call render after a component as been deleted', () => {
+    var renderCount = 0;
+    var componentB = null;
+
+    class B extends React.Component {
+      state = {updates: 0};
+
+      componentDidMount() {
+        componentB = this;
+      }
+
+      render() {
+        renderCount++;
+        return <div />;
+      }
+    }
+
+    class A extends React.Component {
+      state = {showB: true};
+
+      render() {
+        return this.state.showB ? <B /> : <div />;
+      }
+    }
+
+    var component = ReactTestUtils.renderIntoDocument(<A />);
+
+    ReactUpdates.batchedUpdates(function() {
+      // B will have scheduled an update but the batching should ensure that its
+      // update never fires.
+      componentB.setState({updates: 1});
+      component.setState({showB: false});
+    });
+
+    expect(renderCount).toBe(1);
+  });
+
+  it('marks top-level updates', () => {
+    var ReactFeatureFlags = require('ReactFeatureFlags');
+
+    class Foo extends React.Component {
+      render() {
+        return <Bar />;
+      }
+    }
+
+    class Bar extends React.Component {
+      render() {
+        return <div />;
+      }
+    }
+
+    var container = document.createElement('div');
+    ReactDOM.render(<Foo />, container);
+
+    try {
+      ReactFeatureFlags.logTopLevelRenders = true;
+      spyOn(console, 'time');
+      spyOn(console, 'timeEnd');
+
+      ReactDOM.render(<Foo />, container);
+
+      expect(console.time.calls.count()).toBe(1);
+      expect(console.time.calls.argsFor(0)[0]).toBe('React update: Foo');
+      expect(console.timeEnd.calls.count()).toBe(1);
+      expect(console.timeEnd.calls.argsFor(0)[0]).toBe('React update: Foo');
+    } finally {
+      ReactFeatureFlags.logTopLevelRenders = false;
+    }
+  });
+
+  it('throws in setState if the update callback is not a function', () => {
+    function Foo() {
+      this.a = 1;
+      this.b = 2;
+    }
+
+    class A extends React.Component {
+      state = {};
+
+      render() {
+        return <div />;
+      }
+    }
+
+    var component = ReactTestUtils.renderIntoDocument(<A />);
+
+    expect(() => component.setState({}, 'no')).toThrowError(
+      'setState(...): Expected the last optional `callback` argument ' +
+        'to be a function. Instead received: string.',
+    );
+    expect(() => component.setState({}, {})).toThrowError(
+      'setState(...): Expected the last optional `callback` argument ' +
+        'to be a function. Instead received: Object.',
+    );
+    expect(() => component.setState({}, new Foo())).toThrowError(
+      'setState(...): Expected the last optional `callback` argument ' +
+        'to be a function. Instead received: Foo (keys: a, b).',
+    );
+  });
+
+  it('throws in forceUpdate if the update callback is not a function', () => {
+    function Foo() {
+      this.a = 1;
+      this.b = 2;
+    }
+
+    class A extends React.Component {
+      state = {};
+
+      render() {
+        return <div />;
+      }
+    }
+
+    var component = ReactTestUtils.renderIntoDocument(<A />);
+
+    expect(() => component.forceUpdate('no')).toThrowError(
+      'forceUpdate(...): Expected the last optional `callback` argument ' +
+        'to be a function. Instead received: string.',
+    );
+    expect(() => component.forceUpdate({})).toThrowError(
+      'forceUpdate(...): Expected the last optional `callback` argument ' +
+        'to be a function. Instead received: Object.',
+    );
+    expect(() => component.forceUpdate(new Foo())).toThrowError(
+      'forceUpdate(...): Expected the last optional `callback` argument ' +
+        'to be a function. Instead received: Foo (keys: a, b).',
+    );
+  });
+
+  it('does not update one component twice in a batch (#2410)', () => {
+    class Parent extends React.Component {
+      getChild = () => {
+        return this.refs.child;
+      };
+
+      render() {
+        return <Child ref="child" />;
+      }
+    }
+
+    var renderCount = 0;
+    var postRenderCount = 0;
+    var once = false;
+
+    class Child extends React.Component {
+      state = {updated: false};
+
+      componentWillUpdate() {
+        if (!once) {
+          once = true;
+          this.setState({updated: true});
+        }
+      }
+
+      componentDidMount() {
+        expect(renderCount).toBe(postRenderCount + 1);
+        postRenderCount++;
+      }
+
+      componentDidUpdate() {
+        expect(renderCount).toBe(postRenderCount + 1);
+        postRenderCount++;
+      }
+
+      render() {
+        expect(renderCount).toBe(postRenderCount);
+        renderCount++;
+        return <div />;
+      }
+    }
+
+    var parent = ReactTestUtils.renderIntoDocument(<Parent />);
+    var child = parent.getChild();
+    ReactDOM.unstable_batchedUpdates(function() {
+      parent.forceUpdate();
+      child.forceUpdate();
+    });
+  });
+
+  it('does not update one component twice in a batch (#6371)', () => {
+    var callbacks = [];
+    function emitChange() {
+      callbacks.forEach(c => c());
+    }
+
+    class App extends React.Component {
+      constructor(props) {
+        super(props);
+        this.state = {showChild: true};
+      }
+      componentDidMount() {
+        this.setState({showChild: false});
+      }
+      render() {
+        return (
+          <div>
+            <ForceUpdatesOnChange />
+            {this.state.showChild && <EmitsChangeOnUnmount />}
+          </div>
+        );
+      }
+    }
+
+    class EmitsChangeOnUnmount extends React.Component {
+      componentWillUnmount() {
+        emitChange();
+      }
+      render() {
+        return null;
+      }
+    }
+
+    class ForceUpdatesOnChange extends React.Component {
+      componentDidMount() {
+        this.onChange = () => this.forceUpdate();
+        this.onChange();
+        callbacks.push(this.onChange);
+      }
+      componentWillUnmount() {
+        callbacks = callbacks.filter(c => c !== this.onChange);
+      }
+      render() {
+        return <div key={Math.random()} onClick={function() {}} />;
+      }
+    }
+
+    ReactDOM.render(<App />, document.createElement('div'));
+  });
+
+  it('unstable_batchedUpdates should return value from a callback', () => {
+    var result = ReactDOM.unstable_batchedUpdates(function() {
+      return 42;
+    });
+    expect(result).toEqual(42);
+  });
+});
diff --git a/src/renderers/shared/stack/reconciler/__tests__/refs-destruction-test.js b/src/renderers/shared/stack/reconciler/__tests__/refs-destruction-test.js
new file mode 100644
index 000000000000..44df2d61bc72
--- /dev/null
+++ b/src/renderers/shared/stack/reconciler/__tests__/refs-destruction-test.js
@@ -0,0 +1,114 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var React;
+var ReactDOM;
+var ReactTestUtils;
+
+var TestComponent;
+
+describe('refs-destruction', () => {
+  beforeEach(() => {
+    jest.resetModuleRegistry();
+
+    React = require('React');
+    ReactDOM = require('ReactDOM');
+    ReactTestUtils = require('ReactTestUtils');
+
+    TestComponent = class extends React.Component {
+      render() {
+        return (
+          <div>
+            {this.props.destroy
+              ? null
+              : <div ref="theInnerDiv">
+                  Lets try to destroy this.
+                </div>}
+          </div>
+        );
+      }
+    };
+  });
+
+  it('should remove refs when destroying the parent', () => {
+    var container = document.createElement('div');
+    var testInstance = ReactDOM.render(<TestComponent />, container);
+    expect(ReactTestUtils.isDOMComponent(testInstance.refs.theInnerDiv)).toBe(
+      true,
+    );
+    expect(Object.keys(testInstance.refs || {}).length).toEqual(1);
+    ReactDOM.unmountComponentAtNode(container);
+    expect(Object.keys(testInstance.refs || {}).length).toEqual(0);
+  });
+
+  it('should remove refs when destroying the child', () => {
+    var container = document.createElement('div');
+    var testInstance = ReactDOM.render(<TestComponent />, container);
+    expect(ReactTestUtils.isDOMComponent(testInstance.refs.theInnerDiv)).toBe(
+      true,
+    );
+    expect(Object.keys(testInstance.refs || {}).length).toEqual(1);
+    ReactDOM.render(<TestComponent destroy={true} />, container);
+    expect(Object.keys(testInstance.refs || {}).length).toEqual(0);
+  });
+
+  it('should not error when destroying child with ref asynchronously', () => {
+    class Modal extends React.Component {
+      componentDidMount() {
+        this.div = document.createElement('div');
+        document.body.appendChild(this.div);
+        this.componentDidUpdate();
+      }
+
+      componentDidUpdate() {
+        ReactDOM.render(<div>{this.props.children}</div>, this.div);
+      }
+
+      componentWillUnmount() {
+        var self = this;
+        // some async animation
+        setTimeout(function() {
+          expect(function() {
+            ReactDOM.unmountComponentAtNode(self.div);
+          }).not.toThrow();
+          document.body.removeChild(self.div);
+        }, 0);
+      }
+
+      render() {
+        return null;
+      }
+    }
+
+    class AppModal extends React.Component {
+      render() {
+        return (
+          <Modal>
+            <a ref="ref" />
+          </Modal>
+        );
+      }
+    }
+
+    class App extends React.Component {
+      render() {
+        return this.props.hidden ? null : <AppModal onClose={this.close} />;
+      }
+    }
+
+    var container = document.createElement('div');
+    ReactDOM.render(<App />, container);
+    ReactDOM.render(<App hidden={true} />, container);
+    jest.runAllTimers();
+  });
+});
diff --git a/src/renderers/shared/stack/reconciler/__tests__/refs-test.js b/src/renderers/shared/stack/reconciler/__tests__/refs-test.js
new file mode 100644
index 000000000000..b7b835bfc757
--- /dev/null
+++ b/src/renderers/shared/stack/reconciler/__tests__/refs-test.js
@@ -0,0 +1,285 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var React = require('React');
+var ReactTestUtils = require('ReactTestUtils');
+
+var reactComponentExpect = require('reactComponentExpect');
+
+/**
+ * Counts clicks and has a renders an item for each click. Each item rendered
+ * has a ref of the form "clickLogN".
+ */
+class ClickCounter extends React.Component {
+  state = {count: this.props.initialCount};
+
+  triggerReset = () => {
+    this.setState({count: this.props.initialCount});
+  };
+
+  handleClick = () => {
+    this.setState({count: this.state.count + 1});
+  };
+
+  render() {
+    var children = [];
+    var i;
+    for (i = 0; i < this.state.count; i++) {
+      children.push(
+        <div
+          className="clickLogDiv"
+          key={'clickLog' + i}
+          ref={'clickLog' + i}
+        />,
+      );
+    }
+    return (
+      <span className="clickIncrementer" onClick={this.handleClick}>
+        {children}
+      </span>
+    );
+  }
+}
+
+/**
+ * Only purpose is to test that refs are tracked even when applied to a
+ * component that is injected down several layers. Ref systems are difficult to
+ * build in such a way that ownership is maintained in an airtight manner.
+ */
+class GeneralContainerComponent extends React.Component {
+  render() {
+    return <div>{this.props.children}</div>;
+  }
+}
+
+/**
+ * Notice how refs ownership is maintained even when injecting a component
+ * into a different parent.
+ */
+class TestRefsComponent extends React.Component {
+  doReset = () => {
+    this.refs.myCounter.triggerReset();
+  };
+
+  render() {
+    return (
+      <div>
+        <div ref="resetDiv" onClick={this.doReset}>
+          Reset Me By Clicking This.
+        </div>
+        <GeneralContainerComponent ref="myContainer">
+          <ClickCounter ref="myCounter" initialCount={1} />
+        </GeneralContainerComponent>
+      </div>
+    );
+  }
+}
+
+/**
+ * Render a TestRefsComponent and ensure that the main refs are wired up.
+ */
+var renderTestRefsComponent = function() {
+  var testRefsComponent = ReactTestUtils.renderIntoDocument(
+    <TestRefsComponent />,
+  );
+
+  reactComponentExpect(testRefsComponent).toBeCompositeComponentWithType(
+    TestRefsComponent,
+  );
+
+  var generalContainer = testRefsComponent.refs.myContainer;
+  var counter = testRefsComponent.refs.myCounter;
+
+  reactComponentExpect(generalContainer).toBeCompositeComponentWithType(
+    GeneralContainerComponent,
+  );
+  reactComponentExpect(counter).toBeCompositeComponentWithType(ClickCounter);
+
+  return testRefsComponent;
+};
+
+var expectClickLogsLengthToBe = function(instance, length) {
+  var clickLogs = ReactTestUtils.scryRenderedDOMComponentsWithClass(
+    instance,
+    'clickLogDiv',
+  );
+  expect(clickLogs.length).toBe(length);
+  expect(Object.keys(instance.refs.myCounter.refs).length).toBe(length);
+};
+
+describe('reactiverefs', () => {
+  beforeEach(() => {
+    jest.resetModuleRegistry();
+  });
+
+  /**
+   * Ensure that for every click log there is a corresponding ref (from the
+   * perspective of the injected ClickCounter component.
+   */
+  it('Should increase refs with an increase in divs', () => {
+    var testRefsComponent = renderTestRefsComponent();
+    var clickIncrementer = ReactTestUtils.findRenderedDOMComponentWithClass(
+      testRefsComponent,
+      'clickIncrementer',
+    );
+
+    expectClickLogsLengthToBe(testRefsComponent, 1);
+
+    // After clicking the reset, there should still only be one click log ref.
+    ReactTestUtils.Simulate.click(testRefsComponent.refs.resetDiv);
+    expectClickLogsLengthToBe(testRefsComponent, 1);
+
+    // Begin incrementing clicks (and therefore refs).
+    ReactTestUtils.Simulate.click(clickIncrementer);
+    expectClickLogsLengthToBe(testRefsComponent, 2);
+
+    ReactTestUtils.Simulate.click(clickIncrementer);
+    expectClickLogsLengthToBe(testRefsComponent, 3);
+
+    // Now reset again
+    ReactTestUtils.Simulate.click(testRefsComponent.refs.resetDiv);
+    expectClickLogsLengthToBe(testRefsComponent, 1);
+  });
+});
+
+/**
+ * Tests that when a ref hops around children, we can track that correctly.
+ */
+describe('ref swapping', () => {
+  beforeEach(() => {
+    jest.resetModuleRegistry();
+  });
+
+  class RefHopsAround extends React.Component {
+    state = {count: 0};
+
+    moveRef = () => {
+      this.setState({count: this.state.count + 1});
+    };
+
+    render() {
+      var count = this.state.count;
+      /**
+       * What we have here, is three divs with refs (div1/2/3), but a single
+       * moving cursor ref `hopRef` that "hops" around the three. We'll call the
+       * `moveRef()` function several times and make sure that the hop ref
+       * points to the correct divs.
+       */
+      return (
+        <div>
+          <div
+            className="first"
+            ref={count % 3 === 0 ? 'hopRef' : 'divOneRef'}
+          />
+          <div
+            className="second"
+            ref={count % 3 === 1 ? 'hopRef' : 'divTwoRef'}
+          />
+          <div
+            className="third"
+            ref={count % 3 === 2 ? 'hopRef' : 'divThreeRef'}
+          />
+        </div>
+      );
+    }
+  }
+
+  it('Allow refs to hop around children correctly', () => {
+    var refHopsAround = ReactTestUtils.renderIntoDocument(<RefHopsAround />);
+
+    var firstDiv = ReactTestUtils.findRenderedDOMComponentWithClass(
+      refHopsAround,
+      'first',
+    );
+    var secondDiv = ReactTestUtils.findRenderedDOMComponentWithClass(
+      refHopsAround,
+      'second',
+    );
+    var thirdDiv = ReactTestUtils.findRenderedDOMComponentWithClass(
+      refHopsAround,
+      'third',
+    );
+
+    expect(refHopsAround.refs.hopRef).toEqual(firstDiv);
+    expect(refHopsAround.refs.divTwoRef).toEqual(secondDiv);
+    expect(refHopsAround.refs.divThreeRef).toEqual(thirdDiv);
+
+    refHopsAround.moveRef();
+    expect(refHopsAround.refs.divOneRef).toEqual(firstDiv);
+    expect(refHopsAround.refs.hopRef).toEqual(secondDiv);
+    expect(refHopsAround.refs.divThreeRef).toEqual(thirdDiv);
+
+    refHopsAround.moveRef();
+    expect(refHopsAround.refs.divOneRef).toEqual(firstDiv);
+    expect(refHopsAround.refs.divTwoRef).toEqual(secondDiv);
+    expect(refHopsAround.refs.hopRef).toEqual(thirdDiv);
+
+    /**
+     * Make sure that after the third, we're back to where we started and the
+     * refs are completely restored.
+     */
+    refHopsAround.moveRef();
+    expect(refHopsAround.refs.hopRef).toEqual(firstDiv);
+    expect(refHopsAround.refs.divTwoRef).toEqual(secondDiv);
+    expect(refHopsAround.refs.divThreeRef).toEqual(thirdDiv);
+  });
+
+  it('always has a value for this.refs', () => {
+    class Component extends React.Component {
+      render() {
+        return <div />;
+      }
+    }
+
+    var instance = ReactTestUtils.renderIntoDocument(<Component />);
+    expect(!!instance.refs).toBe(true);
+  });
+
+  function testRefCall() {
+    var refCalled = 0;
+    function Inner(props) {
+      return <a ref={props.saveA} />;
+    }
+
+    class Outer extends React.Component {
+      saveA = () => {
+        refCalled++;
+      };
+
+      componentDidMount() {
+        this.setState({});
+      }
+
+      render() {
+        return <Inner saveA={this.saveA} />;
+      }
+    }
+
+    ReactTestUtils.renderIntoDocument(<Outer />);
+    expect(refCalled).toBe(1);
+  }
+
+  it('ref called correctly for stateless component when __DEV__ = false', () => {
+    var originalDev = __DEV__;
+    __DEV__ = false;
+    testRefCall();
+    __DEV__ = originalDev;
+  });
+
+  it('ref called correctly for stateless component when __DEV__ = true', () => {
+    var originalDev = __DEV__;
+    __DEV__ = true;
+    testRefCall();
+    __DEV__ = originalDev;
+  });
+});
diff --git a/src/renderers/shared/stack/reconciler/getHostComponentFromComposite.js b/src/renderers/shared/stack/reconciler/getHostComponentFromComposite.js
new file mode 100644
index 000000000000..597caa50be80
--- /dev/null
+++ b/src/renderers/shared/stack/reconciler/getHostComponentFromComposite.js
@@ -0,0 +1,30 @@
+/**
+ * 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 getHostComponentFromComposite
+ */
+
+'use strict';
+
+var ReactNodeTypes = require('ReactNodeTypes');
+
+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;
diff --git a/src/renderers/shared/stack/reconciler/instantiateReactComponent.js b/src/renderers/shared/stack/reconciler/instantiateReactComponent.js
new file mode 100644
index 000000000000..08484b27ccc0
--- /dev/null
+++ b/src/renderers/shared/stack/reconciler/instantiateReactComponent.js
@@ -0,0 +1,154 @@
+/**
+ * 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 instantiateReactComponent
+ */
+
+'use strict';
+
+var ReactCompositeComponent = require('ReactCompositeComponent');
+var ReactEmptyComponent = require('ReactEmptyComponent');
+var ReactHostComponent = require('ReactHostComponent');
+
+var getNextDebugID = require('getNextDebugID');
+var invariant = require('invariant');
+var warning = require('warning');
+
+// 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 (__DEV__) {
+        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);
+      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,
+      );
+    }
+
+    // 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 {
+    invariant(false, 'Encountered invalid React node of type %s', typeof node);
+  }
+
+  if (__DEV__) {
+    warning(
+      typeof instance.mountComponent === 'function' &&
+        typeof instance.receiveComponent === 'function' &&
+        typeof instance.getHostNode === 'function' &&
+        typeof instance.unmountComponent === 'function',
+      'Only React Components can be mounted.',
+    );
+  }
+
+  // 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 (__DEV__) {
+    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 (__DEV__) {
+    if (Object.preventExtensions) {
+      Object.preventExtensions(instance);
+    }
+  }
+
+  return instance;
+}
+
+Object.assign(
+  ReactCompositeComponentWrapper.prototype,
+  ReactCompositeComponent,
+  {
+    _instantiateReactComponent: instantiateReactComponent,
+  },
+);
+
+module.exports = instantiateReactComponent;
diff --git a/src/shared/utils/CallbackQueue.js b/src/renderers/shared/utils/CallbackQueue.js
similarity index 76%
rename from src/shared/utils/CallbackQueue.js
rename to src/renderers/shared/utils/CallbackQueue.js
index 647c3887109c..00284508bcc9 100644
--- a/src/shared/utils/CallbackQueue.js
+++ b/src/renderers/shared/utils/CallbackQueue.js
@@ -7,6 +7,7 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule CallbackQueue
+ * @flow
  */
 
 'use strict';
@@ -26,12 +27,16 @@ var invariant = require('invariant');
  * @implements PooledClass
  * @internal
  */
-function CallbackQueue() {
-  this._callbacks = null;
-  this._contexts = null;
-}
+class CallbackQueue<T> {
+  _callbacks: ?Array<() => void>;
+  _contexts: ?Array<T>;
+  _arg: ?mixed;
 
-Object.assign(CallbackQueue.prototype, {
+  constructor(arg) {
+    this._callbacks = null;
+    this._contexts = null;
+    this._arg = arg;
+  }
 
   /**
    * Enqueues a callback to be invoked when `notifyAll` is invoked.
@@ -40,12 +45,12 @@ Object.assign(CallbackQueue.prototype, {
    * @param {?object} context Context to call `callback` with.
    * @internal
    */
-  enqueue: function(callback, context) {
+  enqueue(callback: () => void, context: T) {
     this._callbacks = this._callbacks || [];
-    this._contexts = this._contexts || [];
     this._callbacks.push(callback);
+    this._contexts = this._contexts || [];
     this._contexts.push(context);
-  },
+  }
 
   /**
    * Invokes all enqueued callbacks and clears the queue. This is invoked after
@@ -53,54 +58,52 @@ Object.assign(CallbackQueue.prototype, {
    *
    * @internal
    */
-  notifyAll: function() {
+  notifyAll() {
     var callbacks = this._callbacks;
     var contexts = this._contexts;
-    if (callbacks) {
+    var arg = this._arg;
+    if (callbacks && contexts) {
       invariant(
         callbacks.length === contexts.length,
-        'Mismatched list of contexts in callback queue'
+        'Mismatched list of contexts in callback queue',
       );
       this._callbacks = null;
       this._contexts = null;
       for (var i = 0; i < callbacks.length; i++) {
-        callbacks[i].call(contexts[i]);
+        callbacks[i].call(contexts[i], arg);
       }
       callbacks.length = 0;
       contexts.length = 0;
     }
-  },
+  }
 
-  checkpoint: function() {
+  checkpoint() {
     return this._callbacks ? this._callbacks.length : 0;
-  },
+  }
 
-  rollback: function(len) {
-    if (this._callbacks) {
+  rollback(len: number) {
+    if (this._callbacks && this._contexts) {
       this._callbacks.length = len;
       this._contexts.length = len;
     }
-  },
+  }
 
   /**
    * Resets the internal queue.
    *
    * @internal
    */
-  reset: function() {
+  reset() {
     this._callbacks = null;
     this._contexts = null;
-  },
+  }
 
   /**
    * `PooledClass` looks for this.
    */
-  destructor: function() {
+  destructor() {
     this.reset();
-  },
-
-});
-
-PooledClass.addPoolingTo(CallbackQueue);
+  }
+}
 
-module.exports = CallbackQueue;
+module.exports = PooledClass.addPoolingTo(CallbackQueue);
diff --git a/src/shared/utils/ReactErrorUtils.js b/src/renderers/shared/utils/ReactErrorUtils.js
similarity index 76%
rename from src/shared/utils/ReactErrorUtils.js
rename to src/renderers/shared/utils/ReactErrorUtils.js
index cff46bc15e28..d9b1c067e3ec 100644
--- a/src/shared/utils/ReactErrorUtils.js
+++ b/src/renderers/shared/utils/ReactErrorUtils.js
@@ -7,6 +7,7 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule ReactErrorUtils
+ * @flow
  */
 
 'use strict';
@@ -16,19 +17,22 @@ 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 {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, b) {
+function invokeGuardedCallback<A>(
+  name: string,
+  func: (a: A) => void,
+  a: A,
+): void {
   try {
-    return func(a, b);
+    func(a);
   } catch (x) {
     if (caughtError === null) {
       caughtError = x;
     }
-    return undefined;
   }
 }
 
@@ -59,13 +63,19 @@ if (__DEV__) {
    * 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') {
+  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, b) {
-      var boundFunc = func.bind(null, a, b);
+    ReactErrorUtils.invokeGuardedCallback = function<A>(
+      name: string,
+      func: (a: A) => void,
+      a: A,
+    ): void {
+      var boundFunc = func.bind(null, a);
       var evtType = `react-${name}`;
       fakeNode.addEventListener(evtType, boundFunc, false);
       var evt = document.createEvent('Event');
diff --git a/src/shared/utils/ReactFeatureFlags.js b/src/renderers/shared/utils/ReactFeatureFlags.js
similarity index 98%
rename from src/shared/utils/ReactFeatureFlags.js
rename to src/renderers/shared/utils/ReactFeatureFlags.js
index 30b5f4c7de2e..5b3bb1b457bd 100644
--- a/src/shared/utils/ReactFeatureFlags.js
+++ b/src/renderers/shared/utils/ReactFeatureFlags.js
@@ -7,6 +7,7 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule ReactFeatureFlags
+ * @flow
  */
 
 'use strict';
diff --git a/src/shared/utils/Transaction.js b/src/renderers/shared/utils/Transaction.js
similarity index 89%
rename from src/shared/utils/Transaction.js
rename to src/renderers/shared/utils/Transaction.js
index 84b55a25c8e3..4fbe9d88e1f7 100644
--- a/src/shared/utils/Transaction.js
+++ b/src/renderers/shared/utils/Transaction.js
@@ -7,12 +7,15 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule Transaction
+ * @flow
  */
 
 'use strict';
 
 var invariant = require('invariant');
 
+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
@@ -74,7 +77,7 @@ var invariant = require('invariant');
  *
  * @class Transaction
  */
-var Mixin = {
+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
@@ -82,7 +85,7 @@ var Mixin = {
    * That can be useful if you decide to make your subclass of this mixin a
    * "PooledClass".
    */
-  reinitializeTransaction: function() {
+  reinitializeTransaction: function(): void {
     this.transactionWrappers = this.getTransactionWrappers();
     if (this.wrapperInitData) {
       this.wrapperInitData.length = 0;
@@ -100,10 +103,12 @@ var Mixin = {
    */
   getTransactionWrappers: null,
 
-  isInTransaction: function() {
+  isInTransaction: function(): boolean {
     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
@@ -121,11 +126,21 @@ var Mixin = {
    *
    * @return {*} Return value from `method`.
    */
-  perform: function(method, scope, a, b, c, d, e, f) {
+  perform: function<
+    A,
+    B,
+    C,
+    D,
+    E,
+    F,
+    G,
+    T: (a: A, b: B, c: C, d: D, e: E, f: F) => G,
+  >(method: T, scope: any, a: A, b: B, c: C, d: D, e: E, f: F): G {
+    /* eslint-enable space-before-function-paren */
     invariant(
       !this.isInTransaction(),
       'Transaction.perform(...): Cannot initialize a transaction when there ' +
-      'is already an outstanding transaction.'
+        'is already an outstanding transaction.',
     );
     var errorThrown;
     var ret;
@@ -146,8 +161,7 @@ var Mixin = {
           // by invoking `closeAll`.
           try {
             this.closeAll(0);
-          } catch (err) {
-          }
+          } catch (err) {}
         } else {
           // Since `method` didn't throw, we don't want to silence the exception
           // here.
@@ -160,7 +174,7 @@ var Mixin = {
     return ret;
   },
 
-  initializeAll: function(startIndex) {
+  initializeAll: function(startIndex: number): void {
     var transactionWrappers = this.transactionWrappers;
     for (var i = startIndex; i < transactionWrappers.length; i++) {
       var wrapper = transactionWrappers[i];
@@ -169,19 +183,18 @@ var Mixin = {
         // 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] = Transaction.OBSERVED_ERROR;
-        this.wrapperInitData[i] = wrapper.initialize ?
-          wrapper.initialize.call(this) :
-          null;
+        this.wrapperInitData[i] = OBSERVED_ERROR;
+        this.wrapperInitData[i] = wrapper.initialize
+          ? wrapper.initialize.call(this)
+          : null;
       } finally {
-        if (this.wrapperInitData[i] === Transaction.OBSERVED_ERROR) {
+        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) {
-          }
+          } catch (err) {}
         }
       }
     }
@@ -193,10 +206,10 @@ var Mixin = {
    * (`close`rs that correspond to initializers that failed will not be
    * invoked).
    */
-  closeAll: function(startIndex) {
+  closeAll: function(startIndex: number): void {
     invariant(
       this.isInTransaction(),
-      'Transaction.closeAll(): Cannot close transaction when none are open.'
+      'Transaction.closeAll(): Cannot close transaction when none are open.',
     );
     var transactionWrappers = this.transactionWrappers;
     for (var i = startIndex; i < transactionWrappers.length; i++) {
@@ -209,7 +222,7 @@ var Mixin = {
         // close -- if it's still set to true in the finally block, it means
         // wrapper.close threw.
         errorThrown = true;
-        if (initData !== Transaction.OBSERVED_ERROR && wrapper.close) {
+        if (initData !== OBSERVED_ERROR && wrapper.close) {
           wrapper.close.call(this, initData);
         }
         errorThrown = false;
@@ -220,8 +233,7 @@ var Mixin = {
           // first error is the one to bubble up.
           try {
             this.closeAll(i + 1);
-          } catch (e) {
-          }
+          } catch (e) {}
         }
       }
     }
@@ -229,15 +241,6 @@ var Mixin = {
   },
 };
 
-var Transaction = {
-
-  Mixin: Mixin,
-
-  /**
-   * Token to look for to determine if an error occurred.
-   */
-  OBSERVED_ERROR: {},
-
-};
+export type Transaction = typeof TransactionImpl;
 
-module.exports = Transaction;
+module.exports = TransactionImpl;
diff --git a/src/shared/utils/__tests__/Transaction-test.js b/src/renderers/shared/utils/__tests__/Transaction-test.js
similarity index 80%
rename from src/shared/utils/__tests__/Transaction-test.js
rename to src/renderers/shared/utils/__tests__/Transaction-test.js
index ee474a1cc414..7688156265ed 100644
--- a/src/shared/utils/__tests__/Transaction-test.js
+++ b/src/renderers/shared/utils/__tests__/Transaction-test.js
@@ -11,12 +11,11 @@
 
 'use strict';
 
-
 var Transaction;
 
-var INIT_ERRORED = 'initErrored';     // Just a dummy value to check for.
-describe('Transaction', function() {
-  beforeEach(function() {
+var INIT_ERRORED = 'initErrored'; // Just a dummy value to check for.
+describe('Transaction', () => {
+  beforeEach(() => {
     jest.resetModuleRegistry();
     Transaction = require('Transaction');
   });
@@ -26,7 +25,7 @@ describe('Transaction', function() {
    * return values to closers when those inits are successful. We should not
    * invoke the actual method when any of the initializers fail.
    */
-  it('should invoke closers with/only-with init returns', function() {
+  it('should invoke closers with/only-with init returns', () => {
     var throwInInit = function() {
       throw new Error('close[0] should receive Transaction.OBSERVED_ERROR');
     };
@@ -41,11 +40,11 @@ describe('Transaction', function() {
      */
     var TestTransaction = function() {
       this.reinitializeTransaction();
-      this.firstCloseParam = INIT_ERRORED;   // WON'T be set to something else
-      this.secondCloseParam = INIT_ERRORED;  // WILL be set to something else
-      this.lastCloseParam = INIT_ERRORED;    // WON'T be set to something else
+      this.firstCloseParam = INIT_ERRORED; // WON'T be set to something else
+      this.secondCloseParam = INIT_ERRORED; // WILL be set to something else
+      this.lastCloseParam = INIT_ERRORED; // WON'T be set to something else
     };
-    Object.assign(TestTransaction.prototype, Transaction.Mixin);
+    Object.assign(TestTransaction.prototype, Transaction);
     TestTransaction.prototype.getTransactionWrappers = function() {
       return [
         {
@@ -84,19 +83,18 @@ describe('Transaction', function() {
     expect(transaction.isInTransaction()).toBe(false);
   });
 
-  it('should invoke closers and wrapped method when inits success', function() {
-
+  it('should invoke closers and wrapped method when inits success', () => {
     var performSideEffect;
     /**
      * New test Transaction subclass.
      */
     var TestTransaction = function() {
       this.reinitializeTransaction();
-      this.firstCloseParam = INIT_ERRORED;   // WILL be set to something else
-      this.secondCloseParam = INIT_ERRORED;  // WILL be set to something else
-      this.lastCloseParam = INIT_ERRORED;    // WILL be set to something else
+      this.firstCloseParam = INIT_ERRORED; // WILL be set to something else
+      this.secondCloseParam = INIT_ERRORED; // WILL be set to something else
+      this.lastCloseParam = INIT_ERRORED; // WILL be set to something else
     };
-    Object.assign(TestTransaction.prototype, Transaction.Mixin);
+    Object.assign(TestTransaction.prototype, Transaction);
     TestTransaction.prototype.getTransactionWrappers = function() {
       return [
         {
@@ -145,19 +143,18 @@ describe('Transaction', function() {
    * throws an error, the transaction should prefer to throw the error
    * encountered earlier in the operation.
    */
-  it('should throw when wrapped operation throws', function() {
-
+  it('should throw when wrapped operation throws', () => {
     var performSideEffect;
     /**
      * New test Transaction subclass.
      */
     var TestTransaction = function() {
       this.reinitializeTransaction();
-      this.firstCloseParam = INIT_ERRORED;   // WILL be set to something else
-      this.secondCloseParam = INIT_ERRORED;  // WILL be set to something else
-      this.lastCloseParam = INIT_ERRORED;    // WILL be set to something else
+      this.firstCloseParam = INIT_ERRORED; // WILL be set to something else
+      this.secondCloseParam = INIT_ERRORED; // WILL be set to something else
+      this.lastCloseParam = INIT_ERRORED; // WILL be set to something else
     };
-    Object.assign(TestTransaction.prototype, Transaction.Mixin);
+    Object.assign(TestTransaction.prototype, Transaction);
     // Now, none of the close/inits throw, but the operation we wrap will throw.
     TestTransaction.prototype.getTransactionWrappers = function() {
       return [
@@ -198,17 +195,19 @@ describe('Transaction', function() {
 
     var transaction = new TestTransaction();
 
-    expect(function() {
-      var isTypeError = false;
-      try {
-        transaction.perform(function() {
-          throw new TypeError('Thrown in main wrapped operation');
-        });
-      } catch (err) {
-        isTypeError = (err instanceof TypeError);
-      }
-      return isTypeError;
-    }()).toBe(true);
+    expect(
+      (function() {
+        var isTypeError = false;
+        try {
+          transaction.perform(function() {
+            throw new TypeError('Thrown in main wrapped operation');
+          });
+        } catch (err) {
+          isTypeError = err instanceof TypeError;
+        }
+        return isTypeError;
+      })(),
+    ).toBe(true);
 
     expect(performSideEffect).toBe(undefined);
     expect(transaction.firstCloseParam).toBe('firstResult');
@@ -217,11 +216,11 @@ describe('Transaction', function() {
     expect(transaction.isInTransaction()).toBe(false);
   });
 
-  it('should throw errors in transaction close', function() {
+  it('should throw errors in transaction close', () => {
     var TestTransaction = function() {
       this.reinitializeTransaction();
     };
-    Object.assign(TestTransaction.prototype, Transaction.Mixin);
+    Object.assign(TestTransaction.prototype, Transaction);
     var exceptionMsg = 'This exception should throw.';
     TestTransaction.prototype.getTransactionWrappers = function() {
       return [
@@ -236,11 +235,11 @@ describe('Transaction', function() {
     var transaction = new TestTransaction();
     expect(function() {
       transaction.perform(function() {});
-    }).toThrow(exceptionMsg);
+    }).toThrowError(exceptionMsg);
     expect(transaction.isInTransaction()).toBe(false);
   });
 
-  it('should allow nesting of transactions', function() {
+  it('should allow nesting of transactions', () => {
     var performSideEffect;
     var nestedPerformSideEffect;
     /**
@@ -250,7 +249,7 @@ describe('Transaction', function() {
       this.reinitializeTransaction();
       this.firstCloseParam = INIT_ERRORED; // WILL be set to something else
     };
-    Object.assign(TestTransaction.prototype, Transaction.Mixin);
+    Object.assign(TestTransaction.prototype, Transaction);
     TestTransaction.prototype.getTransactionWrappers = function() {
       return [
         {
@@ -278,7 +277,7 @@ describe('Transaction', function() {
     var NestedTransaction = function() {
       this.reinitializeTransaction();
     };
-    Object.assign(NestedTransaction.prototype, Transaction.Mixin);
+    Object.assign(NestedTransaction.prototype, Transaction);
     NestedTransaction.prototype.getTransactionWrappers = function() {
       return [
         {
diff --git a/src/shared/utils/__tests__/accumulateInto-test.js b/src/renderers/shared/utils/__tests__/accumulateInto-test.js
similarity index 75%
rename from src/shared/utils/__tests__/accumulateInto-test.js
rename to src/renderers/shared/utils/__tests__/accumulateInto-test.js
index 8dd9ee6f1465..ab6ebbee59b1 100644
--- a/src/shared/utils/__tests__/accumulateInto-test.js
+++ b/src/renderers/shared/utils/__tests__/accumulateInto-test.js
@@ -11,31 +11,27 @@
 
 'use strict';
 
-jest
-  .dontMock('accumulateInto');
-
 var accumulateInto;
 
-describe('accumulateInto', function() {
-
-  beforeEach(function() {
+describe('accumulateInto', () => {
+  beforeEach(() => {
     accumulateInto = require('accumulateInto');
   });
 
-  it('throws if the second item is null', function() {
+  it('throws if the second item is null', () => {
     expect(function() {
       accumulateInto([], null);
-    }).toThrow(
-      'accumulateInto(...): Accumulated items must not be null or undefined.'
+    }).toThrowError(
+      'accumulateInto(...): Accumulated items must not be null or undefined.',
     );
   });
 
-  it('returns the second item if first is null', function() {
+  it('returns the second item if first is null', () => {
     var a = [];
     expect(accumulateInto(null, a)).toBe(a);
   });
 
-  it('merges the second into the first if first item is an array', function() {
+  it('merges the second into the first if first item is an array', () => {
     var a = [1, 2];
     var b = [3, 4];
     accumulateInto(a, b);
@@ -46,7 +42,7 @@ describe('accumulateInto', function() {
     expect(c).toEqual([1, 2]);
   });
 
-  it('returns a new array if first or both items are scalar', function() {
+  it('returns a new array if first or both items are scalar', () => {
     var a = [2];
     expect(accumulateInto(1, a)).toEqual([1, 2]);
     expect(a).toEqual([2]);
diff --git a/src/renderers/shared/utils/__tests__/adler32-test.js b/src/renderers/shared/utils/__tests__/adler32-test.js
new file mode 100644
index 000000000000..ab6c7a0287cd
--- /dev/null
+++ b/src/renderers/shared/utils/__tests__/adler32-test.js
@@ -0,0 +1,41 @@
+/**
+ * Copyright 2014-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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var adler32 = require('adler32');
+
+describe('adler32', () => {
+  it('generates differing checksums', () => {
+    expect(adler32('foo')).not.toBe(adler32('bar'));
+  });
+
+  it('generates consistent checksums', () => {
+    expect(adler32('linux')).toBe(adler32('linux'));
+  });
+
+  it('is case sensitive', () => {
+    expect(adler32('a')).not.toBe(adler32('A'));
+  });
+
+  it("doesn't barf on large inputs", () => {
+    var str = '';
+    for (var i = 0; i < 100000; i++) {
+      str += 'This will be repeated to be very large indeed. ';
+    }
+    expect(adler32(str)).toBe(692898118);
+  });
+
+  it("doesn't barf on international inputs", () => {
+    var str = 'Linux 是一個真棒操作系統!';
+    expect(adler32(str)).toBe(-1183804097);
+  });
+});
diff --git a/src/renderers/shared/utils/accumulate.js b/src/renderers/shared/utils/accumulate.js
new file mode 100644
index 000000000000..ee6261261101
--- /dev/null
+++ b/src/renderers/shared/utils/accumulate.js
@@ -0,0 +1,50 @@
+/**
+ * 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 accumulate
+ * @flow
+ */
+
+'use strict';
+
+var invariant = require('invariant');
+
+/**
+ * Accumulates items that must not be null or undefined.
+ *
+ * This is used to conserve memory by avoiding array allocations.
+ *
+ * @return {*|array<*>} An accumulation of items.
+ */
+function accumulate<T>(
+  current: ?(T | Array<T>),
+  next: T | Array<T>,
+): T | Array<T> {
+  invariant(
+    next != null,
+    'accumulate(...): Accumulated items must be not be null or undefined.',
+  );
+
+  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)) {
+    return current.concat(next);
+  }
+
+  if (Array.isArray(next)) {
+    return [current].concat(next);
+  }
+
+  return [current, next];
+}
+
+module.exports = accumulate;
diff --git a/src/shared/utils/accumulateInto.js b/src/renderers/shared/utils/accumulateInto.js
similarity index 82%
rename from src/shared/utils/accumulateInto.js
rename to src/renderers/shared/utils/accumulateInto.js
index 291f8fd42d33..803dbd4665d1 100644
--- a/src/shared/utils/accumulateInto.js
+++ b/src/renderers/shared/utils/accumulateInto.js
@@ -7,6 +7,7 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule accumulateInto
+ * @flow
  */
 
 'use strict';
@@ -14,7 +15,6 @@
 var invariant = require('invariant');
 
 /**
- *
  * 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
@@ -27,31 +27,31 @@ var invariant = require('invariant');
  * @return {*|array<*>} An accumulation of items.
  */
 
-function accumulateInto(current, next) {
+function accumulateInto<T>(
+  current: ?(T | Array<T>),
+  next: T | Array<T>,
+): T | Array<T> {
   invariant(
     next != null,
-    'accumulateInto(...): Accumulated items must not be null or undefined.'
+    'accumulateInto(...): Accumulated items must not be null or undefined.',
   );
+
   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).
-  var currentIsArray = Array.isArray(current);
-  var nextIsArray = Array.isArray(next);
-
-  if (currentIsArray && nextIsArray) {
-    current.push.apply(current, next);
-    return current;
-  }
-
-  if (currentIsArray) {
+  if (Array.isArray(current)) {
+    if (Array.isArray(next)) {
+      current.push.apply(current, next);
+      return current;
+    }
     current.push(next);
     return current;
   }
 
-  if (nextIsArray) {
+  if (Array.isArray(next)) {
     // A bit too dangerous to mutate `next`.
     return [current].concat(next);
   }
diff --git a/src/shared/utils/adler32.js b/src/renderers/shared/utils/adler32.js
similarity index 89%
rename from src/shared/utils/adler32.js
rename to src/renderers/shared/utils/adler32.js
index 1248531e23c3..4013f2b26bed 100644
--- a/src/shared/utils/adler32.js
+++ b/src/renderers/shared/utils/adler32.js
@@ -7,6 +7,7 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule adler32
+ * @flow
  */
 
 'use strict';
@@ -18,7 +19,7 @@ var MOD = 65521;
 // 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) {
+function adler32(data: string): number {
   var a = 1;
   var b = 0;
   var i = 0;
@@ -27,18 +28,17 @@ function adler32(data) {
   while (i < m) {
     var n = Math.min(i + 4096, m);
     for (; i < n; i += 4) {
-      b += (
+      b +=
         (a += data.charCodeAt(i)) +
         (a += data.charCodeAt(i + 1)) +
         (a += data.charCodeAt(i + 2)) +
-        (a += data.charCodeAt(i + 3))
-      );
+        (a += data.charCodeAt(i + 3));
     }
     a %= MOD;
     b %= MOD;
   }
   for (; i < l; i++) {
-    b += (a += data.charCodeAt(i));
+    b += a += data.charCodeAt(i);
   }
   a %= MOD;
   b %= MOD;
diff --git a/src/shared/utils/forEachAccumulated.js b/src/renderers/shared/utils/forEachAccumulated.js
similarity index 88%
rename from src/shared/utils/forEachAccumulated.js
rename to src/renderers/shared/utils/forEachAccumulated.js
index 176c025145ff..4ee784d5e460 100644
--- a/src/shared/utils/forEachAccumulated.js
+++ b/src/renderers/shared/utils/forEachAccumulated.js
@@ -7,6 +7,7 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule forEachAccumulated
+ * @flow
  */
 
 'use strict';
@@ -18,12 +19,16 @@
  * handling the case when there is exactly one item (and we do not need to
  * allocate an array).
  */
-var forEachAccumulated = function(arr, cb, scope) {
+function forEachAccumulated<T>(
+  arr: ?(T | Array<T>),
+  cb: (elem: T) => void,
+  scope: ?any,
+) {
   if (Array.isArray(arr)) {
     arr.forEach(cb, scope);
   } else if (arr) {
     cb.call(scope, arr);
   }
-};
+}
 
 module.exports = forEachAccumulated;
diff --git a/src/renderers/shared/utils/isTextInputElement.js b/src/renderers/shared/utils/isTextInputElement.js
new file mode 100644
index 000000000000..633c19ce33af
--- /dev/null
+++ b/src/renderers/shared/utils/isTextInputElement.js
@@ -0,0 +1,50 @@
+/**
+ * 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 isTextInputElement
+ * @flow
+ */
+
+'use strict';
+
+/**
+ * @see http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary
+ */
+var supportedInputTypes: {[key: string]: true | void} = {
+  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: ?HTMLElement): boolean {
+  var nodeName = elem && elem.nodeName && elem.nodeName.toLowerCase();
+
+  if (nodeName === 'input') {
+    return !!supportedInputTypes[((elem: any): HTMLInputElement).type];
+  }
+
+  if (nodeName === 'textarea') {
+    return true;
+  }
+
+  return false;
+}
+
+module.exports = isTextInputElement;
diff --git a/src/renderers/testing/ReactShallowRenderer.js b/src/renderers/testing/ReactShallowRenderer.js
new file mode 100644
index 000000000000..17fe612f796b
--- /dev/null
+++ b/src/renderers/testing/ReactShallowRenderer.js
@@ -0,0 +1,156 @@
+/**
+ * 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 ReactShallowRenderer
+ */
+
+'use strict';
+
+var React = require('React');
+var ReactCompositeComponent = require('ReactCompositeComponent');
+var ReactDefaultBatchingStrategy = require('ReactDefaultBatchingStrategy');
+var ReactReconciler = require('ReactReconciler');
+var ReactReconcileTransaction = require('ReactReconcileTransaction');
+var ReactUpdates = require('ReactUpdates');
+
+var emptyObject = require('emptyObject');
+var getNextDebugID = require('getNextDebugID');
+var invariant = require('invariant');
+
+function injectDefaults() {
+  ReactUpdates.injection.injectReconcileTransaction(ReactReconcileTransaction);
+  ReactUpdates.injection.injectBatchingStrategy(ReactDefaultBatchingStrategy);
+}
+
+class NoopInternalComponent {
+  constructor(element) {
+    this._renderedOutput = element;
+    this._currentElement = element;
+
+    if (__DEV__) {
+      this._debugID = getNextDebugID();
+    }
+  }
+  mountComponent() {}
+  receiveComponent(element) {
+    this._renderedOutput = element;
+    this._currentElement = element;
+  }
+  unmountComponent() {}
+  getHostNode() {
+    return undefined;
+  }
+  getPublicInstance() {
+    return null;
+  }
+}
+
+var ShallowComponentWrapper = function(element) {
+  // TODO: Consolidate with instantiateReactComponent
+  if (__DEV__) {
+    this._debugID = getNextDebugID();
+  }
+
+  this.construct(element);
+};
+Object.assign(ShallowComponentWrapper.prototype, ReactCompositeComponent, {
+  _constructComponent: ReactCompositeComponent._constructComponentWithoutOwner,
+  _instantiateReactComponent: function(element) {
+    return new NoopInternalComponent(element);
+  },
+  _replaceNodeWithMarkup: function() {},
+  _renderValidatedComponent:
+    ReactCompositeComponent._renderValidatedComponentWithoutOwnerOrContext,
+});
+
+function _batchedRender(renderer, element, context) {
+  var transaction = ReactUpdates.ReactReconcileTransaction.getPooled(true);
+  renderer._render(element, transaction, context);
+  ReactUpdates.ReactReconcileTransaction.release(transaction);
+}
+
+class ReactShallowRenderer {
+  _instance = null;
+  getMountedInstance() {
+    return this._instance ? this._instance._instance : null;
+  }
+  render(element, context) {
+    // Ensure we've done the default injections. This might not be true in the
+    // case of a simple test that only requires React and the TestUtils in
+    // conjunction with an inline-requires transform.
+    injectDefaults();
+
+    invariant(
+      React.isValidElement(element),
+      'ReactShallowRenderer render(): Invalid component element.%s',
+      typeof element === 'function'
+        ? ' Instead of passing a component class, make sure to instantiate ' +
+            'it by passing it to React.createElement.'
+        : '',
+    );
+    invariant(
+      typeof element.type !== 'string',
+      'ReactShallowRenderer render(): Shallow rendering works only with custom ' +
+        'components, not primitives (%s). Instead of calling `.render(el)` and ' +
+        'inspecting the rendered output, look at `el.props` directly instead.',
+      element.type,
+    );
+
+    if (!context) {
+      context = emptyObject;
+    }
+    ReactUpdates.batchedUpdates(_batchedRender, this, element, context);
+
+    return this.getRenderOutput();
+  }
+  getRenderOutput() {
+    return (
+      (this._instance &&
+        this._instance._renderedComponent &&
+        this._instance._renderedComponent._renderedOutput) ||
+      null
+    );
+  }
+  unmount() {
+    if (this._instance) {
+      ReactReconciler.unmountComponent(this._instance, false);
+    }
+  }
+  unstable_batchedUpdates(callback, bookkeeping) {
+    // This is used by Enzyme for fake-simulating events in shallow mode.
+    injectDefaults();
+    return ReactUpdates.batchedUpdates(callback, bookkeeping);
+  }
+  _render(element, transaction, context) {
+    if (this._instance) {
+      ReactReconciler.receiveComponent(
+        this._instance,
+        element,
+        transaction,
+        context,
+      );
+    } else {
+      var instance = new ShallowComponentWrapper(element);
+      ReactReconciler.mountComponent(
+        instance,
+        transaction,
+        null,
+        null,
+        context,
+        0,
+      );
+      this._instance = instance;
+    }
+  }
+}
+
+ReactShallowRenderer.createRenderer = function() {
+  return new ReactShallowRenderer();
+};
+
+module.exports = ReactShallowRenderer;
diff --git a/src/renderers/testing/ReactTestEmptyComponent.js b/src/renderers/testing/ReactTestEmptyComponent.js
new file mode 100644
index 000000000000..40b62e03fc31
--- /dev/null
+++ b/src/renderers/testing/ReactTestEmptyComponent.js
@@ -0,0 +1,28 @@
+/**
+ * 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 ReactTestEmptyComponent
+ * @flow
+ */
+
+'use strict';
+
+class ReactTestEmptyComponent {
+  _currentElement: null;
+
+  constructor() {
+    this._currentElement = null;
+  }
+  receiveComponent(): void {}
+  toJSON(): void {}
+  mountComponent(): void {}
+  getHostNode(): void {}
+  unmountComponent(): void {}
+}
+
+module.exports = ReactTestEmptyComponent;
diff --git a/src/renderers/testing/ReactTestMount.js b/src/renderers/testing/ReactTestMount.js
new file mode 100644
index 000000000000..ce4f2162f934
--- /dev/null
+++ b/src/renderers/testing/ReactTestMount.js
@@ -0,0 +1,168 @@
+/**
+ * Copyright (c) 2015-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 ReactTestMount
+ * @flow
+ */
+'use strict';
+
+var React = require('React');
+var ReactReconciler = require('ReactReconciler');
+var ReactUpdates = require('ReactUpdates');
+
+var emptyObject = require('emptyObject');
+var getHostComponentFromComposite = require('getHostComponentFromComposite');
+var instantiateReactComponent = require('instantiateReactComponent');
+var invariant = require('invariant');
+
+export type TestRendererOptions = {
+  createNodeMock: (element: ReactElement<any>) => any,
+};
+
+var defaultTestOptions = {
+  createNodeMock: function() {
+    return 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 TopLevelWrapper = function() {};
+TopLevelWrapper.prototype.isReactComponent = {};
+if (__DEV__) {
+  TopLevelWrapper.displayName = 'TopLevelWrapper';
+}
+TopLevelWrapper.prototype.render = function() {
+  return this.props.child;
+};
+TopLevelWrapper.isReactTopLevelWrapper = true;
+
+/**
+ * Mounts this component and inserts it into the DOM.
+ *
+ * @param {ReactComponent} componentInstance The instance to mount.
+ * @param {ReactReconcileTransaction} transaction
+ * @param {Object} hostParent
+ * @param {Object} hostContainerInfo
+ */
+function mountComponentIntoNode(
+  componentInstance,
+  transaction,
+  hostParent,
+  hostContainerInfo,
+) {
+  var image = ReactReconciler.mountComponent(
+    componentInstance,
+    transaction,
+    null,
+    hostContainerInfo,
+    emptyObject,
+  );
+  componentInstance._renderedComponent._topLevelWrapper = componentInstance;
+  return image;
+}
+
+/**
+ * Batched mount.
+ *
+ * @param {ReactComponent} componentInstance The instance to mount.
+ * @param {number} rootID ID of the root node.
+ * @param {number} containerTag container element to mount into.
+ */
+function batchedMountComponentIntoNode(componentInstance, options) {
+  var transaction = ReactUpdates.ReactReconcileTransaction.getPooled(true);
+  var image = transaction.perform(
+    mountComponentIntoNode,
+    null,
+    componentInstance,
+    transaction,
+    null,
+    options,
+  );
+  ReactUpdates.ReactReconcileTransaction.release(transaction);
+  return image;
+}
+
+var ReactTestInstance = function(component) {
+  this._component = component;
+};
+ReactTestInstance.prototype.getInstance = function() {
+  return this._component._renderedComponent.getPublicInstance();
+};
+ReactTestInstance.prototype.update = function(nextElement) {
+  invariant(
+    this._component,
+    "ReactTestRenderer: .update() can't be called after unmount.",
+  );
+  var nextWrappedElement = React.createElement(TopLevelWrapper, {
+    child: nextElement,
+  });
+  var component = this._component;
+  ReactUpdates.batchedUpdates(function() {
+    var transaction = ReactUpdates.ReactReconcileTransaction.getPooled(true);
+    transaction.perform(function() {
+      ReactReconciler.receiveComponent(
+        component,
+        nextWrappedElement,
+        transaction,
+        emptyObject,
+      );
+    });
+    ReactUpdates.ReactReconcileTransaction.release(transaction);
+  });
+};
+ReactTestInstance.prototype.unmount = function(nextElement) {
+  var component = this._component;
+  ReactUpdates.batchedUpdates(function() {
+    var transaction = ReactUpdates.ReactReconcileTransaction.getPooled(true);
+    transaction.perform(function() {
+      ReactReconciler.unmountComponent(component, false);
+    });
+    ReactUpdates.ReactReconcileTransaction.release(transaction);
+  });
+  this._component = null;
+};
+ReactTestInstance.prototype.toJSON = function() {
+  var inst = getHostComponentFromComposite(this._component);
+  if (inst === null) {
+    return null;
+  }
+  return inst.toJSON();
+};
+
+/**
+ * As soon as `ReactMount` is refactored to not rely on the DOM, we can share
+ * code between the two. For now, we'll hard code the ID logic.
+ */
+var ReactTestMount = {
+  render: function(
+    nextElement: ReactElement<any>,
+    options?: TestRendererOptions,
+  ): ReactTestInstance {
+    var nextWrappedElement = React.createElement(TopLevelWrapper, {
+      child: nextElement,
+    });
+
+    var instance = instantiateReactComponent(nextWrappedElement, 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,
+      instance,
+      Object.assign({}, defaultTestOptions, options),
+    );
+    return new ReactTestInstance(instance);
+  },
+};
+
+module.exports = ReactTestMount;
diff --git a/src/renderers/testing/ReactTestReconcileTransaction.js b/src/renderers/testing/ReactTestReconcileTransaction.js
new file mode 100644
index 000000000000..379be398eb5d
--- /dev/null
+++ b/src/renderers/testing/ReactTestReconcileTransaction.js
@@ -0,0 +1,134 @@
+/**
+ * Copyright (c) 2015-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 ReactTestReconcileTransaction
+ * @flow
+ */
+'use strict';
+
+var CallbackQueue = require('CallbackQueue');
+var PooledClass = require('PooledClass');
+var Transaction = require('Transaction');
+var ReactUpdateQueue = require('ReactUpdateQueue');
+
+import type {TestRendererOptions} from 'ReactTestMount';
+
+/**
+ * Provides a `CallbackQueue` queue for collecting `onDOMReady` callbacks during
+ * the performing of 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 = [ON_DOM_READY_QUEUEING];
+
+/**
+ * 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 ReactTestReconcileTransaction
+ */
+function ReactTestReconcileTransaction(testOptions: TestRendererOptions) {
+  this.reinitializeTransaction();
+  this.testOptions = testOptions;
+  this.reactMountReady = CallbackQueue.getPooled(this);
+}
+
+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.
+   *   TODO: convert to ReactMountReady
+   */
+  getReactMountReady: function() {
+    return this.reactMountReady;
+  },
+
+  /**
+   * @return {object} the options passed to ReactTestRenderer
+   */
+  getTestOptions: function() {
+    return this.testOptions;
+  },
+
+  /**
+   * @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;
+  },
+};
+
+Object.assign(
+  ReactTestReconcileTransaction.prototype,
+  Transaction,
+  ReactTestReconcileTransaction,
+  Mixin,
+);
+
+PooledClass.addPoolingTo(ReactTestReconcileTransaction);
+
+module.exports = ReactTestReconcileTransaction;
diff --git a/src/renderers/testing/ReactTestRenderer.js b/src/renderers/testing/ReactTestRenderer.js
new file mode 100644
index 000000000000..ea63638bacca
--- /dev/null
+++ b/src/renderers/testing/ReactTestRenderer.js
@@ -0,0 +1,156 @@
+/**
+ * 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 ReactTestRenderer
+ * @flow
+ */
+
+'use strict';
+
+var ReactComponentEnvironment = require('ReactComponentEnvironment');
+var ReactDefaultBatchingStrategy = require('ReactDefaultBatchingStrategy');
+var ReactEmptyComponent = require('ReactEmptyComponent');
+var ReactMultiChild = require('ReactMultiChild');
+var ReactHostComponent = require('ReactHostComponent');
+var ReactTestMount = require('ReactTestMount');
+var ReactTestReconcileTransaction = require('ReactTestReconcileTransaction');
+var ReactUpdates = require('ReactUpdates');
+var ReactTestTextComponent = require('ReactTestTextComponent');
+var ReactTestEmptyComponent = require('ReactTestEmptyComponent');
+var invariant = require('invariant');
+
+import type {ReactElement} from 'ReactElementType';
+import type {ReactInstance} from 'ReactInstanceType';
+
+type ReactTestRendererJSON = {
+  type: string,
+  props: {[propName: string]: string},
+  children: null | Array<string | ReactTestRendererJSON>,
+  $$typeof?: any,
+};
+
+/**
+ * Drill down (through composites and empty components) until we get a native or
+ * native 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;
+}
+
+class ReactTestComponent {
+  _currentElement: ReactElement;
+  _renderedChildren: null | Object;
+  _topLevelWrapper: null | ReactInstance;
+  _hostContainerInfo: null | Object;
+
+  constructor(element: ReactElement) {
+    this._currentElement = element;
+    this._renderedChildren = null;
+    this._topLevelWrapper = null;
+    this._hostContainerInfo = null;
+  }
+
+  mountComponent(
+    transaction: ReactTestReconcileTransaction,
+    nativeParent: null | ReactTestComponent,
+    hostContainerInfo: Object,
+    context: Object,
+  ) {
+    var element = this._currentElement;
+    this._hostContainerInfo = hostContainerInfo;
+    // $FlowFixMe https://github.com/facebook/flow/issues/1805
+    this.mountChildren(element.props.children, transaction, context);
+  }
+
+  receiveComponent(
+    nextElement: ReactElement,
+    transaction: ReactTestReconcileTransaction,
+    context: Object,
+  ) {
+    this._currentElement = nextElement;
+    // $FlowFixMe https://github.com/facebook/flow/issues/1805
+    this.updateChildren(nextElement.props.children, transaction, context);
+  }
+
+  getPublicInstance(): Object {
+    var element = this._currentElement;
+    var hostContainerInfo = this._hostContainerInfo;
+    invariant(
+      hostContainerInfo,
+      'hostContainerInfo should be populated before ' +
+        'getPublicInstance is called.',
+    );
+    return hostContainerInfo.createNodeMock(element);
+  }
+
+  toJSON(): ReactTestRendererJSON {
+    // not using `children`, but I don't want to rewrite without destructuring
+    // eslint-disable-next-line no-unused-vars
+    var {children, ...props} = this._currentElement.props;
+    var childrenJSON = [];
+    for (var key in this._renderedChildren) {
+      var inst = this._renderedChildren[key];
+      inst = getRenderedHostOrTextFromComponent(inst);
+      var json = inst.toJSON();
+      if (json !== undefined) {
+        childrenJSON.push(json);
+      }
+    }
+    var object: ReactTestRendererJSON = {
+      type: this._currentElement.type,
+      props: props,
+      children: childrenJSON.length ? childrenJSON : null,
+    };
+    Object.defineProperty(object, '$$typeof', {
+      value: Symbol.for('react.test.json'),
+    });
+    return object;
+  }
+
+  getHostNode(): void {}
+  unmountComponent(safely, skipLifecycle): void {
+    // $FlowFixMe https://github.com/facebook/flow/issues/1805
+    this.unmountChildren(safely, skipLifecycle);
+  }
+}
+
+Object.assign(ReactTestComponent.prototype, ReactMultiChild.Mixin);
+
+// =============================================================================
+
+ReactUpdates.injection.injectReconcileTransaction(
+  ReactTestReconcileTransaction,
+);
+ReactUpdates.injection.injectBatchingStrategy(ReactDefaultBatchingStrategy);
+
+ReactHostComponent.injection.injectGenericComponentClass(ReactTestComponent);
+ReactHostComponent.injection.injectTextComponentClass(ReactTestTextComponent);
+ReactEmptyComponent.injection.injectEmptyComponentFactory(function() {
+  return new ReactTestEmptyComponent();
+});
+
+ReactComponentEnvironment.injection.injectEnvironment({
+  processChildrenUpdates: function() {},
+  replaceNodeWithMarkup: function() {},
+});
+
+var ReactTestRenderer = {
+  create: ReactTestMount.render,
+  /* eslint-disable camelcase */
+  unstable_batchedUpdates: ReactUpdates.batchedUpdates,
+  /* eslint-enable camelcase */
+};
+
+module.exports = ReactTestRenderer;
diff --git a/src/renderers/testing/ReactTestTextComponent.js b/src/renderers/testing/ReactTestTextComponent.js
new file mode 100644
index 000000000000..deb2c674e112
--- /dev/null
+++ b/src/renderers/testing/ReactTestTextComponent.js
@@ -0,0 +1,37 @@
+/**
+ * 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 ReactTestTextComponent
+ * @flow
+ */
+
+'use strict';
+
+import type {ReactText} from 'ReactTypes';
+
+class ReactTestTextComponent {
+  _currentElement: ReactText;
+
+  constructor(element: ReactText) {
+    this._currentElement = element;
+  }
+
+  receiveComponent(nextElement: ReactText) {
+    this._currentElement = nextElement;
+  }
+
+  toJSON(): ReactText {
+    return this._currentElement;
+  }
+
+  mountComponent(): void {}
+  getHostNode(): void {}
+  unmountComponent(): void {}
+}
+
+module.exports = ReactTestTextComponent;
diff --git a/src/renderers/testing/__tests__/ReactTestRenderer-test.js b/src/renderers/testing/__tests__/ReactTestRenderer-test.js
new file mode 100644
index 000000000000..bc793202a49e
--- /dev/null
+++ b/src/renderers/testing/__tests__/ReactTestRenderer-test.js
@@ -0,0 +1,403 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var React = require('React');
+var ReactTestRenderer = require('ReactTestRenderer');
+
+describe('ReactTestRenderer', () => {
+  it('renders a simple component', () => {
+    function Link() {
+      return <a role="link" />;
+    }
+    var renderer = ReactTestRenderer.create(<Link />);
+    expect(renderer.toJSON()).toEqual({
+      type: 'a',
+      props: {role: 'link'},
+      children: null,
+    });
+  });
+
+  it('renders a top-level empty component', () => {
+    function Empty() {
+      return null;
+    }
+    var renderer = ReactTestRenderer.create(<Empty />);
+    expect(renderer.toJSON()).toEqual(null);
+  });
+
+  it('exposes a type flag', () => {
+    function Link() {
+      return <a role="link" />;
+    }
+    var renderer = ReactTestRenderer.create(<Link />);
+    var object = renderer.toJSON();
+    expect(object.$$typeof).toBe(Symbol.for('react.test.json'));
+
+    // $$typeof should not be enumerable.
+    for (var key in object) {
+      if (Object.prototype.hasOwnProperty.call(object, key)) {
+        expect(key).not.toBe('$$typeof');
+      }
+    }
+  });
+
+  it('renders some basics with an update', () => {
+    var renders = 0;
+
+    class Component extends React.Component {
+      state = {x: 3};
+
+      render() {
+        renders++;
+        return (
+          <div className="purple">
+            {this.state.x}
+            <Child />
+            <Null />
+          </div>
+        );
+      }
+
+      componentDidMount() {
+        this.setState({x: 7});
+      }
+    }
+
+    var Child = () => {
+      renders++;
+      return <moo />;
+    };
+
+    var Null = () => {
+      renders++;
+      return null;
+    };
+
+    var renderer = ReactTestRenderer.create(<Component />);
+    expect(renderer.toJSON()).toEqual({
+      type: 'div',
+      props: {className: 'purple'},
+      children: [7, {type: 'moo', props: {}, children: null}],
+    });
+    expect(renders).toBe(6);
+  });
+
+  it('exposes the instance', () => {
+    class Mouse extends React.Component {
+      constructor() {
+        super();
+        this.state = {mouse: 'mouse'};
+      }
+      handleMoose() {
+        this.setState({mouse: 'moose'});
+      }
+      render() {
+        return <div>{this.state.mouse}</div>;
+      }
+    }
+    var renderer = ReactTestRenderer.create(<Mouse />);
+
+    expect(renderer.toJSON()).toEqual({
+      type: 'div',
+      props: {},
+      children: ['mouse'],
+    });
+
+    var mouse = renderer.getInstance();
+    mouse.handleMoose();
+    expect(renderer.toJSON()).toEqual({
+      type: 'div',
+      props: {},
+      children: ['moose'],
+    });
+  });
+
+  it('updates types', () => {
+    var renderer = ReactTestRenderer.create(<div>mouse</div>);
+    expect(renderer.toJSON()).toEqual({
+      type: 'div',
+      props: {},
+      children: ['mouse'],
+    });
+
+    renderer.update(<span>mice</span>);
+    expect(renderer.toJSON()).toEqual({
+      type: 'span',
+      props: {},
+      children: ['mice'],
+    });
+  });
+
+  it('updates children', () => {
+    var renderer = ReactTestRenderer.create(
+      <div>
+        <span key="a">A</span>
+        <span key="b">B</span>
+        <span key="c">C</span>
+      </div>,
+    );
+    expect(renderer.toJSON()).toEqual({
+      type: 'div',
+      props: {},
+      children: [
+        {type: 'span', props: {}, children: ['A']},
+        {type: 'span', props: {}, children: ['B']},
+        {type: 'span', props: {}, children: ['C']},
+      ],
+    });
+
+    renderer.update(
+      <div>
+        <span key="d">D</span>
+        <span key="c">C</span>
+        <span key="b">B</span>
+      </div>,
+    );
+    expect(renderer.toJSON()).toEqual({
+      type: 'div',
+      props: {},
+      children: [
+        {type: 'span', props: {}, children: ['D']},
+        {type: 'span', props: {}, children: ['C']},
+        {type: 'span', props: {}, children: ['B']},
+      ],
+    });
+  });
+
+  it('does the full lifecycle', () => {
+    var log = [];
+    class Log extends React.Component {
+      render() {
+        log.push('render ' + this.props.name);
+        return <div />;
+      }
+      componentDidMount() {
+        log.push('mount ' + this.props.name);
+      }
+      componentWillUnmount() {
+        log.push('unmount ' + this.props.name);
+      }
+    }
+
+    var renderer = ReactTestRenderer.create(<Log key="foo" name="Foo" />);
+    renderer.update(<Log key="bar" name="Bar" />);
+    renderer.unmount();
+
+    expect(log).toEqual([
+      'render Foo',
+      'mount Foo',
+      'unmount Foo',
+      'render Bar',
+      'mount Bar',
+      'unmount Bar',
+    ]);
+  });
+
+  it('gives a ref to native components', () => {
+    var log = [];
+    ReactTestRenderer.create(<div ref={r => log.push(r)} />);
+    expect(log).toEqual([null]);
+  });
+
+  it('warns correctly for refs on SFCs', () => {
+    spyOn(console, 'error');
+    function Bar() {
+      return <div>Hello, world</div>;
+    }
+    class Foo extends React.Component {
+      render() {
+        return <Bar ref="foo" />;
+      }
+    }
+    class Baz extends React.Component {
+      render() {
+        return <div ref="baz" />;
+      }
+    }
+    ReactTestRenderer.create(<Baz />);
+    ReactTestRenderer.create(<Foo />);
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'Stateless function components cannot be given refs ' +
+        '(See ref "foo" in Bar created by Foo). ' +
+        'Attempts to access this ref will fail.',
+    );
+  });
+
+  it('allows an optional createNodeMock function', () => {
+    var mockDivInstance = {appendChild: () => {}};
+    var mockInputInstance = {focus: () => {}};
+    var mockListItemInstance = {click: () => {}};
+    var mockAnchorInstance = {hover: () => {}};
+    var log = [];
+    class Foo extends React.Component {
+      componentDidMount() {
+        log.push(this.refs.bar);
+      }
+      render() {
+        return <a ref="bar">Hello, world</a>;
+      }
+    }
+    function createNodeMock(element) {
+      switch (element.type) {
+        case 'div':
+          return mockDivInstance;
+        case 'input':
+          return mockInputInstance;
+        case 'li':
+          return mockListItemInstance;
+        case 'a':
+          return mockAnchorInstance;
+        default:
+          return {};
+      }
+    }
+    ReactTestRenderer.create(<div ref={r => log.push(r)} />, {createNodeMock});
+    ReactTestRenderer.create(<input ref={r => log.push(r)} />, {
+      createNodeMock,
+    });
+    ReactTestRenderer.create(
+      <div>
+        <span>
+          <ul>
+            <li ref={r => log.push(r)} />
+          </ul>
+          <ul>
+            <li ref={r => log.push(r)} />
+            <li ref={r => log.push(r)} />
+          </ul>
+        </span>
+      </div>,
+      {createNodeMock, foobar: true},
+    );
+    ReactTestRenderer.create(<Foo />, {createNodeMock});
+    ReactTestRenderer.create(<div ref={r => log.push(r)} />);
+    ReactTestRenderer.create(<div ref={r => log.push(r)} />, {});
+    expect(log).toEqual([
+      mockDivInstance,
+      mockInputInstance,
+      mockListItemInstance,
+      mockListItemInstance,
+      mockListItemInstance,
+      mockAnchorInstance,
+      null,
+      null,
+    ]);
+  });
+
+  it('supports unmounting when using refs', () => {
+    class Foo extends React.Component {
+      render() {
+        return <div ref="foo" />;
+      }
+    }
+    const inst = ReactTestRenderer.create(<Foo />, {
+      createNodeMock: () => 'foo',
+    });
+    expect(() => inst.unmount()).not.toThrow();
+  });
+
+  it('supports unmounting inner instances', () => {
+    let count = 0;
+    class Foo extends React.Component {
+      componentWillUnmount() {
+        count++;
+      }
+      render() {
+        return <div />;
+      }
+    }
+    const inst = ReactTestRenderer.create(<div><Foo /></div>, {
+      createNodeMock: () => 'foo',
+    });
+    expect(() => inst.unmount()).not.toThrow();
+    expect(count).toEqual(1);
+  });
+
+  it('supports updates when using refs', () => {
+    const log = [];
+    const createNodeMock = element => {
+      log.push(element.type);
+      return element.type;
+    };
+    class Foo extends React.Component {
+      render() {
+        return this.props.useDiv ? <div ref="foo" /> : <span ref="foo" />;
+      }
+    }
+    const inst = ReactTestRenderer.create(<Foo useDiv={true} />, {
+      createNodeMock,
+    });
+    inst.update(<Foo useDiv={false} />);
+    // It's called with 'div' twice (mounting and unmounting)
+    expect(log).toEqual(['div', 'div', 'span']);
+  });
+
+  it('supports error boundaries', () => {
+    var log = [];
+    class Angry extends React.Component {
+      render() {
+        log.push('Angry render');
+        throw new Error('Please, do not render me.');
+      }
+      componentDidMount() {
+        log.push('Angry componentDidMount');
+      }
+      componentWillUnmount() {
+        log.push('Angry componentWillUnmount');
+      }
+    }
+
+    class Boundary extends React.Component {
+      constructor(props) {
+        super(props);
+        this.state = {error: false};
+      }
+      render() {
+        log.push('Boundary render');
+        if (!this.state.error) {
+          return (
+            <div><button onClick={this.onClick}>ClickMe</button><Angry /></div>
+          );
+        } else {
+          return <div>Happy Birthday!</div>;
+        }
+      }
+      componentDidMount() {
+        log.push('Boundary componentDidMount');
+      }
+      componentWillUnmount() {
+        log.push('Boundary componentWillUnmount');
+      }
+      onClick() {
+        /* do nothing */
+      }
+      unstable_handleError() {
+        this.setState({error: true});
+      }
+    }
+
+    var renderer = ReactTestRenderer.create(<Boundary />);
+    expect(renderer.toJSON()).toEqual({
+      type: 'div',
+      props: {},
+      children: ['Happy Birthday!'],
+    });
+    expect(log).toEqual([
+      'Boundary render',
+      'Angry render',
+      'Boundary render',
+      'Boundary componentDidMount',
+    ]);
+  });
+});
diff --git a/src/shared/types/ReactPropTypeLocationNames.js b/src/shared/types/ReactPropTypeLocationNames.js
new file mode 100644
index 000000000000..f416a1344f60
--- /dev/null
+++ b/src/shared/types/ReactPropTypeLocationNames.js
@@ -0,0 +1,29 @@
+/**
+ * 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.
+ *
+ * @flow
+ * @providesModule ReactPropTypeLocationNames
+ */
+
+'use strict';
+
+import type {ReactPropTypeLocations} from 'ReactPropTypeLocations';
+
+type NamesType = {[key: ReactPropTypeLocations]: string};
+
+var ReactPropTypeLocationNames: NamesType = {};
+
+if (__DEV__) {
+  ReactPropTypeLocationNames = {
+    prop: 'prop',
+    context: 'context',
+    childContext: 'child context',
+  };
+}
+
+module.exports = ReactPropTypeLocationNames;
diff --git a/src/shared/types/ReactPropTypeLocations.js b/src/shared/types/ReactPropTypeLocations.js
new file mode 100644
index 000000000000..9b0752a75f64
--- /dev/null
+++ b/src/shared/types/ReactPropTypeLocations.js
@@ -0,0 +1,15 @@
+/**
+ * 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.
+ *
+ * @flow
+ * @providesModule ReactPropTypeLocations
+ */
+
+'use strict';
+
+export type ReactPropTypeLocations = 'prop' | 'context' | 'childContext';
diff --git a/src/shared/types/ReactPropTypesSecret.js b/src/shared/types/ReactPropTypesSecret.js
new file mode 100644
index 000000000000..0f47ff2afb91
--- /dev/null
+++ b/src/shared/types/ReactPropTypesSecret.js
@@ -0,0 +1,17 @@
+/**
+ * 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.
+ *
+ * @flow
+ * @providesModule ReactPropTypesSecret
+ */
+
+'use strict';
+
+const ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED';
+
+module.exports = ReactPropTypesSecret;
diff --git a/src/shared/types/checkReactTypeSpec.js b/src/shared/types/checkReactTypeSpec.js
new file mode 100644
index 000000000000..44f45786b91a
--- /dev/null
+++ b/src/shared/types/checkReactTypeSpec.js
@@ -0,0 +1,133 @@
+/**
+ * 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 checkReactTypeSpec
+ */
+
+'use strict';
+
+var ReactPropTypeLocationNames = require('ReactPropTypeLocationNames');
+var ReactPropTypesSecret = require('ReactPropTypesSecret');
+
+var invariant = require('invariant');
+var warning = require('warning');
+
+import type {ReactPropTypeLocations} from 'ReactPropTypeLocations';
+
+var ReactComponentTreeHook;
+
+if (
+  typeof process !== 'undefined' &&
+  process.env &&
+  process.env.NODE_ENV === '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 = require('ReactComponentTreeHook');
+}
+
+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: ReactPropTypeLocations,
+  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.
+        invariant(
+          typeof typeSpecs[typeSpecName] === 'function',
+          '%s: %s type `%s` is invalid; it must be a function, usually from ' +
+            'React.PropTypes.',
+          componentName || 'React class',
+          ReactPropTypeLocationNames[location],
+          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',
+        ReactPropTypeLocationNames[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 componentStackInfo = '';
+
+        if (__DEV__) {
+          if (!ReactComponentTreeHook) {
+            ReactComponentTreeHook = require('ReactComponentTreeHook');
+          }
+          if (debugID !== null) {
+            componentStackInfo = ReactComponentTreeHook.getStackAddendumByID(
+              debugID,
+            );
+          } else if (element !== null) {
+            componentStackInfo = ReactComponentTreeHook.getCurrentStackAddendum(
+              element,
+            );
+          }
+        }
+
+        warning(
+          false,
+          'Failed %s type: %s%s',
+          location,
+          error.message,
+          componentStackInfo,
+        );
+      }
+    }
+  }
+}
+
+module.exports = checkReactTypeSpec;
diff --git a/src/shared/utils/KeyEscapeUtils.js b/src/shared/utils/KeyEscapeUtils.js
new file mode 100644
index 000000000000..b7ed7a00b296
--- /dev/null
+++ b/src/shared/utils/KeyEscapeUtils.js
@@ -0,0 +1,60 @@
+/**
+ * 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 KeyEscapeUtils
+ * @flow
+ */
+
+'use strict';
+
+/**
+ * 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: string): string {
+  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: string): string {
+  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;
diff --git a/src/shared/utils/PooledClass.js b/src/shared/utils/PooledClass.js
index 5000ca726fc0..10674b8d9a1d 100644
--- a/src/shared/utils/PooledClass.js
+++ b/src/shared/utils/PooledClass.js
@@ -7,6 +7,7 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule PooledClass
+ * @flow
  */
 
 'use strict';
@@ -64,22 +65,11 @@ var fourArgumentPooler = function(a1, a2, a3, a4) {
   }
 };
 
-var fiveArgumentPooler = function(a1, a2, a3, a4, a5) {
-  var Klass = this;
-  if (Klass.instancePool.length) {
-    var instance = Klass.instancePool.pop();
-    Klass.call(instance, a1, a2, a3, a4, a5);
-    return instance;
-  } else {
-    return new Klass(a1, a2, a3, a4, a5);
-  }
-};
-
 var standardReleaser = function(instance) {
   var Klass = this;
   invariant(
     instance instanceof Klass,
-    'Trying to release an instance into a pool of a different type.'
+    'Trying to release an instance into a pool of a different type.',
   );
   instance.destructor();
   if (Klass.instancePool.length < Klass.poolSize) {
@@ -90,17 +80,27 @@ var standardReleaser = function(instance) {
 var DEFAULT_POOL_SIZE = 10;
 var DEFAULT_POOLER = oneArgumentPooler;
 
+type Pooler = any;
+
 /**
  * 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 (optional).
+ * prototypical `destructor` on instances.
  *
  * @param {Function} CopyConstructor Constructor that can be used to reset.
  * @param {Function} pooler Customizable pooler.
  */
-var addPoolingTo = function(CopyConstructor, pooler) {
-  var NewKlass = CopyConstructor;
+var addPoolingTo = function<T>(
+  CopyConstructor: Class<T>,
+  pooler: Pooler,
+): Class<T> & {
+  getPooled(): /* arguments of the constructor */ T,
+  release(): void,
+} {
+  // Casting as any so that flow ignores the actual implementation and trusts
+  // it to match the type we declared
+  var NewKlass = (CopyConstructor: any);
   NewKlass.instancePool = [];
   NewKlass.getPooled = pooler || DEFAULT_POOLER;
   if (!NewKlass.poolSize) {
@@ -112,11 +112,10 @@ var addPoolingTo = function(CopyConstructor, pooler) {
 
 var PooledClass = {
   addPoolingTo: addPoolingTo,
-  oneArgumentPooler: oneArgumentPooler,
-  twoArgumentPooler: twoArgumentPooler,
-  threeArgumentPooler: threeArgumentPooler,
-  fourArgumentPooler: fourArgumentPooler,
-  fiveArgumentPooler: fiveArgumentPooler,
+  oneArgumentPooler: (oneArgumentPooler: Pooler),
+  twoArgumentPooler: (twoArgumentPooler: Pooler),
+  threeArgumentPooler: (threeArgumentPooler: Pooler),
+  fourArgumentPooler: (fourArgumentPooler: Pooler),
 };
 
 module.exports = PooledClass;
diff --git a/src/shared/utils/ReactElementSymbol.js b/src/shared/utils/ReactElementSymbol.js
new file mode 100644
index 000000000000..9d59d505e78b
--- /dev/null
+++ b/src/shared/utils/ReactElementSymbol.js
@@ -0,0 +1,21 @@
+/**
+ * Copyright 2014-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 ReactElementSymbol
+ * @flow
+ */
+
+'use strict';
+
+// 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;
diff --git a/src/shared/utils/__tests__/KeyEscapeUtils-test.js b/src/shared/utils/__tests__/KeyEscapeUtils-test.js
new file mode 100644
index 000000000000..eed9f46785b6
--- /dev/null
+++ b/src/shared/utils/__tests__/KeyEscapeUtils-test.js
@@ -0,0 +1,38 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+var KeyEscapeUtils;
+
+describe('KeyEscapeUtils', () => {
+  beforeEach(() => {
+    jest.resetModuleRegistry();
+
+    KeyEscapeUtils = require('KeyEscapeUtils');
+  });
+
+  describe('escape', () => {
+    it('should properly escape and wrap user defined keys', () => {
+      expect(KeyEscapeUtils.escape('1')).toBe('$1');
+      expect(KeyEscapeUtils.escape('1=::=2')).toBe('$1=0=2=2=02');
+    });
+  });
+
+  describe('unescape', () => {
+    it('should properly unescape and unwrap user defined keys', () => {
+      expect(KeyEscapeUtils.unescape('.1')).toBe('1');
+      expect(KeyEscapeUtils.unescape('$1')).toBe('1');
+      expect(KeyEscapeUtils.unescape('.$1')).toBe('1');
+      expect(KeyEscapeUtils.unescape('$1=0=2=2=02')).toBe('1=::=2');
+    });
+  });
+});
diff --git a/src/shared/utils/__tests__/OrderedMap-test.js b/src/shared/utils/__tests__/OrderedMap-test.js
deleted file mode 100644
index cdcff5aa4aaf..000000000000
--- a/src/shared/utils/__tests__/OrderedMap-test.js
+++ /dev/null
@@ -1,941 +0,0 @@
-/**
- * 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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-var OrderedMap;
-
-/**
- * Shared, reusable objects.
- */
-var hasEmptyStringKey = {
-  'thisKeyIsFine': {data: []},
-  '': {thisShouldCauseAFailure: []},
-  'thisKeyIsAlsoFine': {data: []},
-};
-
-/**
- * Used as map/forEach callback.
- */
-var duplicate = function(itm, key, count) {
-  return {
-    uniqueID: itm.uniqueID,
-    val: itm.val + key + count + this.justToTestScope,
-  };
-};
-
-// Should not be allowed - because then null/'null' become impossible to
-// distinguish. Every key MUST be a string period!
-var hasNullAndUndefStringKey = [
-  {uniqueID: 'undefined', val: 'thisIsUndefined'},
-  {uniqueID: 'null', val: 'thisIsNull'},
-];
-var hasNullKey = [
-  {uniqueID: 'thisKeyIsFine', data: []},
-  {uniqueID: 'thisKeyIsAlsoFine', data: []},
-  {uniqueID: null, data: []},
-];
-
-var hasObjectKey = [
-  {uniqueID: 'thisKeyIsFine', data: []},
-  {uniqueID: 'thisKeyIsAlsoFine', data: []},
-  {uniqueID: {}, data: []},
-];
-
-var hasArrayKey = [
-  {uniqueID: 'thisKeyIsFine', data: []},
-  {uniqueID: 'thisKeyIsAlsoFine', data: []},
-  {uniqueID: [], data: []},
-];
-
-// This should be allowed
-var hasNullStringKey = [
-  {uniqueID: 'thisKeyIsFine', data: []},
-  {uniqueID: 'thisKeyIsAlsoFine', data: []},
-  {uniqueID: 'null', data: []},
-];
-
-var hasUndefinedKey = [
-  {uniqueID: 'thisKeyIsFine', data: []},
-  {uniqueID: 'thisKeyIsAlsoFine', data: []},
-  {uniqueID: undefined, data: []},
-];
-
-var hasUndefinedStringKey = [
-  {uniqueID: 'thisKeyIsFine', data: []},
-  {uniqueID: 'thisKeyIsAlsoFine', data: []},
-  {uniqueID: 'undefined', data: []},
-];
-
-var hasPositiveNumericKey = [
-  {uniqueID: 'notANumber', data: []},
-  {uniqueID: '5', data: []},
-  {uniqueID: 'notAnotherNumber', data: []},
-];
-
-var hasZeroStringKey = [
-  {uniqueID: 'greg', data: 'grego'},
-  {uniqueID: '0', data: '0o'},
-  {uniqueID: 'tom', data: 'tomo'},
-];
-
-var hasZeroNumberKey = [
-  {uniqueID: 'greg', data: 'grego'},
-  {uniqueID: 0, data: '0o'},
-  {uniqueID: 'tom', data: 'tomo'},
-];
-
-var hasAllNumericStringKeys = [
-  {uniqueID: '0', name: 'Gregory'},
-  {uniqueID: '2', name: 'James'},
-  {uniqueID: '1', name: 'Tom'},
-];
-
-var hasAllNumericKeys = [
-  {uniqueID: 0, name: 'Gregory'},
-  {uniqueID: 2, name: 'James'},
-  {uniqueID: 1, name: 'Tom'},
-];
-
-var hasAllValidKeys = [
-  {uniqueID: 'keyOne', value: 'valueOne'},
-  {uniqueID: 'keyTwo', value: 'valueTwo'},
-];
-
-var hasDuplicateKeys = [
-  {uniqueID: 'keyOne', value: 'valueOne'},
-  {uniqueID: 'keyTwo', value: 'valueTwo'},
-  {uniqueID: 'keyOne', value: 'valueThree'},
-];
-
-var idEntities = [
-  {uniqueID: 'greg', name: 'Gregory'},
-  {uniqueID: 'james', name: 'James'},
-  {uniqueID: 'tom', name: 'Tom'},
-];
-
-var hasEmptyKey = [
-  {uniqueID: 'greg', name: 'Gregory'},
-  {uniqueID: '', name: 'James'},
-  {uniqueID: 'tom', name: 'Tom'},
-];
-
-var extractUniqueID = function(entity) {
-  return entity.uniqueID;
-};
-
-describe('OrderedMap', function() {
-  beforeEach(function() {
-    jest.resetModuleRegistry();
-    OrderedMap = require('OrderedMap');
-  });
-
-  it('should create according to simple object with keys', function() {
-    OrderedMap.fromArray(hasAllValidKeys, extractUniqueID);
-    // Iterate over and ensure key order.
-  });
-
-  it('should create from array when providing an identity CB', function() {
-    expect(function() {
-      OrderedMap.fromArray(idEntities, extractUniqueID);
-    }).not.toThrow();
-  });
-
-  it('should throw if constructing from Array without identity CB', function() {
-    OrderedMap.fromArray(idEntities, extractUniqueID);
-    // Iterate and ensure key order
-  });
-
-  it('should not throw when fromArray extracts a numeric key', function() {
-    expect(function() {
-      OrderedMap.fromArray(hasPositiveNumericKey, extractUniqueID);
-    }).not.toThrow();
-
-  });
-
-  it('should throw when any key is the empty string', function() {
-    expect(function() {
-      OrderedMap.fromArray(hasEmptyKey, extractUniqueID);
-    }).toThrow();
-  });
-
-  it('should not throw when a key is the string "undefined" or "null"',
-    function() {
-      var om = OrderedMap.fromArray(hasNullAndUndefStringKey, extractUniqueID);
-      expect(om.length).toBe(2);
-      expect(om.indexOfKey('undefined')).toBe(0);
-      expect(om.indexOfKey('null')).toBe(1);
-      expect(om.keyAfter('undefined')).toBe('null');
-      expect(om.keyAfter('null')).toBe(undefined);
-      expect(om.keyBefore('undefined')).toBe(undefined);
-      expect(om.has('undefined')).toBe(true);
-      expect(om.has('null')).toBe(true);
-      expect(om.get('undefined').val).toBe('thisIsUndefined');
-      expect(om.get('null').val).toBe('thisIsNull');
-    });
-
-
-  /**
-   * Numeric keys are cast to strings.
-   */
-  it('should not throw when a key is the number zero', function() {
-    var om = OrderedMap.fromArray(hasZeroNumberKey, extractUniqueID);
-    expect(om.length).toBe(3);
-    expect(om.indexOfKey('0')).toBe(1);
-    expect(om.indexOfKey(0)).toBe(1);
-  });
-
-  it('should throw when any key is falsey', function() {
-    expect(function() {
-      OrderedMap.fromArray(hasEmptyStringKey, extractUniqueID);
-    }).toThrow();
-
-    expect(function() {
-      OrderedMap.fromArray(hasNullKey, extractUniqueID);
-    }).toThrow();
-
-    expect(function() {
-      OrderedMap.fromArray(hasUndefinedKey, extractUniqueID);
-    }).toThrow();
-  });
-
-  it('should not throw on string keys "undefined/null"', function() {
-    expect(function() {
-      OrderedMap.fromArray(hasNullStringKey, extractUniqueID);
-    }).not.toThrow();
-
-    expect(function() {
-      OrderedMap.fromArray(hasUndefinedStringKey, extractUniqueID);
-    }).not.toThrow();
-  });
-
-  it('should throw on extracting keys that are not strings/nums', function() {
-    expect(function() {
-      OrderedMap.fromArray(hasObjectKey, extractUniqueID);
-    }).toThrow();
-
-    expect(function() {
-      OrderedMap.fromArray(hasArrayKey, extractUniqueID);
-    }).toThrow();
-  });
-
-  it('should throw if instantiating with duplicate key', function() {
-    expect(function() {
-      OrderedMap.fromArray(hasDuplicateKeys, extractUniqueID);
-    }).toThrow();
-  });
-
-  it('should not throw when a key is the string "0"', function() {
-    var verifyOM = function(om) {
-      expect(om.length).toBe(3);
-      expect(om.indexOfKey('greg')).toBe(0);
-      expect(om.indexOfKey('0')).toBe(1);
-      expect(om.indexOfKey(0)).toBe(1); // Casts on writes and reads.
-      expect(om.indexOfKey('tom')).toBe(2);
-      expect(om.keyAfter('greg')).toBe('0');
-      expect(om.keyAfter('0')).toBe('tom');
-      expect(om.keyAfter(0)).toBe('tom');
-      expect(om.keyAfter('tom')).toBe(undefined);
-      expect(om.keyBefore('greg')).toBe(undefined);
-      expect(om.keyBefore(0)).toBe('greg');
-      expect(om.keyBefore('0')).toBe('greg');
-      expect(om.keyBefore('tom')).toBe('0');
-      expect(om.has('undefined')).toBe(false);
-      expect(om.has(0)).toBe(true);
-      expect(om.has('0')).toBe(true);
-    };
-    verifyOM(OrderedMap.fromArray(hasZeroStringKey, extractUniqueID));
-    verifyOM(OrderedMap.fromArray(hasZeroNumberKey, extractUniqueID));
-  });
-
-  it('should throw when getting invalid public key', function() {
-    var om = OrderedMap.fromArray(hasAllValidKeys, extractUniqueID);
-    expect(function() {
-      om.has(undefined);
-    }).toThrow();
-    expect(function() {
-      om.get(undefined);
-    }).toThrow();
-    expect(function() {
-      om.has(null);
-    }).toThrow();
-    expect(function() {
-      om.get(null);
-    }).toThrow();
-    expect(function() {
-      om.has('');
-    }).toThrow();
-    expect(function() {
-      om.get('');
-    }).toThrow();
-  });
-
-  it('should throw when any key is falsey', function() {
-    expect(function() {
-      OrderedMap.fromArray(hasEmptyStringKey, extractUniqueID);
-    }).toThrow();
-
-    expect(function() {
-      OrderedMap.fromArray(hasNullKey, extractUniqueID);
-    }).toThrow();
-
-    expect(function() {
-      OrderedMap.fromArray(hasUndefinedKey, extractUniqueID);
-    }).toThrow();
-  });
-
-
-  it('should throw when fromArray is passed crazy args', function() {
-    // Test passing another OrderedMap (when it expects a plain object.)
-    // This is probably not what you meant to do! We should error.
-    var validOM = OrderedMap.fromArray(hasAllValidKeys, extractUniqueID);
-    expect(function() {
-      OrderedMap.fromArray({uniqueID: 'asdf'}, extractUniqueID);
-    }).toThrow();
-    expect(function() {
-      OrderedMap.fromArray(validOM, extractUniqueID);
-    }).toThrow();
-  });
-
-  it('should throw when fromArray is passed crazy things', function() {
-    expect(function() {
-      OrderedMap.fromArray(null, extractUniqueID);
-    }).toThrow();
-    expect(function() {
-      OrderedMap.fromArray('stringgg', extractUniqueID);
-    }).toThrow();
-    expect(function() {
-      OrderedMap.fromArray(undefined, extractUniqueID);
-    }).toThrow();
-    expect(function() {
-      OrderedMap.fromArray(new Date(), extractUniqueID);
-    }).toThrow();
-    expect(function() {
-      OrderedMap.fromArray({}, extractUniqueID);
-    }).toThrow();
-
-    // Test failure without extractor
-    expect(function() {
-      OrderedMap.fromArray(idEntities);
-    }).toThrow();
-    expect(function() {
-      OrderedMap.fromArray(idEntities, extractUniqueID);
-    }).not.toThrow();
-  });
-
-  // Testing methods that accept other `OrderedMap`s.
-  it('should throw when from/merge is passed an non-OrderedMap.', function() {
-    // Test passing an array to construction.
-    expect(function() {
-      OrderedMap.from(idEntities, extractUniqueID);
-    }).toThrow();
-
-    // Test passing an array to merge.
-    expect(function() {
-      OrderedMap.fromArray(idEntities, extractUniqueID)
-        .merge(idEntities, extractUniqueID);
-    }).toThrow();
-
-
-    // Test passing a plain object to merge.
-    expect(function() {
-      OrderedMap.fromArray(
-        idEntities,
-        extractUniqueID
-      ).merge({blah: 'willFail'});
-    }).toThrow();
-  });
-
-  it('should throw when accessing key before/after of non-key', function() {
-    var om = OrderedMap.fromArray(
-      [
-        {uniqueID: 'first'},
-        {uniqueID: 'two'},
-      ], extractUniqueID
-    );
-    expect(function() {
-      om.keyBefore('dog');
-    }).toThrow();
-    expect(function() {
-      om.keyAfter('cat');
-    }).toThrow();
-    expect(function() {
-      om.keyAfter(null);
-    }).toThrow();
-    expect(function() {
-      om.keyAfter(undefined);
-    }).toThrow();
-  });
-
-  it('should throw passing invalid/not-present-keys to before/after',
-    function() {
-      var om = OrderedMap.fromArray([
-        {uniqueID: 'one', val: 'first'},
-        {uniqueID: 'two', val: 'second'},
-        {uniqueID: 'three', val: 'third'},
-        {uniqueID: 'four', val: 'fourth'},
-      ], extractUniqueID);
-
-      expect(function() {
-        om.keyBefore('');
-      }).toThrow();
-      expect(function() {
-        om.keyBefore(null);
-      }).toThrow();
-      expect(function() {
-        om.keyBefore(undefined);
-      }).toThrow();
-      expect(function() {
-        om.keyBefore('notInTheOrderedMap!');
-      }).toThrow();
-
-      expect(function() {
-        om.keyAfter('');
-      }).toThrow();
-      expect(function() {
-        om.keyAfter(null);
-      }).toThrow();
-      expect(function() {
-        om.keyAfter(undefined);
-      }).toThrow();
-      expect(function() {
-        om.keyAfter('notInTheOrderedMap!');
-      }).toThrow();
-
-      expect(function() {
-        om.nthKeyAfter('', 1);
-      }).toThrow();
-      expect(function() {
-        om.nthKeyAfter(null, 1);
-      }).toThrow();
-      expect(function() {
-        om.nthKeyAfter(undefined, 1);
-      }).toThrow();
-      expect(function() {
-        om.nthKeyAfter('notInTheOrderedMap!', 1);
-      }).toThrow();
-
-      expect(function() {
-        om.nthKeyBefore('', 1);
-      }).toThrow();
-      expect(function() {
-        om.nthKeyBefore(null, 1);
-      }).toThrow();
-      expect(function() {
-        om.nthKeyBefore(undefined, 1);
-      }).toThrow();
-      expect(function() {
-        om.nthKeyBefore('notInTheOrderedMap!', 1);
-      }).toThrow();
-    });
-
-  it('should correctly determine the nth key after before', function() {
-    var om = OrderedMap.fromArray([
-      {uniqueID: 'one', val: 'first'},
-      {uniqueID: 'two', val: 'second'},
-      {uniqueID: 'three', val: 'third'},
-      {uniqueID: 'four', val: 'fourth'},
-    ], extractUniqueID);
-    expect(om.keyBefore('one')).toBe(undefined); // first key
-    expect(om.keyBefore('two')).toBe('one');
-    expect(om.keyBefore('three')).toBe('two');
-    expect(om.keyBefore('four')).toBe('three');
-
-    expect(om.keyAfter('one')).toBe('two'); // first key
-    expect(om.keyAfter('two')).toBe('three');
-    expect(om.keyAfter('three')).toBe('four');
-    expect(om.keyAfter('four')).toBe(undefined);
-
-    expect(om.nthKeyBefore('one', 0)).toBe('one'); // first key
-    expect(om.nthKeyBefore('one', 1)).toBe(undefined);
-    expect(om.nthKeyBefore('one', 2)).toBe(undefined);
-    expect(om.nthKeyBefore('two', 0)).toBe('two');
-    expect(om.nthKeyBefore('two', 1)).toBe('one');
-    expect(om.nthKeyBefore('four', 0)).toBe('four');
-    expect(om.nthKeyBefore('four', 1)).toBe('three');
-
-    expect(om.nthKeyAfter('one', 0)).toBe('one');
-    expect(om.nthKeyAfter('one', 1)).toBe('two');
-    expect(om.nthKeyAfter('one', 2)).toBe('three');
-    expect(om.nthKeyAfter('two', 0)).toBe('two');
-    expect(om.nthKeyAfter('two', 1)).toBe('three');
-    expect(om.nthKeyAfter('four', 0)).toBe('four');
-    expect(om.nthKeyAfter('four', 1)).toBe(undefined);
-  });
-
-  it('should compute key indices correctly', function() {
-    var om = OrderedMap.fromArray([
-      {uniqueID: 'one', val: 'first'},
-      {uniqueID: 'two', val: 'second'},
-    ], extractUniqueID);
-    expect(om.keyAtIndex(0)).toBe('one');
-    expect(om.keyAtIndex(1)).toBe('two');
-    expect(om.keyAtIndex(2)).toBe(undefined);
-    expect(om.indexOfKey('one')).toBe(0);
-    expect(om.indexOfKey('two')).toBe(1);
-    expect(om.indexOfKey('nope')).toBe(undefined);
-    expect(function() {
-      om.indexOfKey(null);
-    }).toThrow();
-    expect(function() {
-      om.indexOfKey(undefined);
-    }).toThrow();
-    expect(function() {
-      om.indexOfKey(''); // Empty key is not allowed
-    }).toThrow();
-  });
-
-  it('should compute indices on array that extracted numeric ids', function() {
-    var som = OrderedMap.fromArray(hasZeroStringKey, extractUniqueID);
-    expect(som.keyAtIndex(0)).toBe('greg');
-    expect(som.keyAtIndex(1)).toBe('0');
-    expect(som.keyAtIndex(2)).toBe('tom');
-    expect(som.indexOfKey('greg')).toBe(0);
-    expect(som.indexOfKey('0')).toBe(1);
-    expect(som.indexOfKey('tom')).toBe(2);
-
-
-    var verifyNumericKeys = function(nom) {
-      expect(nom.keyAtIndex(0)).toBe('0');
-      expect(nom.keyAtIndex(1)).toBe('2');
-      expect(nom.keyAtIndex(2)).toBe('1');
-      expect(nom.indexOfKey('0')).toBe(0);
-      expect(nom.indexOfKey('2')).toBe(1); // Prove these are not ordered by
-      expect(nom.indexOfKey('1')).toBe(2); // their keys
-    };
-    var omStringNumberKeys =
-      OrderedMap.fromArray(hasAllNumericStringKeys, extractUniqueID);
-    verifyNumericKeys(omStringNumberKeys);
-    var omNumericKeys =
-      OrderedMap.fromArray(hasAllNumericKeys, extractUniqueID);
-    verifyNumericKeys(omNumericKeys);
-  });
-
-  it('should compute indices on mutually exclusive merge', function() {
-    var om = OrderedMap.fromArray([
-      {uniqueID: 'one', val: 'first'},
-      {uniqueID: 'two', val: 'second'},
-    ], extractUniqueID);
-    var om2 = OrderedMap.fromArray([
-      {uniqueID: 'three', val: 'third'},
-    ], extractUniqueID);
-    var res = om.merge(om2);
-
-    expect(res.length).toBe(3);
-
-    expect(res.keyAtIndex(0)).toBe('one');
-    expect(res.keyAtIndex(1)).toBe('two');
-    expect(res.keyAtIndex(2)).toBe('three');
-    expect(res.keyAtIndex(3)).toBe(undefined);
-
-    expect(res.indexOfKey('one')).toBe(0);
-    expect(res.indexOfKey('two')).toBe(1);
-    expect(res.indexOfKey('three')).toBe(2);
-    expect(res.indexOfKey('dog')).toBe(undefined);
-
-    expect(res.has('one')).toBe(true);
-    expect(res.has('two')).toBe(true);
-    expect(res.has('three')).toBe(true);
-    expect(res.has('dog')).toBe(false);
-
-    expect(res.get('one').val).toBe('first');
-    expect(res.get('two').val).toBe('second');
-    expect(res.get('three').val).toBe('third');
-    expect(res.get('dog')).toBe(undefined);
-  });
-
-  it('should compute indices on intersected merge', function() {
-    var oneTwo = OrderedMap.fromArray([
-      {uniqueID: 'one', val: 'first'},
-      {uniqueID: 'two', val: 'secondOM1'},
-    ], extractUniqueID);
-
-    var testOneTwoMergedWithTwoThree = function(res) {
-      expect(res.length).toBe(3);
-      expect(res.keyAtIndex(0)).toBe('one');
-      expect(res.keyAtIndex(1)).toBe('two');
-      expect(res.keyAtIndex(2)).toBe('three');
-      expect(res.keyAtIndex(3)).toBe(undefined);
-      expect(res.indexOfKey('one')).toBe(0);
-      expect(res.indexOfKey('two')).toBe(1);
-      expect(res.indexOfKey('three')).toBe(2);
-      expect(res.indexOfKey('dog')).toBe(undefined);
-      expect(res.has('one')).toBe(true);
-      expect(res.has('two')).toBe(true);
-      expect(res.has('three')).toBe(true);
-      expect(res.has('dog')).toBe(false);
-      expect(res.get('one').val).toBe('first');
-      expect(res.get('two').val).toBe('secondOM2');
-      expect(res.get('three').val).toBe('third');
-      expect(res.get('dog')).toBe(undefined);
-    };
-
-    var result =
-      oneTwo.merge(OrderedMap.fromArray([
-        {uniqueID: 'two', val: 'secondOM2'},
-        {uniqueID: 'three', val: 'third'},
-      ], extractUniqueID));
-    testOneTwoMergedWithTwoThree(result);
-
-    // Everything should be exactly as before, since the ordering of `two` was
-    // already determined by `om`.
-    result = oneTwo.merge(
-      OrderedMap.fromArray([
-        {uniqueID: 'three', val: 'third'},
-        {uniqueID: 'two', val:'secondOM2'},
-      ], extractUniqueID)
-    );
-    testOneTwoMergedWithTwoThree(result);
-
-
-    var testTwoThreeMergedWithOneTwo = function(res) {
-      expect(res.length).toBe(3);
-      expect(res.keyAtIndex(0)).toBe('two');
-      expect(res.keyAtIndex(1)).toBe('three');
-      expect(res.keyAtIndex(2)).toBe('one');
-      expect(res.keyAtIndex(3)).toBe(undefined);
-      expect(res.indexOfKey('two')).toBe(0);
-      expect(res.indexOfKey('three')).toBe(1);
-      expect(res.indexOfKey('one')).toBe(2);
-      expect(res.indexOfKey('cat')).toBe(undefined);
-      expect(res.has('two')).toBe(true);
-      expect(res.has('three')).toBe(true);
-      expect(res.has('one')).toBe(true);
-      expect(res.has('dog')).toBe(false);
-      expect(res.get('one').val).toBe('first');
-      expect(res.get('two').val).toBe('secondOM1');
-      expect(res.get('three').val).toBe('third');
-      expect(res.get('dog')).toBe(undefined);
-    };
-    result = OrderedMap.fromArray([
-      {uniqueID: 'two', val: 'secondOM2'},
-      {uniqueID: 'three', val: 'third'},
-    ], extractUniqueID).merge(oneTwo);
-    testTwoThreeMergedWithOneTwo(result);
-
-  });
-
-  it('should merge mutually exclusive keys to the end.', function() {
-    var om = OrderedMap.fromArray([
-      {uniqueID: 'one', val: 'first'},
-      {uniqueID: 'two', val: 'second'},
-    ], extractUniqueID);
-    var om2 = OrderedMap.fromArray([
-      {uniqueID: 'three', val: 'first'},
-      {uniqueID: 'four', val: 'second'},
-    ], extractUniqueID);
-    var res = om.merge(om2);
-    expect(res.length).toBe(4);
-
-  });
-
-  it('should map correctly', function() {
-    var om = OrderedMap.fromArray([
-      {uniqueID: 'x', val: 'xx'},
-      {uniqueID: 'y', val: 'yy'},
-      {uniqueID: 'z', val: 'zz'},
-    ], extractUniqueID);
-    var scope = {justToTestScope: 'justTestingScope'};
-    var verifyResult = function(omResult) {
-      expect(omResult.length).toBe(3);
-      expect(omResult.keyAtIndex(0)).toBe('x');
-      expect(omResult.keyAtIndex(1)).toBe('y');
-      expect(omResult.keyAtIndex(2)).toBe('z');
-      expect(omResult.get('x').val).toBe('xxx0justTestingScope');
-      expect(omResult.get('y').val).toBe('yyy1justTestingScope');
-      expect(omResult.get('z').val).toBe('zzz2justTestingScope');
-    };
-    var resultOM = om.map(function(itm, key, count) {
-      return {
-        uniqueID: itm.uniqueID,
-        val: itm.val + key + count + this.justToTestScope,
-      };
-    }, scope);
-    verifyResult(resultOM);
-
-    var resArray = [];
-    om.forEach(function(itm, key, count) {
-      resArray.push({
-        uniqueID: itm.uniqueID,
-        val: itm.val + key + count + this.justToTestScope,
-      });
-    }, scope);
-    resultOM = OrderedMap.fromArray(resArray, extractUniqueID);
-    verifyResult(resultOM);
-  });
-
-  it('should filter correctly', function() {
-    var om = OrderedMap.fromArray([
-      {uniqueID: 'x', val: 'xx'},
-      {uniqueID: 'y', val: 'yy'},
-      {uniqueID: 'z', val: 'zz'},
-    ], extractUniqueID);
-    var scope = {justToTestScope: 'justTestingScope'};
-
-    var filteringCallback = function(item, key, indexInOriginal) {
-      expect(this).toBe(scope);
-      expect(key === 'x' || key === 'y' || key === 'z').toBe(true);
-      if (key === 'x') {
-        expect(item.val).toBe('xx');
-        expect(indexInOriginal).toBe(0);
-        return false;
-      } else if (key === 'y') {
-        expect(item.val).toBe('yy');
-        expect(indexInOriginal).toBe(1);
-        return true;
-      } else {
-        expect(item.val).toBe('zz');
-        expect(indexInOriginal).toBe(2);
-        return true;
-      }
-    };
-
-    var verifyResult = function(omResult) {
-      expect(omResult.length).toBe(2);
-      expect(omResult.keyAtIndex(0)).toBe('y');
-      expect(omResult.keyAtIndex(1)).toBe('z');
-      expect(omResult.has('x')).toBe(false);
-      expect(omResult.has('z')).toBe(true);
-      expect(omResult.get('z').val).toBe('zz');
-      expect(omResult.has('y')).toBe(true);
-      expect(omResult.get('y').val).toBe('yy');
-    };
-
-    var resultOM = om.filter(filteringCallback, scope);
-    verifyResult(resultOM);
-  });
-
-  it('should throw when providing invalid ranges to ranging', function() {
-    var om = OrderedMap.fromArray([
-      {uniqueID: 'x', val: 'xx'},
-      {uniqueID: 'y', val: 'yy'},
-      {uniqueID: 'z', val: 'zz'},
-    ], extractUniqueID);
-    var scope = {justToTestScope: 'justTestingScope'};
-
-    expect(function() {
-      om.mapRange(duplicate, 0, 3, scope);
-    }).not.toThrow();
-    expect(function() {
-      om.filterRange(duplicate, 0, 3, scope);
-    }).not.toThrow();
-    expect(function() {
-      om.forEachRange(duplicate, 0, 3, scope);
-    }).not.toThrow();
-    expect(function() {
-      om.mapKeyRange(duplicate, 'x', 3, scope);
-    }).toThrow(
-      'mapKeyRange must be given keys that are present.'
-    );
-    expect(function() {
-      om.forEachKeyRange(duplicate, 'x', 3, scope);
-    }).toThrow(
-      'forEachKeyRange must be given keys that are present.'
-    );
-
-    expect(function() {
-      om.mapRange(duplicate, 0, 4, scope);
-    }).toThrow();
-    expect(function() {
-      om.filterRange(duplicate, 0, 4, scope);
-    }).toThrow();
-    expect(function() {
-      om.forEachRange(duplicate, 0, 4, scope);
-    }).toThrow();
-    expect(function() {
-      om.mapKeyRange(duplicate, 'x', null, scope);
-    }).toThrow();
-    expect(function() {
-      om.forEachKeyRange(duplicate, 'x', null, scope);
-    }).toThrow();
-
-    expect(function() {
-      om.mapRange(duplicate, -1, 1, scope);
-    }).toThrow();
-    expect(function() {
-      om.filterRange(duplicate, -1, 1, scope);
-    }).toThrow();
-    expect(function() {
-      om.forEachRange(duplicate, -1, 1, scope);
-    }).toThrow();
-    expect(function() {
-      om.mapKeyRange(duplicate, null, 'y', scope);
-    }).toThrow();
-    expect(function() {
-      om.forEachKeyRange(duplicate, null, 'y', scope);
-    }).toThrow();
-
-    expect(function() {
-      om.mapRange(duplicate, 0, 0, scope);
-    }).not.toThrow();
-    expect(function() {
-      om.filterRange(duplicate, 0, 0, scope);
-    }).not.toThrow();
-    expect(function() {
-      om.forEachRange(duplicate, 0, 0, scope);
-    }).not.toThrow();
-    expect(function() {
-      om.mapKeyRange(duplicate, 'x', 'x', scope);
-    }).not.toThrow();
-    expect(function() {
-      om.forEachKeyRange(duplicate, 'x', 'x', scope);
-    }).not.toThrow();
-
-    expect(function() {
-      om.mapRange(duplicate, 0, -1, scope);
-    }).toThrow();
-    expect(function() {
-      om.filterRange(duplicate, 0, -1, scope);
-    }).toThrow();
-    expect(function() {
-      om.forEachRange(duplicate, 0, -1, scope);
-    }).toThrow();
-    expect(function() {
-      om.mapKeyRange(duplicate, 'x', null, scope);
-    }).toThrow();
-    expect(function() {
-      om.forEachKeyRange(duplicate, 'x', null, scope);
-    }).toThrow();
-
-    expect(function() {
-      om.mapRange(duplicate, 2, 1, scope);
-    }).not.toThrow();
-    expect(function() {
-      om.filterRange(duplicate, 2, 1, scope);
-    }).not.toThrow();
-    expect(function() {
-      om.forEachRange(duplicate, 2, 1, scope);
-    }).not.toThrow();
-    expect(function() {
-      om.mapKeyRange(duplicate, 'z', 'z', scope);
-    }).not.toThrow();
-    expect(function() {
-      om.forEachKeyRange(duplicate, 'z', 'z', scope);
-    }).not.toThrow();
-
-    expect(function() {
-      om.mapRange(duplicate, 2, 2, scope);
-    }).toThrow();
-    expect(function() {
-      om.filterRange(duplicate, 2, 2, scope);
-    }).toThrow();
-    expect(function() {
-      om.forEachRange(duplicate, 2, 2, scope);
-    }).toThrow();
-    expect(function() {
-      om.mapKeyRange(duplicate, 'z', null, scope);
-    }).toThrow();
-    expect(function() {
-      om.forEachKeyRange(duplicate, 'z', null, scope);
-    }).toThrow();
-
-    // Provide keys in reverse order - should throw.
-    expect(function() {
-      om.mapKeyRange(duplicate, 'y', 'x', scope);
-    }).toThrow();
-    expect(function() {
-      om.forEachKeyRange(duplicate, 'y', 'x', scope);
-    }).toThrow();
-  });
-
-  // TEST length zero map, or keyrange start===end
-
-  it('should map range correctly', function() {
-    var om = OrderedMap.fromArray([
-      {uniqueID: 'x', val: 'xx'},
-      {uniqueID: 'y', val: 'yy'},
-      {uniqueID: 'z', val: 'zz'},
-    ], extractUniqueID);
-    var scope = {justToTestScope: 'justTestingScope'};
-    var verifyThreeItems = function(omResult) {
-      expect(omResult.length).toBe(3);
-      expect(omResult.keyAtIndex(0)).toBe('x');
-      expect(omResult.keyAtIndex(1)).toBe('y');
-      expect(omResult.keyAtIndex(2)).toBe('z');
-      expect(omResult.get('x').val).toBe('xxx0justTestingScope');
-      expect(omResult.get('y').val).toBe('yyy1justTestingScope');
-      expect(omResult.get('z').val).toBe('zzz2justTestingScope');
-    };
-    var verifyFirstTwoItems = function(omResult) {
-      expect(omResult.length).toBe(2);
-      expect(omResult.keyAtIndex(0)).toBe('x');
-      expect(omResult.keyAtIndex(1)).toBe('y');
-      expect(omResult.get('x').val).toBe('xxx0justTestingScope');
-      expect(omResult.get('y').val).toBe('yyy1justTestingScope');
-    };
-
-    var verifyLastTwoItems = function(omResult) {
-      expect(omResult.length).toBe(2);
-      expect(omResult.keyAtIndex(0)).toBe('y');
-      expect(omResult.keyAtIndex(1)).toBe('z');
-      expect(omResult.get('y').val).toBe('yyy1justTestingScope');
-      expect(omResult.get('z').val).toBe('zzz2justTestingScope');
-    };
-
-    var verifyMiddleItem = function(omResult) {
-      expect(omResult.length).toBe(1);
-      expect(omResult.keyAtIndex(0)).toBe('y');
-      expect(omResult.get('y').val).toBe('yyy1justTestingScope');
-    };
-
-    var verifyEmpty = function(omResult) {
-      expect(omResult.length).toBe(0);
-    };
-
-    var omResultThree = om.mapRange(duplicate, 0, 3, scope);
-    verifyThreeItems(omResultThree);
-    var resArray = [];
-    var pushToResArray = function(itm, key, count) {
-      resArray.push({
-        uniqueID: itm.uniqueID,
-        val: itm.val + key + count + this.justToTestScope,
-      });
-    };
-
-    om.forEachRange(pushToResArray, 0, 3, scope);
-    omResultThree = OrderedMap.fromArray(resArray, extractUniqueID);
-    verifyThreeItems(omResultThree);
-
-    var omResultFirstTwo = om.mapRange(duplicate, 0, 2, scope);
-    verifyFirstTwoItems(omResultFirstTwo);
-    resArray = [];
-    om.forEachRange(pushToResArray, 0, 2, scope);
-    omResultFirstTwo = OrderedMap.fromArray(resArray, extractUniqueID);
-    verifyFirstTwoItems(omResultFirstTwo);
-
-    var omResultLastTwo = om.mapRange(duplicate, 1, 2, scope);
-    verifyLastTwoItems(omResultLastTwo);
-    resArray = [];
-    om.forEachRange(pushToResArray, 1, 2, scope);
-    omResultLastTwo = OrderedMap.fromArray(resArray, extractUniqueID);
-    verifyLastTwoItems(omResultLastTwo);
-
-    var omResultMiddle = om.mapRange(duplicate, 1, 1, scope);
-    verifyMiddleItem(omResultMiddle);
-    resArray = [];
-    om.forEachRange(pushToResArray, 1, 1, scope);
-    omResultMiddle = OrderedMap.fromArray(resArray, extractUniqueID);
-    verifyMiddleItem(omResultMiddle);
-
-    var omResultNone = om.mapRange(duplicate, 1, 0, scope);
-    verifyEmpty(omResultNone);
-  });
-
-  it('should extract the original array correctly', function() {
-    var sourceArray = [
-      {uniqueID: 'x', val: 'xx'},
-      {uniqueID: 'y', val: 'yy'},
-      {uniqueID: 'z', val: 'zz'},
-    ];
-    var om = OrderedMap.fromArray(sourceArray, extractUniqueID);
-    expect(om.toArray()).toEqual(sourceArray);
-  });
-});
diff --git a/src/shared/utils/__tests__/PooledClass-test.js b/src/shared/utils/__tests__/PooledClass-test.js
index 51e6ae408aaa..3c206b74aeaf 100644
--- a/src/shared/utils/__tests__/PooledClass-test.js
+++ b/src/shared/utils/__tests__/PooledClass-test.js
@@ -14,40 +14,38 @@
 var PooledClass;
 var PoolableClass;
 
-describe('Pooled class', function() {
-  beforeEach(function() {
+describe('Pooled class', () => {
+  beforeEach(() => {
     PooledClass = require('PooledClass');
     PoolableClass = function() {};
     PoolableClass.prototype.destructor = function() {};
     PooledClass.addPoolingTo(PoolableClass);
   });
 
-  it('should initialize a pool correctly', function() {
+  it('should initialize a pool correctly', () => {
     expect(PoolableClass.instancePool).toBeDefined();
   });
 
-  it('should return a new instance when the pool is empty', function() {
+  it('should return a new instance when the pool is empty', () => {
     var instance = PoolableClass.getPooled();
     expect(instance instanceof PoolableClass).toBe(true);
   });
 
-  it('should return the instance back into the pool when it gets released',
-    function() {
-      var instance = PoolableClass.getPooled();
-      PoolableClass.release(instance);
-      expect(PoolableClass.instancePool.length).toBe(1);
-      expect(PoolableClass.instancePool[0]).toBe(instance);
-    }
-  );
+  it('should return the instance back into the pool when it gets released', () => {
+    var instance = PoolableClass.getPooled();
+    PoolableClass.release(instance);
+    expect(PoolableClass.instancePool.length).toBe(1);
+    expect(PoolableClass.instancePool[0]).toBe(instance);
+  });
 
-  it('should return an old instance if available in the pool', function() {
+  it('should return an old instance if available in the pool', () => {
     var instance = PoolableClass.getPooled();
     PoolableClass.release(instance);
     var instance2 = PoolableClass.getPooled();
     expect(instance).toBe(instance2);
   });
 
-  it('should call the destructor when instance gets released', function() {
+  it('should call the destructor when instance gets released', () => {
     var log = [];
     var PoolableClassWithDestructor = function() {};
     PoolableClassWithDestructor.prototype.destructor = function() {
@@ -59,7 +57,7 @@ describe('Pooled class', function() {
     expect(log).toEqual(['released']);
   });
 
-  it('should accept poolers with different arguments', function() {
+  it('should accept poolers with different arguments', () => {
     var log = [];
     var PoolableClassWithMultiArguments = function(a, b) {
       log.push(a, b);
@@ -67,56 +65,50 @@ describe('Pooled class', function() {
     PoolableClassWithMultiArguments.prototype.destructor = function() {};
     PooledClass.addPoolingTo(
       PoolableClassWithMultiArguments,
-      PooledClass.twoArgumentPooler
+      PooledClass.twoArgumentPooler,
     );
     PoolableClassWithMultiArguments.getPooled('a', 'b', 'c');
     expect(log).toEqual(['a', 'b']);
   });
 
-  it('should call a new constructor with arguments', function() {
+  it('should call a new constructor with arguments', () => {
     var log = [];
     var PoolableClassWithOneArgument = function(a) {
       log.push(a);
     };
     PoolableClassWithOneArgument.prototype.destructor = function() {};
-    PooledClass.addPoolingTo(
-      PoolableClassWithOneArgument
-    );
+    PooledClass.addPoolingTo(PoolableClassWithOneArgument);
     PoolableClassWithOneArgument.getPooled('new');
     expect(log).toEqual(['new']);
   });
 
-  it('should call an old constructor with arguments', function() {
+  it('should call an old constructor with arguments', () => {
     var log = [];
     var PoolableClassWithOneArgument = function(a) {
       log.push(a);
     };
     PoolableClassWithOneArgument.prototype.destructor = function() {};
-    PooledClass.addPoolingTo(
-      PoolableClassWithOneArgument
-    );
+    PooledClass.addPoolingTo(PoolableClassWithOneArgument);
     var instance = PoolableClassWithOneArgument.getPooled('new');
     PoolableClassWithOneArgument.release(instance);
     PoolableClassWithOneArgument.getPooled('old');
     expect(log).toEqual(['new', 'old']);
   });
 
-  it('should throw when the class releases an instance of a different type',
-    function() {
-      var RandomClass = function() {};
-      RandomClass.prototype.destructor = function() {};
-      PooledClass.addPoolingTo(RandomClass);
-      var randomInstance = RandomClass.getPooled();
-      PoolableClass.getPooled();
-      expect(function() {
-        PoolableClass.release(randomInstance);
-      }).toThrow(
-        'Trying to release an instance into a pool of a different type.'
-      );
-    }
-  );
+  it('should throw when the class releases an instance of a different type', () => {
+    var RandomClass = function() {};
+    RandomClass.prototype.destructor = function() {};
+    PooledClass.addPoolingTo(RandomClass);
+    var randomInstance = RandomClass.getPooled();
+    PoolableClass.getPooled();
+    expect(function() {
+      PoolableClass.release(randomInstance);
+    }).toThrowError(
+      'Trying to release an instance into a pool of a different type.',
+    );
+  });
 
-  it('should throw if no destructor is defined', function() {
+  it('should throw if no destructor is defined', () => {
     var ImmortalClass = function() {};
     PooledClass.addPoolingTo(ImmortalClass);
     var inst = ImmortalClass.getPooled();
diff --git a/src/shared/utils/__tests__/adler32-test.js b/src/shared/utils/__tests__/adler32-test.js
deleted file mode 100644
index b8ccc7a2e291..000000000000
--- a/src/shared/utils/__tests__/adler32-test.js
+++ /dev/null
@@ -1,41 +0,0 @@
-/**
- * Copyright 2014-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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-var adler32 = require('adler32');
-
-describe('adler32', function() {
-  it('generates differing checksums', function() {
-    expect(adler32('foo')).not.toBe(adler32('bar'));
-  });
-
-  it('generates consistent checksums', function() {
-    expect(adler32('linux')).toBe(adler32('linux'));
-  });
-
-  it('is case sensitive', function() {
-    expect(adler32('a')).not.toBe(adler32('A'));
-  });
-
-  it('doesn\'t barf on large inputs', function() {
-    var str = '';
-    for (var i = 0; i < 100000; i++) {
-      str += 'This will be repeated to be very large indeed. ';
-    }
-    expect(adler32(str)).toBe(692898118);
-  });
-
-  it('doesn\'t barf on international inputs', function() {
-    var str = 'Linux 是一個真棒操作系統!';
-    expect(adler32(str)).toBe(-1183804097);
-  });
-});
diff --git a/src/shared/utils/__tests__/reactProdInvariant-test.js b/src/shared/utils/__tests__/reactProdInvariant-test.js
new file mode 100644
index 000000000000..d4348818dcc6
--- /dev/null
+++ b/src/shared/utils/__tests__/reactProdInvariant-test.js
@@ -0,0 +1,49 @@
+/**
+ * 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.
+ *
+ * @emails react-core
+ */
+'use strict';
+
+var reactProdInvariant;
+
+describe('reactProdInvariant', () => {
+  beforeEach(() => {
+    jest.resetModuleRegistry();
+    reactProdInvariant = require('reactProdInvariant');
+  });
+
+  it('should throw with the correct number of `%s`s in the URL', () => {
+    expect(function() {
+      reactProdInvariant(124, 'foo', 'bar');
+    }).toThrowError(
+      'Minified React error #124; visit ' +
+        'http://facebook.github.io/react/docs/error-decoder.html?invariant=124&args[]=foo&args[]=bar' +
+        ' for the full message or use the non-minified dev environment' +
+        ' for full errors and additional helpful warnings.',
+    );
+
+    expect(function() {
+      reactProdInvariant(20);
+    }).toThrowError(
+      'Minified React error #20; visit ' +
+        'http://facebook.github.io/react/docs/error-decoder.html?invariant=20' +
+        ' for the full message or use the non-minified dev environment' +
+        ' for full errors and additional helpful warnings.',
+    );
+
+    expect(function() {
+      reactProdInvariant(77, '<div>', '&?bar');
+    }).toThrowError(
+      'Minified React error #77; visit ' +
+        'http://facebook.github.io/react/docs/error-decoder.html?invariant=77&args[]=%3Cdiv%3E&args[]=%26%3Fbar' +
+        ' for the full message or use the non-minified dev environment' +
+        ' for full errors and additional helpful warnings.',
+    );
+  });
+});
diff --git a/src/shared/utils/__tests__/traverseAllChildren-test.js b/src/shared/utils/__tests__/traverseAllChildren-test.js
index 206222dc0756..b339f6419293 100644
--- a/src/shared/utils/__tests__/traverseAllChildren-test.js
+++ b/src/shared/utils/__tests__/traverseAllChildren-test.js
@@ -11,25 +11,29 @@
 
 'use strict';
 
-describe('traverseAllChildren', function() {
+describe('traverseAllChildren', () => {
   var traverseAllChildren;
   var React;
   var ReactFragment;
-  beforeEach(function() {
+  var ReactTestUtils;
+
+  beforeEach(() => {
     jest.resetModuleRegistry();
     traverseAllChildren = require('traverseAllChildren');
     React = require('React');
     ReactFragment = require('ReactFragment');
+    ReactTestUtils = require('ReactTestUtils');
   });
 
   function frag(obj) {
     return ReactFragment.create(obj);
   }
 
-  it('should support identity for simple', function() {
+  it('should support identity for simple', () => {
     var traverseContext = [];
-    var traverseFn =
-      jasmine.createSpy().andCallFake(function(context, kid, key, index) {
+    var traverseFn = jasmine
+      .createSpy()
+      .and.callFake(function(context, kid, key, index) {
         context.push(true);
       });
 
@@ -41,53 +45,47 @@ describe('traverseAllChildren', function() {
     expect(traverseFn).toHaveBeenCalledWith(
       traverseContext,
       simpleKid,
-      '.$simple'
+      '.$simple',
     );
     expect(traverseContext.length).toEqual(1);
   });
 
-  it('should treat single arrayless child as being in array', function() {
+  it('should treat single arrayless child as being in array', () => {
     var traverseContext = [];
-    var traverseFn =
-      jasmine.createSpy().andCallFake(function(context, kid, key, index) {
+    var traverseFn = jasmine
+      .createSpy()
+      .and.callFake(function(context, kid, key, index) {
         context.push(true);
       });
 
     var simpleKid = <span />;
     var instance = <div>{simpleKid}</div>;
     traverseAllChildren(instance.props.children, traverseFn, traverseContext);
-    expect(traverseFn).toHaveBeenCalledWith(
-      traverseContext,
-      simpleKid,
-      '.0'
-    );
+    expect(traverseFn).toHaveBeenCalledWith(traverseContext, simpleKid, '.0');
     expect(traverseContext.length).toEqual(1);
   });
 
-  it('should treat single child in array as expected', function() {
+  it('should treat single child in array as expected', () => {
     spyOn(console, 'error');
     var traverseContext = [];
-    var traverseFn =
-      jasmine.createSpy().andCallFake(function(context, kid, key, index) {
+    var traverseFn = jasmine
+      .createSpy()
+      .and.callFake(function(context, kid, key, index) {
         context.push(true);
       });
 
     var simpleKid = <span />;
     var instance = <div>{[simpleKid]}</div>;
     traverseAllChildren(instance.props.children, traverseFn, traverseContext);
-    expect(traverseFn).toHaveBeenCalledWith(
-      traverseContext,
-      simpleKid,
-      '.0'
-    );
+    expect(traverseFn).toHaveBeenCalledWith(traverseContext, simpleKid, '.0');
     expect(traverseContext.length).toEqual(1);
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
-      'Warning: Each child in an array or iterator should have a unique "key" prop.'
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'Warning: Each child in an array or iterator should have a unique "key" prop.',
     );
   });
 
-  it('should be called for each child', function() {
+  it('should be called for each child', () => {
     var zero = <div key="keyZero" />;
     var one = null;
     var two = <div key="keyTwo" />;
@@ -95,8 +93,9 @@ describe('traverseAllChildren', function() {
     var four = <div key="keyFour" />;
 
     var traverseContext = [];
-    var traverseFn =
-      jasmine.createSpy().andCallFake(function(context, kid, key, index) {
+    var traverseFn = jasmine
+      .createSpy()
+      .and.callFake(function(context, kid, key, index) {
         context.push(true);
       });
 
@@ -111,33 +110,22 @@ describe('traverseAllChildren', function() {
     );
 
     traverseAllChildren(instance.props.children, traverseFn, traverseContext);
-    expect(traverseFn).toHaveBeenCalledWith(
-      traverseContext,
-      zero,
-      '.$keyZero'
-    );
+    expect(traverseFn).toHaveBeenCalledWith(traverseContext, zero, '.$keyZero');
     expect(traverseFn).toHaveBeenCalledWith(traverseContext, one, '.1');
-    expect(traverseFn).toHaveBeenCalledWith(
-      traverseContext,
-      two,
-      '.$keyTwo'
-    );
+    expect(traverseFn).toHaveBeenCalledWith(traverseContext, two, '.$keyTwo');
     expect(traverseFn).toHaveBeenCalledWith(traverseContext, three, '.3');
-    expect(traverseFn).toHaveBeenCalledWith(
-      traverseContext,
-      four,
-      '.$keyFour'
-    );
+    expect(traverseFn).toHaveBeenCalledWith(traverseContext, four, '.$keyFour');
   });
 
-  it('should traverse children of different kinds', function() {
+  it('should traverse children of different kinds', () => {
     var div = <div key="divNode" />;
     var span = <span key="spanNode" />;
     var a = <a key="aNode" />;
 
     var traverseContext = [];
-    var traverseFn =
-      jasmine.createSpy().andCallFake(function(context, kid, key, index) {
+    var traverseFn = jasmine
+      .createSpy()
+      .and.callFake(function(context, kid, key, index) {
         context.push(true);
       });
 
@@ -157,39 +145,29 @@ describe('traverseAllChildren', function() {
 
     traverseAllChildren(instance.props.children, traverseFn, traverseContext);
 
-    expect(traverseFn.calls.length).toBe(9);
+    expect(traverseFn.calls.count()).toBe(9);
     expect(traverseContext.length).toEqual(9);
 
+    expect(traverseFn).toHaveBeenCalledWith(traverseContext, div, '.$divNode');
     expect(traverseFn).toHaveBeenCalledWith(
-      traverseContext, div, '.$divNode'
-    );
-    expect(traverseFn).toHaveBeenCalledWith(
-      traverseContext, <span key="span/.$spanNode" />, '.1:0:$span/.$spanNode'
-    );
-    expect(traverseFn).toHaveBeenCalledWith(
-      traverseContext, <a key="a/.$aNode" />, '.2:$a/.$aNode'
-    );
-    expect(traverseFn).toHaveBeenCalledWith(
-      traverseContext, 'string', '.3'
-    );
-    expect(traverseFn).toHaveBeenCalledWith(
-      traverseContext, 1234, '.4'
-    );
-    expect(traverseFn).toHaveBeenCalledWith(
-      traverseContext, null, '.5'
-    );
-    expect(traverseFn).toHaveBeenCalledWith(
-      traverseContext, null, '.6'
-    );
-    expect(traverseFn).toHaveBeenCalledWith(
-      traverseContext, null, '.7'
+      traverseContext,
+      <span key="span/.$spanNode" />,
+      '.1:0:$span/.$spanNode',
     );
     expect(traverseFn).toHaveBeenCalledWith(
-      traverseContext, null, '.8'
-    );
+      traverseContext,
+      <a key="a/.$aNode" />,
+      '.2:$a/.$aNode',
+    );
+    expect(traverseFn).toHaveBeenCalledWith(traverseContext, 'string', '.3');
+    expect(traverseFn).toHaveBeenCalledWith(traverseContext, 1234, '.4');
+    expect(traverseFn).toHaveBeenCalledWith(traverseContext, null, '.5');
+    expect(traverseFn).toHaveBeenCalledWith(traverseContext, null, '.6');
+    expect(traverseFn).toHaveBeenCalledWith(traverseContext, null, '.7');
+    expect(traverseFn).toHaveBeenCalledWith(traverseContext, null, '.8');
   });
 
-  it('should be called for each child in nested structure', function() {
+  it('should be called for each child in nested structure', () => {
     var zero = <div key="keyZero" />;
     var one = null;
     var two = <div key="keyTwo" />;
@@ -202,59 +180,60 @@ describe('traverseAllChildren', function() {
     // 1. If grouped in an Object, the object key combined with `key` prop
     // 2. If grouped in an Array, the `key` prop, falling back to array index
 
-
     var traverseContext = [];
-    var traverseFn =
-      jasmine.createSpy().andCallFake(function(context, kid, key, index) {
+    var traverseFn = jasmine
+      .createSpy()
+      .and.callFake(function(context, kid, key, index) {
         context.push(true);
       });
 
     var instance = (
-      <div>{
-        [
+      <div>
+        {[
           frag({
             firstHalfKey: [zero, one, two],
             secondHalfKey: [three, four],
             keyFive: five,
           }),
-        ]
-      }</div>
+        ]}
+      </div>
     );
 
     traverseAllChildren(instance.props.children, traverseFn, traverseContext);
-    expect(traverseFn.calls.length).toBe(4);
+    expect(traverseFn.calls.count()).toBe(4);
     expect(traverseContext.length).toEqual(4);
     expect(traverseFn).toHaveBeenCalledWith(
       traverseContext,
       <div key="firstHalfKey/.$keyZero" />,
-      '.0:$firstHalfKey/.$keyZero'
+      '.0:$firstHalfKey/.$keyZero',
     );
 
     expect(traverseFn).toHaveBeenCalledWith(
       traverseContext,
       <div key="firstHalfKey/.$keyTwo" />,
-      '.0:$firstHalfKey/.$keyTwo'
+      '.0:$firstHalfKey/.$keyTwo',
     );
 
     expect(traverseFn).toHaveBeenCalledWith(
       traverseContext,
       <div key="secondHalfKey/.$keyFour" />,
-      '.0:$secondHalfKey/.$keyFour'
+      '.0:$secondHalfKey/.$keyFour',
     );
 
     expect(traverseFn).toHaveBeenCalledWith(
       traverseContext,
       <div key="keyFive/.$keyFiveInner" />,
-      '.0:$keyFive/.$keyFiveInner'
+      '.0:$keyFive/.$keyFiveInner',
     );
   });
 
-  it('should retain key across two mappings', function() {
+  it('should retain key across two mappings', () => {
     var zeroForceKey = <div key="keyZero" />;
     var oneForceKey = <div key="keyOne" />;
     var traverseContext = [];
-    var traverseFn =
-      jasmine.createSpy().andCallFake(function(context, kid, key, index) {
+    var traverseFn = jasmine
+      .createSpy()
+      .and.callFake(function(context, kid, key, index) {
         context.push(true);
       });
 
@@ -270,16 +249,16 @@ describe('traverseAllChildren', function() {
     expect(traverseFn).toHaveBeenCalledWith(
       traverseContext,
       zeroForceKey,
-      '.$keyZero'
+      '.$keyZero',
     );
     expect(traverseFn).toHaveBeenCalledWith(
       traverseContext,
       oneForceKey,
-      '.$keyOne'
+      '.$keyOne',
     );
   });
 
-  it('should be called for each child in an iterable without keys', function() {
+  it('should be called for each child in an iterable without keys', () => {
     spyOn(console, 'error');
     var threeDivIterable = {
       '@@iterator': function() {
@@ -297,8 +276,9 @@ describe('traverseAllChildren', function() {
     };
 
     var traverseContext = [];
-    var traverseFn =
-      jasmine.createSpy().andCallFake(function(context, kid, key, index) {
+    var traverseFn = jasmine
+      .createSpy()
+      .and.callFake(function(context, kid, key, index) {
         context.push(kid);
       });
 
@@ -309,31 +289,31 @@ describe('traverseAllChildren', function() {
     );
 
     traverseAllChildren(instance.props.children, traverseFn, traverseContext);
-    expect(traverseFn.calls.length).toBe(3);
+    expect(traverseFn.calls.count()).toBe(3);
 
     expect(traverseFn).toHaveBeenCalledWith(
       traverseContext,
       traverseContext[0],
-      '.0'
+      '.0',
     );
     expect(traverseFn).toHaveBeenCalledWith(
       traverseContext,
       traverseContext[1],
-      '.1'
+      '.1',
     );
     expect(traverseFn).toHaveBeenCalledWith(
       traverseContext,
       traverseContext[2],
-      '.2'
+      '.2',
     );
 
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
-      'Warning: Each child in an array or iterator should have a unique "key" prop.'
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
+      'Warning: Each child in an array or iterator should have a unique "key" prop.',
     );
   });
 
-  it('should be called for each child in an iterable with keys', function() {
+  it('should be called for each child in an iterable with keys', () => {
     var threeDivIterable = {
       '@@iterator': function() {
         var i = 0;
@@ -350,8 +330,9 @@ describe('traverseAllChildren', function() {
     };
 
     var traverseContext = [];
-    var traverseFn =
-      jasmine.createSpy().andCallFake(function(context, kid, key, index) {
+    var traverseFn = jasmine
+      .createSpy()
+      .and.callFake(function(context, kid, key, index) {
         context.push(kid);
       });
 
@@ -362,26 +343,26 @@ describe('traverseAllChildren', function() {
     );
 
     traverseAllChildren(instance.props.children, traverseFn, traverseContext);
-    expect(traverseFn.calls.length).toBe(3);
+    expect(traverseFn.calls.count()).toBe(3);
 
     expect(traverseFn).toHaveBeenCalledWith(
       traverseContext,
       traverseContext[0],
-      '.$#1'
+      '.$#1',
     );
     expect(traverseFn).toHaveBeenCalledWith(
       traverseContext,
       traverseContext[1],
-      '.$#2'
+      '.$#2',
     );
     expect(traverseFn).toHaveBeenCalledWith(
       traverseContext,
       traverseContext[2],
-      '.$#3'
+      '.$#3',
     );
   });
 
-  it('should use keys from entry iterables', function() {
+  it('should use keys from entry iterables', () => {
     spyOn(console, 'error');
 
     var threeDivEntryIterable = {
@@ -401,8 +382,9 @@ describe('traverseAllChildren', function() {
     threeDivEntryIterable.entries = threeDivEntryIterable['@@iterator'];
 
     var traverseContext = [];
-    var traverseFn =
-      jasmine.createSpy().andCallFake(function(context, kid, key, index) {
+    var traverseFn = jasmine
+      .createSpy()
+      .and.callFake(function(context, kid, key, index) {
         context.push(kid);
       });
 
@@ -413,33 +395,33 @@ describe('traverseAllChildren', function() {
     );
 
     traverseAllChildren(instance.props.children, traverseFn, traverseContext);
-    expect(traverseFn.calls.length).toBe(3);
+    expect(traverseFn.calls.count()).toBe(3);
 
     expect(traverseFn).toHaveBeenCalledWith(
       traverseContext,
       traverseContext[0],
-      '.$#1:0'
+      '.$#1:0',
     );
     expect(traverseFn).toHaveBeenCalledWith(
       traverseContext,
       traverseContext[1],
-      '.$#2:0'
+      '.$#2:0',
     );
     expect(traverseFn).toHaveBeenCalledWith(
       traverseContext,
       traverseContext[2],
-      '.$#3:0'
+      '.$#3:0',
     );
 
-    expect(console.error.argsForCall.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toContain(
       'Warning: 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.'
+        'experimental feature that might be removed. Convert it to a sequence ' +
+        '/ iterable of keyed ReactElements instead.',
     );
   });
 
-  it('should not enumerate enumerable numbers (#4776)', function() {
+  it('should not enumerate enumerable numbers (#4776)', () => {
     /*eslint-disable no-extend-native */
     Number.prototype['@@iterator'] = function() {
       throw new Error('number iterator called');
@@ -458,29 +440,17 @@ describe('traverseAllChildren', function() {
       var traverseFn = jasmine.createSpy();
 
       traverseAllChildren(instance.props.children, traverseFn, null);
-      expect(traverseFn.calls.length).toBe(3);
+      expect(traverseFn.calls.count()).toBe(3);
 
-      expect(traverseFn).toHaveBeenCalledWith(
-        null,
-        5,
-        '.0'
-      );
-      expect(traverseFn).toHaveBeenCalledWith(
-        null,
-        12,
-        '.1'
-      );
-      expect(traverseFn).toHaveBeenCalledWith(
-        null,
-        13,
-        '.2'
-      );
+      expect(traverseFn).toHaveBeenCalledWith(null, 5, '.0');
+      expect(traverseFn).toHaveBeenCalledWith(null, 12, '.1');
+      expect(traverseFn).toHaveBeenCalledWith(null, 13, '.2');
     } finally {
       delete Number.prototype['@@iterator'];
     }
   });
 
-  it('should allow extension of native prototypes', function() {
+  it('should allow extension of native prototypes', () => {
     /*eslint-disable no-extend-native */
     String.prototype.key = 'react';
     Number.prototype.key = 'rocks';
@@ -496,44 +466,54 @@ describe('traverseAllChildren', function() {
     var traverseFn = jasmine.createSpy();
 
     traverseAllChildren(instance.props.children, traverseFn, null);
-    expect(traverseFn.calls.length).toBe(2);
+    expect(traverseFn.calls.count()).toBe(2);
 
-    expect(traverseFn).toHaveBeenCalledWith(
-      null,
-      'a',
-      '.0'
-    );
-    expect(traverseFn).toHaveBeenCalledWith(
-      null,
-      13,
-      '.1'
-    );
+    expect(traverseFn).toHaveBeenCalledWith(null, 'a', '.0');
+    expect(traverseFn).toHaveBeenCalledWith(null, 13, '.1');
 
     delete String.prototype.key;
     delete Number.prototype.key;
   });
 
-  it('should throw on object', function() {
+  it('should throw on object', () => {
     expect(function() {
       traverseAllChildren({a: 1, b: 2}, function() {}, null);
-    }).toThrow(
+    }).toThrowError(
       'Objects are not valid as a React child (found: object with keys ' +
-      '{a, b}). 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.'
+        '{a, b}). 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.',
     );
   });
 
-  it('should throw on regex', function() {
+  it('should throw on regex', () => {
     // Really, we care about dates (#4840) but those have nondeterministic
     // serialization (timezones) so let's test a regex instead:
     expect(function() {
       traverseAllChildren(/abc/, function() {}, null);
-    }).toThrow(
+    }).toThrowError(
       'Objects are not valid as a React child (found: /abc/). 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.'
+        'to render a collection of children, use an array instead or wrap the ' +
+        'object using createFragment(object) from the React add-ons.',
     );
   });
 
+  it('should warn for using maps as children with owner info', () => {
+    spyOn(console, 'error');
+
+    class Parent extends React.Component {
+      render() {
+        return <div>{new Map([['foo', 0], ['bar', 1]])}</div>;
+      }
+    }
+
+    ReactTestUtils.renderIntoDocument(<Parent />);
+
+    expect(console.error.calls.count()).toBe(1);
+    expect(console.error.calls.argsFor(0)[0]).toBe(
+      'Warning: 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. Check the render method of `Parent`.',
+    );
+  });
 });
diff --git a/src/shared/utils/accumulate.js b/src/shared/utils/accumulate.js
deleted file mode 100644
index 07fc3db2bbde..000000000000
--- a/src/shared/utils/accumulate.js
+++ /dev/null
@@ -1,47 +0,0 @@
-/**
- * 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 accumulate
- */
-
-'use strict';
-
-var invariant = require('invariant');
-
-/**
- * Accumulates items that must not be null or undefined.
- *
- * This is used to conserve memory by avoiding array allocations.
- *
- * @return {*|array<*>} An accumulation of items.
- */
-function accumulate(current, next) {
-  invariant(
-    next != null,
-    'accumulate(...): Accumulated items must be not be null or undefined.'
-  );
-  if (current == null) {
-    return next;
-  } else {
-    // 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).
-    var currentIsArray = Array.isArray(current);
-    var nextIsArray = Array.isArray(next);
-    if (currentIsArray) {
-      return current.concat(next);
-    } else {
-      if (nextIsArray) {
-        return [current].concat(next);
-      } else {
-        return [current, next];
-      }
-    }
-  }
-}
-
-module.exports = accumulate;
diff --git a/src/shared/utils/canDefineProperty.js b/src/shared/utils/canDefineProperty.js
index 864a4732498a..402eb6e53384 100644
--- a/src/shared/utils/canDefineProperty.js
+++ b/src/shared/utils/canDefineProperty.js
@@ -6,6 +6,7 @@
  * 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.
  *
+ * @flow
  * @providesModule canDefineProperty
  */
 
@@ -14,6 +15,7 @@
 var canDefineProperty = false;
 if (__DEV__) {
   try {
+    // $FlowFixMe https://github.com/facebook/flow/issues/285
     Object.defineProperty({}, 'x', {get: function() {}});
     canDefineProperty = true;
   } catch (x) {
diff --git a/src/shared/utils/deprecated.js b/src/shared/utils/deprecated.js
index fd8edec6e431..81e24cfd98d5 100644
--- a/src/shared/utils/deprecated.js
+++ b/src/shared/utils/deprecated.js
@@ -7,11 +7,12 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule deprecated
+ * @flow
  */
 
 'use strict';
 
-var warning = require('warning');
+var lowPriorityWarning = require('lowPriorityWarning');
 
 /**
  * This will log a single deprecation notice per function and forward the call
@@ -24,22 +25,29 @@ var warning = require('warning');
  * @param {function} fn The function to forward on to
  * @return {function} The function that will warn once and then call fn
  */
-function deprecated(fnName, newModule, newPackage, ctx, fn) {
+function deprecated<T: Function>(
+  fnName: string,
+  newModule: string,
+  newPackage: string,
+  ctx: mixed,
+  fn: T,
+): T {
   var warned = false;
   if (__DEV__) {
     var newFn = function() {
-      warning(
+      lowPriorityWarning(
         warned,
         /* eslint-disable no-useless-concat */
         // Require examples in this string must be split to prevent React's
         // build tools from mistaking them for real requires.
         // Otherwise the build tools will attempt to build a '%s' module.
-        'React.%s is deprecated. Please use %s.%s from require' + '(\'%s\') ' +
-        'instead.',
+        'React.%s is deprecated. Please use %s.%s from require' +
+          "('%s') " +
+          'instead.',
         fnName,
         newModule,
         fnName,
-        newPackage
+        newPackage,
       );
       /* eslint-enable no-useless-concat */
       warned = true;
@@ -47,7 +55,12 @@ function deprecated(fnName, newModule, newPackage, ctx, fn) {
     };
     // We need to make sure all properties of the original fn are copied over.
     // In particular, this is needed to support PropTypes
-    return Object.assign(newFn, fn);
+    Object.assign(newFn, (fn: Object));
+
+    // Flow is not smart enough to figure out that newFn is of the same type as
+    // fn. Since we don't want to lose out the type of the function, casting
+    // to any and force flow to use T.
+    return ((newFn: any): T);
   }
 
   return fn;
diff --git a/src/shared/utils/flattenChildren.js b/src/shared/utils/flattenChildren.js
index b25d399fa84e..7274bb6dde48 100644
--- a/src/shared/utils/flattenChildren.js
+++ b/src/shared/utils/flattenChildren.js
@@ -7,33 +7,64 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule flattenChildren
+ * @flow
  */
 
 'use strict';
 
+var KeyEscapeUtils = require('KeyEscapeUtils');
 var traverseAllChildren = require('traverseAllChildren');
 var warning = require('warning');
 
+var ReactComponentTreeHook;
+
+if (
+  typeof process !== 'undefined' &&
+  process.env &&
+  process.env.NODE_ENV === '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 = require('ReactComponentTreeHook');
+}
+
 /**
  * @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) {
+function flattenSingleChildIntoContext(
+  traverseContext: mixed,
+  child: ReactElement<any>,
+  name: string,
+  selfDebugID?: number,
+): void {
   // We found a component instance.
-  var result = traverseContext;
-  var keyUnique = (result[name] === undefined);
-  if (__DEV__) {
-    warning(
-      keyUnique,
-      '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.',
-      name
-    );
-  }
-  if (keyUnique && child != null) {
-    result[name] = child;
+  if (traverseContext && typeof traverseContext === 'object') {
+    const result = traverseContext;
+    const keyUnique = result[name] === undefined;
+    if (__DEV__) {
+      if (!ReactComponentTreeHook) {
+        ReactComponentTreeHook = require('ReactComponentTreeHook');
+      }
+      if (!keyUnique) {
+        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),
+        );
+      }
+    }
+    if (keyUnique && child != null) {
+      result[name] = child;
+    }
   }
 }
 
@@ -42,12 +73,30 @@ function flattenSingleChildIntoContext(traverseContext, child, name) {
  * children will not be included in the resulting object.
  * @return {!object} flattened children keyed by name.
  */
-function flattenChildren(children) {
+function flattenChildren(
+  children: ReactElement<any>,
+  selfDebugID?: number,
+): ?{[name: string]: ReactElement<any>} {
   if (children == null) {
     return children;
   }
   var result = {};
-  traverseAllChildren(children, flattenSingleChildIntoContext, result);
+
+  if (__DEV__) {
+    traverseAllChildren(
+      children,
+      (traverseContext, child, name) =>
+        flattenSingleChildIntoContext(
+          traverseContext,
+          child,
+          name,
+          selfDebugID,
+        ),
+      result,
+    );
+  } else {
+    traverseAllChildren(children, flattenSingleChildIntoContext, result);
+  }
   return result;
 }
 
diff --git a/src/shared/utils/getIteratorFn.js b/src/shared/utils/getIteratorFn.js
index 5da5c4846a0c..017e5537b2c4 100644
--- a/src/shared/utils/getIteratorFn.js
+++ b/src/shared/utils/getIteratorFn.js
@@ -7,6 +7,7 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule getIteratorFn
+ * @flow
  */
 
 'use strict';
@@ -29,11 +30,11 @@ var FAUX_ITERATOR_SYMBOL = '@@iterator'; // Before Symbol spec.
  * @param {?object} maybeIterable
  * @return {?function}
  */
-function getIteratorFn(maybeIterable) {
-  var iteratorFn = maybeIterable && (
-    (ITERATOR_SYMBOL && maybeIterable[ITERATOR_SYMBOL]) ||
-    maybeIterable[FAUX_ITERATOR_SYMBOL]
-  );
+function getIteratorFn(maybeIterable: ?any): ?(p: ReactElement<any>) => void {
+  var iteratorFn =
+    maybeIterable &&
+    ((ITERATOR_SYMBOL && maybeIterable[ITERATOR_SYMBOL]) ||
+      maybeIterable[FAUX_ITERATOR_SYMBOL]);
   if (typeof iteratorFn === 'function') {
     return iteratorFn;
   }
diff --git a/src/shared/utils/getNativeComponentFromComposite.js b/src/shared/utils/getNativeComponentFromComposite.js
deleted file mode 100644
index ff808c3383e4..000000000000
--- a/src/shared/utils/getNativeComponentFromComposite.js
+++ /dev/null
@@ -1,30 +0,0 @@
-/**
- * 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 getNativeComponentFromComposite
- */
-
-'use strict';
-
-var ReactNodeTypes = require('ReactNodeTypes');
-
-function getNativeComponentFromComposite(inst) {
-  var type;
-
-  while ((type = inst._renderedNodeType) === ReactNodeTypes.COMPOSITE) {
-    inst = inst._renderedComponent;
-  }
-
-  if (type === ReactNodeTypes.NATIVE) {
-    return inst._renderedComponent;
-  } else if (type === ReactNodeTypes.EMPTY) {
-    return null;
-  }
-}
-
-module.exports = getNativeComponentFromComposite;
diff --git a/src/shared/utils/isTextInputElement.js b/src/shared/utils/isTextInputElement.js
deleted file mode 100644
index 0b0075dca1a9..000000000000
--- a/src/shared/utils/isTextInputElement.js
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * 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 isTextInputElement
- */
-
-'use strict';
-
-/**
- * @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();
-  return nodeName && (
-    (nodeName === 'input' && supportedInputTypes[elem.type]) ||
-    nodeName === 'textarea'
-  );
-}
-
-module.exports = isTextInputElement;
diff --git a/src/shared/utils/lowPriorityWarning.js b/src/shared/utils/lowPriorityWarning.js
new file mode 100644
index 000000000000..6de5fee71fb0
--- /dev/null
+++ b/src/shared/utils/lowPriorityWarning.js
@@ -0,0 +1,58 @@
+/**
+ * Copyright 2014-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule lowPriorityWarning
+ */
+
+'use strict';
+
+/**
+ * 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 (__DEV__) {
+  const printWarning = function(format, ...args) {
+    var argIndex = 0;
+    var message = 'Warning: ' + format.replace(/%s/g, () => 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, ...args) {
+    if (format === undefined) {
+      throw new Error(
+        '`warning(condition, format, ...args)` requires a warning ' +
+          'message argument',
+      );
+    }
+    if (!condition) {
+      printWarning(format, ...args);
+    }
+  };
+}
+
+module.exports = lowPriorityWarning;
diff --git a/src/shared/utils/reactProdInvariant.js b/src/shared/utils/reactProdInvariant.js
new file mode 100644
index 000000000000..9390b9eaa706
--- /dev/null
+++ b/src/shared/utils/reactProdInvariant.js
@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) 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 reactProdInvariant
+ * @flow
+ */
+'use strict';
+
+/**
+ * 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: string): void {
+  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: Error & {framesToPop?: number} = new Error(message);
+  error.name = 'Invariant Violation';
+  error.framesToPop = 1; // we don't care about reactProdInvariant's own frame
+
+  throw error;
+}
+
+module.exports = reactProdInvariant;
diff --git a/src/shared/utils/traverseAllChildren.js b/src/shared/utils/traverseAllChildren.js
index be0dcc0fd2ba..8bad6e6a9084 100644
--- a/src/shared/utils/traverseAllChildren.js
+++ b/src/shared/utils/traverseAllChildren.js
@@ -12,33 +12,29 @@
 'use strict';
 
 var ReactCurrentOwner = require('ReactCurrentOwner');
-var ReactElement = require('ReactElement');
+var REACT_ELEMENT_TYPE = require('ReactElementSymbol');
 
 var getIteratorFn = require('getIteratorFn');
 var invariant = require('invariant');
+var KeyEscapeUtils = require('KeyEscapeUtils');
 var warning = require('warning');
 
 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 userProvidedKeyEscaperLookup = {
-  '=': '=0',
-  ':': '=2',
-};
-
-var userProvidedKeyEscapeRegex = /[=:]/g;
-
 var didWarnAboutMaps = false;
 
-function userProvidedKeyEscaper(match) {
-  return userProvidedKeyEscaperLookup[match];
-}
-
 /**
  * Generate a key string that identifies a component within a set.
  *
@@ -51,36 +47,12 @@ function getComponentKey(component, index) {
   // that we don't block potential future ES APIs.
   if (component && typeof component === 'object' && component.key != null) {
     // Explicit key
-    return wrapUserProvidedKey(component.key);
+    return KeyEscapeUtils.escape(component.key);
   }
   // Implicit key determined by the index in the set
   return index.toString(36);
 }
 
-/**
- * Escape a component key so that it is safe to use in a reactid.
- *
- * @param {*} text Component key to be escaped.
- * @return {string} An escaped string.
- */
-function escapeUserProvidedKey(text) {
-  return ('' + text).replace(
-    userProvidedKeyEscapeRegex,
-    userProvidedKeyEscaper
-  );
-}
-
-/**
- * Wrap a `key` value explicitly provided by the user to distinguish it from
- * implicitly-generated keys generated by a component's index in its parent.
- *
- * @param {string} key Value of a user-provided `key` attribute
- * @return {string}
- */
-function wrapUserProvidedKey(key) {
-  return '$' + escapeUserProvidedKey(key);
-}
-
 /**
  * @param {?*} children Children tree container.
  * @param {!string} nameSoFar Name of the key path so far.
@@ -93,7 +65,7 @@ function traverseAllChildrenImpl(
   children,
   nameSoFar,
   callback,
-  traverseContext
+  traverseContext,
 ) {
   var type = typeof children;
 
@@ -102,16 +74,20 @@ function traverseAllChildrenImpl(
     children = null;
   }
 
-  if (children === null ||
-      type === 'string' ||
-      type === 'number' ||
-      ReactElement.isValidElement(children)) {
+  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
+      nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar,
     );
     return 1;
   }
@@ -129,7 +105,7 @@ function traverseAllChildrenImpl(
         child,
         nextName,
         callback,
-        traverseContext
+        traverseContext,
       );
     }
   } else {
@@ -146,16 +122,27 @@ function traverseAllChildrenImpl(
             child,
             nextName,
             callback,
-            traverseContext
+            traverseContext,
           );
         }
       } else {
         if (__DEV__) {
+          var mapsAsChildrenAddendum = '';
+          if (ReactCurrentOwner.current) {
+            var mapsAsChildrenOwnerName = ReactCurrentOwner.current.getName();
+            if (mapsAsChildrenOwnerName) {
+              mapsAsChildrenAddendum =
+                ' Check the render method of `' +
+                mapsAsChildrenOwnerName +
+                '`.';
+            }
+          }
           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.'
+              'experimental feature that might be removed. Convert it to a ' +
+              'sequence / iterable of keyed ReactElements instead.%s',
+            mapsAsChildrenAddendum,
           );
           didWarnAboutMaps = true;
         }
@@ -164,16 +151,16 @@ function traverseAllChildrenImpl(
           var entry = step.value;
           if (entry) {
             child = entry[1];
-            nextName = (
+            nextName =
               nextNamePrefix +
-              wrapUserProvidedKey(entry[0]) + SUBSEPARATOR +
-              getComponentKey(child, 0)
-            );
+              KeyEscapeUtils.escape(entry[0]) +
+              SUBSEPARATOR +
+              getComponentKey(child, 0);
             subtreeCount += traverseAllChildrenImpl(
               child,
               nextName,
               callback,
-              traverseContext
+              traverseContext,
             );
           }
         }
@@ -187,7 +174,7 @@ function traverseAllChildrenImpl(
           'React add-ons.';
         if (children._isReactElement) {
           addendum =
-            ' It looks like you\'re using an element created by a different ' +
+            " 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) {
@@ -201,10 +188,10 @@ function traverseAllChildrenImpl(
       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
+        childrenString === '[object Object]'
+          ? 'object with keys {' + Object.keys(children).join(', ') + '}'
+          : childrenString,
+        addendum,
       );
     }
   }
diff --git a/src/test/MetaMatchers.js b/src/test/MetaMatchers.js
deleted file mode 100644
index 3605de66d170..000000000000
--- a/src/test/MetaMatchers.js
+++ /dev/null
@@ -1,128 +0,0 @@
-/**
- * Copyright 2015-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 MetaMatchers
- */
-
-'use strict';
-
-/**
- * This modules adds a jasmine matcher toEqualSpecsIn that can be used to
- * compare the specs in two different "describe" functions and their result.
- * It can be used to test a test.
- */
-
-function getRunnerWithResults(describeFunction) {
-  if (describeFunction._cachedRunner) {
-    // Cached result of execution. This is a convenience way to test against
-    // the same authoritative function multiple times.
-    return describeFunction._cachedRunner;
-  }
-  // Patch the current global environment.
-  var env = new jasmine.Env();
-  // Execute the tests synchronously.
-  env.updateInterval = 0;
-  var outerGetEnv = jasmine.getEnv;
-  jasmine.getEnv = function() {
-    return env;
-  };
-  // TODO: Bring over matchers from the existing environment.
-  var runner = env.currentRunner();
-  try {
-    env.describe('', describeFunction);
-    env.execute();
-  } finally {
-    // Restore the environment.
-    jasmine.getEnv = outerGetEnv;
-  }
-  describeFunction._cachedRunner = runner;
-  return runner;
-}
-
-function compareSpec(actual, expected) {
-  if (actual.results().totalCount !== expected.results().totalCount) {
-    return (
-      'Expected ' + expected.results().totalCount + ' expects, ' +
-      'but got ' + actual.results().totalCount + ':' +
-      actual.getFullName()
-    );
-  }
-  return null;
-}
-
-function includesDescription(specs, description, startIndex) {
-  for (var i = startIndex; i < specs.length; i++) {
-    if (specs[i].description === description) {
-      return true;
-    }
-  }
-  return false;
-}
-
-function compareSpecs(actualSpecs, expectedSpecs) {
-  for (var i = 0; i < actualSpecs.length && i < expectedSpecs.length; i++) {
-    var actual = actualSpecs[i];
-    var expected = expectedSpecs[i];
-    if (actual.description === expected.description) {
-      var errorMessage = compareSpec(actual, expected);
-      if (errorMessage) {
-        return errorMessage;
-      }
-      continue;
-    } else if (includesDescription(actualSpecs, expected.description, i)) {
-      return 'Did not expect the spec:' + actualSpecs[i].getFullName();
-    } else {
-      return 'Expected an equivalent to:' + expectedSpecs[i].getFullName();
-    }
-  }
-  if (i < actualSpecs.length) {
-    return 'Did not expect the spec:' + actualSpecs[i].getFullName();
-  }
-  if (i < expectedSpecs.length) {
-    return 'Expected an equivalent to:' + expectedSpecs[i].getFullName();
-  }
-  return null;
-}
-
-function compareDescription(a, b) {
-  if (a.description === b.description) {
-    return 0;
-  }
-  return a.description < b.description ? -1 : 1;
-}
-
-function compareRunners(actual, expected) {
-  return compareSpecs(
-    actual.specs().sort(compareDescription),
-    expected.specs().sort(compareDescription)
-  );
-}
-
-var MetaMatchers = {
-  toEqualSpecsIn: function(expectedDescribeFunction) {
-    var actualDescribeFunction = this.actual;
-    if (typeof actualDescribeFunction !== 'function') {
-      throw Error('toEqualSpecsIn() should be used on a describe function');
-    }
-    if (typeof expectedDescribeFunction !== 'function') {
-      throw Error('toEqualSpecsIn() should be passed a describe function');
-    }
-    var actual = getRunnerWithResults(actualDescribeFunction);
-    var expected = getRunnerWithResults(expectedDescribeFunction);
-    var errorMessage = compareRunners(actual, expected);
-    this.message = function() {
-      return [
-        errorMessage,
-        'The specs are equal. Expected them to be different.',
-      ];
-    };
-    return !errorMessage;
-  },
-};
-
-module.exports = MetaMatchers;
diff --git a/src/test/ReactComponentTreeTestUtils.js b/src/test/ReactComponentTreeTestUtils.js
new file mode 100644
index 000000000000..889e72b116d7
--- /dev/null
+++ b/src/test/ReactComponentTreeTestUtils.js
@@ -0,0 +1,107 @@
+/**
+ * Copyright 2016-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 ReactComponentTreeTestUtils
+ */
+
+'use strict';
+
+var ReactComponentTreeHook = require('ReactComponentTreeHook');
+
+function getRootDisplayNames() {
+  return ReactComponentTreeHook.getRootIDs().map(
+    ReactComponentTreeHook.getDisplayName,
+  );
+}
+
+function getRegisteredDisplayNames() {
+  return ReactComponentTreeHook.getRegisteredIDs().map(
+    ReactComponentTreeHook.getDisplayName,
+  );
+}
+
+function expectTree(rootID, expectedTree, parentPath) {
+  var displayName = ReactComponentTreeHook.getDisplayName(rootID);
+  var ownerID = ReactComponentTreeHook.getOwnerID(rootID);
+  var parentID = ReactComponentTreeHook.getParentID(rootID);
+  var childIDs = ReactComponentTreeHook.getChildIDs(rootID);
+  var text = ReactComponentTreeHook.getText(rootID);
+  var element = ReactComponentTreeHook.getElement(rootID);
+  var path = parentPath ? `${parentPath} > ${displayName}` : displayName;
+
+  function expectEqual(actual, expected, name) {
+    // Get Jasmine to print descriptive error messages.
+    // We pass path so that we know where the mismatch occurred.
+    expect({
+      path,
+      [name]: actual,
+    }).toEqual({
+      path,
+      [name]: expected,
+    });
+  }
+
+  if (expectedTree.parentDisplayName !== undefined) {
+    expectEqual(
+      ReactComponentTreeHook.getDisplayName(parentID),
+      expectedTree.parentDisplayName,
+      'parentDisplayName',
+    );
+  }
+  if (expectedTree.ownerDisplayName !== undefined) {
+    expectEqual(
+      ReactComponentTreeHook.getDisplayName(ownerID),
+      expectedTree.ownerDisplayName,
+      'ownerDisplayName',
+    );
+  }
+  if (expectedTree.parentID !== undefined) {
+    expectEqual(parentID, expectedTree.parentID, 'parentID');
+  }
+  if (expectedTree.text !== undefined) {
+    expectEqual(text, expectedTree.text, 'text');
+    expectEqual('' + element, expectedTree.text, 'element.toString()');
+  } else {
+    expectEqual(text, null, 'text');
+  }
+  if (expectedTree.element !== undefined) {
+    // TODO: Comparing elements makes tests run out of memory on errors.
+    // For now, compare just types.
+    expectEqual(
+      element && element.type,
+      expectedTree.element && expectedTree.element.type,
+      'element.type',
+    );
+  } else if (text == null) {
+    expectEqual(typeof element, 'object', 'typeof element');
+  }
+  if (expectedTree.children !== undefined) {
+    expectEqual(
+      childIDs.length,
+      expectedTree.children.length,
+      'children.length',
+    );
+    for (var i = 0; i < childIDs.length; i++) {
+      expectTree(
+        childIDs[i],
+        {parentID: rootID, ...expectedTree.children[i]},
+        path,
+      );
+    }
+  } else {
+    expectEqual(childIDs, [], 'childIDs');
+  }
+}
+
+var ReactComponentTreeTestUtils = {
+  expectTree,
+  getRootDisplayNames,
+  getRegisteredDisplayNames,
+};
+
+module.exports = ReactComponentTreeTestUtils;
diff --git a/src/test/ReactDefaultPerf.js b/src/test/ReactDefaultPerf.js
deleted file mode 100644
index 5cb43e9048e0..000000000000
--- a/src/test/ReactDefaultPerf.js
+++ /dev/null
@@ -1,361 +0,0 @@
-/**
- * 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 ReactDefaultPerf
- */
-
-'use strict';
-
-var DOMProperty = require('DOMProperty');
-var ReactDOMComponentTree = require('ReactDOMComponentTree');
-var ReactDefaultPerfAnalysis = require('ReactDefaultPerfAnalysis');
-var ReactMount = require('ReactMount');
-var ReactPerf = require('ReactPerf');
-
-var performanceNow = require('performanceNow');
-var warning = require('warning');
-
-function roundFloat(val) {
-  return Math.floor(val * 100) / 100;
-}
-
-function addValue(obj, key, val) {
-  obj[key] = (obj[key] || 0) + val;
-}
-
-// Composite/text components don't have any built-in ID: we have to make our own
-var compositeIDMap;
-var compositeIDCounter = 17000;
-function getIDOfComposite(inst) {
-  if (!compositeIDMap) {
-    compositeIDMap = new WeakMap();
-  }
-  if (compositeIDMap.has(inst)) {
-    return compositeIDMap.get(inst);
-  } else {
-    var id = compositeIDCounter++;
-    compositeIDMap.set(inst, id);
-    return id;
-  }
-}
-
-function getID(inst) {
-  if (inst.hasOwnProperty('_rootNodeID')) {
-    return inst._rootNodeID;
-  } else {
-    return getIDOfComposite(inst);
-  }
-}
-
-function stripComplexValues(key, value) {
-  if (typeof value !== 'object' || Array.isArray(value) || value == null) {
-    return value;
-  }
-  var prototype = Object.getPrototypeOf(value);
-  if (!prototype || prototype === Object.prototype) {
-    return value;
-  }
-  return '<not serializable>';
-}
-
-// This implementation of ReactPerf is going away some time mid 15.x.
-// While we plan to keep most of the API, the actual format of measurements
-// will change dramatically. To signal this, we wrap them into an opaque-ish
-// object to discourage reaching into it until the API stabilizes.
-function wrapLegacyMeasurements(measurements) {
-  return { __unstable_this_format_will_change: measurements };
-}
-function unwrapLegacyMeasurements(measurements) {
-  return measurements && measurements.__unstable_this_format_will_change || measurements;
-}
-
-var warnedAboutPrintDOM = false;
-var warnedAboutGetMeasurementsSummaryMap = false;
-
-var ReactDefaultPerf = {
-  _allMeasurements: [], // last item in the list is the current one
-  _mountStack: [0],
-  _compositeStack: [],
-  _injected: false,
-
-  start: function() {
-    if (!ReactDefaultPerf._injected) {
-      ReactPerf.injection.injectMeasure(ReactDefaultPerf.measure);
-    }
-
-    ReactDefaultPerf._allMeasurements.length = 0;
-    ReactPerf.enableMeasure = true;
-  },
-
-  stop: function() {
-    ReactPerf.enableMeasure = false;
-  },
-
-  getLastMeasurements: function() {
-    return wrapLegacyMeasurements(ReactDefaultPerf._allMeasurements);
-  },
-
-  printExclusive: function(measurements) {
-    measurements = unwrapLegacyMeasurements(measurements || ReactDefaultPerf._allMeasurements);
-    var summary = ReactDefaultPerfAnalysis.getExclusiveSummary(measurements);
-    console.table(summary.map(function(item) {
-      return {
-        'Component class name': item.componentName,
-        'Total inclusive time (ms)': roundFloat(item.inclusive),
-        'Exclusive mount time (ms)': roundFloat(item.exclusive),
-        'Exclusive render time (ms)': roundFloat(item.render),
-        'Mount time per instance (ms)': roundFloat(item.exclusive / item.count),
-        'Render time per instance (ms)': roundFloat(item.render / item.count),
-        'Instances': item.count,
-      };
-    }));
-    // TODO: ReactDefaultPerfAnalysis.getTotalTime() does not return the correct
-    // number.
-  },
-
-  printInclusive: function(measurements) {
-    measurements = unwrapLegacyMeasurements(measurements || ReactDefaultPerf._allMeasurements);
-    var summary = ReactDefaultPerfAnalysis.getInclusiveSummary(measurements);
-    console.table(summary.map(function(item) {
-      return {
-        'Owner > component': item.componentName,
-        'Inclusive time (ms)': roundFloat(item.time),
-        'Instances': item.count,
-      };
-    }));
-    console.log(
-      'Total time:',
-      ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'
-    );
-  },
-
-  getMeasurementsSummaryMap: function(measurements) {
-    warning(
-      warnedAboutGetMeasurementsSummaryMap,
-      '`ReactPerf.getMeasurementsSummaryMap(...)` is deprecated. Use ' +
-      '`ReactPerf.getWasted(...)` instead.'
-    );
-    warnedAboutGetMeasurementsSummaryMap = true;
-    return ReactDefaultPerf.getWasted(measurements);
-  },
-
-  getWasted: function(measurements) {
-    measurements = unwrapLegacyMeasurements(measurements);
-    var summary = ReactDefaultPerfAnalysis.getInclusiveSummary(
-      measurements,
-      true
-    );
-    return summary.map(function(item) {
-      return {
-        'Owner > component': item.componentName,
-        'Wasted time (ms)': item.time,
-        'Instances': item.count,
-      };
-    });
-  },
-
-  printWasted: function(measurements) {
-    measurements = unwrapLegacyMeasurements(measurements || ReactDefaultPerf._allMeasurements);
-    console.table(ReactDefaultPerf.getWasted(measurements));
-    console.log(
-      'Total time:',
-      ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'
-    );
-  },
-
-  printDOM: function(measurements) {
-    warning(
-      warnedAboutPrintDOM,
-      '`ReactPerf.printDOM(...)` is deprecated. Use ' +
-      '`ReactPerf.printOperations(...)` instead.'
-    );
-    warnedAboutPrintDOM = true;
-    return ReactDefaultPerf.printOperations(measurements);
-  },
-
-  printOperations: function(measurements) {
-    measurements = unwrapLegacyMeasurements(measurements || ReactDefaultPerf._allMeasurements);
-    var summary = ReactDefaultPerfAnalysis.getDOMSummary(measurements);
-    console.table(summary.map(function(item) {
-      var result = {};
-      result[DOMProperty.ID_ATTRIBUTE_NAME] = item.id;
-      result.type = item.type;
-      result.args = JSON.stringify(item.args, stripComplexValues);
-      return result;
-    }));
-    console.log(
-      'Total time:',
-      ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'
-    );
-  },
-
-  _recordWrite: function(id, fnName, totalTime, args) {
-    // TODO: totalTime isn't that useful since it doesn't count paints/reflows
-    var entry =
-      ReactDefaultPerf
-        ._allMeasurements[ReactDefaultPerf._allMeasurements.length - 1];
-    var writes = entry.writes;
-    writes[id] = writes[id] || [];
-    writes[id].push({
-      type: fnName,
-      time: totalTime,
-      args: args,
-    });
-  },
-
-  measure: function(moduleName, fnName, func) {
-    return function(...args) {
-      var totalTime;
-      var rv;
-      var start;
-
-      var entry = ReactDefaultPerf._allMeasurements[
-        ReactDefaultPerf._allMeasurements.length - 1
-      ];
-
-      if (fnName === '_renderNewRootComponent' ||
-          fnName === 'flushBatchedUpdates') {
-        // A "measurement" is a set of metrics recorded for each flush. We want
-        // to group the metrics for a given flush together so we can look at the
-        // components that rendered and the DOM operations that actually
-        // happened to determine the amount of "wasted work" performed.
-        ReactDefaultPerf._allMeasurements.push(entry = {
-          exclusive: {},
-          inclusive: {},
-          render: {},
-          counts: {},
-          writes: {},
-          displayNames: {},
-          hierarchy: {},
-          totalTime: 0,
-          created: {},
-        });
-        start = performanceNow();
-        rv = func.apply(this, args);
-        entry.totalTime = performanceNow() - start;
-        return rv;
-      } else if (fnName === '_mountImageIntoNode' ||
-          moduleName === 'ReactDOMIDOperations' ||
-          moduleName === 'CSSPropertyOperations' ||
-          moduleName === 'DOMChildrenOperations' ||
-          moduleName === 'DOMPropertyOperations' ||
-          moduleName === 'ReactComponentBrowserEnvironment') {
-        start = performanceNow();
-        rv = func.apply(this, args);
-        totalTime = performanceNow() - start;
-
-        if (fnName === '_mountImageIntoNode') {
-          ReactDefaultPerf._recordWrite('', fnName, totalTime, args[0]);
-        } else if (fnName === 'dangerouslyProcessChildrenUpdates') {
-          // special format
-          args[1].forEach(function(update) {
-            var writeArgs = {};
-            if (update.fromIndex !== null) {
-              writeArgs.fromIndex = update.fromIndex;
-            }
-            if (update.toIndex !== null) {
-              writeArgs.toIndex = update.toIndex;
-            }
-            if (update.content !== null) {
-              writeArgs.content = update.content;
-            }
-            ReactDefaultPerf._recordWrite(
-              args[0]._rootNodeID,
-              update.type,
-              totalTime,
-              writeArgs
-            );
-          });
-        } else {
-          // basic format
-          var id = args[0];
-          if (moduleName === 'EventPluginHub') {
-            id = id._rootNodeID;
-          } else if (fnName === 'replaceNodeWithMarkup') {
-            // Old node is already unmounted; can't get its instance
-            id = ReactDOMComponentTree.getInstanceFromNode(args[1].node)._rootNodeID;
-          } else if (fnName === 'replaceDelimitedText') {
-            id = getID(ReactDOMComponentTree.getInstanceFromNode(args[0]));
-          } else if (typeof id === 'object') {
-            id = getID(ReactDOMComponentTree.getInstanceFromNode(args[0]));
-          }
-          ReactDefaultPerf._recordWrite(
-            id,
-            fnName,
-            totalTime,
-            Array.prototype.slice.call(args, 1)
-          );
-        }
-        return rv;
-      } else if (moduleName === 'ReactCompositeComponent' && (
-        fnName === 'mountComponent' ||
-        fnName === 'updateComponent' || // TODO: receiveComponent()?
-        fnName === '_renderValidatedComponent')) {
-
-        if (this._currentElement.type === ReactMount.TopLevelWrapper) {
-          return func.apply(this, args);
-        }
-
-        var rootNodeID = getIDOfComposite(this);
-        var isRender = fnName === '_renderValidatedComponent';
-        var isMount = fnName === 'mountComponent';
-
-        var mountStack = ReactDefaultPerf._mountStack;
-
-        if (isRender) {
-          addValue(entry.counts, rootNodeID, 1);
-        } else if (isMount) {
-          entry.created[rootNodeID] = true;
-          mountStack.push(0);
-        }
-
-        ReactDefaultPerf._compositeStack.push(rootNodeID);
-
-        start = performanceNow();
-        rv = func.apply(this, args);
-        totalTime = performanceNow() - start;
-
-        ReactDefaultPerf._compositeStack.pop();
-
-        if (isRender) {
-          addValue(entry.render, rootNodeID, totalTime);
-        } else if (isMount) {
-          var subMountTime = mountStack.pop();
-          mountStack[mountStack.length - 1] += totalTime;
-          addValue(entry.exclusive, rootNodeID, totalTime - subMountTime);
-          addValue(entry.inclusive, rootNodeID, totalTime);
-        } else {
-          addValue(entry.inclusive, rootNodeID, totalTime);
-        }
-
-        entry.displayNames[rootNodeID] = {
-          current: this.getName(),
-          owner: this._currentElement._owner ?
-            this._currentElement._owner.getName() :
-            '<root>',
-        };
-
-        return rv;
-      } else if (
-        (moduleName === 'ReactDOMComponent' ||
-         moduleName === 'ReactDOMTextComponent') &&
-        (fnName === 'mountComponent' ||
-         fnName === 'receiveComponent')) {
-
-        rv = func.apply(this, args);
-        entry.hierarchy[getID(this)] =
-          ReactDefaultPerf._compositeStack.slice();
-        return rv;
-      } else {
-        return func.apply(this, args);
-      }
-    };
-  },
-};
-
-module.exports = ReactDefaultPerf;
diff --git a/src/test/ReactDefaultPerfAnalysis.js b/src/test/ReactDefaultPerfAnalysis.js
deleted file mode 100644
index bf7cb30feca6..000000000000
--- a/src/test/ReactDefaultPerfAnalysis.js
+++ /dev/null
@@ -1,213 +0,0 @@
-/**
- * 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 ReactDefaultPerfAnalysis
- */
-
-'use strict';
-
-
-// Don't try to save users less than 1.2ms (a number I made up)
-var DONT_CARE_THRESHOLD = 1.2;
-var DOM_OPERATION_TYPES = {
-  '_mountImageIntoNode': 'set innerHTML',
-  INSERT_MARKUP: 'set innerHTML',
-  MOVE_EXISTING: 'move',
-  REMOVE_NODE: 'remove',
-  SET_MARKUP: 'set innerHTML',
-  TEXT_CONTENT: 'set textContent',
-  'setValueForProperty': 'update attribute',
-  'setValueForAttribute': 'update attribute',
-  'deleteValueForProperty': 'remove attribute',
-  'setValueForStyles': 'update styles',
-  'replaceNodeWithMarkup': 'replace',
-  'replaceDelimitedText': 'replace',
-};
-
-function getTotalTime(measurements) {
-  // TODO: return number of DOM ops? could be misleading.
-  // TODO: measure dropped frames after reconcile?
-  // TODO: log total time of each reconcile and the top-level component
-  // class that triggered it.
-  var totalTime = 0;
-  for (var i = 0; i < measurements.length; i++) {
-    var measurement = measurements[i];
-    totalTime += measurement.totalTime;
-  }
-  return totalTime;
-}
-
-function getDOMSummary(measurements) {
-  var items = [];
-  measurements.forEach(function(measurement) {
-    Object.keys(measurement.writes).forEach(function(id) {
-      measurement.writes[id].forEach(function(write) {
-        items.push({
-          id: id,
-          type: DOM_OPERATION_TYPES[write.type] || write.type,
-          args: write.args,
-        });
-      });
-    });
-  });
-  return items;
-}
-
-function getExclusiveSummary(measurements) {
-  var candidates = {};
-  var displayName;
-
-  for (var i = 0; i < measurements.length; i++) {
-    var measurement = measurements[i];
-    var allIDs = Object.assign(
-      {},
-      measurement.exclusive,
-      measurement.inclusive
-    );
-
-    for (var id in allIDs) {
-      displayName = measurement.displayNames[id].current;
-
-      candidates[displayName] = candidates[displayName] || {
-        componentName: displayName,
-        inclusive: 0,
-        exclusive: 0,
-        render: 0,
-        count: 0,
-      };
-      if (measurement.render[id]) {
-        candidates[displayName].render += measurement.render[id];
-      }
-      if (measurement.exclusive[id]) {
-        candidates[displayName].exclusive += measurement.exclusive[id];
-      }
-      if (measurement.inclusive[id]) {
-        candidates[displayName].inclusive += measurement.inclusive[id];
-      }
-      if (measurement.counts[id]) {
-        candidates[displayName].count += measurement.counts[id];
-      }
-    }
-  }
-
-  // Now make a sorted array with the results.
-  var arr = [];
-  for (displayName in candidates) {
-    if (candidates[displayName].exclusive >= DONT_CARE_THRESHOLD) {
-      arr.push(candidates[displayName]);
-    }
-  }
-
-  arr.sort(function(a, b) {
-    return b.exclusive - a.exclusive;
-  });
-
-  return arr;
-}
-
-function getInclusiveSummary(measurements, onlyClean) {
-  var candidates = {};
-  var inclusiveKey;
-
-  for (var i = 0; i < measurements.length; i++) {
-    var measurement = measurements[i];
-    var allIDs = Object.assign(
-      {},
-      measurement.exclusive,
-      measurement.inclusive
-    );
-    var cleanComponents;
-
-    if (onlyClean) {
-      cleanComponents = getUnchangedComponents(measurement);
-    }
-
-    for (var id in allIDs) {
-      if (onlyClean && !cleanComponents[id]) {
-        continue;
-      }
-
-      var displayName = measurement.displayNames[id];
-
-      // Inclusive time is not useful for many components without knowing where
-      // they are instantiated. So we aggregate inclusive time with both the
-      // owner and current displayName as the key.
-      inclusiveKey = displayName.owner + ' > ' + displayName.current;
-
-      candidates[inclusiveKey] = candidates[inclusiveKey] || {
-        componentName: inclusiveKey,
-        time: 0,
-        count: 0,
-      };
-
-      if (measurement.inclusive[id]) {
-        candidates[inclusiveKey].time += measurement.inclusive[id];
-      }
-      if (measurement.counts[id]) {
-        candidates[inclusiveKey].count += measurement.counts[id];
-      }
-    }
-  }
-
-  // Now make a sorted array with the results.
-  var arr = [];
-  for (inclusiveKey in candidates) {
-    if (candidates[inclusiveKey].time >= DONT_CARE_THRESHOLD) {
-      arr.push(candidates[inclusiveKey]);
-    }
-  }
-
-  arr.sort(function(a, b) {
-    return b.time - a.time;
-  });
-
-  return arr;
-}
-
-function getUnchangedComponents(measurement) {
-  // For a given reconcile, look at which components did not actually
-  // render anything to the DOM and return a mapping of their ID to
-  // the amount of time it took to render the entire subtree.
-  var cleanComponents = {};
-  var writes = measurement.writes;
-  var dirtyComposites = {};
-  Object.keys(writes).forEach(function(id) {
-    writes[id].forEach(function(write) {
-      // Root mounting (innerHTML set) is recorded with an ID of ''
-      if (id !== '') {
-        measurement.hierarchy[id].forEach((c) => dirtyComposites[c] = true);
-      }
-    });
-  });
-  var allIDs = Object.assign({}, measurement.exclusive, measurement.inclusive);
-
-  for (var id in allIDs) {
-    var isDirty = false;
-    // See if any of the DOM operations applied to this component's subtree.
-    if (dirtyComposites[id]) {
-      isDirty = true;
-    }
-    // check if component newly created
-    if (measurement.created[id]) {
-      isDirty = true;
-    }
-    if (!isDirty && measurement.counts[id] > 0) {
-      cleanComponents[id] = true;
-    }
-  }
-  return cleanComponents;
-}
-
-var ReactDefaultPerfAnalysis = {
-  getExclusiveSummary: getExclusiveSummary,
-  getInclusiveSummary: getInclusiveSummary,
-  getDOMSummary: getDOMSummary,
-  getTotalTime: getTotalTime,
-};
-
-module.exports = ReactDefaultPerfAnalysis;
diff --git a/src/test/ReactPerf.js b/src/test/ReactPerf.js
deleted file mode 100644
index 1eb803a4e8cd..000000000000
--- a/src/test/ReactPerf.js
+++ /dev/null
@@ -1,99 +0,0 @@
-/**
- * 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 ReactPerf
- */
-
-'use strict';
-
-/**
- * ReactPerf is a general AOP system designed to measure performance. This
- * module only has the hooks: see ReactDefaultPerf for the analysis tool.
- */
-var ReactPerf = {
-  /**
-   * Boolean to enable/disable measurement. Set to false by default to prevent
-   * accidental logging and perf loss.
-   */
-  enableMeasure: false,
-
-  /**
-   * Holds onto the measure function in use. By default, don't measure
-   * anything, but we'll override this if we inject a measure function.
-   */
-  storedMeasure: _noMeasure,
-
-  /**
-   * @param {object} object
-   * @param {string} objectName
-   * @param {object<string>} methodNames
-   */
-  measureMethods: function(object, objectName, methodNames) {
-    if (__DEV__) {
-      for (var key in methodNames) {
-        if (!methodNames.hasOwnProperty(key)) {
-          continue;
-        }
-        object[key] = ReactPerf.measure(
-          objectName,
-          methodNames[key],
-          object[key]
-        );
-      }
-    }
-  },
-
-  /**
-   * Use this to wrap methods you want to measure. Zero overhead in production.
-   *
-   * @param {string} objName
-   * @param {string} fnName
-   * @param {function} func
-   * @return {function}
-   */
-  measure: function(objName, fnName, func) {
-    if (__DEV__) {
-      var measuredFunc = null;
-      var wrapper = function() {
-        if (ReactPerf.enableMeasure) {
-          if (!measuredFunc) {
-            measuredFunc = ReactPerf.storedMeasure(objName, fnName, func);
-          }
-          return measuredFunc.apply(this, arguments);
-        }
-        return func.apply(this, arguments);
-      };
-      wrapper.displayName = objName + '_' + fnName;
-      return wrapper;
-    }
-    return func;
-  },
-
-  injection: {
-    /**
-     * @param {function} measure
-     */
-    injectMeasure: function(measure) {
-      ReactPerf.storedMeasure = measure;
-    },
-  },
-};
-
-/**
- * Simply passes through the measured function, without measuring it.
- *
- * @param {string} objName
- * @param {string} fnName
- * @param {function} func
- * @return {function}
- */
-function _noMeasure(objName, fnName, func) {
-  return func;
-}
-
-module.exports = ReactPerf;
diff --git a/src/test/ReactTestUtils.js b/src/test/ReactTestUtils.js
index d1365b50c541..13e1b27709e6 100644
--- a/src/test/ReactTestUtils.js
+++ b/src/test/ReactTestUtils.js
@@ -16,24 +16,37 @@ var EventPluginHub = require('EventPluginHub');
 var EventPluginRegistry = require('EventPluginRegistry');
 var EventPropagators = require('EventPropagators');
 var React = require('React');
-var ReactDefaultInjection = require('ReactDefaultInjection');
 var ReactDOM = require('ReactDOM');
 var ReactDOMComponentTree = require('ReactDOMComponentTree');
-var ReactElement = require('ReactElement');
 var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
-var ReactCompositeComponent = require('ReactCompositeComponent');
 var ReactInstanceMap = require('ReactInstanceMap');
 var ReactUpdates = require('ReactUpdates');
 var SyntheticEvent = require('SyntheticEvent');
+var ReactShallowRenderer = require('ReactShallowRenderer');
 
-var emptyObject = require('emptyObject');
 var findDOMNode = require('findDOMNode');
 var invariant = require('invariant');
+var warning = require('warning');
 
 var topLevelTypes = EventConstants.topLevelTypes;
 
 function Event(suffix) {}
 
+// In react 16+ shallowRenderer will not be accessible via ReactTestUtils.createRenderer()
+// Instead it will be available via react-test-renderer/shallow
+// Maintain backwards compat for 15.5.0 release, but warn about using the deprecated method
+let hasWarnedAboutCreateRenderer = false;
+function createRendererWithWarning() {
+  warning(
+    hasWarnedAboutCreateRenderer,
+    'Shallow renderer has been moved to react-test-renderer/shallow. ' +
+      'Update references to remove this warning.',
+  );
+  hasWarnedAboutCreateRenderer = true;
+
+  return new ReactShallowRenderer();
+}
+
 /**
  * @class ReactTestUtils
  */
@@ -53,48 +66,46 @@ function findAllInRenderedTreeInternal(inst, test) {
         continue;
       }
       ret = ret.concat(
-        findAllInRenderedTreeInternal(
-          renderedChildren[key],
-          test
-        )
+        findAllInRenderedTreeInternal(renderedChildren[key], test),
       );
     }
   } else if (
-    ReactElement.isValidElement(currentElement) &&
+    React.isValidElement(currentElement) &&
     typeof currentElement.type === 'function'
   ) {
     ret = ret.concat(
-      findAllInRenderedTreeInternal(inst._renderedComponent, test)
+      findAllInRenderedTreeInternal(inst._renderedComponent, test),
     );
   }
   return ret;
 }
 
 /**
+ * Utilities for making it easy to test React components.
+ *
+ * See https://facebook.github.io/react/docs/test-utils.html
+ *
  * Todo: Support the entire DOM.scry query syntax. For now, these simple
  * utilities will suffice for testing purposes.
  * @lends ReactTestUtils
  */
 var ReactTestUtils = {
-  renderIntoDocument: function(instance) {
+  renderIntoDocument: function(element) {
     var div = document.createElement('div');
     // None of our tests actually require attaching the container to the
     // DOM, and doing so creates a mess that we rely on test isolation to
     // clean up, so we're going to stop honoring the name of this method
     // (and probably rename it eventually) if no problems arise.
     // document.documentElement.appendChild(div);
-    return ReactDOM.render(instance, div);
+    return ReactDOM.render(element, div);
   },
 
   isElement: function(element) {
-    return ReactElement.isValidElement(element);
+    return React.isValidElement(element);
   },
 
   isElementOfType: function(inst, convenienceConstructor) {
-    return (
-      ReactElement.isValidElement(inst) &&
-      inst.type === convenienceConstructor
-    );
+    return React.isValidElement(inst) && inst.type === convenienceConstructor;
   },
 
   isDOMComponent: function(inst) {
@@ -102,9 +113,7 @@ var ReactTestUtils = {
   },
 
   isDOMComponentElement: function(inst) {
-    return !!(inst &&
-              ReactElement.isValidElement(inst) &&
-              !!inst.tagName);
+    return !!(inst && React.isValidElement(inst) && !!inst.tagName);
   },
 
   isCompositeComponent: function(inst) {
@@ -113,9 +122,11 @@ var ReactTestUtils = {
       // this returns when we have DOM nodes as refs directly
       return false;
     }
-    return inst != null &&
-           typeof inst.render === 'function' &&
-           typeof inst.setState === 'function';
+    return (
+      inst != null &&
+      typeof inst.render === 'function' &&
+      typeof inst.setState === 'function'
+    );
   },
 
   isCompositeComponentWithType: function(inst, type) {
@@ -123,15 +134,13 @@ var ReactTestUtils = {
       return false;
     }
     var internalInstance = ReactInstanceMap.get(inst);
-    var constructor = internalInstance
-      ._currentElement
-      .type;
+    var constructor = internalInstance._currentElement.type;
 
-    return (constructor === type);
+    return constructor === type;
   },
 
   isCompositeComponentElement: function(inst) {
-    if (!ReactElement.isValidElement(inst)) {
+    if (!React.isValidElement(inst)) {
       return false;
     }
     // We check the prototype of the type that will get mounted, not the
@@ -145,12 +154,11 @@ var ReactTestUtils = {
 
   isCompositeComponentElementWithType: function(inst, type) {
     var internalInstance = ReactInstanceMap.get(inst);
-    var constructor = internalInstance
-      ._currentElement
-      .type;
+    var constructor = internalInstance._currentElement.type;
 
-    return !!(ReactTestUtils.isCompositeComponentElement(inst) &&
-             (constructor === type));
+    return !!(
+      ReactTestUtils.isCompositeComponentElement(inst) && constructor === type
+    );
   },
 
   getRenderedChildOfCompositeComponent: function(inst) {
@@ -167,7 +175,7 @@ var ReactTestUtils = {
     }
     invariant(
       ReactTestUtils.isCompositeComponent(inst),
-      'findAllInRenderedTree(...): instance must be a composite component'
+      'findAllInRenderedTree(...): instance must be a composite component',
     );
     return findAllInRenderedTreeInternal(ReactInstanceMap.get(inst), test);
   },
@@ -178,9 +186,6 @@ var ReactTestUtils = {
    * @return {array} an array of all the matches.
    */
   scryRenderedDOMComponentsWithClass: function(root, classNames) {
-    if (!Array.isArray(classNames)) {
-      classNames = classNames.split(/\s+/);
-    }
     return ReactTestUtils.findAllInRenderedTree(root, function(inst) {
       if (ReactTestUtils.isDOMComponent(inst)) {
         var className = inst.className;
@@ -189,6 +194,15 @@ var ReactTestUtils = {
           className = inst.getAttribute('class') || '';
         }
         var classList = className.split(/\s+/);
+
+        if (!Array.isArray(classNames)) {
+          invariant(
+            classNames !== undefined,
+            'TestUtils.scryRenderedDOMComponentsWithClass expects a ' +
+              'className as a second argument.',
+          );
+          classNames = classNames.split(/\s+/);
+        }
         return classNames.every(function(name) {
           return classList.indexOf(name) !== -1;
         });
@@ -204,18 +218,22 @@ var ReactTestUtils = {
    * @return {!ReactDOMComponent} The one match.
    */
   findRenderedDOMComponentWithClass: function(root, className) {
-    var all =
-      ReactTestUtils.scryRenderedDOMComponentsWithClass(root, className);
+    var all = ReactTestUtils.scryRenderedDOMComponentsWithClass(
+      root,
+      className,
+    );
     if (all.length !== 1) {
       throw new Error(
-        'Did not find exactly one match (found: ' + all.length + ') ' +
-        'for class:' + className
+        'Did not find exactly one match (found: ' +
+          all.length +
+          ') ' +
+          'for class:' +
+          className,
       );
     }
     return all[0];
   },
 
-
   /**
    * Finds all instance of components in the rendered tree that are DOM
    * components with the tag name matching `tagName`.
@@ -223,8 +241,10 @@ var ReactTestUtils = {
    */
   scryRenderedDOMComponentsWithTag: function(root, tagName) {
     return ReactTestUtils.findAllInRenderedTree(root, function(inst) {
-      return ReactTestUtils.isDOMComponent(inst) &&
-            inst.tagName.toUpperCase() === tagName.toUpperCase();
+      return (
+        ReactTestUtils.isDOMComponent(inst) &&
+        inst.tagName.toUpperCase() === tagName.toUpperCase()
+      );
     });
   },
 
@@ -238,24 +258,23 @@ var ReactTestUtils = {
     var all = ReactTestUtils.scryRenderedDOMComponentsWithTag(root, tagName);
     if (all.length !== 1) {
       throw new Error(
-        'Did not find exactly one match (found: ' + all.length + ') ' +
-        'for tag:' + tagName
+        'Did not find exactly one match (found: ' +
+          all.length +
+          ') ' +
+          'for tag:' +
+          tagName,
       );
     }
     return all[0];
   },
 
-
   /**
    * Finds all instances of components with type equal to `componentType`.
    * @return {array} an array of all the matches.
    */
   scryRenderedComponentsWithType: function(root, componentType) {
     return ReactTestUtils.findAllInRenderedTree(root, function(inst) {
-      return ReactTestUtils.isCompositeComponentWithType(
-        inst,
-        componentType
-      );
+      return ReactTestUtils.isCompositeComponentWithType(inst, componentType);
     });
   },
 
@@ -268,12 +287,15 @@ var ReactTestUtils = {
   findRenderedComponentWithType: function(root, componentType) {
     var all = ReactTestUtils.scryRenderedComponentsWithType(
       root,
-      componentType
+      componentType,
     );
     if (all.length !== 1) {
       throw new Error(
-        'Did not find exactly one match (found: ' + all.length + ') ' +
-        'for componentType:' + componentType
+        'Did not find exactly one match (found: ' +
+          all.length +
+          ') ' +
+          'for componentType:' +
+          componentType,
       );
     }
     return all[0];
@@ -296,11 +318,7 @@ var ReactTestUtils = {
     mockTagName = mockTagName || module.mockTagName || 'div';
 
     module.prototype.render.mockImplementation(function() {
-      return React.createElement(
-        mockTagName,
-        null,
-        this.props.children
-      );
+      return React.createElement(mockTagName, null, this.props.children);
     });
 
     return this;
@@ -315,9 +333,10 @@ var ReactTestUtils = {
    */
   simulateNativeEventOnNode: function(topLevelType, node, fakeNativeEvent) {
     fakeNativeEvent.target = node;
+    fakeNativeEvent.simulated = true;
     ReactBrowserEventEmitter.ReactEventListener.dispatchEvent(
       topLevelType,
-      fakeNativeEvent
+      fakeNativeEvent,
     );
   },
 
@@ -329,146 +348,29 @@ var ReactTestUtils = {
    * @param {?Event} fakeNativeEvent Fake native event to use in SyntheticEvent.
    */
   simulateNativeEventOnDOMComponent: function(
-      topLevelType,
-      comp,
-      fakeNativeEvent) {
+    topLevelType,
+    comp,
+    fakeNativeEvent,
+  ) {
     ReactTestUtils.simulateNativeEventOnNode(
       topLevelType,
       findDOMNode(comp),
-      fakeNativeEvent
+      fakeNativeEvent,
     );
   },
 
   nativeTouchData: function(x, y) {
     return {
-      touches: [
-        {pageX: x, pageY: y},
-      ],
+      touches: [{pageX: x, pageY: y}],
     };
   },
 
-  createRenderer: function() {
-    return new ReactShallowRenderer();
-  },
+  createRenderer: createRendererWithWarning,
 
   Simulate: null,
   SimulateNative: {},
 };
 
-/**
- * @class ReactShallowRenderer
- */
-var ReactShallowRenderer = function() {
-  this._instance = null;
-};
-
-ReactShallowRenderer.prototype.getMountedInstance = function() {
-  return this._instance ? this._instance._instance : null;
-};
-
-var NoopInternalComponent = function(element) {
-  this._renderedOutput = element;
-  this._currentElement = element;
-};
-
-NoopInternalComponent.prototype = {
-
-  mountComponent: function() {
-  },
-
-  receiveComponent: function(element) {
-    this._renderedOutput = element;
-    this._currentElement = element;
-  },
-
-  getNativeNode: function() {
-    return undefined;
-  },
-
-  unmountComponent: function() {
-  },
-
-  getPublicInstance: function() {
-    return null;
-  },
-};
-
-var ShallowComponentWrapper = function(element) {
-  this.construct(element);
-};
-Object.assign(
-  ShallowComponentWrapper.prototype,
-  ReactCompositeComponent.Mixin, {
-    _instantiateReactComponent: function(element) {
-      return new NoopInternalComponent(element);
-    },
-    _replaceNodeWithMarkup: function() {},
-    _renderValidatedComponent:
-      ReactCompositeComponent.Mixin
-        ._renderValidatedComponentWithoutOwnerOrContext,
-  }
-);
-
-ReactShallowRenderer.prototype.render = function(element, context) {
-  // Ensure we've done the default injections. This might not be true in the
-  // case of a simple test that only requires React and the TestUtils in
-  // conjunction with an inline-requires transform.
-  ReactDefaultInjection.inject();
-
-  invariant(
-    ReactElement.isValidElement(element),
-    'ReactShallowRenderer render(): Invalid component element.%s',
-    typeof element === 'function' ?
-      ' Instead of passing a component class, make sure to instantiate ' +
-      'it by passing it to React.createElement.' :
-      ''
-  );
-  invariant(
-    typeof element.type !== 'string',
-    'ReactShallowRenderer render(): Shallow rendering works only with custom ' +
-    'components, not primitives (%s). Instead of calling `.render(el)` and ' +
-    'inspecting the rendered output, look at `el.props` directly instead.',
-    element.type
-  );
-
-  if (!context) {
-    context = emptyObject;
-  }
-  ReactUpdates.batchedUpdates(_batchedRender, this, element, context);
-
-  return this.getRenderOutput();
-};
-
-function _batchedRender(renderer, element, context) {
-  var transaction = ReactUpdates.ReactReconcileTransaction.getPooled(true);
-  renderer._render(element, transaction, context);
-  ReactUpdates.ReactReconcileTransaction.release(transaction);
-}
-
-ReactShallowRenderer.prototype.getRenderOutput = function() {
-  return (
-    (this._instance && this._instance._renderedComponent &&
-     this._instance._renderedComponent._renderedOutput)
-    || null
-  );
-};
-
-ReactShallowRenderer.prototype.unmount = function() {
-  if (this._instance) {
-    this._instance.unmountComponent(false);
-  }
-};
-
-ReactShallowRenderer.prototype._render = function(element, transaction, context) {
-  if (this._instance) {
-    this._instance.receiveComponent(element, transaction, context);
-  } else {
-    var instance = new ShallowComponentWrapper(element);
-    instance.mountComponent(transaction, null, null, context);
-    this._instance = instance;
-  }
-};
-
 /**
  * Exports:
  *
@@ -483,7 +385,7 @@ function makeSimulator(eventType) {
     invariant(
       !React.isValidElement(domComponentOrNode),
       'TestUtils.Simulate expects a component instance and not a ReactElement.' +
-      'TestUtils.Simulate will not work if you are using shallow rendering.'
+        'TestUtils.Simulate will not work if you are using shallow rendering.',
     );
     if (ReactTestUtils.isDOMComponent(domComponentOrNode)) {
       node = findDOMNode(domComponentOrNode);
@@ -496,13 +398,15 @@ function makeSimulator(eventType) {
 
     var fakeNativeEvent = new Event();
     fakeNativeEvent.target = node;
+    fakeNativeEvent.type = eventType.toLowerCase();
+
     // We don't use SyntheticEvent.getPooled in order to not have to worry about
     // properly destroying any properties assigned from `eventData` upon release
     var event = new SyntheticEvent(
       dispatchConfig,
       ReactDOMComponentTree.getInstanceFromNode(node),
       fakeNativeEvent,
-      node
+      node,
     );
     // Since we aren't using pooling, always persist the event. This will make
     // sure it's marked and won't warn when setting additional properties.
@@ -573,14 +477,14 @@ function makeNativeSimulator(eventType) {
       ReactTestUtils.simulateNativeEventOnDOMComponent(
         eventType,
         domComponentOrNode,
-        fakeNativeEvent
+        fakeNativeEvent,
       );
     } else if (domComponentOrNode.tagName) {
       // Will allow on actual dom nodes.
       ReactTestUtils.simulateNativeEventOnNode(
         eventType,
         domComponentOrNode,
-        fakeNativeEvent
+        fakeNativeEvent,
       );
     }
   };
@@ -588,14 +492,16 @@ function makeNativeSimulator(eventType) {
 
 Object.keys(topLevelTypes).forEach(function(eventType) {
   // Event type is stored as 'topClick' - we transform that to 'click'
-  var convenienceName = eventType.indexOf('top') === 0 ?
-    eventType.charAt(3).toLowerCase() + eventType.substr(4) : eventType;
+  var convenienceName = eventType.indexOf('top') === 0
+    ? eventType.charAt(3).toLowerCase() + eventType.substr(4)
+    : eventType;
   /**
    * @param {!Element|ReactDOMComponent} domComponentOrNode
    * @param {?Event} nativeEventData Fake native event to use in SyntheticEvent.
    */
-  ReactTestUtils.SimulateNative[convenienceName] =
-    makeNativeSimulator(eventType);
+  ReactTestUtils.SimulateNative[convenienceName] = makeNativeSimulator(
+    eventType,
+  );
 });
 
 module.exports = ReactTestUtils;
diff --git a/src/test/__tests__/MetaMatchers-test.js b/src/test/__tests__/MetaMatchers-test.js
deleted file mode 100644
index be03c9604ba6..000000000000
--- a/src/test/__tests__/MetaMatchers-test.js
+++ /dev/null
@@ -1,62 +0,0 @@
-/**
- * Copyright 2015-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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-var MetaMatchers = require('MetaMatchers');
-
-describe('meta-matchers', function() {
-
-  beforeEach(function() {
-    this.addMatchers(MetaMatchers);
-  });
-
-  function a() {
-    it('should add 1 and 2', function() {
-      expect(1 + 2).toBe(3);
-    });
-  }
-
-  function b() {
-    it('should add 1 and 2', function() {
-      expect(1 + 2).toBe(3);
-    });
-  }
-
-  function c() {
-    it('should add 1 and 2', function() {
-      expect(1 + 2).toBe(3);
-    });
-    it('should mutiply 1 and 2', function() {
-      expect(1 * 2).toBe(2);
-    });
-  }
-
-  function d() {
-    it('should add 1 and 2', function() {
-      expect(1 + 2).toBe(3);
-    });
-    it('should mutiply 1 and 2', function() {
-      expect(1 * 2).toBe(2);
-      expect(2 * 1).toBe(2);
-    });
-  }
-
-  it('tests equality of specs', function() {
-    expect(a).toEqualSpecsIn(b);
-  });
-
-  it('tests inequality of specs and expects', function() {
-    expect(b).not.toEqualSpecsIn(c);
-    expect(c).not.toEqualSpecsIn(d);
-  });
-
-});
diff --git a/src/test/__tests__/ReactDefaultPerf-test.js b/src/test/__tests__/ReactDefaultPerf-test.js
deleted file mode 100644
index cc16c8846215..000000000000
--- a/src/test/__tests__/ReactDefaultPerf-test.js
+++ /dev/null
@@ -1,287 +0,0 @@
-/**
- * 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.
- *
- * @emails react-core
- */
-
-'use strict';
-
-describe('ReactDefaultPerf', function() {
-  var React;
-  var ReactDOM;
-  var ReactDOMFeatureFlags;
-  var ReactDefaultPerf;
-  var ReactTestUtils;
-  var ReactDefaultPerfAnalysis;
-
-  var App;
-  var Box;
-  var Div;
-
-  beforeEach(function() {
-    var now = 0;
-    jest.setMock('fbjs/lib/performanceNow', function() {
-      return now++;
-    });
-
-    if (typeof console.table !== 'function') {
-      console.table = () => {};
-      console.table.isFake = true;
-    }
-
-    React = require('React');
-    ReactDOM = require('ReactDOM');
-    ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
-    ReactDefaultPerf = require('ReactDefaultPerf');
-    ReactTestUtils = require('ReactTestUtils');
-    ReactDefaultPerfAnalysis = require('ReactDefaultPerfAnalysis');
-
-    App = React.createClass({
-      render: function() {
-        return <div><Box /><Box flip={this.props.flipSecond} /></div>;
-      },
-    });
-
-    Box = React.createClass({
-      render: function() {
-        return <div key={!!this.props.flip}><input /></div>;
-      },
-    });
-
-    // ReactPerf only measures composites, so we put everything in one.
-    Div = React.createClass({
-      render: function() {
-        return <div {...this.props} />;
-      },
-    });
-  });
-
-  afterEach(function() {
-    if (console.table.isFake) {
-      delete console.table;
-    }
-  });
-
-  function measure(fn) {
-    ReactDefaultPerf.start();
-    fn();
-    ReactDefaultPerf.stop();
-    return ReactDefaultPerf.getLastMeasurements().__unstable_this_format_will_change;
-  }
-
-  it('should count no-op update as waste', function() {
-    var container = document.createElement('div');
-    ReactDOM.render(<App />, container);
-    var measurements = measure(() => {
-      ReactDOM.render(<App />, container);
-    });
-
-    var summary = ReactDefaultPerf.getWasted(measurements);
-    expect(summary.length).toBe(2);
-
-    /*eslint-disable dot-notation */
-
-    expect(summary[0]['Owner > component']).toBe('<root> > App');
-    expect(summary[0]['Wasted time (ms)']).not.toBe(0);
-    expect(summary[0]['Instances']).toBe(1);
-
-    expect(summary[1]['Owner > component']).toBe('App > Box');
-    expect(summary[1]['Wasted time (ms)']).not.toBe(0);
-    expect(summary[1]['Instances']).toBe(2);
-
-    /*eslint-enable dot-notation */
-  });
-
-  it('should count no-op update in child as waste', function() {
-    var container = document.createElement('div');
-    ReactDOM.render(<App />, container);
-
-    // Here, we add a Box -- two of the <Box /> updates are wasted time (but the
-    // addition of the third is not)
-    var measurements = measure(() => {
-      ReactDOM.render(<App flipSecond={true} />, container);
-    });
-
-    var summary = ReactDefaultPerf.getWasted(measurements);
-    expect(summary.length).toBe(1);
-
-    /*eslint-disable dot-notation */
-
-    expect(summary[0]['Owner > component']).toBe('App > Box');
-    expect(summary[0]['Wasted time (ms)']).not.toBe(0);
-    expect(summary[0]['Instances']).toBe(1);
-
-    /*eslint-enable dot-notation */
-  });
-
-  function expectNoWaste(fn) {
-    var measurements = measure(fn);
-    var summary = ReactDefaultPerf.getWasted(measurements);
-    expect(summary).toEqual([]);
-  }
-
-  it('should not count initial render as waste', function() {
-    expectNoWaste(() => {
-      ReactTestUtils.renderIntoDocument(<App />);
-    });
-  });
-
-  it('should not count unmount as waste', function() {
-    var container = document.createElement('div');
-    ReactDOM.render(<Div>hello</Div>, container);
-    expectNoWaste(() => {
-      ReactDOM.unmountComponentAtNode(container);
-    });
-  });
-
-  it('should not count content update as waste', function() {
-    var container = document.createElement('div');
-    ReactDOM.render(<Div>hello</Div>, container);
-    expectNoWaste(() => {
-      ReactDOM.render(<Div>hello world</Div>, container);
-    });
-  });
-
-  it('should not count child addition as waste', function() {
-    var container = document.createElement('div');
-    ReactDOM.render(<Div><span /></Div>, container);
-    expectNoWaste(() => {
-      ReactDOM.render(<Div><span /><span /></Div>, container);
-    });
-  });
-
-  it('should not count child removal as waste', function() {
-    var container = document.createElement('div');
-    ReactDOM.render(<Div><span /><span /></Div>, container);
-    expectNoWaste(() => {
-      ReactDOM.render(<Div><span /></Div>, container);
-    });
-  });
-
-  it('should not count property update as waste', function() {
-    var container = document.createElement('div');
-    ReactDOM.render(<Div className="yellow">hey</Div>, container);
-    expectNoWaste(() => {
-      ReactDOM.render(<Div className="blue">hey</Div>, container);
-    });
-  });
-
-  it('should not count style update as waste', function() {
-    var container = document.createElement('div');
-    ReactDOM.render(<Div style={{color: 'yellow'}}>hey</Div>, container);
-    expectNoWaste(() => {
-      ReactDOM.render(<Div style={{color: 'blue'}}>hey</Div>, container);
-    });
-  });
-
-  it('should not count property removal as waste', function() {
-    var container = document.createElement('div');
-    ReactDOM.render(<Div className="yellow">hey</Div>, container);
-    expectNoWaste(() => {
-      ReactDOM.render(<Div>hey</Div>, container);
-    });
-  });
-
-  it('should not count raw HTML update as waste', function() {
-    var container = document.createElement('div');
-    ReactDOM.render(
-      <Div dangerouslySetInnerHTML={{__html: 'me'}} />,
-      container
-    );
-    expectNoWaste(() => {
-      ReactDOM.render(
-        <Div dangerouslySetInnerHTML={{__html: 'you'}} />,
-        container
-      );
-    });
-  });
-
-  it('should not count child reordering as waste', function() {
-    var container = document.createElement('div');
-    ReactDOM.render(<Div><div key="A" /><div key="B" /></Div>, container);
-    expectNoWaste(() => {
-      ReactDOM.render(<Div><div key="B" /><div key="A" /></Div>, container);
-    });
-  });
-
-  it('should not count text update as waste', function() {
-    var container = document.createElement('div');
-    ReactDOM.render(<Div>{'hello'}{'world'}</Div>, container);
-    expectNoWaste(() => {
-      ReactDOM.render(<Div>{'hello'}{'friend'}</Div>, container);
-    });
-  });
-
-  it('putListener should not be instrumented', function() {
-    var container = document.createElement('div');
-    ReactDOM.render(<Div onClick={function() {}}>hey</Div>, container);
-    var measurements = measure(() => {
-      ReactDOM.render(<Div onClick={function() {}}>hey</Div>, container);
-    });
-
-    var summary = ReactDefaultPerfAnalysis.getDOMSummary(measurements);
-    expect(summary).toEqual([]);
-  });
-
-  it('deleteListener should not be instrumented', function() {
-    var container = document.createElement('div');
-    ReactDOM.render(<Div onClick={function() {}}>hey</Div>, container);
-    var measurements = measure(() => {
-      ReactDOM.render(<Div>hey</Div>, container);
-    });
-
-    var summary = ReactDefaultPerfAnalysis.getDOMSummary(measurements);
-    expect(summary).toEqual([]);
-  });
-
-  it('should print a table after calling printOperations', function() {
-    var container = document.createElement('div');
-    var measurements = measure(() => {
-      ReactDOM.render(<Div>hey</Div>, container);
-    });
-    spyOn(console, 'table');
-    ReactDefaultPerf.printOperations(measurements);
-    expect(console.table.calls.length).toBe(1);
-    expect(console.table.argsForCall[0][0]).toEqual([{
-      'data-reactid': '',
-      type: 'set innerHTML',
-      args: ReactDOMFeatureFlags.useCreateElement ?
-        '{"node":"<not serializable>","children":[],"html":null,"text":null}' :
-        '"<div data-reactroot=\\"\\" data-reactid=\\"1\\">hey</div>"',
-    }]);
-  });
-
-  it('warns once when using getMeasurementsSummaryMap', function() {
-    var measurements = measure(() => {});
-    spyOn(console, 'error');
-    ReactDefaultPerf.getMeasurementsSummaryMap(measurements);
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
-      '`ReactPerf.getMeasurementsSummaryMap(...)` is deprecated. Use ' +
-      '`ReactPerf.getWasted(...)` instead.'
-    );
-
-    ReactDefaultPerf.getMeasurementsSummaryMap(measurements);
-    expect(console.error.calls.length).toBe(1);
-  });
-
-  it('warns once when using printDOM', function() {
-    var measurements = measure(() => {});
-    spyOn(console, 'error');
-    ReactDefaultPerf.printDOM(measurements);
-    expect(console.error.calls.length).toBe(1);
-    expect(console.error.argsForCall[0][0]).toContain(
-      '`ReactPerf.printDOM(...)` is deprecated. Use ' +
-      '`ReactPerf.printOperations(...)` instead.'
-    );
-
-    ReactDefaultPerf.printDOM(measurements);
-    expect(console.error.calls.length).toBe(1);
-  });
-
-});
diff --git a/src/test/__tests__/ReactTestUtils-test.js b/src/test/__tests__/ReactTestUtils-test.js
index 81fda9cebf65..d53db7121fc8 100644
--- a/src/test/__tests__/ReactTestUtils-test.js
+++ b/src/test/__tests__/ReactTestUtils-test.js
@@ -15,29 +15,52 @@ var React;
 var ReactDOM;
 var ReactDOMServer;
 var ReactTestUtils;
+var ReactShallowRenderer;
+var PropTypes;
 
-describe('ReactTestUtils', function() {
-
-  beforeEach(function() {
+describe('ReactTestUtils', () => {
+  beforeEach(() => {
     React = require('React');
     ReactDOM = require('ReactDOM');
     ReactDOMServer = require('ReactDOMServer');
     ReactTestUtils = require('ReactTestUtils');
+    ReactShallowRenderer = require('ReactShallowRenderer');
+    PropTypes = require('prop-types');
   });
 
-  it('should have shallow rendering', function() {
-    var SomeComponent = React.createClass({
-      render: function() {
+  it('should have shallow rendering', () => {
+    class SomeComponent extends React.Component {
+      render() {
         return (
           <div>
             <span className="child1" />
             <span className="child2" />
           </div>
         );
-      },
-    });
+      }
+    }
+
+    var shallowRenderer = new ReactShallowRenderer();
+    var result = shallowRenderer.render(<SomeComponent />);
+
+    expect(result.type).toBe('div');
+    expect(result.props.children).toEqual([
+      <span className="child1" />,
+      <span className="child2" />,
+    ]);
+  });
 
-    var shallowRenderer = ReactTestUtils.createRenderer();
+  it('should shallow render a functional component', () => {
+    function SomeComponent() {
+      return (
+        <div>
+          <span className="child1" />
+          <span className="child2" />
+        </div>
+      );
+    }
+
+    var shallowRenderer = new ReactShallowRenderer();
     var result = shallowRenderer.render(<SomeComponent />);
 
     expect(result.type).toBe('div');
@@ -47,88 +70,83 @@ describe('ReactTestUtils', function() {
     ]);
   });
 
-  it('should throw for invalid elements', function() {
-    var SomeComponent = React.createClass({
-      render: function() {
+  it('should throw for invalid elements', () => {
+    class SomeComponent extends React.Component {
+      render() {
         return <div />;
-      },
-    });
+      }
+    }
 
-    var shallowRenderer = ReactTestUtils.createRenderer();
-    expect(() => shallowRenderer.render(SomeComponent)).toThrow(
+    var shallowRenderer = new ReactShallowRenderer();
+    expect(() => shallowRenderer.render(SomeComponent)).toThrowError(
       'ReactShallowRenderer render(): Invalid component element. Instead of ' +
-      'passing a component class, make sure to instantiate it by passing it ' +
-      'to React.createElement.'
+        'passing a component class, make sure to instantiate it by passing it ' +
+        'to React.createElement.',
     );
-    expect(() => shallowRenderer.render(<div />)).toThrow(
+    expect(() => shallowRenderer.render(<div />)).toThrowError(
       'ReactShallowRenderer render(): Shallow rendering works only with ' +
-      'custom components, not primitives (div). Instead of calling ' +
-      '`.render(el)` and inspecting the rendered output, look at `el.props` ' +
-      'directly instead.'
+        'custom components, not primitives (div). Instead of calling ' +
+        '`.render(el)` and inspecting the rendered output, look at `el.props` ' +
+        'directly instead.',
     );
   });
 
-  it('should have shallow unmounting', function() {
-    var componentWillUnmount = jest.genMockFn();
+  it('should have shallow unmounting', () => {
+    var componentWillUnmount = jest.fn();
 
-    var SomeComponent = React.createClass({
-      render: function() {
+    class SomeComponent extends React.Component {
+      componentWillUnmount = componentWillUnmount;
+      render() {
         return <div />;
-      },
-      componentWillUnmount,
-    });
+      }
+    }
 
-    var shallowRenderer = ReactTestUtils.createRenderer();
+    var shallowRenderer = new ReactShallowRenderer();
     shallowRenderer.render(<SomeComponent />);
     shallowRenderer.unmount();
 
     expect(componentWillUnmount).toBeCalled();
   });
 
-  it('can shallow render to null', function() {
-    var SomeComponent = React.createClass({
-      render: function() {
+  it('can shallow render to null', () => {
+    class SomeComponent extends React.Component {
+      render() {
         return null;
-      },
-    });
+      }
+    }
 
-    var shallowRenderer = ReactTestUtils.createRenderer();
+    var shallowRenderer = new ReactShallowRenderer();
     var result = shallowRenderer.render(<SomeComponent />);
 
     expect(result).toBe(null);
   });
 
-  it('can shallow render with a ref', function() {
-    var SomeComponent = React.createClass({
-      render: function() {
+  it('can shallow render with a ref', () => {
+    class SomeComponent extends React.Component {
+      render() {
         return <div ref="hello" />;
-      },
-    });
+      }
+    }
 
-    var shallowRenderer = ReactTestUtils.createRenderer();
+    var shallowRenderer = new ReactShallowRenderer();
     // Shouldn't crash.
     shallowRenderer.render(<SomeComponent />);
   });
 
-  it('lets you update shallowly rendered components', function() {
-    var SomeComponent = React.createClass({
-      getInitialState: function() {
-        return {clicked: false};
-      },
+  it('lets you update shallowly rendered components', () => {
+    class SomeComponent extends React.Component {
+      state = {clicked: false};
 
-      onClick: function() {
+      onClick = () => {
         this.setState({clicked: true});
-      },
+      };
 
-      render: function() {
+      render() {
         var className = this.state.clicked ? 'was-clicked' : '';
 
         if (this.props.aNew === 'prop') {
           return (
-            <a
-              href="#"
-              onClick={this.onClick}
-              className={className}>
+            <a href="#" onClick={this.onClick} className={className}>
               Test link
             </a>
           );
@@ -140,10 +158,10 @@ describe('ReactTestUtils', function() {
             </div>
           );
         }
-      },
-    });
+      }
+    }
 
-    var shallowRenderer = ReactTestUtils.createRenderer();
+    var shallowRenderer = new ReactShallowRenderer();
     var result = shallowRenderer.render(<SomeComponent />);
     expect(result.type).toBe('div');
     expect(result.props.children).toEqual([
@@ -162,45 +180,47 @@ describe('ReactTestUtils', function() {
     expect(updatedResultCausedByClick.props.className).toBe('was-clicked');
   });
 
-  it('can access the mounted component instance', function() {
-    var SimpleComponent = React.createClass({
-      someMethod: function() {
+  it('can access the mounted component instance', () => {
+    class SimpleComponent extends React.Component {
+      someMethod = () => {
         return this.props.n;
-      },
-      render: function() {
+      };
+
+      render() {
         return <div>{this.props.n}</div>;
-      },
-    });
+      }
+    }
 
-    var shallowRenderer = ReactTestUtils.createRenderer();
+    var shallowRenderer = new ReactShallowRenderer();
     shallowRenderer.render(<SimpleComponent n={5} />);
     expect(shallowRenderer.getMountedInstance().someMethod()).toEqual(5);
   });
 
-  it('can shallowly render components with contextTypes', function() {
-    var SimpleComponent = React.createClass({
-      contextTypes: {
-        name: React.PropTypes.string,
-      },
-      render: function() {
+  it('can shallowly render components with contextTypes', () => {
+    class SimpleComponent extends React.Component {
+      static contextTypes = {
+        name: PropTypes.string,
+      };
+
+      render() {
         return <div />;
-      },
-    });
+      }
+    }
 
-    var shallowRenderer = ReactTestUtils.createRenderer();
+    var shallowRenderer = new ReactShallowRenderer();
     var result = shallowRenderer.render(<SimpleComponent />);
     expect(result).toEqual(<div />);
   });
 
-  it('can shallowly render components with ref as function', function() {
-    var SimpleComponent = React.createClass({
-      getInitialState: function() {
-        return {clicked: false};
-      },
-      handleUserClick: function() {
-        this.setState({ clicked: true });
-      },
-      render: function() {
+  it('can shallowly render components with ref as function', () => {
+    class SimpleComponent extends React.Component {
+      state = {clicked: false};
+
+      handleUserClick = () => {
+        this.setState({clicked: true});
+      };
+
+      render() {
         return (
           <div
             ref={() => {}}
@@ -208,10 +228,10 @@ describe('ReactTestUtils', function() {
             className={this.state.clicked ? 'clicked' : ''}
           />
         );
-      },
-    });
+      }
+    }
 
-    var shallowRenderer = ReactTestUtils.createRenderer();
+    var shallowRenderer = new ReactShallowRenderer();
     shallowRenderer.render(<SimpleComponent />);
     var result = shallowRenderer.getRenderOutput();
     expect(result.type).toEqual('div');
@@ -223,88 +243,118 @@ describe('ReactTestUtils', function() {
     expect(result.props.className).toEqual('clicked');
   });
 
-  it('can setState in componentWillMount when shallow rendering', function() {
-    var SimpleComponent = React.createClass({
+  it('can setState in componentWillMount when shallow rendering', () => {
+    class SimpleComponent extends React.Component {
       componentWillMount() {
         this.setState({groovy: 'doovy'});
-      },
+      }
+
       render() {
         return <div>{this.state.groovy}</div>;
-      },
-    });
+      }
+    }
 
-    var shallowRenderer = ReactTestUtils.createRenderer();
+    var shallowRenderer = new ReactShallowRenderer();
     var result = shallowRenderer.render(<SimpleComponent />);
     expect(result).toEqual(<div>doovy</div>);
   });
 
-  it('can pass context when shallowly rendering', function() {
-    var SimpleComponent = React.createClass({
-      contextTypes: {
-        name: React.PropTypes.string,
-      },
-      render: function() {
+  it('can pass context when shallowly rendering', () => {
+    class SimpleComponent extends React.Component {
+      static contextTypes = {
+        name: PropTypes.string,
+      };
+
+      render() {
         return <div>{this.context.name}</div>;
-      },
-    });
+      }
+    }
 
-    var shallowRenderer = ReactTestUtils.createRenderer();
+    var shallowRenderer = new ReactShallowRenderer();
     var result = shallowRenderer.render(<SimpleComponent />, {
       name: 'foo',
     });
     expect(result).toEqual(<div>foo</div>);
   });
 
-  it('can scryRenderedDOMComponentsWithClass with TextComponent', function() {
-    var Wrapper = React.createClass({
-      render: function() {
+  it('can fail context when shallowly rendering', () => {
+    spyOn(console, 'error');
+
+    class SimpleComponent extends React.Component {
+      static contextTypes = {
+        name: PropTypes.string.isRequired,
+      };
+
+      render() {
+        return <div>{this.context.name}</div>;
+      }
+    }
+
+    var shallowRenderer = new ReactShallowRenderer();
+    shallowRenderer.render(<SimpleComponent />);
+    expect(console.error.calls.count()).toBe(1);
+    expect(
+      console.error.calls.argsFor(0)[0].replace(/\(at .+?:\d+\)/g, '(at **)'),
+    ).toBe(
+      'Warning: Failed context type: The context `name` is marked as ' +
+        'required in `SimpleComponent`, but its value is `undefined`.\n' +
+        '    in SimpleComponent (at **)',
+    );
+  });
+
+  it('can scryRenderedDOMComponentsWithClass with TextComponent', () => {
+    class Wrapper extends React.Component {
+      render() {
         return <div>Hello <span>Jim</span></div>;
-      },
-    });
+      }
+    }
+
     var renderedComponent = ReactTestUtils.renderIntoDocument(<Wrapper />);
     var scryResults = ReactTestUtils.scryRenderedDOMComponentsWithClass(
       renderedComponent,
-      'NonExistentClass'
+      'NonExistentClass',
     );
     expect(scryResults.length).toBe(0);
   });
 
-  it('can scryRenderedDOMComponentsWithClass with className contains \\n', function() {
-    var Wrapper = React.createClass({
-      render: function() {
+  it('can scryRenderedDOMComponentsWithClass with className contains \\n', () => {
+    class Wrapper extends React.Component {
+      render() {
         return <div>Hello <span className={'x\ny'}>Jim</span></div>;
-      },
-    });
+      }
+    }
+
     var renderedComponent = ReactTestUtils.renderIntoDocument(<Wrapper />);
     var scryResults = ReactTestUtils.scryRenderedDOMComponentsWithClass(
       renderedComponent,
-      'x'
+      'x',
     );
     expect(scryResults.length).toBe(1);
   });
 
-  it('can scryRenderedDOMComponentsWithClass with multiple classes', function() {
-    var Wrapper = React.createClass({
-      render: function() {
+  it('can scryRenderedDOMComponentsWithClass with multiple classes', () => {
+    class Wrapper extends React.Component {
+      render() {
         return <div>Hello <span className={'x y z'}>Jim</span></div>;
-      },
-    });
+      }
+    }
+
     var renderedComponent = ReactTestUtils.renderIntoDocument(<Wrapper />);
     var scryResults1 = ReactTestUtils.scryRenderedDOMComponentsWithClass(
       renderedComponent,
-      'x y'
+      'x y',
     );
     expect(scryResults1.length).toBe(1);
 
     var scryResults2 = ReactTestUtils.scryRenderedDOMComponentsWithClass(
       renderedComponent,
-      'x z'
+      'x z',
     );
     expect(scryResults2.length).toBe(1);
 
     var scryResults3 = ReactTestUtils.scryRenderedDOMComponentsWithClass(
       renderedComponent,
-      ['x', 'y']
+      ['x', 'y'],
     );
     expect(scryResults3.length).toBe(1);
 
@@ -313,23 +363,23 @@ describe('ReactTestUtils', function() {
 
     var scryResults4 = ReactTestUtils.scryRenderedDOMComponentsWithClass(
       renderedComponent,
-      ['x', 'a']
+      ['x', 'a'],
     );
     expect(scryResults4.length).toBe(0);
 
     var scryResults5 = ReactTestUtils.scryRenderedDOMComponentsWithClass(
       renderedComponent,
-      ['x a']
+      ['x a'],
     );
     expect(scryResults5.length).toBe(0);
   });
 
-  it('traverses children in the correct order', function() {
-    var Wrapper = React.createClass({
-      render: function() {
+  it('traverses children in the correct order', () => {
+    class Wrapper extends React.Component {
+      render() {
         return <div>{this.props.children}</div>;
-      },
-    });
+      }
+    }
 
     var container = document.createElement('div');
     ReactDOM.render(
@@ -337,14 +387,14 @@ describe('ReactTestUtils', function() {
         {null}
         <div>purple</div>
       </Wrapper>,
-      container
+      container,
     );
     var tree = ReactDOM.render(
       <Wrapper>
         <div>orange</div>
         <div>purple</div>
       </Wrapper>,
-      container
+      container,
     );
 
     var log = [];
@@ -358,7 +408,7 @@ describe('ReactTestUtils', function() {
     expect(log).toEqual(['orangepurple', 'orange', 'purple']);
   });
 
-  it('should support injected wrapper components as DOM components', function() {
+  it('should support injected wrapper components as DOM components', () => {
     var getTestDocument = require('getTestDocument');
 
     var injectedDOMComponents = [
@@ -374,7 +424,7 @@ describe('ReactTestUtils', function() {
 
     injectedDOMComponents.forEach(function(type) {
       var testComponent = ReactTestUtils.renderIntoDocument(
-        React.createElement(type)
+        React.createElement(type),
       );
       expect(testComponent.tagName).toBe(type.toUpperCase());
       expect(ReactTestUtils.isDOMComponent(testComponent)).toBe(true);
@@ -382,8 +432,8 @@ describe('ReactTestUtils', function() {
 
     // Full-page components (html, head, body) can't be rendered into a div
     // directly...
-    var Root = React.createClass({
-      render: function() {
+    class Root extends React.Component {
+      render() {
         return (
           <html ref="html">
             <head ref="head">
@@ -394,8 +444,8 @@ describe('ReactTestUtils', function() {
             </body>
           </html>
         );
-      },
-    });
+      }
+    }
 
     var markup = ReactDOMServer.renderToString(<Root />);
     var testDocument = getTestDocument(markup);
@@ -409,110 +459,142 @@ describe('ReactTestUtils', function() {
     expect(ReactTestUtils.isDOMComponent(component.refs.body)).toBe(true);
   });
 
-  it('should change the value of an input field', function() {
+  it('should change the value of an input field', () => {
     var obj = {
       handler: function(e) {
         e.persist();
       },
     };
-    spyOn(obj, 'handler').andCallThrough();
+    spyOn(obj, 'handler').and.callThrough();
     var container = document.createElement('div');
-    var instance = ReactDOM.render(<input type="text" onChange={obj.handler} />, container);
+    var instance = ReactDOM.render(
+      <input type="text" onChange={obj.handler} />,
+      container,
+    );
 
     var node = ReactDOM.findDOMNode(instance);
     node.value = 'giraffe';
     ReactTestUtils.Simulate.change(node);
 
-    expect(obj.handler).toHaveBeenCalledWith(jasmine.objectContaining({target: node}));
+    expect(obj.handler).toHaveBeenCalledWith(
+      jasmine.objectContaining({target: node}),
+    );
   });
 
-  it('should change the value of an input field in a component', function() {
-    var SomeComponent = React.createClass({
-      render: function() {
+  it('should change the value of an input field in a component', () => {
+    class SomeComponent extends React.Component {
+      render() {
         return (
           <div>
             <input type="text" ref="input" onChange={this.props.handleChange} />
           </div>
         );
-      },
-    });
+      }
+    }
 
     var obj = {
       handler: function(e) {
         e.persist();
       },
     };
-    spyOn(obj, 'handler').andCallThrough();
+    spyOn(obj, 'handler').and.callThrough();
     var container = document.createElement('div');
-    var instance = ReactDOM.render(<SomeComponent handleChange={obj.handler} />, container);
+    var instance = ReactDOM.render(
+      <SomeComponent handleChange={obj.handler} />,
+      container,
+    );
 
     var node = ReactDOM.findDOMNode(instance.refs.input);
     node.value = 'zebra';
     ReactTestUtils.Simulate.change(node);
 
-    expect(obj.handler).toHaveBeenCalledWith(jasmine.objectContaining({target: node}));
+    expect(obj.handler).toHaveBeenCalledWith(
+      jasmine.objectContaining({target: node}),
+    );
   });
 
-  it('should throw when attempting to use ReactTestUtils.Simulate with shallow rendering', function() {
-    var SomeComponent = React.createClass({
-      render: function() {
+  it('should throw when attempting to use ReactTestUtils.Simulate with shallow rendering', () => {
+    class SomeComponent extends React.Component {
+      render() {
         return (
           <div onClick={this.props.handleClick}>
             hello, world.
           </div>
         );
-      },
-    });
+      }
+    }
+
     var handler = jasmine.createSpy('spy');
-    var shallowRenderer = ReactTestUtils.createRenderer();
-    var result = shallowRenderer.render(<SomeComponent handleClick={handler} />);
+    var shallowRenderer = new ReactShallowRenderer();
+    var result = shallowRenderer.render(
+      <SomeComponent handleClick={handler} />,
+    );
 
-    expect(() => ReactTestUtils.Simulate.click(result)).toThrow(
+    expect(() => ReactTestUtils.Simulate.click(result)).toThrowError(
       'TestUtils.Simulate expects a component instance and not a ReactElement.' +
-      'TestUtils.Simulate will not work if you are using shallow rendering.'
+        'TestUtils.Simulate will not work if you are using shallow rendering.',
     );
     expect(handler).not.toHaveBeenCalled();
   });
 
-  it('should not warn when simulating events with extra properties', function() {
+  it('should not warn when simulating events with extra properties', () => {
     spyOn(console, 'error');
 
     var CLIENT_X = 100;
 
-    var Component = React.createClass({
-      handleClick: function(e) {
+    class Component extends React.Component {
+      handleClick = e => {
         expect(e.clientX).toBe(CLIENT_X);
-      },
-      render: function() {
+      };
+
+      render() {
         return <div onClick={this.handleClick} />;
-      },
-    });
+      }
+    }
 
     var element = document.createElement('div');
     var instance = ReactDOM.render(<Component />, element);
-    ReactTestUtils.Simulate.click(
-      ReactDOM.findDOMNode(instance),
-      {clientX: CLIENT_X}
-    );
-    expect(console.error.calls.length).toBe(0);
+    ReactTestUtils.Simulate.click(ReactDOM.findDOMNode(instance), {
+      clientX: CLIENT_X,
+    });
+    expect(console.error.calls.count()).toBe(0);
   });
 
-  it('can scry with stateless components involved', function() {
+  it('can scry with stateless components involved', () => {
     var Stateless = () => <div><hr /></div>;
-    var SomeComponent = React.createClass({
-      render: function() {
+
+    class SomeComponent extends React.Component {
+      render() {
         return (
           <div>
             <Stateless />
             <hr />
           </div>
         );
-      },
-    });
+      }
+    }
 
     var inst = ReactTestUtils.renderIntoDocument(<SomeComponent />);
     var hrs = ReactTestUtils.scryRenderedDOMComponentsWithTag(inst, 'hr');
     expect(hrs.length).toBe(2);
   });
 
+  describe('Simulate', () => {
+    it('should set the type of the event', () => {
+      let event;
+      const stub = jest.genMockFn().mockImplementation(e => {
+        e.persist();
+        event = e;
+      });
+
+      const container = document.createElement('div');
+      const instance = ReactDOM.render(<div onKeyDown={stub} />, container);
+      const node = ReactDOM.findDOMNode(instance);
+
+      ReactTestUtils.Simulate.keyDown(node);
+
+      expect(event.type).toBe('keydown');
+      expect(event.nativeEvent.type).toBe('keydown');
+    });
+  });
 });
diff --git a/src/test/__tests__/reactComponentExpect-test.js b/src/test/__tests__/reactComponentExpect-test.js
index 494095a82e2a..a522d43aa484 100644
--- a/src/test/__tests__/reactComponentExpect-test.js
+++ b/src/test/__tests__/reactComponentExpect-test.js
@@ -15,25 +15,24 @@ var React;
 var ReactTestUtils;
 var reactComponentExpect;
 
-describe('reactComponentExpect', function() {
-
-  beforeEach(function() {
+describe('reactComponentExpect', () => {
+  beforeEach(() => {
     React = require('React');
     ReactTestUtils = require('ReactTestUtils');
     reactComponentExpect = require('reactComponentExpect');
   });
 
-  it('should detect text components', function() {
-    var SomeComponent = React.createClass({
-      render: function() {
+  it('should detect text components', () => {
+    class SomeComponent extends React.Component {
+      render() {
         return (
           <div>
             <div>This is a div</div>
             {'This is text'}
           </div>
         );
-      },
-    });
+      }
+    }
 
     var component = ReactTestUtils.renderIntoDocument(<SomeComponent />);
 
diff --git a/src/test/createHierarchyRenderer.js b/src/test/createHierarchyRenderer.js
deleted file mode 100644
index 45aac35e26ea..000000000000
--- a/src/test/createHierarchyRenderer.js
+++ /dev/null
@@ -1,82 +0,0 @@
-/**
- * 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 createHierarchyRenderer
- */
-
-'use strict';
-
-var React = require('React');
-
-/**
- * Creates a render method that makes it easier to create, render, and inspect a
- * hierarchy of mock React component classes.
- *
- * A component class is created for each of the supplied render methods. Each
- * render method is invoked with the classes created using the render methods
- * that come after it in the supplied list of render methods.
- *
- *   var renderHierarchy = createHierarchyRenderer(
- *     function ComponentA(ComponentB, ComponentC) {...},
- *     function ComponentB(ComponentC) {...},
- *     function ComponentC() {...}
- *   );
- *
- * When the hierarchy is invoked, a two-dimensional array is returned. Each
- * array corresponds to a supplied render method and contains the instances
- * returned by that render method in the order it was invoked.
- *
- *   var instances = renderHierarchy(
- *     function(ComponentA[, ComponentB, ComponentC]) {
- *       ReactDOM.render(<ComponentA />, ...);
- *     })
- *   );
- *   instances[0][0]; // First return value of first render method.
- *   instances[1][0]; // First return value of second render method.
- *   instances[1][1]; // Second return value of second render method.
- *
- * Refs should be used to reference components that are not the return value of
- * render methods.
- *
- *   expect(instances[0][0].refs.X).toBe(...);
- *
- * NOTE: The component classes created for each render method are re-used for
- * each invocation of the hierarchy renderer. If new classes are needed, you
- * should re-execute `createHierarchyRenderer` with the same arguments.
- *
- * @param {array<function>} ...renderMethods
- * @return {function}
- */
-function createHierarchyRenderer(...renderMethods) {
-  var instances;
-  var Components = renderMethods.reduceRight(
-    function(ComponentsAccumulator, renderMethod, depth) {
-      var Component = React.createClass({
-        displayName: renderMethod.name,
-        render: function() {
-          instances[depth].push(this);
-          return renderMethod.apply(this, ComponentsAccumulator);
-        },
-      });
-      return [Component].concat(ComponentsAccumulator);
-    },
-    []
-  );
-  /**
-   * @param {function} renderComponent
-   * @return {array<array<*>>}
-   */
-  function renderHierarchy(renderComponent) {
-    instances = renderMethods.map(() => []);
-    renderComponent.apply(null, Components);
-    return instances;
-  }
-  return renderHierarchy;
-}
-
-module.exports = createHierarchyRenderer;
diff --git a/src/test/getTestDocument.js b/src/test/getTestDocument.js
index 8f681cd4288c..bd0c0e9cba72 100644
--- a/src/test/getTestDocument.js
+++ b/src/test/getTestDocument.js
@@ -14,7 +14,8 @@
 function getTestDocument(markup) {
   document.open();
   document.write(
-    markup || '<!doctype html><html><meta charset=utf-8><title>test doc</title>'
+    markup ||
+      '<!doctype html><html><meta charset=utf-8><title>test doc</title>',
   );
   document.close();
   return document;
diff --git a/src/test/reactComponentExpect.js b/src/test/reactComponentExpect.js
index 0905387025ad..7ba2ab1d8b1f 100644
--- a/src/test/reactComponentExpect.js
+++ b/src/test/reactComponentExpect.js
@@ -7,7 +7,6 @@
  * of patent rights can be found in the PATENTS file in the same directory.
  *
  * @providesModule reactComponentExpect
- * @nolint
  */
 
 'use strict';
@@ -31,7 +30,7 @@ function reactComponentExpect(instance) {
 
   invariant(
     ReactTestUtils.isCompositeComponent(instance),
-    'reactComponentExpect(...): instance must be a composite component'
+    'reactComponentExpect(...): instance must be a composite component',
   );
   var internalInstance = ReactInstanceMap.get(instance);
 
@@ -84,8 +83,7 @@ Object.assign(reactComponentExpectInternal.prototype, {
     // Currently only dom components have arrays of children, but that will
     // change soon.
     this.toBeDOMComponent();
-    var renderedChildren =
-      this._instance._renderedChildren || {};
+    var renderedChildren = this._instance._renderedChildren || {};
     for (var name in renderedChildren) {
       if (!renderedChildren.hasOwnProperty(name)) {
         continue;
@@ -116,9 +114,7 @@ Object.assign(reactComponentExpectInternal.prototype, {
   // Matchers ------------------------------------------------------------------
 
   toBeComponentOfType: function(constructor) {
-    expect(
-      this._instance._currentElement.type === constructor
-    ).toBe(true);
+    expect(this._instance._currentElement.type === constructor).toBe(true);
     return this;
   },
 
@@ -129,16 +125,14 @@ Object.assign(reactComponentExpectInternal.prototype, {
   toBeCompositeComponent: function() {
     expect(
       typeof this.instance() === 'object' &&
-      typeof this.instance().render === 'function'
+        typeof this.instance().render === 'function',
     ).toBe(true);
     return this;
   },
 
   toBeCompositeComponentWithType: function(constructor) {
     this.toBeCompositeComponent();
-    expect(
-      this._instance._currentElement.type === constructor
-    ).toBe(true);
+    expect(this._instance._currentElement.type === constructor).toBe(true);
     return this;
   },
 
@@ -187,8 +181,9 @@ Object.assign(reactComponentExpectInternal.prototype, {
       if (!stateNameToExpectedValue.hasOwnProperty(stateName)) {
         continue;
       }
-      expect(this.instance().state[stateName])
-        .toEqual(stateNameToExpectedValue[stateName]);
+      expect(this.instance().state[stateName]).toEqual(
+        stateNameToExpectedValue[stateName],
+      );
     }
     return this;
   },
@@ -203,8 +198,9 @@ Object.assign(reactComponentExpectInternal.prototype, {
       if (!propNameToExpectedValue.hasOwnProperty(propName)) {
         continue;
       }
-      expect(this.instance().props[propName])
-        .toEqual(propNameToExpectedValue[propName]);
+      expect(this.instance().props[propName]).toEqual(
+        propNameToExpectedValue[propName],
+      );
     }
     return this;
   },
@@ -219,8 +215,9 @@ Object.assign(reactComponentExpectInternal.prototype, {
       if (!contextNameToExpectedValue.hasOwnProperty(contextName)) {
         continue;
       }
-      expect(this.instance().context[contextName])
-        .toEqual(contextNameToExpectedValue[contextName]);
+      expect(this.instance().context[contextName]).toEqual(
+        contextNameToExpectedValue[contextName],
+      );
     }
     return this;
   },
diff --git a/src/umd/ReactDOMServerUMDEntry.js b/src/umd/ReactDOMServerUMDEntry.js
new file mode 100644
index 000000000000..7a55540e2b72
--- /dev/null
+++ b/src/umd/ReactDOMServerUMDEntry.js
@@ -0,0 +1,16 @@
+/**
+ * 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 ReactDOMServerUMDEntry
+ */
+
+'use strict';
+
+var ReactDOMServer = require('ReactDOMServer');
+
+module.exports = ReactDOMServer;
diff --git a/src/umd/ReactDOMUMDEntry.js b/src/umd/ReactDOMUMDEntry.js
new file mode 100644
index 000000000000..03a0318a1050
--- /dev/null
+++ b/src/umd/ReactDOMUMDEntry.js
@@ -0,0 +1,34 @@
+/**
+ * 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 ReactDOMUMDEntry
+ */
+
+'use strict';
+
+var React = require('React');
+var ReactDOM = require('ReactDOM');
+
+var ReactDOMUMDEntry = ReactDOM;
+
+if (__DEV__) {
+  ReactDOMUMDEntry.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = {
+    // ReactPerf and ReactTestUtils currently only work with the DOM renderer
+    // so we expose them from here, but only in DEV mode.
+    ReactPerf: require('ReactPerf'),
+    ReactTestUtils: require('ReactTestUtils'),
+  };
+}
+
+// Inject ReactDOM into React for the addons UMD build that depends on ReactDOM (TransitionGroup).
+// We can remove this after we deprecate and remove the addons UMD build.
+if (React.addons) {
+  React.__SECRET_INJECTED_REACT_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = ReactDOMUMDEntry;
+}
+
+module.exports = ReactDOMUMDEntry;
diff --git a/src/umd/ReactUMDEntry.js b/src/umd/ReactUMDEntry.js
index dda648759473..0a31c66f3756 100644
--- a/src/umd/ReactUMDEntry.js
+++ b/src/umd/ReactUMDEntry.js
@@ -11,15 +11,24 @@
 
 'use strict';
 
-var ReactDOM = require('ReactDOM');
-var ReactDOMServer = require('ReactDOMServer');
 var React = require('React');
 
+// `version` will be added here by the React module.
+var ReactUMDEntry = Object.assign(React, {
+  __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: {
+    ReactCurrentOwner: require('ReactCurrentOwner'),
+  },
+});
 
-// `version` will be added here by ReactIsomorphic.
-var ReactUMDEntry = Object.assign({
-  __SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: ReactDOM,
-  __SECRET_DOM_SERVER_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: ReactDOMServer,
-}, React);
+if (__DEV__) {
+  Object.assign(
+    ReactUMDEntry.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
+    {
+      // ReactComponentTreeHook should not be included in production.
+      ReactComponentTreeHook: require('ReactComponentTreeHook'),
+      getNextDebugID: require('getNextDebugID'),
+    },
+  );
+}
 
 module.exports = ReactUMDEntry;
diff --git a/src/umd/ReactWithAddonsUMDEntry.js b/src/umd/ReactWithAddonsUMDEntry.js
index cf59eb9c85ed..102b3e68e163 100644
--- a/src/umd/ReactWithAddonsUMDEntry.js
+++ b/src/umd/ReactWithAddonsUMDEntry.js
@@ -11,15 +11,25 @@
 
 'use strict';
 
-var ReactDOM = require('ReactDOM');
-var ReactDOMServer = require('ReactDOMServer');
 var ReactWithAddons = require('ReactWithAddons');
 
+// `version` will be added here by the React module.
+var ReactWithAddonsUMDEntry = Object.assign(ReactWithAddons, {
+  __SECRET_INJECTED_REACT_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: null, // Will be injected by ReactDOM UMD build.
+  __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: {
+    ReactCurrentOwner: require('ReactCurrentOwner'),
+  },
+});
 
-// `version` will be added here by ReactIsomorphic.
-var ReactWithAddonsUMDEntry = Object.assign({
-  __SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: ReactDOM,
-  __SECRET_DOM_SERVER_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: ReactDOMServer,
-}, ReactWithAddons);
+if (__DEV__) {
+  Object.assign(
+    ReactWithAddonsUMDEntry.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
+    {
+      // ReactComponentTreeHook should not be included in production.
+      ReactComponentTreeHook: require('ReactComponentTreeHook'),
+      getNextDebugID: require('getNextDebugID'),
+    },
+  );
+}
 
 module.exports = ReactWithAddonsUMDEntry;
diff --git a/src/umd/shims/ReactAddonsDOMDependenciesUMDShim.js b/src/umd/shims/ReactAddonsDOMDependenciesUMDShim.js
new file mode 100644
index 000000000000..a72615f75c74
--- /dev/null
+++ b/src/umd/shims/ReactAddonsDOMDependenciesUMDShim.js
@@ -0,0 +1,39 @@
+/**
+ * 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 ReactAddonsDOMDependenciesUMDShim
+ */
+
+'use strict';
+
+var ReactDOM;
+
+function getReactDOM() {
+  if (!ReactDOM) {
+    // This is safe to use because current module only exists in the addons build:
+    var ReactWithAddonsUMDEntry = require('ReactWithAddonsUMDEntry');
+    // This is injected by the ReactDOM UMD build:
+    ReactDOM =
+      ReactWithAddonsUMDEntry.__SECRET_INJECTED_REACT_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
+  }
+  return ReactDOM;
+}
+
+exports.getReactDOM = getReactDOM;
+
+if (__DEV__) {
+  exports.getReactPerf = function() {
+    return getReactDOM().__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
+      .ReactPerf;
+  };
+
+  exports.getReactTestUtils = function() {
+    return getReactDOM().__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
+      .ReactTestUtils;
+  };
+}
diff --git a/src/umd/shims/ReactComponentTreeHookUMDShim.js b/src/umd/shims/ReactComponentTreeHookUMDShim.js
new file mode 100644
index 000000000000..82a5cf6e1521
--- /dev/null
+++ b/src/umd/shims/ReactComponentTreeHookUMDShim.js
@@ -0,0 +1,18 @@
+/**
+ * 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 ReactComponentTreeHookUMDShim
+ */
+
+/* globals React */
+
+'use strict';
+
+var ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
+
+module.exports = ReactInternals.ReactComponentTreeHook;
diff --git a/src/umd/shims/ReactCurrentOwnerUMDShim.js b/src/umd/shims/ReactCurrentOwnerUMDShim.js
new file mode 100644
index 000000000000..79ef232b54b0
--- /dev/null
+++ b/src/umd/shims/ReactCurrentOwnerUMDShim.js
@@ -0,0 +1,18 @@
+/**
+ * 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 ReactCurrentOwnerUMDShim
+ */
+
+/* globals React */
+
+'use strict';
+
+var ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
+
+module.exports = ReactInternals.ReactCurrentOwner;
diff --git a/src/umd/shims/ReactUMDShim.js b/src/umd/shims/ReactUMDShim.js
new file mode 100644
index 000000000000..84ae35c47505
--- /dev/null
+++ b/src/umd/shims/ReactUMDShim.js
@@ -0,0 +1,16 @@
+/**
+ * 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 ReactUMDShim
+ */
+
+/* globals React */
+
+'use strict';
+
+module.exports = React;
diff --git a/src/umd/shims/getNextDebugIDUMDShim.js b/src/umd/shims/getNextDebugIDUMDShim.js
new file mode 100644
index 000000000000..2fb7ac255ee1
--- /dev/null
+++ b/src/umd/shims/getNextDebugIDUMDShim.js
@@ -0,0 +1,18 @@
+/**
+ * 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 getNextDebugId
+ */
+
+/* globals React */
+
+'use strict';
+
+var ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
+
+module.exports = ReactInternals.getNextDebugID;
diff --git a/starter/README.md b/starter/README.md
deleted file mode 100644
index 372ca4887a98..000000000000
--- a/starter/README.md
+++ /dev/null
@@ -1,11 +0,0 @@
-# Welcome to React!
-
-You've just downloaded the React starter kit... Congratulations!
-
-To begin, check out the `examples/` directory for a bunch of examples, or check out [Getting Started](https://facebook.github.io/react/docs/getting-started.html) for more information.
-
-In some browsers our examples won't work from the local file system; run `python -m SimpleHTTPServer` and visit `http://localhost:8000/` to view them.
-
-Want to start your own app? Just copy `examples/basic-jsx-external` and start hacking! Remember: before launching you'll want to precompile your JSX code as we do in `examples/basic-jsx-precompile`; this requires doing `npm install -g react-tools` and then running our `jsx` tool. See [Getting Started](https://facebook.github.io/react/docs/getting-started.html) for more information.
-
-Happy Hacking!
diff --git a/vendor/react-dom-server.js b/vendor/react-dom-server.js
deleted file mode 100644
index 783456c54bb2..000000000000
--- a/vendor/react-dom-server.js
+++ /dev/null
@@ -1,31 +0,0 @@
-// Based off https://github.com/ForbesLindesay/umd/blob/master/template.js
-;(function(f) {
-  // CommonJS
-  if (typeof exports === "object" && typeof module !== "undefined") {
-    module.exports = f(require('react'));
-
-  // RequireJS
-  } else if (typeof define === "function" && define.amd) {
-    define(['react'], f);
-
-  // <script>
-  } else {
-    var g;
-    if (typeof window !== "undefined") {
-      g = window;
-    } else if (typeof global !== "undefined") {
-      g = global;
-    } else if (typeof self !== "undefined") {
-      g = self;
-    } else {
-      // works providing we're not in "use strict";
-      // needed for Java 8 Nashorn
-      // see https://github.com/facebook/react/issues/3037
-      g = this;
-    }
-    g.ReactDOMServer = f(g.React);
-  }
-
-})(function(React) {
-  return React.__SECRET_DOM_SERVER_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
-});
diff --git a/vendor/react-dom.js b/vendor/react-dom.js
deleted file mode 100644
index aa1b3f1755fa..000000000000
--- a/vendor/react-dom.js
+++ /dev/null
@@ -1,31 +0,0 @@
-// Based off https://github.com/ForbesLindesay/umd/blob/master/template.js
-;(function(f) {
-  // CommonJS
-  if (typeof exports === "object" && typeof module !== "undefined") {
-    module.exports = f(require('react'));
-
-  // RequireJS
-  } else if (typeof define === "function" && define.amd) {
-    define(['react'], f);
-
-  // <script>
-  } else {
-    var g;
-    if (typeof window !== "undefined") {
-      g = window;
-    } else if (typeof global !== "undefined") {
-      g = global;
-    } else if (typeof self !== "undefined") {
-      g = self;
-    } else {
-      // works providing we're not in "use strict";
-      // needed for Java 8 Nashorn
-      // see https://github.com/facebook/react/issues/3037
-      g = this;
-    }
-    g.ReactDOM = f(g.React);
-  }
-
-})(function(React) {
-  return React.__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
-});
diff --git a/yarn.lock b/yarn.lock
new file mode 100644
index 000000000000..c6a961babdb4
--- /dev/null
+++ b/yarn.lock
@@ -0,0 +1,5450 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+JSONStream@^1.0.3:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.1.tgz#707f761e01dae9e16f1bcf93703b78c70966579a"
+  dependencies:
+    jsonparse "^1.2.0"
+    through ">=2.2.7 <3"
+
+abab@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.3.tgz#b81de5f7274ec4e756d797cd834f303642724e5d"
+
+abbrev@1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f"
+
+acorn-globals@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-3.1.0.tgz#fd8270f71fbb4996b004fa880ee5d46573a731bf"
+  dependencies:
+    acorn "^4.0.4"
+
+acorn-jsx@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b"
+  dependencies:
+    acorn "^3.0.4"
+
+acorn@^1.0.3:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-1.2.2.tgz#c8ce27de0acc76d896d2b1fad3df588d9e82f014"
+
+acorn@^3.0.4:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a"
+
+acorn@^4.0.3, acorn@^4.0.4:
+  version "4.0.13"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787"
+
+acorn@^5.0.0, acorn@^5.0.1:
+  version "5.0.3"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.0.3.tgz#c460df08491463f028ccb82eab3730bf01087b3d"
+
+ajv-keywords@^1.0.0:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c"
+
+ajv@^4.7.0, ajv@^4.9.1:
+  version "4.11.8"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536"
+  dependencies:
+    co "^4.6.0"
+    json-stable-stringify "^1.0.1"
+
+aliasify@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/aliasify/-/aliasify-2.1.0.tgz#7c30825b9450b9e6185ba27533eaf6e2067d4b42"
+  dependencies:
+    browserify-transform-tools "~1.7.0"
+
+align-text@^0.1.1, align-text@^0.1.3:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
+  dependencies:
+    kind-of "^3.0.2"
+    longest "^1.0.1"
+    repeat-string "^1.5.2"
+
+alter@~0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/alter/-/alter-0.2.0.tgz#c7588808617572034aae62480af26b1d4d1cb3cd"
+  dependencies:
+    stable "~0.1.3"
+
+amdefine@>=0.0.4:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
+
+ansi-escapes@^1.1.0, ansi-escapes@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
+
+ansi-regex@^2.0.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
+
+ansi-styles@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
+
+ansicolors@~0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.2.1.tgz#be089599097b74a5c9c4a84a0cdbcdb62bd87aef"
+
+anymatch@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507"
+  dependencies:
+    arrify "^1.0.0"
+    micromatch "^2.1.5"
+
+append-transform@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-0.4.0.tgz#d76ebf8ca94d276e247a36bad44a4b74ab611991"
+  dependencies:
+    default-require-extensions "^1.0.0"
+
+aproba@^1.0.3:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.2.tgz#45c6629094de4e96f693ef7eab74ae079c240fc1"
+
+archy@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40"
+
+are-we-there-yet@~1.1.2:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d"
+  dependencies:
+    delegates "^1.0.0"
+    readable-stream "^2.0.6"
+
+argparse@^1.0.7:
+  version "1.0.9"
+  resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86"
+  dependencies:
+    sprintf-js "~1.0.2"
+
+"argparse@~ 0.1.11":
+  version "0.1.16"
+  resolved "https://registry.yarnpkg.com/argparse/-/argparse-0.1.16.tgz#cfd01e0fbba3d6caed049fbd758d40f65196f57c"
+  dependencies:
+    underscore "~1.7.0"
+    underscore.string "~2.4.0"
+
+arr-diff@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf"
+  dependencies:
+    arr-flatten "^1.0.1"
+
+arr-flatten@^1.0.1:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.3.tgz#a274ed85ac08849b6bd7847c4580745dc51adfb1"
+
+array-differ@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031"
+
+array-equal@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93"
+
+array-filter@~0.0.0:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec"
+
+array-map@~0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/array-map/-/array-map-0.0.0.tgz#88a2bab73d1cf7bcd5c1b118a003f66f665fa662"
+
+array-reduce@~0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/array-reduce/-/array-reduce-0.0.0.tgz#173899d3ffd1c7d9383e4479525dbe278cab5f2b"
+
+array-union@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
+  dependencies:
+    array-uniq "^1.0.1"
+
+array-uniq@^1.0.1, array-uniq@^1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6"
+
+array-unique@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
+
+array.prototype.find@^2.0.1:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/array.prototype.find/-/array.prototype.find-2.0.4.tgz#556a5c5362c08648323ddaeb9de9d14bc1864c90"
+  dependencies:
+    define-properties "^1.1.2"
+    es-abstract "^1.7.0"
+
+arrify@^1.0.0, arrify@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
+
+art@^0.10.1:
+  version "0.10.1"
+  resolved "https://registry.yarnpkg.com/art/-/art-0.10.1.tgz#38541883e399225c5e193ff246e8f157cf7b2146"
+
+asap@~2.0.3:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f"
+
+asn1.js@^4.0.0:
+  version "4.9.1"
+  resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.1.tgz#48ba240b45a9280e94748990ba597d216617fd40"
+  dependencies:
+    bn.js "^4.0.0"
+    inherits "^2.0.1"
+    minimalistic-assert "^1.0.0"
+
+asn1@~0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86"
+
+assert-plus@1.0.0, assert-plus@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
+
+assert-plus@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234"
+
+assert@^1.4.0:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91"
+  dependencies:
+    util "0.10.3"
+
+ast-traverse@~0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/ast-traverse/-/ast-traverse-0.1.1.tgz#69cf2b8386f19dcda1bb1e05d68fe359d8897de6"
+
+ast-types@0.8.12:
+  version "0.8.12"
+  resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.8.12.tgz#a0d90e4351bb887716c83fd637ebf818af4adfcc"
+
+ast-types@0.8.15:
+  version "0.8.15"
+  resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.8.15.tgz#8eef0827f04dff0ec8857ba925abe3fea6194e52"
+
+ast-types@0.9.6:
+  version "0.9.6"
+  resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9"
+
+astw@^2.0.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/astw/-/astw-2.2.0.tgz#7bd41784d32493987aeb239b6b4e1c57a873b917"
+  dependencies:
+    acorn "^4.0.3"
+
+async-each@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
+
+async@^1.4.0, async@^1.5.0:
+  version "1.5.2"
+  resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
+
+async@^2.1.4:
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/async/-/async-2.4.1.tgz#62a56b279c98a11d0987096a01cc3eeb8eb7bbd7"
+  dependencies:
+    lodash "^4.14.0"
+
+async@~0.1.22:
+  version "0.1.22"
+  resolved "https://registry.yarnpkg.com/async/-/async-0.1.22.tgz#0fc1aaa088a0e3ef0ebe2d8831bab0dcf8845061"
+
+asynckit@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+
+aws-sign2@~0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f"
+
+aws4@^1.2.1:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e"
+
+babel-cli@^6.6.5:
+  version "6.24.1"
+  resolved "https://registry.yarnpkg.com/babel-cli/-/babel-cli-6.24.1.tgz#207cd705bba61489b2ea41b5312341cf6aca2283"
+  dependencies:
+    babel-core "^6.24.1"
+    babel-polyfill "^6.23.0"
+    babel-register "^6.24.1"
+    babel-runtime "^6.22.0"
+    commander "^2.8.1"
+    convert-source-map "^1.1.0"
+    fs-readdir-recursive "^1.0.0"
+    glob "^7.0.0"
+    lodash "^4.2.0"
+    output-file-sync "^1.1.0"
+    path-is-absolute "^1.0.0"
+    slash "^1.0.0"
+    source-map "^0.5.0"
+    v8flags "^2.0.10"
+  optionalDependencies:
+    chokidar "^1.6.1"
+
+babel-code-frame@^6.16.0, babel-code-frame@^6.22.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4"
+  dependencies:
+    chalk "^1.1.0"
+    esutils "^2.0.2"
+    js-tokens "^3.0.0"
+
+babel-core@^5.6.21:
+  version "5.8.38"
+  resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-5.8.38.tgz#1fcaee79d7e61b750b00b8e54f6dfc9d0af86558"
+  dependencies:
+    babel-plugin-constant-folding "^1.0.1"
+    babel-plugin-dead-code-elimination "^1.0.2"
+    babel-plugin-eval "^1.0.1"
+    babel-plugin-inline-environment-variables "^1.0.1"
+    babel-plugin-jscript "^1.0.4"
+    babel-plugin-member-expression-literals "^1.0.1"
+    babel-plugin-property-literals "^1.0.1"
+    babel-plugin-proto-to-assign "^1.0.3"
+    babel-plugin-react-constant-elements "^1.0.3"
+    babel-plugin-react-display-name "^1.0.3"
+    babel-plugin-remove-console "^1.0.1"
+    babel-plugin-remove-debugger "^1.0.1"
+    babel-plugin-runtime "^1.0.7"
+    babel-plugin-undeclared-variables-check "^1.0.2"
+    babel-plugin-undefined-to-void "^1.1.6"
+    babylon "^5.8.38"
+    bluebird "^2.9.33"
+    chalk "^1.0.0"
+    convert-source-map "^1.1.0"
+    core-js "^1.0.0"
+    debug "^2.1.1"
+    detect-indent "^3.0.0"
+    esutils "^2.0.0"
+    fs-readdir-recursive "^0.1.0"
+    globals "^6.4.0"
+    home-or-tmp "^1.0.0"
+    is-integer "^1.0.4"
+    js-tokens "1.0.1"
+    json5 "^0.4.0"
+    lodash "^3.10.0"
+    minimatch "^2.0.3"
+    output-file-sync "^1.1.0"
+    path-exists "^1.0.0"
+    path-is-absolute "^1.0.0"
+    private "^0.1.6"
+    regenerator "0.8.40"
+    regexpu "^1.3.0"
+    repeating "^1.1.2"
+    resolve "^1.1.6"
+    shebang-regex "^1.0.0"
+    slash "^1.0.0"
+    source-map "^0.5.0"
+    source-map-support "^0.2.10"
+    to-fast-properties "^1.0.0"
+    trim-right "^1.0.0"
+    try-resolve "^1.0.0"
+
+babel-core@^6.0.0, babel-core@^6.0.2, babel-core@^6.24.1:
+  version "6.25.0"
+  resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.25.0.tgz#7dd42b0463c742e9d5296deb3ec67a9322dad729"
+  dependencies:
+    babel-code-frame "^6.22.0"
+    babel-generator "^6.25.0"
+    babel-helpers "^6.24.1"
+    babel-messages "^6.23.0"
+    babel-register "^6.24.1"
+    babel-runtime "^6.22.0"
+    babel-template "^6.25.0"
+    babel-traverse "^6.25.0"
+    babel-types "^6.25.0"
+    babylon "^6.17.2"
+    convert-source-map "^1.1.0"
+    debug "^2.1.1"
+    json5 "^0.5.0"
+    lodash "^4.2.0"
+    minimatch "^3.0.2"
+    path-is-absolute "^1.0.0"
+    private "^0.1.6"
+    slash "^1.0.0"
+    source-map "^0.5.0"
+
+babel-eslint@^7.1.0:
+  version "7.2.3"
+  resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-7.2.3.tgz#b2fe2d80126470f5c19442dc757253a897710827"
+  dependencies:
+    babel-code-frame "^6.22.0"
+    babel-traverse "^6.23.1"
+    babel-types "^6.23.0"
+    babylon "^6.17.0"
+
+babel-generator@^6.18.0, babel-generator@^6.25.0:
+  version "6.25.0"
+  resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.25.0.tgz#33a1af70d5f2890aeb465a4a7793c1df6a9ea9fc"
+  dependencies:
+    babel-messages "^6.23.0"
+    babel-runtime "^6.22.0"
+    babel-types "^6.25.0"
+    detect-indent "^4.0.0"
+    jsesc "^1.3.0"
+    lodash "^4.2.0"
+    source-map "^0.5.0"
+    trim-right "^1.0.1"
+
+babel-helper-builder-react-jsx@^6.24.1:
+  version "6.24.1"
+  resolved "https://registry.yarnpkg.com/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.24.1.tgz#0ad7917e33c8d751e646daca4e77cc19377d2cbc"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-types "^6.24.1"
+    esutils "^2.0.0"
+
+babel-helper-call-delegate@^6.24.1:
+  version "6.24.1"
+  resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d"
+  dependencies:
+    babel-helper-hoist-variables "^6.24.1"
+    babel-runtime "^6.22.0"
+    babel-traverse "^6.24.1"
+    babel-types "^6.24.1"
+
+babel-helper-define-map@^6.24.1:
+  version "6.24.1"
+  resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.24.1.tgz#7a9747f258d8947d32d515f6aa1c7bd02204a080"
+  dependencies:
+    babel-helper-function-name "^6.24.1"
+    babel-runtime "^6.22.0"
+    babel-types "^6.24.1"
+    lodash "^4.2.0"
+
+babel-helper-function-name@^6.24.1:
+  version "6.24.1"
+  resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9"
+  dependencies:
+    babel-helper-get-function-arity "^6.24.1"
+    babel-runtime "^6.22.0"
+    babel-template "^6.24.1"
+    babel-traverse "^6.24.1"
+    babel-types "^6.24.1"
+
+babel-helper-get-function-arity@^6.24.1:
+  version "6.24.1"
+  resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-types "^6.24.1"
+
+babel-helper-hoist-variables@^6.24.1:
+  version "6.24.1"
+  resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-types "^6.24.1"
+
+babel-helper-optimise-call-expression@^6.24.1:
+  version "6.24.1"
+  resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-types "^6.24.1"
+
+babel-helper-replace-supers@^6.24.1:
+  version "6.24.1"
+  resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a"
+  dependencies:
+    babel-helper-optimise-call-expression "^6.24.1"
+    babel-messages "^6.23.0"
+    babel-runtime "^6.22.0"
+    babel-template "^6.24.1"
+    babel-traverse "^6.24.1"
+    babel-types "^6.24.1"
+
+babel-helpers@^6.24.1:
+  version "6.24.1"
+  resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-template "^6.24.1"
+
+babel-jest@18.0.0, babel-jest@^18.0.0:
+  version "18.0.0"
+  resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-18.0.0.tgz#17ebba8cb3285c906d859e8707e4e79795fb65e3"
+  dependencies:
+    babel-core "^6.0.0"
+    babel-plugin-istanbul "^3.0.0"
+    babel-preset-jest "^18.0.0"
+
+babel-messages@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e"
+  dependencies:
+    babel-runtime "^6.22.0"
+
+babel-plugin-check-es2015-constants@^6.5.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a"
+  dependencies:
+    babel-runtime "^6.22.0"
+
+babel-plugin-constant-folding@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/babel-plugin-constant-folding/-/babel-plugin-constant-folding-1.0.1.tgz#8361d364c98e449c3692bdba51eff0844290aa8e"
+
+babel-plugin-dead-code-elimination@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz#5f7c451274dcd7cccdbfbb3e0b85dd28121f0f65"
+
+babel-plugin-eval@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/babel-plugin-eval/-/babel-plugin-eval-1.0.1.tgz#a2faed25ce6be69ade4bfec263f70169195950da"
+
+babel-plugin-inline-environment-variables@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/babel-plugin-inline-environment-variables/-/babel-plugin-inline-environment-variables-1.0.1.tgz#1f58ce91207ad6a826a8bf645fafe68ff5fe3ffe"
+
+babel-plugin-istanbul@^3.0.0:
+  version "3.1.2"
+  resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-3.1.2.tgz#11d5abde18425ec24b5d648c7e0b5d25cd354a22"
+  dependencies:
+    find-up "^1.1.2"
+    istanbul-lib-instrument "^1.4.2"
+    object-assign "^4.1.0"
+    test-exclude "^3.3.0"
+
+babel-plugin-jest-hoist@^18.0.0:
+  version "18.0.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-18.0.0.tgz#4150e70ecab560e6e7344adc849498072d34e12a"
+
+babel-plugin-jscript@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/babel-plugin-jscript/-/babel-plugin-jscript-1.0.4.tgz#8f342c38276e87a47d5fa0a8bd3d5eb6ccad8fcc"
+
+babel-plugin-member-expression-literals@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/babel-plugin-member-expression-literals/-/babel-plugin-member-expression-literals-1.0.1.tgz#cc5edb0faa8dc927170e74d6d1c02440021624d3"
+
+babel-plugin-property-literals@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/babel-plugin-property-literals/-/babel-plugin-property-literals-1.0.1.tgz#0252301900192980b1c118efea48ce93aab83336"
+
+babel-plugin-proto-to-assign@^1.0.3:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/babel-plugin-proto-to-assign/-/babel-plugin-proto-to-assign-1.0.4.tgz#c49e7afd02f577bc4da05ea2df002250cf7cd123"
+  dependencies:
+    lodash "^3.9.3"
+
+babel-plugin-react-constant-elements@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/babel-plugin-react-constant-elements/-/babel-plugin-react-constant-elements-1.0.3.tgz#946736e8378429cbc349dcff62f51c143b34e35a"
+
+babel-plugin-react-display-name@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/babel-plugin-react-display-name/-/babel-plugin-react-display-name-1.0.3.tgz#754fe38926e8424a4e7b15ab6ea6139dee0514fc"
+
+babel-plugin-remove-console@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/babel-plugin-remove-console/-/babel-plugin-remove-console-1.0.1.tgz#d8f24556c3a05005d42aaaafd27787f53ff013a7"
+
+babel-plugin-remove-debugger@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/babel-plugin-remove-debugger/-/babel-plugin-remove-debugger-1.0.1.tgz#fd2ea3cd61a428ad1f3b9c89882ff4293e8c14c7"
+
+babel-plugin-runtime@^1.0.7:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/babel-plugin-runtime/-/babel-plugin-runtime-1.0.7.tgz#bf7c7d966dd56ecd5c17fa1cb253c9acb7e54aaf"
+
+babel-plugin-syntax-class-properties@^6.8.0:
+  version "6.13.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de"
+
+babel-plugin-syntax-flow@^6.18.0:
+  version "6.18.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d"
+
+babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0:
+  version "6.18.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946"
+
+babel-plugin-syntax-object-rest-spread@^6.8.0:
+  version "6.13.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5"
+
+babel-plugin-syntax-trailing-function-commas@^6.5.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3"
+
+babel-plugin-transform-class-properties@^6.11.5:
+  version "6.24.1"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac"
+  dependencies:
+    babel-helper-function-name "^6.24.1"
+    babel-plugin-syntax-class-properties "^6.8.0"
+    babel-runtime "^6.22.0"
+    babel-template "^6.24.1"
+
+babel-plugin-transform-es2015-arrow-functions@^6.5.2:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221"
+  dependencies:
+    babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-block-scoped-functions@^6.5.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141"
+  dependencies:
+    babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-block-scoping@^6.5.0:
+  version "6.24.1"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.24.1.tgz#76c295dc3a4741b1665adfd3167215dcff32a576"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-template "^6.24.1"
+    babel-traverse "^6.24.1"
+    babel-types "^6.24.1"
+    lodash "^4.2.0"
+
+babel-plugin-transform-es2015-classes@^6.5.2:
+  version "6.24.1"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db"
+  dependencies:
+    babel-helper-define-map "^6.24.1"
+    babel-helper-function-name "^6.24.1"
+    babel-helper-optimise-call-expression "^6.24.1"
+    babel-helper-replace-supers "^6.24.1"
+    babel-messages "^6.23.0"
+    babel-runtime "^6.22.0"
+    babel-template "^6.24.1"
+    babel-traverse "^6.24.1"
+    babel-types "^6.24.1"
+
+babel-plugin-transform-es2015-computed-properties@^6.5.2:
+  version "6.24.1"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-template "^6.24.1"
+
+babel-plugin-transform-es2015-destructuring@^6.5.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d"
+  dependencies:
+    babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-for-of@^6.5.2:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691"
+  dependencies:
+    babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-literals@^6.5.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e"
+  dependencies:
+    babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-modules-commonjs@^6.5.2:
+  version "6.24.1"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.24.1.tgz#d3e310b40ef664a36622200097c6d440298f2bfe"
+  dependencies:
+    babel-plugin-transform-strict-mode "^6.24.1"
+    babel-runtime "^6.22.0"
+    babel-template "^6.24.1"
+    babel-types "^6.24.1"
+
+babel-plugin-transform-es2015-object-super@^6.5.0:
+  version "6.24.1"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d"
+  dependencies:
+    babel-helper-replace-supers "^6.24.1"
+    babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-parameters@^6.5.0:
+  version "6.24.1"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b"
+  dependencies:
+    babel-helper-call-delegate "^6.24.1"
+    babel-helper-get-function-arity "^6.24.1"
+    babel-runtime "^6.22.0"
+    babel-template "^6.24.1"
+    babel-traverse "^6.24.1"
+    babel-types "^6.24.1"
+
+babel-plugin-transform-es2015-shorthand-properties@^6.5.0:
+  version "6.24.1"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-types "^6.24.1"
+
+babel-plugin-transform-es2015-spread@^6.5.2:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1"
+  dependencies:
+    babel-runtime "^6.22.0"
+
+babel-plugin-transform-es2015-template-literals@^6.5.2:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d"
+  dependencies:
+    babel-runtime "^6.22.0"
+
+babel-plugin-transform-es3-member-expression-literals@^6.5.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es3-member-expression-literals/-/babel-plugin-transform-es3-member-expression-literals-6.22.0.tgz#733d3444f3ecc41bef8ed1a6a4e09657b8969ebb"
+  dependencies:
+    babel-runtime "^6.22.0"
+
+babel-plugin-transform-es3-property-literals@^6.5.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es3-property-literals/-/babel-plugin-transform-es3-property-literals-6.22.0.tgz#b2078d5842e22abf40f73e8cde9cd3711abd5758"
+  dependencies:
+    babel-runtime "^6.22.0"
+
+babel-plugin-transform-flow-strip-types@^6.22.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz#84cb672935d43714fdc32bce84568d87441cf7cf"
+  dependencies:
+    babel-plugin-syntax-flow "^6.18.0"
+    babel-runtime "^6.22.0"
+
+babel-plugin-transform-object-rest-spread@^6.6.5:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.23.0.tgz#875d6bc9be761c58a2ae3feee5dc4895d8c7f921"
+  dependencies:
+    babel-plugin-syntax-object-rest-spread "^6.8.0"
+    babel-runtime "^6.22.0"
+
+babel-plugin-transform-react-display-name@^6.23.0:
+  version "6.25.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.25.0.tgz#67e2bf1f1e9c93ab08db96792e05392bf2cc28d1"
+  dependencies:
+    babel-runtime "^6.22.0"
+
+babel-plugin-transform-react-jsx-self@^6.22.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.22.0.tgz#df6d80a9da2612a121e6ddd7558bcbecf06e636e"
+  dependencies:
+    babel-plugin-syntax-jsx "^6.8.0"
+    babel-runtime "^6.22.0"
+
+babel-plugin-transform-react-jsx-source@^6.22.0, babel-plugin-transform-react-jsx-source@^6.8.0:
+  version "6.22.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.22.0.tgz#66ac12153f5cd2d17b3c19268f4bf0197f44ecd6"
+  dependencies:
+    babel-plugin-syntax-jsx "^6.8.0"
+    babel-runtime "^6.22.0"
+
+babel-plugin-transform-react-jsx@^6.24.1:
+  version "6.24.1"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz#840a028e7df460dfc3a2d29f0c0d91f6376e66a3"
+  dependencies:
+    babel-helper-builder-react-jsx "^6.24.1"
+    babel-plugin-syntax-jsx "^6.8.0"
+    babel-runtime "^6.22.0"
+
+babel-plugin-transform-strict-mode@^6.24.1:
+  version "6.24.1"
+  resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-types "^6.24.1"
+
+babel-plugin-undeclared-variables-check@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/babel-plugin-undeclared-variables-check/-/babel-plugin-undeclared-variables-check-1.0.2.tgz#5cf1aa539d813ff64e99641290af620965f65dee"
+  dependencies:
+    leven "^1.0.2"
+
+babel-plugin-undefined-to-void@^1.1.6:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/babel-plugin-undefined-to-void/-/babel-plugin-undefined-to-void-1.1.6.tgz#7f578ef8b78dfae6003385d8417a61eda06e2f81"
+
+babel-polyfill@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.23.0.tgz#8364ca62df8eafb830499f699177466c3b03499d"
+  dependencies:
+    babel-runtime "^6.22.0"
+    core-js "^2.4.0"
+    regenerator-runtime "^0.10.0"
+
+babel-preset-flow@^6.23.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz#e71218887085ae9a24b5be4169affb599816c49d"
+  dependencies:
+    babel-plugin-transform-flow-strip-types "^6.22.0"
+
+babel-preset-jest@^18.0.0:
+  version "18.0.0"
+  resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-18.0.0.tgz#84faf8ca3ec65aba7d5e3f59bbaed935ab24049e"
+  dependencies:
+    babel-plugin-jest-hoist "^18.0.0"
+
+babel-preset-react@^6.5.0:
+  version "6.24.1"
+  resolved "https://registry.yarnpkg.com/babel-preset-react/-/babel-preset-react-6.24.1.tgz#ba69dfaea45fc3ec639b6a4ecea6e17702c91380"
+  dependencies:
+    babel-plugin-syntax-jsx "^6.3.13"
+    babel-plugin-transform-react-display-name "^6.23.0"
+    babel-plugin-transform-react-jsx "^6.24.1"
+    babel-plugin-transform-react-jsx-self "^6.22.0"
+    babel-plugin-transform-react-jsx-source "^6.22.0"
+    babel-preset-flow "^6.23.0"
+
+babel-register@^6.24.1:
+  version "6.24.1"
+  resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.24.1.tgz#7e10e13a2f71065bdfad5a1787ba45bca6ded75f"
+  dependencies:
+    babel-core "^6.24.1"
+    babel-runtime "^6.22.0"
+    core-js "^2.4.0"
+    home-or-tmp "^2.0.0"
+    lodash "^4.2.0"
+    mkdirp "^0.5.1"
+    source-map-support "^0.4.2"
+
+babel-runtime@^6.22.0:
+  version "6.23.0"
+  resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b"
+  dependencies:
+    core-js "^2.4.0"
+    regenerator-runtime "^0.10.0"
+
+babel-template@^6.16.0, babel-template@^6.24.1, babel-template@^6.25.0:
+  version "6.25.0"
+  resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.25.0.tgz#665241166b7c2aa4c619d71e192969552b10c071"
+  dependencies:
+    babel-runtime "^6.22.0"
+    babel-traverse "^6.25.0"
+    babel-types "^6.25.0"
+    babylon "^6.17.2"
+    lodash "^4.2.0"
+
+babel-traverse@^6.18.0, babel-traverse@^6.23.1, babel-traverse@^6.24.1, babel-traverse@^6.25.0, babel-traverse@^6.9.0:
+  version "6.25.0"
+  resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.25.0.tgz#2257497e2fcd19b89edc13c4c91381f9512496f1"
+  dependencies:
+    babel-code-frame "^6.22.0"
+    babel-messages "^6.23.0"
+    babel-runtime "^6.22.0"
+    babel-types "^6.25.0"
+    babylon "^6.17.2"
+    debug "^2.2.0"
+    globals "^9.0.0"
+    invariant "^2.2.0"
+    lodash "^4.2.0"
+
+babel-types@^6.18.0, babel-types@^6.23.0, babel-types@^6.24.1, babel-types@^6.25.0:
+  version "6.25.0"
+  resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.25.0.tgz#70afb248d5660e5d18f811d91c8303b54134a18e"
+  dependencies:
+    babel-runtime "^6.22.0"
+    esutils "^2.0.2"
+    lodash "^4.2.0"
+    to-fast-properties "^1.0.1"
+
+babel@^5.4.7:
+  version "5.8.38"
+  resolved "https://registry.yarnpkg.com/babel/-/babel-5.8.38.tgz#dfb087c22894917c576fb67ce9cf328d458629fb"
+  dependencies:
+    babel-core "^5.6.21"
+    chokidar "^1.0.0"
+    commander "^2.6.0"
+    convert-source-map "^1.1.0"
+    fs-readdir-recursive "^0.1.0"
+    glob "^5.0.5"
+    lodash "^3.2.0"
+    output-file-sync "^1.1.0"
+    path-exists "^1.0.0"
+    path-is-absolute "^1.0.0"
+    slash "^1.0.0"
+    source-map "^0.5.0"
+
+babylon@6.15.0:
+  version "6.15.0"
+  resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.15.0.tgz#ba65cfa1a80e1759b0e89fb562e27dccae70348e"
+
+babylon@^5.8.38:
+  version "5.8.38"
+  resolved "https://registry.yarnpkg.com/babylon/-/babylon-5.8.38.tgz#ec9b120b11bf6ccd4173a18bf217e60b79859ffd"
+
+babylon@^6.13.0, babylon@^6.17.0, babylon@^6.17.2:
+  version "6.17.3"
+  resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.17.3.tgz#1327d709950b558f204e5352587fd0290f8d8e48"
+
+balanced-match@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
+
+base64-js@^1.0.2:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1"
+
+bcrypt-pbkdf@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d"
+  dependencies:
+    tweetnacl "^0.14.3"
+
+beeper@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/beeper/-/beeper-1.1.1.tgz#e6d5ea8c5dad001304a70b22638447f69cb2f809"
+
+binary-extensions@^1.0.0:
+  version "1.8.0"
+  resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.8.0.tgz#48ec8d16df4377eae5fa5884682480af4d95c774"
+
+block-stream@*:
+  version "0.0.9"
+  resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a"
+  dependencies:
+    inherits "~2.0.0"
+
+bluebird@^2.9.33:
+  version "2.11.0"
+  resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1"
+
+bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0:
+  version "4.11.6"
+  resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215"
+
+boom@2.x.x:
+  version "2.10.1"
+  resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f"
+  dependencies:
+    hoek "2.x.x"
+
+brace-expansion@^1.0.0, brace-expansion@^1.1.7:
+  version "1.1.8"
+  resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292"
+  dependencies:
+    balanced-match "^1.0.0"
+    concat-map "0.0.1"
+
+braces@^1.8.2:
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7"
+  dependencies:
+    expand-range "^1.8.1"
+    preserve "^0.2.0"
+    repeat-element "^1.1.2"
+
+breakable@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/breakable/-/breakable-1.0.0.tgz#784a797915a38ead27bad456b5572cb4bbaa78c1"
+
+brorand@^1.0.1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
+
+browser-pack@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/browser-pack/-/browser-pack-5.0.1.tgz#4197719b20c6e0aaa09451c5111e53efb6fbc18d"
+  dependencies:
+    JSONStream "^1.0.3"
+    combine-source-map "~0.6.1"
+    defined "^1.0.0"
+    through2 "^1.0.0"
+    umd "^3.0.0"
+
+browser-pack@^6.0.1:
+  version "6.0.2"
+  resolved "https://registry.yarnpkg.com/browser-pack/-/browser-pack-6.0.2.tgz#f86cd6cef4f5300c8e63e07a4d512f65fbff4531"
+  dependencies:
+    JSONStream "^1.0.3"
+    combine-source-map "~0.7.1"
+    defined "^1.0.0"
+    through2 "^2.0.0"
+    umd "^3.0.0"
+
+browser-resolve@^1.11.0, browser-resolve@^1.11.2, browser-resolve@^1.7.0:
+  version "1.11.2"
+  resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.2.tgz#8ff09b0a2c421718a1051c260b32e48f442938ce"
+  dependencies:
+    resolve "1.1.7"
+
+browser-unpack@^1.1.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/browser-unpack/-/browser-unpack-1.2.0.tgz#357aee31fc467831684d063e4355e070a782970d"
+  dependencies:
+    acorn "^4.0.3"
+    browser-pack "^5.0.1"
+    concat-stream "^1.5.0"
+    minimist "^1.1.1"
+
+browserify-aes@^1.0.0, browserify-aes@^1.0.4:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.0.6.tgz#5e7725dbdef1fd5930d4ebab48567ce451c48a0a"
+  dependencies:
+    buffer-xor "^1.0.2"
+    cipher-base "^1.0.0"
+    create-hash "^1.1.0"
+    evp_bytestokey "^1.0.0"
+    inherits "^2.0.1"
+
+browserify-cipher@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.0.tgz#9988244874bf5ed4e28da95666dcd66ac8fc363a"
+  dependencies:
+    browserify-aes "^1.0.4"
+    browserify-des "^1.0.0"
+    evp_bytestokey "^1.0.0"
+
+browserify-des@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.0.tgz#daa277717470922ed2fe18594118a175439721dd"
+  dependencies:
+    cipher-base "^1.0.1"
+    des.js "^1.0.0"
+    inherits "^2.0.1"
+
+browserify-rsa@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524"
+  dependencies:
+    bn.js "^4.1.0"
+    randombytes "^2.0.1"
+
+browserify-sign@^4.0.0:
+  version "4.0.4"
+  resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298"
+  dependencies:
+    bn.js "^4.1.1"
+    browserify-rsa "^4.0.0"
+    create-hash "^1.1.0"
+    create-hmac "^1.1.2"
+    elliptic "^6.0.0"
+    inherits "^2.0.1"
+    parse-asn1 "^5.0.0"
+
+browserify-transform-tools@~1.7.0:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/browserify-transform-tools/-/browserify-transform-tools-1.7.0.tgz#83e277221f63259bed2e7eb2a283a970a501f4c4"
+  dependencies:
+    falafel "^2.0.0"
+    through "^2.3.7"
+
+browserify-zlib@~0.1.2:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d"
+  dependencies:
+    pako "~0.2.0"
+
+browserify@^13.0.0:
+  version "13.3.0"
+  resolved "https://registry.yarnpkg.com/browserify/-/browserify-13.3.0.tgz#b5a9c9020243f0c70e4675bec8223bc627e415ce"
+  dependencies:
+    JSONStream "^1.0.3"
+    assert "^1.4.0"
+    browser-pack "^6.0.1"
+    browser-resolve "^1.11.0"
+    browserify-zlib "~0.1.2"
+    buffer "^4.1.0"
+    cached-path-relative "^1.0.0"
+    concat-stream "~1.5.1"
+    console-browserify "^1.1.0"
+    constants-browserify "~1.0.0"
+    crypto-browserify "^3.0.0"
+    defined "^1.0.0"
+    deps-sort "^2.0.0"
+    domain-browser "~1.1.0"
+    duplexer2 "~0.1.2"
+    events "~1.1.0"
+    glob "^7.1.0"
+    has "^1.0.0"
+    htmlescape "^1.1.0"
+    https-browserify "~0.0.0"
+    inherits "~2.0.1"
+    insert-module-globals "^7.0.0"
+    labeled-stream-splicer "^2.0.0"
+    module-deps "^4.0.8"
+    os-browserify "~0.1.1"
+    parents "^1.0.1"
+    path-browserify "~0.0.0"
+    process "~0.11.0"
+    punycode "^1.3.2"
+    querystring-es3 "~0.2.0"
+    read-only-stream "^2.0.0"
+    readable-stream "^2.0.2"
+    resolve "^1.1.4"
+    shasum "^1.0.0"
+    shell-quote "^1.6.1"
+    stream-browserify "^2.0.0"
+    stream-http "^2.0.0"
+    string_decoder "~0.10.0"
+    subarg "^1.0.0"
+    syntax-error "^1.1.1"
+    through2 "^2.0.0"
+    timers-browserify "^1.0.1"
+    tty-browserify "~0.0.0"
+    url "~0.11.0"
+    util "~0.10.1"
+    vm-browserify "~0.0.1"
+    xtend "^4.0.0"
+
+bser@1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/bser/-/bser-1.0.2.tgz#381116970b2a6deea5646dd15dd7278444b56169"
+  dependencies:
+    node-int64 "^0.4.0"
+
+buffer-xor@^1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9"
+
+buffer@^4.1.0:
+  version "4.9.1"
+  resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298"
+  dependencies:
+    base64-js "^1.0.2"
+    ieee754 "^1.1.4"
+    isarray "^1.0.0"
+
+builtin-modules@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
+
+builtin-status-codes@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
+
+bundle-collapser@^1.1.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/bundle-collapser/-/bundle-collapser-1.2.1.tgz#e119afc92638e440b9085f47ae081fa756cba33d"
+  dependencies:
+    browser-pack "^5.0.1"
+    browser-unpack "^1.1.0"
+    concat-stream "^1.5.0"
+    falafel "^1.2.0"
+    minimist "^1.1.1"
+    through2 "^2.0.0"
+
+cached-path-relative@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/cached-path-relative/-/cached-path-relative-1.0.1.tgz#d09c4b52800aa4c078e2dd81a869aac90d2e54e7"
+
+caller-path@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f"
+  dependencies:
+    callsites "^0.2.0"
+
+callsites@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca"
+
+callsites@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50"
+
+camelcase@^1.0.2, camelcase@^1.2.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39"
+
+camelcase@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
+
+cardinal@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/cardinal/-/cardinal-1.0.0.tgz#50e21c1b0aa37729f9377def196b5a9cec932ee9"
+  dependencies:
+    ansicolors "~0.2.1"
+    redeyed "~1.0.0"
+
+caseless@~0.11.0:
+  version "0.11.0"
+  resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7"
+
+caseless@~0.12.0:
+  version "0.12.0"
+  resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
+
+center-align@^0.1.1:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad"
+  dependencies:
+    align-text "^0.1.3"
+    lazy-cache "^1.0.3"
+
+chalk@*, chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
+  dependencies:
+    ansi-styles "^2.2.1"
+    escape-string-regexp "^1.0.2"
+    has-ansi "^2.0.0"
+    strip-ansi "^3.0.0"
+    supports-color "^2.0.0"
+
+chokidar@^1.0.0, chokidar@^1.6.1:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
+  dependencies:
+    anymatch "^1.3.0"
+    async-each "^1.0.0"
+    glob-parent "^2.0.0"
+    inherits "^2.0.1"
+    is-binary-path "^1.0.0"
+    is-glob "^2.0.0"
+    path-is-absolute "^1.0.0"
+    readdirp "^2.0.0"
+  optionalDependencies:
+    fsevents "^1.0.0"
+
+ci-info@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.0.0.tgz#dc5285f2b4e251821683681c381c3388f46ec534"
+
+cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.3.tgz#eeabf194419ce900da3018c207d212f2a6df0a07"
+  dependencies:
+    inherits "^2.0.1"
+
+circular-json@^0.3.1:
+  version "0.3.1"
+  resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d"
+
+cli-cursor@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987"
+  dependencies:
+    restore-cursor "^1.0.1"
+
+cli-table@^0.3.1:
+  version "0.3.1"
+  resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23"
+  dependencies:
+    colors "1.0.3"
+
+cli-usage@^0.1.1:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/cli-usage/-/cli-usage-0.1.4.tgz#7c01e0dc706c234b39c933838c8e20b2175776e2"
+  dependencies:
+    marked "^0.3.6"
+    marked-terminal "^1.6.2"
+
+cli-width@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a"
+
+cliui@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1"
+  dependencies:
+    center-align "^0.1.1"
+    right-align "^0.1.1"
+    wordwrap "0.0.2"
+
+cliui@^3.2.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
+  dependencies:
+    string-width "^1.0.1"
+    strip-ansi "^3.0.1"
+    wrap-ansi "^2.0.0"
+
+clone-stats@^0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-0.0.1.tgz#b88f94a82cf38b8791d58046ea4029ad88ca99d1"
+
+clone@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/clone/-/clone-0.2.0.tgz#c6126a90ad4f72dbf5acdb243cc37724fe93fc1f"
+
+clone@^1.0.0, clone@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149"
+
+co@^4.6.0:
+  version "4.6.0"
+  resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
+
+code-point-at@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
+
+coffee-script@^1.8.0:
+  version "1.12.6"
+  resolved "https://registry.yarnpkg.com/coffee-script/-/coffee-script-1.12.6.tgz#285a3f7115689065064d6bf9ef4572db66695cbf"
+
+coffee-script@~1.3.3:
+  version "1.3.3"
+  resolved "https://registry.yarnpkg.com/coffee-script/-/coffee-script-1.3.3.tgz#150d6b4cb522894369efed6a2101c20bc7f4a4f4"
+
+colors@1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b"
+
+colors@~0.6.2:
+  version "0.6.2"
+  resolved "https://registry.yarnpkg.com/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc"
+
+combine-source-map@~0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/combine-source-map/-/combine-source-map-0.6.1.tgz#9b4a09c316033d768e0f11e029fa2730e079ad96"
+  dependencies:
+    convert-source-map "~1.1.0"
+    inline-source-map "~0.5.0"
+    lodash.memoize "~3.0.3"
+    source-map "~0.4.2"
+
+combine-source-map@~0.7.1:
+  version "0.7.2"
+  resolved "https://registry.yarnpkg.com/combine-source-map/-/combine-source-map-0.7.2.tgz#0870312856b307a87cc4ac486f3a9a62aeccc09e"
+  dependencies:
+    convert-source-map "~1.1.0"
+    inline-source-map "~0.6.0"
+    lodash.memoize "~3.0.3"
+    source-map "~0.5.3"
+
+combined-stream@^1.0.5, combined-stream@~1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009"
+  dependencies:
+    delayed-stream "~1.0.0"
+
+commander@^2.5.0, commander@^2.6.0, commander@^2.8.1, commander@^2.9.0:
+  version "2.9.0"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4"
+  dependencies:
+    graceful-readlink ">= 1.0.0"
+
+commoner@~0.10.3:
+  version "0.10.8"
+  resolved "https://registry.yarnpkg.com/commoner/-/commoner-0.10.8.tgz#34fc3672cd24393e8bb47e70caa0293811f4f2c5"
+  dependencies:
+    commander "^2.5.0"
+    detective "^4.3.1"
+    glob "^5.0.15"
+    graceful-fs "^4.1.2"
+    iconv-lite "^0.4.5"
+    mkdirp "^0.5.0"
+    private "^0.1.6"
+    q "^1.1.2"
+    recast "^0.11.17"
+
+concat-map@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+
+concat-stream@^1.4.6, concat-stream@^1.4.7, concat-stream@^1.5.0, concat-stream@^1.5.2:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7"
+  dependencies:
+    inherits "^2.0.3"
+    readable-stream "^2.2.2"
+    typedarray "^0.0.6"
+
+concat-stream@~1.5.0, concat-stream@~1.5.1:
+  version "1.5.2"
+  resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.2.tgz#708978624d856af41a5a741defdd261da752c266"
+  dependencies:
+    inherits "~2.0.1"
+    readable-stream "~2.0.0"
+    typedarray "~0.0.5"
+
+console-browserify@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10"
+  dependencies:
+    date-now "^0.1.4"
+
+console-control-strings@^1.0.0, console-control-strings@~1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
+
+constants-browserify@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
+
+content-type-parser@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/content-type-parser/-/content-type-parser-1.0.1.tgz#c3e56988c53c65127fb46d4032a3a900246fdc94"
+
+convert-source-map@^1.1.0:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5"
+
+convert-source-map@~1.1.0:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.1.3.tgz#4829c877e9fe49b3161f3bf3673888e204699860"
+
+core-js@^1.0.0:
+  version "1.2.7"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
+
+core-js@^2.2.1, core-js@^2.4.0:
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e"
+
+core-util-is@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
+
+coveralls@^2.11.6:
+  version "2.13.1"
+  resolved "https://registry.yarnpkg.com/coveralls/-/coveralls-2.13.1.tgz#d70bb9acc1835ec4f063ff9dac5423c17b11f178"
+  dependencies:
+    js-yaml "3.6.1"
+    lcov-parse "0.0.10"
+    log-driver "1.2.5"
+    minimist "1.2.0"
+    request "2.79.0"
+
+"crc32@>= 0.2.2":
+  version "0.2.2"
+  resolved "https://registry.yarnpkg.com/crc32/-/crc32-0.2.2.tgz#7ad220d6ffdcd119f9fc127a7772cacea390a4ba"
+
+create-ecdh@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.0.tgz#888c723596cdf7612f6498233eebd7a35301737d"
+  dependencies:
+    bn.js "^4.1.0"
+    elliptic "^6.0.0"
+
+create-hash@^1.1.0, create-hash@^1.1.1, create-hash@^1.1.2:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.3.tgz#606042ac8b9262750f483caddab0f5819172d8fd"
+  dependencies:
+    cipher-base "^1.0.1"
+    inherits "^2.0.1"
+    ripemd160 "^2.0.0"
+    sha.js "^2.4.0"
+
+create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.6.tgz#acb9e221a4e17bdb076e90657c42b93e3726cf06"
+  dependencies:
+    cipher-base "^1.0.3"
+    create-hash "^1.1.0"
+    inherits "^2.0.1"
+    ripemd160 "^2.0.0"
+    safe-buffer "^5.0.1"
+    sha.js "^2.4.8"
+
+create-react-class@^15.6.0:
+  version "15.6.0"
+  resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.6.0.tgz#ab448497c26566e1e29413e883207d57cfe7bed4"
+  dependencies:
+    fbjs "^0.8.9"
+    loose-envify "^1.3.1"
+    object-assign "^4.1.1"
+
+cross-spawn-async@^2.2.2:
+  version "2.2.5"
+  resolved "https://registry.yarnpkg.com/cross-spawn-async/-/cross-spawn-async-2.2.5.tgz#845ff0c0834a3ded9d160daca6d390906bb288cc"
+  dependencies:
+    lru-cache "^4.0.0"
+    which "^1.2.8"
+
+cross-spawn@^2.1.5:
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-2.2.3.tgz#fac56202dfd3d0dd861778f2da203bf434bb821c"
+  dependencies:
+    cross-spawn-async "^2.2.2"
+    spawn-sync "^1.0.15"
+
+cryptiles@2.x.x:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8"
+  dependencies:
+    boom "2.x.x"
+
+crypto-browserify@^3.0.0:
+  version "3.11.0"
+  resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.11.0.tgz#3652a0906ab9b2a7e0c3ce66a408e957a2485522"
+  dependencies:
+    browserify-cipher "^1.0.0"
+    browserify-sign "^4.0.0"
+    create-ecdh "^4.0.0"
+    create-hash "^1.1.0"
+    create-hmac "^1.1.0"
+    diffie-hellman "^5.0.0"
+    inherits "^2.0.1"
+    pbkdf2 "^3.0.3"
+    public-encrypt "^4.0.0"
+    randombytes "^2.0.0"
+
+cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0":
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.2.tgz#b8036170c79f07a90ff2f16e22284027a243848b"
+
+"cssstyle@>= 0.2.37 < 0.3.0":
+  version "0.2.37"
+  resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-0.2.37.tgz#541097234cb2513c83ceed3acddc27ff27987d54"
+  dependencies:
+    cssom "0.3.x"
+
+d@1:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f"
+  dependencies:
+    es5-ext "^0.10.9"
+
+dashdash@^1.12.0:
+  version "1.14.1"
+  resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
+  dependencies:
+    assert-plus "^1.0.0"
+
+date-now@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
+
+dateformat@1.0.2-1.2.3:
+  version "1.0.2-1.2.3"
+  resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-1.0.2-1.2.3.tgz#b0220c02de98617433b72851cf47de3df2cdbee9"
+
+dateformat@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-2.0.0.tgz#2743e3abb5c3fc2462e527dca445e04e9f4dee17"
+
+debug@^2.1.1, debug@^2.2.0, debug@^2.6.3:
+  version "2.6.8"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc"
+  dependencies:
+    ms "2.0.0"
+
+decamelize@^1.0.0, decamelize@^1.1.1:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
+
+deep-extend@~0.4.0:
+  version "0.4.2"
+  resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f"
+
+deep-is@~0.1.3:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
+
+default-require-extensions@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8"
+  dependencies:
+    strip-bom "^2.0.0"
+
+defaults@^1.0.0:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d"
+  dependencies:
+    clone "^1.0.2"
+
+define-properties@^1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94"
+  dependencies:
+    foreach "^2.0.5"
+    object-keys "^1.0.8"
+
+defined@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
+
+"deflate-js@>= 0.2.2":
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/deflate-js/-/deflate-js-0.2.3.tgz#f85abb58ebc5151a306147473d57c3e4f7e4426b"
+
+defs@~1.1.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/defs/-/defs-1.1.1.tgz#b22609f2c7a11ba7a3db116805c139b1caffa9d2"
+  dependencies:
+    alter "~0.2.0"
+    ast-traverse "~0.1.1"
+    breakable "~1.0.0"
+    esprima-fb "~15001.1001.0-dev-harmony-fb"
+    simple-fmt "~0.1.0"
+    simple-is "~0.2.0"
+    stringmap "~0.2.2"
+    stringset "~0.2.1"
+    tryor "~0.1.2"
+    yargs "~3.27.0"
+
+del@^2.0.2:
+  version "2.2.2"
+  resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8"
+  dependencies:
+    globby "^5.0.0"
+    is-path-cwd "^1.0.0"
+    is-path-in-cwd "^1.0.0"
+    object-assign "^4.0.1"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+    rimraf "^2.2.8"
+
+delayed-stream@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+
+delegates@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
+
+deprecated@^0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/deprecated/-/deprecated-0.0.1.tgz#f9c9af5464afa1e7a971458a8bdef2aa94d5bb19"
+
+deps-sort@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/deps-sort/-/deps-sort-2.0.0.tgz#091724902e84658260eb910748cccd1af6e21fb5"
+  dependencies:
+    JSONStream "^1.0.3"
+    shasum "^1.0.0"
+    subarg "^1.0.0"
+    through2 "^2.0.0"
+
+derequire@^2.0.3:
+  version "2.0.6"
+  resolved "https://registry.yarnpkg.com/derequire/-/derequire-2.0.6.tgz#31a414bb7ca176239fa78b116636ef77d517e768"
+  dependencies:
+    acorn "^4.0.3"
+    concat-stream "^1.4.6"
+    escope "^3.6.0"
+    through2 "^2.0.0"
+    yargs "^6.5.0"
+
+des.js@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc"
+  dependencies:
+    inherits "^2.0.1"
+    minimalistic-assert "^1.0.0"
+
+detect-file@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-0.1.0.tgz#4935dedfd9488648e006b0129566e9386711ea63"
+  dependencies:
+    fs-exists-sync "^0.1.0"
+
+detect-indent@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-3.0.1.tgz#9dc5e5ddbceef8325764b9451b02bc6d54084f75"
+  dependencies:
+    get-stdin "^4.0.1"
+    minimist "^1.1.0"
+    repeating "^1.1.0"
+
+detect-indent@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208"
+  dependencies:
+    repeating "^2.0.0"
+
+detective@^4.0.0, detective@^4.3.1:
+  version "4.5.0"
+  resolved "https://registry.yarnpkg.com/detective/-/detective-4.5.0.tgz#6e5a8c6b26e6c7a254b1c6b6d7490d98ec91edd1"
+  dependencies:
+    acorn "^4.0.3"
+    defined "^1.0.0"
+
+diff@^3.0.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9"
+
+diffie-hellman@^5.0.0:
+  version "5.0.2"
+  resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.2.tgz#b5835739270cfe26acf632099fded2a07f209e5e"
+  dependencies:
+    bn.js "^4.1.0"
+    miller-rabin "^4.0.0"
+    randombytes "^2.0.0"
+
+doctrine@^1.2.2:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa"
+  dependencies:
+    esutils "^2.0.2"
+    isarray "^1.0.0"
+
+doctrine@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.0.0.tgz#c73d8d2909d22291e1a007a395804da8b665fe63"
+  dependencies:
+    esutils "^2.0.2"
+    isarray "^1.0.0"
+
+domain-browser@~1.1.0:
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc"
+
+duplexer2@0.0.2:
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.0.2.tgz#c614dcf67e2fb14995a91711e5a617e8a60a31db"
+  dependencies:
+    readable-stream "~1.1.9"
+
+duplexer2@^0.1.2, duplexer2@~0.1.0, duplexer2@~0.1.2:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1"
+  dependencies:
+    readable-stream "^2.0.2"
+
+ecc-jsbn@~0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505"
+  dependencies:
+    jsbn "~0.1.0"
+
+elliptic@^6.0.0:
+  version "6.4.0"
+  resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df"
+  dependencies:
+    bn.js "^4.4.0"
+    brorand "^1.0.1"
+    hash.js "^1.0.0"
+    hmac-drbg "^1.0.0"
+    inherits "^2.0.1"
+    minimalistic-assert "^1.0.0"
+    minimalistic-crypto-utils "^1.0.0"
+
+encoding@^0.1.11:
+  version "0.1.12"
+  resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb"
+  dependencies:
+    iconv-lite "~0.4.13"
+
+end-of-stream@~0.1.5:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-0.1.5.tgz#8e177206c3c80837d85632e8b9359dfe8b2f6eaf"
+  dependencies:
+    once "~1.3.0"
+
+"errno@>=0.1.1 <0.2.0-0":
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d"
+  dependencies:
+    prr "~0.0.0"
+
+error-ex@^1.2.0:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc"
+  dependencies:
+    is-arrayish "^0.2.1"
+
+es-abstract@^1.7.0:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.7.0.tgz#dfade774e01bfcd97f96180298c449c8623fb94c"
+  dependencies:
+    es-to-primitive "^1.1.1"
+    function-bind "^1.1.0"
+    is-callable "^1.1.3"
+    is-regex "^1.0.3"
+
+es-to-primitive@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d"
+  dependencies:
+    is-callable "^1.1.1"
+    is-date-object "^1.0.1"
+    is-symbol "^1.0.1"
+
+es5-ext@^0.10.14, es5-ext@^0.10.9, es5-ext@~0.10.14:
+  version "0.10.23"
+  resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.23.tgz#7578b51be974207a5487821b56538c224e4e7b38"
+  dependencies:
+    es6-iterator "2"
+    es6-symbol "~3.1"
+
+es6-iterator@2, es6-iterator@^2.0.1, es6-iterator@~2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.1.tgz#8e319c9f0453bf575d374940a655920e59ca5512"
+  dependencies:
+    d "1"
+    es5-ext "^0.10.14"
+    es6-symbol "^3.1"
+
+es6-map@^0.1.3:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0"
+  dependencies:
+    d "1"
+    es5-ext "~0.10.14"
+    es6-iterator "~2.0.1"
+    es6-set "~0.1.5"
+    es6-symbol "~3.1.1"
+    event-emitter "~0.3.5"
+
+es6-set@~0.1.5:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1"
+  dependencies:
+    d "1"
+    es5-ext "~0.10.14"
+    es6-iterator "~2.0.1"
+    es6-symbol "3.1.1"
+    event-emitter "~0.3.5"
+
+es6-symbol@3.1.1, es6-symbol@^3.1, es6-symbol@^3.1.1, es6-symbol@~3.1, es6-symbol@~3.1.1:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77"
+  dependencies:
+    d "1"
+    es5-ext "~0.10.14"
+
+es6-weak-map@^2.0.1:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f"
+  dependencies:
+    d "1"
+    es5-ext "^0.10.14"
+    es6-iterator "^2.0.1"
+    es6-symbol "^3.1.1"
+
+escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+
+escodegen@^1.6.1:
+  version "1.8.1"
+  resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018"
+  dependencies:
+    esprima "^2.7.1"
+    estraverse "^1.9.1"
+    esutils "^2.0.2"
+    optionator "^0.8.1"
+  optionalDependencies:
+    source-map "~0.2.0"
+
+escope@^3.6.0:
+  version "3.6.0"
+  resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3"
+  dependencies:
+    es6-map "^0.1.3"
+    es6-weak-map "^2.0.1"
+    esrecurse "^4.1.0"
+    estraverse "^4.1.1"
+
+eslint-config-fbjs@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/eslint-config-fbjs/-/eslint-config-fbjs-1.1.1.tgz#dd29f8d912e8a755257e9eeef00bae1cce57f73a"
+
+eslint-plugin-babel@^3.3.0:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-babel/-/eslint-plugin-babel-3.3.0.tgz#2f494aedcf6f4aa4e75b9155980837bc1fbde193"
+
+eslint-plugin-flowtype@^2.25.0:
+  version "2.34.0"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.34.0.tgz#b9875f314652e5081623c9d2b18a346bbb759c09"
+  dependencies:
+    lodash "^4.15.0"
+
+"eslint-plugin-react-internal@file:eslint-rules":
+  version "0.0.0"
+
+eslint-plugin-react@^6.7.1:
+  version "6.10.3"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-6.10.3.tgz#c5435beb06774e12c7db2f6abaddcbf900cd3f78"
+  dependencies:
+    array.prototype.find "^2.0.1"
+    doctrine "^1.2.2"
+    has "^1.0.1"
+    jsx-ast-utils "^1.3.4"
+    object.assign "^4.0.4"
+
+eslint@^3.10.2:
+  version "3.19.0"
+  resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.19.0.tgz#c8fc6201c7f40dd08941b87c085767386a679acc"
+  dependencies:
+    babel-code-frame "^6.16.0"
+    chalk "^1.1.3"
+    concat-stream "^1.5.2"
+    debug "^2.1.1"
+    doctrine "^2.0.0"
+    escope "^3.6.0"
+    espree "^3.4.0"
+    esquery "^1.0.0"
+    estraverse "^4.2.0"
+    esutils "^2.0.2"
+    file-entry-cache "^2.0.0"
+    glob "^7.0.3"
+    globals "^9.14.0"
+    ignore "^3.2.0"
+    imurmurhash "^0.1.4"
+    inquirer "^0.12.0"
+    is-my-json-valid "^2.10.0"
+    is-resolvable "^1.0.0"
+    js-yaml "^3.5.1"
+    json-stable-stringify "^1.0.0"
+    levn "^0.3.0"
+    lodash "^4.0.0"
+    mkdirp "^0.5.0"
+    natural-compare "^1.4.0"
+    optionator "^0.8.2"
+    path-is-inside "^1.0.1"
+    pluralize "^1.2.1"
+    progress "^1.1.8"
+    require-uncached "^1.0.2"
+    shelljs "^0.7.5"
+    strip-bom "^3.0.0"
+    strip-json-comments "~2.0.1"
+    table "^3.7.8"
+    text-table "~0.2.0"
+    user-home "^2.0.0"
+
+espree@^3.4.0:
+  version "3.4.3"
+  resolved "https://registry.yarnpkg.com/espree/-/espree-3.4.3.tgz#2910b5ccd49ce893c2ffffaab4fd8b3a31b82374"
+  dependencies:
+    acorn "^5.0.1"
+    acorn-jsx "^3.0.0"
+
+esprima-fb@~15001.1001.0-dev-harmony-fb:
+  version "15001.1001.0-dev-harmony-fb"
+  resolved "https://registry.yarnpkg.com/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz#43beb57ec26e8cf237d3dd8b33e42533577f2659"
+
+esprima@^2.6.0, esprima@^2.7.1:
+  version "2.7.3"
+  resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
+
+esprima@^3.1.1, esprima@~3.1.0:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633"
+
+"esprima@~ 1.0.2":
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.0.4.tgz#9f557e08fc3b4d26ece9dd34f8fbf476b62585ad"
+
+esprima@~3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.0.0.tgz#53cf247acda77313e551c3aa2e73342d3fb4f7d9"
+
+esquery@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.0.tgz#cfba8b57d7fba93f17298a8a006a04cda13d80fa"
+  dependencies:
+    estraverse "^4.0.0"
+
+esrecurse@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220"
+  dependencies:
+    estraverse "~4.1.0"
+    object-assign "^4.0.1"
+
+estraverse@^1.9.1:
+  version "1.9.3"
+  resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44"
+
+estraverse@^4.0.0, estraverse@^4.1.1, estraverse@^4.2.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13"
+
+estraverse@~4.1.0:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2"
+
+esutils@^2.0.0, esutils@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
+
+event-emitter@~0.3.5:
+  version "0.3.5"
+  resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39"
+  dependencies:
+    d "1"
+    es5-ext "~0.10.14"
+
+eventemitter2@~0.4.13:
+  version "0.4.14"
+  resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-0.4.14.tgz#8f61b75cde012b2e9eb284d4545583b5643b61ab"
+
+events@~1.1.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924"
+
+evp_bytestokey@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.0.tgz#497b66ad9fef65cd7c08a6180824ba1476b66e53"
+  dependencies:
+    create-hash "^1.1.1"
+
+exec-sh@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.0.tgz#14f75de3f20d286ef933099b2ce50a90359cef10"
+  dependencies:
+    merge "^1.1.3"
+
+exit-hook@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8"
+
+exit@~0.1.1:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c"
+
+expand-brackets@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
+  dependencies:
+    is-posix-bracket "^0.1.0"
+
+expand-range@^1.8.1:
+  version "1.8.2"
+  resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337"
+  dependencies:
+    fill-range "^2.1.0"
+
+expand-tilde@^1.2.1, expand-tilde@^1.2.2:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449"
+  dependencies:
+    os-homedir "^1.0.1"
+
+extend@^1.2.1:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/extend/-/extend-1.3.0.tgz#d1516fb0ff5624d2ebf9123ea1dac5a1994004f8"
+
+extend@^3.0.0, extend@~3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444"
+
+extglob@^0.3.1:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1"
+  dependencies:
+    is-extglob "^1.0.0"
+
+extsprintf@1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550"
+
+falafel@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/falafel/-/falafel-1.2.0.tgz#c18d24ef5091174a497f318cd24b026a25cddab4"
+  dependencies:
+    acorn "^1.0.3"
+    foreach "^2.0.5"
+    isarray "0.0.1"
+    object-keys "^1.0.6"
+
+falafel@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/falafel/-/falafel-2.1.0.tgz#96bb17761daba94f46d001738b3cedf3a67fe06c"
+  dependencies:
+    acorn "^5.0.0"
+    foreach "^2.0.5"
+    isarray "0.0.1"
+    object-keys "^1.0.6"
+
+fancy-log@^1.1.0, fancy-log@^1.2.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.0.tgz#45be17d02bb9917d60ccffd4995c999e6c8c9948"
+  dependencies:
+    chalk "^1.1.1"
+    time-stamp "^1.0.0"
+
+fast-levenshtein@~2.0.4:
+  version "2.0.6"
+  resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
+
+fb-watchman@^1.8.0, fb-watchman@^1.9.0:
+  version "1.9.2"
+  resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-1.9.2.tgz#a24cf47827f82d38fb59a69ad70b76e3b6ae7383"
+  dependencies:
+    bser "1.0.2"
+
+fbjs-scripts@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/fbjs-scripts/-/fbjs-scripts-0.6.0.tgz#da9ffc065c13eb2bf4437bb96a42bbd6ca05dcce"
+  dependencies:
+    babel "^5.4.7"
+    core-js "^1.0.0"
+    cross-spawn "^2.1.5"
+    gulp-util "^3.0.4"
+    object-assign "^4.0.1"
+    semver "^5.1.0"
+    through2 "^2.0.0"
+
+fbjs@^0.8.9:
+  version "0.8.12"
+  resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.12.tgz#10b5d92f76d45575fd63a217d4ea02bea2f8ed04"
+  dependencies:
+    core-js "^1.0.0"
+    isomorphic-fetch "^2.1.1"
+    loose-envify "^1.0.0"
+    object-assign "^4.1.0"
+    promise "^7.1.1"
+    setimmediate "^1.0.5"
+    ua-parser-js "^0.7.9"
+
+figures@^1.3.5:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e"
+  dependencies:
+    escape-string-regexp "^1.0.5"
+    object-assign "^4.1.0"
+
+file-entry-cache@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361"
+  dependencies:
+    flat-cache "^1.2.1"
+    object-assign "^4.0.1"
+
+filename-regex@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26"
+
+fileset@^2.0.2:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/fileset/-/fileset-2.0.3.tgz#8e7548a96d3cc2327ee5e674168723a333bba2a0"
+  dependencies:
+    glob "^7.0.3"
+    minimatch "^3.0.3"
+
+fill-range@^2.1.0:
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723"
+  dependencies:
+    is-number "^2.1.0"
+    isobject "^2.0.0"
+    randomatic "^1.1.3"
+    repeat-element "^1.1.2"
+    repeat-string "^1.5.2"
+
+find-index@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/find-index/-/find-index-0.1.1.tgz#675d358b2ca3892d795a1ab47232f8b6e2e0dde4"
+
+find-up@^1.0.0, find-up@^1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
+  dependencies:
+    path-exists "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+findup-sync@^0.4.0, findup-sync@^0.4.2:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.4.3.tgz#40043929e7bc60adf0b7f4827c4c6e75a0deca12"
+  dependencies:
+    detect-file "^0.1.0"
+    is-glob "^2.0.1"
+    micromatch "^2.3.7"
+    resolve-dir "^0.1.0"
+
+findup-sync@~0.1.0, findup-sync@~0.1.2:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.1.3.tgz#7f3e7a97b82392c653bf06589bd85190e93c3683"
+  dependencies:
+    glob "~3.2.9"
+    lodash "~2.4.1"
+
+fined@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/fined/-/fined-1.0.2.tgz#5b28424b760d7598960b7ef8480dff8ad3660e97"
+  dependencies:
+    expand-tilde "^1.2.1"
+    lodash.assignwith "^4.0.7"
+    lodash.isempty "^4.2.1"
+    lodash.isplainobject "^4.0.4"
+    lodash.isstring "^4.0.1"
+    lodash.pick "^4.2.1"
+    parse-filepath "^1.0.1"
+
+first-chunk-stream@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz#59bfb50cd905f60d7c394cd3d9acaab4e6ad934e"
+
+flagged-respawn@^0.3.2:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/flagged-respawn/-/flagged-respawn-0.3.2.tgz#ff191eddcd7088a675b2610fffc976be9b8074b5"
+
+flat-cache@^1.2.1:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.2.tgz#fa86714e72c21db88601761ecf2f555d1abc6b96"
+  dependencies:
+    circular-json "^0.3.1"
+    del "^2.0.2"
+    graceful-fs "^4.1.2"
+    write "^0.2.1"
+
+flow-bin@^0.37.0:
+  version "0.37.4"
+  resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.37.4.tgz#3d8da2ef746e80e730d166e09040f4198969b76b"
+
+for-in@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
+
+for-own@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce"
+  dependencies:
+    for-in "^1.0.1"
+
+foreach@^2.0.5:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99"
+
+forever-agent@~0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
+
+form-data@~2.1.1:
+  version "2.1.4"
+  resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1"
+  dependencies:
+    asynckit "^0.4.0"
+    combined-stream "^1.0.5"
+    mime-types "^2.1.12"
+
+fs-exists-sync@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add"
+
+fs-readdir-recursive@^0.1.0:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz#315b4fb8c1ca5b8c47defef319d073dad3568059"
+
+fs-readdir-recursive@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.0.0.tgz#8cd1745c8b4f8a29c8caec392476921ba195f560"
+
+fs.realpath@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+
+fsevents@^1.0.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.2.tgz#3282b713fb3ad80ede0e9fcf4611b5aa6fc033f4"
+  dependencies:
+    nan "^2.3.0"
+    node-pre-gyp "^0.6.36"
+
+fstream-ignore@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105"
+  dependencies:
+    fstream "^1.0.0"
+    inherits "2"
+    minimatch "^3.0.0"
+
+fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2:
+  version "1.0.11"
+  resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171"
+  dependencies:
+    graceful-fs "^4.1.2"
+    inherits "~2.0.0"
+    mkdirp ">=0.5 0"
+    rimraf "2"
+
+function-bind@^1.0.2, function-bind@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771"
+
+gauge@~2.7.3:
+  version "2.7.4"
+  resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
+  dependencies:
+    aproba "^1.0.3"
+    console-control-strings "^1.0.0"
+    has-unicode "^2.0.0"
+    object-assign "^4.1.0"
+    signal-exit "^3.0.0"
+    string-width "^1.0.1"
+    strip-ansi "^3.0.1"
+    wide-align "^1.1.0"
+
+gaze@^0.5.1:
+  version "0.5.2"
+  resolved "https://registry.yarnpkg.com/gaze/-/gaze-0.5.2.tgz#40b709537d24d1d45767db5a908689dfe69ac44f"
+  dependencies:
+    globule "~0.1.0"
+
+generate-function@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74"
+
+generate-object-property@^1.1.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0"
+  dependencies:
+    is-property "^1.0.0"
+
+get-caller-file@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5"
+
+get-stdin@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
+
+getobject@~0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/getobject/-/getobject-0.1.0.tgz#047a449789fa160d018f5486ed91320b6ec7885c"
+
+getpass@^0.1.1:
+  version "0.1.7"
+  resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
+  dependencies:
+    assert-plus "^1.0.0"
+
+glob-base@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
+  dependencies:
+    glob-parent "^2.0.0"
+    is-glob "^2.0.0"
+
+glob-parent@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28"
+  dependencies:
+    is-glob "^2.0.0"
+
+glob-stream@^3.1.5:
+  version "3.1.18"
+  resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-3.1.18.tgz#9170a5f12b790306fdfe598f313f8f7954fd143b"
+  dependencies:
+    glob "^4.3.1"
+    glob2base "^0.0.12"
+    minimatch "^2.0.1"
+    ordered-read-streams "^0.1.0"
+    through2 "^0.6.1"
+    unique-stream "^1.0.0"
+
+glob-watcher@^0.0.6:
+  version "0.0.6"
+  resolved "https://registry.yarnpkg.com/glob-watcher/-/glob-watcher-0.0.6.tgz#b95b4a8df74b39c83298b0c05c978b4d9a3b710b"
+  dependencies:
+    gaze "^0.5.1"
+
+glob2base@^0.0.12:
+  version "0.0.12"
+  resolved "https://registry.yarnpkg.com/glob2base/-/glob2base-0.0.12.tgz#9d419b3e28f12e83a362164a277055922c9c0d56"
+  dependencies:
+    find-index "^0.1.1"
+
+glob@^4.3.1:
+  version "4.5.3"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f"
+  dependencies:
+    inflight "^1.0.4"
+    inherits "2"
+    minimatch "^2.0.1"
+    once "^1.3.0"
+
+glob@^5.0.15, glob@^5.0.5:
+  version "5.0.15"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1"
+  dependencies:
+    inflight "^1.0.4"
+    inherits "2"
+    minimatch "2 || 3"
+    once "^1.3.0"
+    path-is-absolute "^1.0.0"
+
+glob@^6.0.1:
+  version "6.0.4"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22"
+  dependencies:
+    inflight "^1.0.4"
+    inherits "2"
+    minimatch "2 || 3"
+    once "^1.3.0"
+    path-is-absolute "^1.0.0"
+
+glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.0:
+  version "7.1.2"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
+  dependencies:
+    fs.realpath "^1.0.0"
+    inflight "^1.0.4"
+    inherits "2"
+    minimatch "^3.0.4"
+    once "^1.3.0"
+    path-is-absolute "^1.0.0"
+
+glob@~3.1.21:
+  version "3.1.21"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-3.1.21.tgz#d29e0a055dea5138f4d07ed40e8982e83c2066cd"
+  dependencies:
+    graceful-fs "~1.2.0"
+    inherits "1"
+    minimatch "~0.2.11"
+
+glob@~3.2.9:
+  version "3.2.11"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.11.tgz#4a973f635b9190f715d10987d5c00fd2815ebe3d"
+  dependencies:
+    inherits "2"
+    minimatch "0.3"
+
+global-modules@^0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d"
+  dependencies:
+    global-prefix "^0.1.4"
+    is-windows "^0.2.0"
+
+global-prefix@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f"
+  dependencies:
+    homedir-polyfill "^1.0.0"
+    ini "^1.3.4"
+    is-windows "^0.2.0"
+    which "^1.2.12"
+
+globals@^6.4.0:
+  version "6.4.1"
+  resolved "https://registry.yarnpkg.com/globals/-/globals-6.4.1.tgz#8498032b3b6d1cc81eebc5f79690d8fe29fabf4f"
+
+globals@^9.0.0, globals@^9.14.0:
+  version "9.18.0"
+  resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a"
+
+globby@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d"
+  dependencies:
+    array-union "^1.0.1"
+    arrify "^1.0.0"
+    glob "^7.0.3"
+    object-assign "^4.0.1"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+globule@~0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/globule/-/globule-0.1.0.tgz#d9c8edde1da79d125a151b79533b978676346ae5"
+  dependencies:
+    glob "~3.1.21"
+    lodash "~1.0.1"
+    minimatch "~0.2.11"
+
+glogg@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/glogg/-/glogg-1.0.0.tgz#7fe0f199f57ac906cf512feead8f90ee4a284fc5"
+  dependencies:
+    sparkles "^1.0.0"
+
+graceful-fs@^3.0.0:
+  version "3.0.11"
+  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-3.0.11.tgz#7613c778a1afea62f25c630a086d7f3acbbdd818"
+  dependencies:
+    natives "^1.1.0"
+
+graceful-fs@^4.1.2, graceful-fs@^4.1.4, graceful-fs@^4.1.6:
+  version "4.1.11"
+  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
+
+graceful-fs@~1.2.0:
+  version "1.2.3"
+  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-1.2.3.tgz#15a4806a57547cb2d2dbf27f42e89a8c3451b364"
+
+"graceful-readlink@>= 1.0.0":
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
+
+growly@^1.2.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
+
+grunt-cli@^0.1.13:
+  version "0.1.13"
+  resolved "https://registry.yarnpkg.com/grunt-cli/-/grunt-cli-0.1.13.tgz#e9ebc4047631f5012d922770c39378133cad10f4"
+  dependencies:
+    findup-sync "~0.1.0"
+    nopt "~1.0.10"
+    resolve "~0.3.1"
+
+grunt-compare-size@^0.4.0:
+  version "0.4.2"
+  resolved "https://registry.yarnpkg.com/grunt-compare-size/-/grunt-compare-size-0.4.2.tgz#d2abf1d3cd9d39a16203e11d23b718b57579ef51"
+  dependencies:
+    lodash "^4.11.1"
+
+grunt-contrib-clean@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/grunt-contrib-clean/-/grunt-contrib-clean-0.6.0.tgz#f532dba4b8212674c7c013e146bda6638b9048f6"
+  dependencies:
+    rimraf "~2.2.1"
+
+grunt-legacy-log-utils@~0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/grunt-legacy-log-utils/-/grunt-legacy-log-utils-0.1.1.tgz#c0706b9dd9064e116f36f23fe4e6b048672c0f7e"
+  dependencies:
+    colors "~0.6.2"
+    lodash "~2.4.1"
+    underscore.string "~2.3.3"
+
+grunt-legacy-log@~0.1.0:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/grunt-legacy-log/-/grunt-legacy-log-0.1.3.tgz#ec29426e803021af59029f87d2f9cd7335a05531"
+  dependencies:
+    colors "~0.6.2"
+    grunt-legacy-log-utils "~0.1.1"
+    hooker "~0.2.3"
+    lodash "~2.4.1"
+    underscore.string "~2.3.3"
+
+grunt-legacy-util@~0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/grunt-legacy-util/-/grunt-legacy-util-0.2.0.tgz#93324884dbf7e37a9ff7c026dff451d94a9e554b"
+  dependencies:
+    async "~0.1.22"
+    exit "~0.1.1"
+    getobject "~0.1.0"
+    hooker "~0.2.3"
+    lodash "~0.9.2"
+    underscore.string "~2.2.1"
+    which "~1.0.5"
+
+grunt@^0.4.5:
+  version "0.4.5"
+  resolved "https://registry.yarnpkg.com/grunt/-/grunt-0.4.5.tgz#56937cd5194324adff6d207631832a9d6ba4e7f0"
+  dependencies:
+    async "~0.1.22"
+    coffee-script "~1.3.3"
+    colors "~0.6.2"
+    dateformat "1.0.2-1.2.3"
+    eventemitter2 "~0.4.13"
+    exit "~0.1.1"
+    findup-sync "~0.1.2"
+    getobject "~0.1.0"
+    glob "~3.1.21"
+    grunt-legacy-log "~0.1.0"
+    grunt-legacy-util "~0.2.0"
+    hooker "~0.2.3"
+    iconv-lite "~0.2.11"
+    js-yaml "~2.0.5"
+    lodash "~0.9.2"
+    minimatch "~0.2.12"
+    nopt "~1.0.10"
+    rimraf "~2.2.8"
+    underscore.string "~2.2.1"
+    which "~1.0.5"
+
+gulp-babel@^6.0.0:
+  version "6.1.2"
+  resolved "https://registry.yarnpkg.com/gulp-babel/-/gulp-babel-6.1.2.tgz#7c0176e4ba3f244c60588a0c4b320a45d1adefce"
+  dependencies:
+    babel-core "^6.0.2"
+    gulp-util "^3.0.0"
+    object-assign "^4.0.1"
+    replace-ext "0.0.1"
+    through2 "^2.0.0"
+    vinyl-sourcemaps-apply "^0.2.0"
+
+gulp-flatten@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/gulp-flatten/-/gulp-flatten-0.2.0.tgz#892d517e38d7900fd454cf9a1e0210300e92eb06"
+  dependencies:
+    gulp-util "^3.0.1"
+    through2 "^2.0.0"
+
+gulp-load-plugins@^1.2.4:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/gulp-load-plugins/-/gulp-load-plugins-1.5.0.tgz#4c419f7e5764d9a0e33061bab9618f81b73d4171"
+  dependencies:
+    array-unique "^0.2.1"
+    fancy-log "^1.2.0"
+    findup-sync "^0.4.0"
+    gulplog "^1.0.0"
+    has-gulplog "^0.1.0"
+    micromatch "^2.3.8"
+    resolve "^1.1.7"
+
+gulp-util@*, gulp-util@^3.0.0, gulp-util@^3.0.1, gulp-util@^3.0.4, gulp-util@^3.0.7:
+  version "3.0.8"
+  resolved "https://registry.yarnpkg.com/gulp-util/-/gulp-util-3.0.8.tgz#0054e1e744502e27c04c187c3ecc505dd54bbb4f"
+  dependencies:
+    array-differ "^1.0.0"
+    array-uniq "^1.0.2"
+    beeper "^1.0.0"
+    chalk "^1.0.0"
+    dateformat "^2.0.0"
+    fancy-log "^1.1.0"
+    gulplog "^1.0.0"
+    has-gulplog "^0.1.0"
+    lodash._reescape "^3.0.0"
+    lodash._reevaluate "^3.0.0"
+    lodash._reinterpolate "^3.0.0"
+    lodash.template "^3.0.0"
+    minimist "^1.1.0"
+    multipipe "^0.1.2"
+    object-assign "^3.0.0"
+    replace-ext "0.0.1"
+    through2 "^2.0.0"
+    vinyl "^0.5.0"
+
+gulp@^3.9.0:
+  version "3.9.1"
+  resolved "https://registry.yarnpkg.com/gulp/-/gulp-3.9.1.tgz#571ce45928dd40af6514fc4011866016c13845b4"
+  dependencies:
+    archy "^1.0.0"
+    chalk "^1.0.0"
+    deprecated "^0.0.1"
+    gulp-util "^3.0.0"
+    interpret "^1.0.0"
+    liftoff "^2.1.0"
+    minimist "^1.1.0"
+    orchestrator "^0.3.0"
+    pretty-hrtime "^1.0.0"
+    semver "^4.1.0"
+    tildify "^1.0.0"
+    v8flags "^2.0.2"
+    vinyl-fs "^0.3.0"
+
+gulplog@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/gulplog/-/gulplog-1.0.0.tgz#e28c4d45d05ecbbed818363ce8f9c5926229ffe5"
+  dependencies:
+    glogg "^1.0.0"
+
+gzip-js@~0.3.2:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/gzip-js/-/gzip-js-0.3.2.tgz#23117efeeb28cf385248deff0dffad894836d96b"
+  dependencies:
+    crc32 ">= 0.2.2"
+    deflate-js ">= 0.2.2"
+
+handlebars@^4.0.3:
+  version "4.0.10"
+  resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.10.tgz#3d30c718b09a3d96f23ea4cc1f403c4d3ba9ff4f"
+  dependencies:
+    async "^1.4.0"
+    optimist "^0.6.1"
+    source-map "^0.4.4"
+  optionalDependencies:
+    uglify-js "^2.6"
+
+har-schema@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e"
+
+har-validator@~2.0.6:
+  version "2.0.6"
+  resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d"
+  dependencies:
+    chalk "^1.1.1"
+    commander "^2.9.0"
+    is-my-json-valid "^2.12.4"
+    pinkie-promise "^2.0.0"
+
+har-validator@~4.2.1:
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a"
+  dependencies:
+    ajv "^4.9.1"
+    har-schema "^1.0.5"
+
+has-ansi@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
+  dependencies:
+    ansi-regex "^2.0.0"
+
+has-flag@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
+
+has-gulplog@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/has-gulplog/-/has-gulplog-0.1.0.tgz#6414c82913697da51590397dafb12f22967811ce"
+  dependencies:
+    sparkles "^1.0.0"
+
+has-unicode@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
+
+has@^1.0.0, has@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28"
+  dependencies:
+    function-bind "^1.0.2"
+
+hash-base@^2.0.0:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1"
+  dependencies:
+    inherits "^2.0.1"
+
+hash.js@^1.0.0, hash.js@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.0.3.tgz#1332ff00156c0a0ffdd8236013d07b77a0451573"
+  dependencies:
+    inherits "^2.0.1"
+
+hawk@~3.1.3:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4"
+  dependencies:
+    boom "2.x.x"
+    cryptiles "2.x.x"
+    hoek "2.x.x"
+    sntp "1.x.x"
+
+hmac-drbg@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
+  dependencies:
+    hash.js "^1.0.3"
+    minimalistic-assert "^1.0.0"
+    minimalistic-crypto-utils "^1.0.1"
+
+hoek@2.x.x:
+  version "2.16.3"
+  resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed"
+
+home-or-tmp@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-1.0.0.tgz#4b9f1e40800c3e50c6c27f781676afcce71f3985"
+  dependencies:
+    os-tmpdir "^1.0.1"
+    user-home "^1.1.1"
+
+home-or-tmp@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8"
+  dependencies:
+    os-homedir "^1.0.0"
+    os-tmpdir "^1.0.1"
+
+homedir-polyfill@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc"
+  dependencies:
+    parse-passwd "^1.0.0"
+
+hooker@~0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/hooker/-/hooker-0.2.3.tgz#b834f723cc4a242aa65963459df6d984c5d3d959"
+
+hosted-git-info@^2.1.4:
+  version "2.4.2"
+  resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.4.2.tgz#0076b9f46a270506ddbaaea56496897460612a67"
+
+html-encoding-sniffer@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.1.tgz#79bf7a785ea495fe66165e734153f363ff5437da"
+  dependencies:
+    whatwg-encoding "^1.0.1"
+
+htmlescape@^1.1.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/htmlescape/-/htmlescape-1.1.1.tgz#3a03edc2214bca3b66424a3e7959349509cb0351"
+
+http-signature@~1.1.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf"
+  dependencies:
+    assert-plus "^0.2.0"
+    jsprim "^1.2.2"
+    sshpk "^1.7.0"
+
+https-browserify@~0.0.0:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82"
+
+iconv-lite@0.4.13:
+  version "0.4.13"
+  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2"
+
+iconv-lite@^0.4.5, iconv-lite@~0.4.13:
+  version "0.4.18"
+  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.18.tgz#23d8656b16aae6742ac29732ea8f0336a4789cf2"
+
+iconv-lite@~0.2.11:
+  version "0.2.11"
+  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.2.11.tgz#1ce60a3a57864a292d1321ff4609ca4bb965adc8"
+
+ieee754@^1.1.4:
+  version "1.1.8"
+  resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4"
+
+ignore@^3.2.0:
+  version "3.3.3"
+  resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.3.tgz#432352e57accd87ab3110e82d3fea0e47812156d"
+
+imurmurhash@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
+
+indexof@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d"
+
+inflight@^1.0.4:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+  dependencies:
+    once "^1.3.0"
+    wrappy "1"
+
+inherits@1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-1.0.2.tgz#ca4309dadee6b54cc0b8d247e8d7c7a0975bdc9b"
+
+inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
+
+inherits@2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
+
+ini@^1.3.4, ini@~1.3.0:
+  version "1.3.4"
+  resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e"
+
+inline-source-map@~0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/inline-source-map/-/inline-source-map-0.5.0.tgz#4a4c5dd8e4fb5e9b3cda60c822dfadcaee66e0af"
+  dependencies:
+    source-map "~0.4.0"
+
+inline-source-map@~0.6.0:
+  version "0.6.2"
+  resolved "https://registry.yarnpkg.com/inline-source-map/-/inline-source-map-0.6.2.tgz#f9393471c18a79d1724f863fa38b586370ade2a5"
+  dependencies:
+    source-map "~0.5.3"
+
+inquirer@^0.12.0:
+  version "0.12.0"
+  resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e"
+  dependencies:
+    ansi-escapes "^1.1.0"
+    ansi-regex "^2.0.0"
+    chalk "^1.0.0"
+    cli-cursor "^1.0.1"
+    cli-width "^2.0.0"
+    figures "^1.3.5"
+    lodash "^4.3.0"
+    readline2 "^1.0.1"
+    run-async "^0.1.0"
+    rx-lite "^3.1.2"
+    string-width "^1.0.1"
+    strip-ansi "^3.0.0"
+    through "^2.3.6"
+
+insert-module-globals@^7.0.0:
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/insert-module-globals/-/insert-module-globals-7.0.1.tgz#c03bf4e01cb086d5b5e5ace8ad0afe7889d638c3"
+  dependencies:
+    JSONStream "^1.0.3"
+    combine-source-map "~0.7.1"
+    concat-stream "~1.5.1"
+    is-buffer "^1.1.0"
+    lexical-scope "^1.2.0"
+    process "~0.11.0"
+    through2 "^2.0.0"
+    xtend "^4.0.0"
+
+interpret@^1.0.0:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.3.tgz#cbc35c62eeee73f19ab7b10a801511401afc0f90"
+
+invariant@^2.2.0:
+  version "2.2.2"
+  resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360"
+  dependencies:
+    loose-envify "^1.0.0"
+
+invert-kv@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
+
+is-absolute@^0.2.3:
+  version "0.2.6"
+  resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-0.2.6.tgz#20de69f3db942ef2d87b9c2da36f172235b1b5eb"
+  dependencies:
+    is-relative "^0.2.1"
+    is-windows "^0.2.0"
+
+is-arrayish@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
+
+is-binary-path@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
+  dependencies:
+    binary-extensions "^1.0.0"
+
+is-buffer@^1.1.0, is-buffer@^1.1.5:
+  version "1.1.5"
+  resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc"
+
+is-builtin-module@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe"
+  dependencies:
+    builtin-modules "^1.0.0"
+
+is-callable@^1.1.1, is-callable@^1.1.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2"
+
+is-ci@^1.0.9:
+  version "1.0.10"
+  resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.0.10.tgz#f739336b2632365061a9d48270cd56ae3369318e"
+  dependencies:
+    ci-info "^1.0.0"
+
+is-date-object@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16"
+
+is-dotfile@^1.0.0:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1"
+
+is-equal-shallow@^0.1.3:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534"
+  dependencies:
+    is-primitive "^2.0.0"
+
+is-extendable@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
+
+is-extglob@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
+
+is-finite@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa"
+  dependencies:
+    number-is-nan "^1.0.0"
+
+is-fullwidth-code-point@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
+  dependencies:
+    number-is-nan "^1.0.0"
+
+is-fullwidth-code-point@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
+
+is-glob@^2.0.0, is-glob@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
+  dependencies:
+    is-extglob "^1.0.0"
+
+is-integer@^1.0.4:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/is-integer/-/is-integer-1.0.7.tgz#6bde81aacddf78b659b6629d629cadc51a886d5c"
+  dependencies:
+    is-finite "^1.0.0"
+
+is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4:
+  version "2.16.0"
+  resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz#f079dd9bfdae65ee2038aae8acbc86ab109e3693"
+  dependencies:
+    generate-function "^2.0.0"
+    generate-object-property "^1.1.0"
+    jsonpointer "^4.0.0"
+    xtend "^4.0.0"
+
+is-number@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
+  dependencies:
+    kind-of "^3.0.2"
+
+is-number@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
+  dependencies:
+    kind-of "^3.0.2"
+
+is-path-cwd@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d"
+
+is-path-in-cwd@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc"
+  dependencies:
+    is-path-inside "^1.0.0"
+
+is-path-inside@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f"
+  dependencies:
+    path-is-inside "^1.0.1"
+
+is-posix-bracket@^0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
+
+is-primitive@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
+
+is-property@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84"
+
+is-regex@^1.0.3:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491"
+  dependencies:
+    has "^1.0.1"
+
+is-relative@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-0.2.1.tgz#d27f4c7d516d175fb610db84bbeef23c3bc97aa5"
+  dependencies:
+    is-unc-path "^0.1.1"
+
+is-resolvable@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62"
+  dependencies:
+    tryit "^1.0.1"
+
+is-stream@^1.0.1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
+
+is-symbol@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572"
+
+is-typedarray@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
+
+is-unc-path@^0.1.1:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/is-unc-path/-/is-unc-path-0.1.2.tgz#6ab053a72573c10250ff416a3814c35178af39b9"
+  dependencies:
+    unc-path-regex "^0.1.0"
+
+is-utf8@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
+
+is-windows@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c"
+
+isarray@0.0.1, isarray@~0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
+
+isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
+
+isexe@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+
+isobject@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
+  dependencies:
+    isarray "1.0.0"
+
+isomorphic-fetch@^2.1.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
+  dependencies:
+    node-fetch "^1.0.1"
+    whatwg-fetch ">=0.10.0"
+
+isstream@~0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
+
+istanbul-api@^1.0.0-aplha.10:
+  version "1.1.9"
+  resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-1.1.9.tgz#2827920d380d4286d857d57a2968a841db8a7ec8"
+  dependencies:
+    async "^2.1.4"
+    fileset "^2.0.2"
+    istanbul-lib-coverage "^1.1.1"
+    istanbul-lib-hook "^1.0.7"
+    istanbul-lib-instrument "^1.7.2"
+    istanbul-lib-report "^1.1.1"
+    istanbul-lib-source-maps "^1.2.1"
+    istanbul-reports "^1.1.1"
+    js-yaml "^3.7.0"
+    mkdirp "^0.5.1"
+    once "^1.4.0"
+
+istanbul-lib-coverage@^1.0.0, istanbul-lib-coverage@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.1.tgz#73bfb998885299415c93d38a3e9adf784a77a9da"
+
+istanbul-lib-hook@^1.0.7:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.0.7.tgz#dd6607f03076578fe7d6f2a630cf143b49bacddc"
+  dependencies:
+    append-transform "^0.4.0"
+
+istanbul-lib-instrument@^1.1.1, istanbul-lib-instrument@^1.4.2, istanbul-lib-instrument@^1.7.2:
+  version "1.7.2"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.7.2.tgz#6014b03d3470fb77638d5802508c255c06312e56"
+  dependencies:
+    babel-generator "^6.18.0"
+    babel-template "^6.16.0"
+    babel-traverse "^6.18.0"
+    babel-types "^6.18.0"
+    babylon "^6.13.0"
+    istanbul-lib-coverage "^1.1.1"
+    semver "^5.3.0"
+
+istanbul-lib-report@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz#f0e55f56655ffa34222080b7a0cd4760e1405fc9"
+  dependencies:
+    istanbul-lib-coverage "^1.1.1"
+    mkdirp "^0.5.1"
+    path-parse "^1.0.5"
+    supports-color "^3.1.2"
+
+istanbul-lib-source-maps@^1.2.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.1.tgz#a6fe1acba8ce08eebc638e572e294d267008aa0c"
+  dependencies:
+    debug "^2.6.3"
+    istanbul-lib-coverage "^1.1.1"
+    mkdirp "^0.5.1"
+    rimraf "^2.6.1"
+    source-map "^0.5.3"
+
+istanbul-reports@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.1.1.tgz#042be5c89e175bc3f86523caab29c014e77fee4e"
+  dependencies:
+    handlebars "^4.0.3"
+
+jest-changed-files@^17.0.2:
+  version "17.0.2"
+  resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-17.0.2.tgz#f5657758736996f590a51b87e5c9369d904ba7b7"
+
+jest-cli@18.0.0:
+  version "18.0.0"
+  resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-18.0.0.tgz#11d141f5e9158d4f02c5c303815b5280f6887c55"
+  dependencies:
+    ansi-escapes "^1.4.0"
+    callsites "^2.0.0"
+    chalk "^1.1.1"
+    graceful-fs "^4.1.6"
+    is-ci "^1.0.9"
+    istanbul-api "^1.0.0-aplha.10"
+    istanbul-lib-coverage "^1.0.0"
+    istanbul-lib-instrument "^1.1.1"
+    jest-changed-files "^17.0.2"
+    jest-config "^18.0.0"
+    jest-environment-jsdom "^18.0.0"
+    jest-file-exists "^17.0.0"
+    jest-haste-map "^18.0.0"
+    jest-jasmine2 "^18.0.0"
+    jest-mock "^18.0.0"
+    jest-resolve "^18.0.0"
+    jest-resolve-dependencies "^18.0.0"
+    jest-runtime "^18.0.0"
+    jest-snapshot "^18.0.0"
+    jest-util "^18.0.0"
+    json-stable-stringify "^1.0.0"
+    node-notifier "^4.6.1"
+    sane "~1.4.1"
+    strip-ansi "^3.0.1"
+    throat "^3.0.0"
+    which "^1.1.1"
+    worker-farm "^1.3.1"
+    yargs "^6.3.0"
+
+jest-config@^18.0.0, jest-config@^18.1.0:
+  version "18.1.0"
+  resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-18.1.0.tgz#6111740a6d48aab86ff5a9e6ab0b98bd993b6ff4"
+  dependencies:
+    chalk "^1.1.1"
+    jest-environment-jsdom "^18.1.0"
+    jest-environment-node "^18.1.0"
+    jest-jasmine2 "^18.1.0"
+    jest-mock "^18.0.0"
+    jest-resolve "^18.1.0"
+    jest-util "^18.1.0"
+    json-stable-stringify "^1.0.0"
+
+jest-diff@^18.1.0:
+  version "18.1.0"
+  resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-18.1.0.tgz#4ff79e74dd988c139195b365dc65d87f606f4803"
+  dependencies:
+    chalk "^1.1.3"
+    diff "^3.0.0"
+    jest-matcher-utils "^18.1.0"
+    pretty-format "^18.1.0"
+
+jest-environment-jsdom@^18.0.0, jest-environment-jsdom@^18.1.0:
+  version "18.1.0"
+  resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-18.1.0.tgz#18b42f0c4ea2bae9f36cab3639b1e8f8c384e24e"
+  dependencies:
+    jest-mock "^18.0.0"
+    jest-util "^18.1.0"
+    jsdom "^9.9.1"
+
+jest-environment-node@^18.1.0:
+  version "18.1.0"
+  resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-18.1.0.tgz#4d6797572c8dda99acf5fae696eb62945547c779"
+  dependencies:
+    jest-mock "^18.0.0"
+    jest-util "^18.1.0"
+
+jest-file-exists@^17.0.0:
+  version "17.0.0"
+  resolved "https://registry.yarnpkg.com/jest-file-exists/-/jest-file-exists-17.0.0.tgz#7f63eb73a1c43a13f461be261768b45af2cdd169"
+
+jest-haste-map@^18.0.0, jest-haste-map@^18.1.0:
+  version "18.1.0"
+  resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-18.1.0.tgz#06839c74b770a40c1a106968851df8d281c08375"
+  dependencies:
+    fb-watchman "^1.9.0"
+    graceful-fs "^4.1.6"
+    micromatch "^2.3.11"
+    sane "~1.4.1"
+    worker-farm "^1.3.1"
+
+jest-jasmine2@^18.0.0, jest-jasmine2@^18.1.0:
+  version "18.1.0"
+  resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-18.1.0.tgz#094e104c2c189708766c77263bb2aecb5860a80b"
+  dependencies:
+    graceful-fs "^4.1.6"
+    jest-matcher-utils "^18.1.0"
+    jest-matchers "^18.1.0"
+    jest-snapshot "^18.1.0"
+    jest-util "^18.1.0"
+
+jest-matcher-utils@^18.1.0:
+  version "18.1.0"
+  resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-18.1.0.tgz#1ac4651955ee2a60cef1e7fcc98cdfd773c0f932"
+  dependencies:
+    chalk "^1.1.3"
+    pretty-format "^18.1.0"
+
+jest-matchers@^18.1.0:
+  version "18.1.0"
+  resolved "https://registry.yarnpkg.com/jest-matchers/-/jest-matchers-18.1.0.tgz#0341484bf87a1fd0bac0a4d2c899e2b77a3f1ead"
+  dependencies:
+    jest-diff "^18.1.0"
+    jest-matcher-utils "^18.1.0"
+    jest-util "^18.1.0"
+    pretty-format "^18.1.0"
+
+jest-mock@^18.0.0:
+  version "18.0.0"
+  resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-18.0.0.tgz#5c248846ea33fa558b526f5312ab4a6765e489b3"
+
+jest-resolve-dependencies@^18.0.0:
+  version "18.1.0"
+  resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-18.1.0.tgz#8134fb5caf59c9ed842fe0152ab01c52711f1bbb"
+  dependencies:
+    jest-file-exists "^17.0.0"
+    jest-resolve "^18.1.0"
+
+jest-resolve@^18.0.0, jest-resolve@^18.1.0:
+  version "18.1.0"
+  resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-18.1.0.tgz#6800accb536658c906cd5e29de412b1ab9ac249b"
+  dependencies:
+    browser-resolve "^1.11.2"
+    jest-file-exists "^17.0.0"
+    jest-haste-map "^18.1.0"
+    resolve "^1.2.0"
+
+jest-runtime@^18.0.0:
+  version "18.1.0"
+  resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-18.1.0.tgz#3abfd687175b21fc3b85a2b8064399e997859922"
+  dependencies:
+    babel-core "^6.0.0"
+    babel-jest "^18.0.0"
+    babel-plugin-istanbul "^3.0.0"
+    chalk "^1.1.3"
+    graceful-fs "^4.1.6"
+    jest-config "^18.1.0"
+    jest-file-exists "^17.0.0"
+    jest-haste-map "^18.1.0"
+    jest-mock "^18.0.0"
+    jest-resolve "^18.1.0"
+    jest-snapshot "^18.1.0"
+    jest-util "^18.1.0"
+    json-stable-stringify "^1.0.0"
+    micromatch "^2.3.11"
+    yargs "^6.3.0"
+
+jest-snapshot@^18.0.0, jest-snapshot@^18.1.0:
+  version "18.1.0"
+  resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-18.1.0.tgz#55b96d2ee639c9bce76f87f2a3fd40b71c7a5916"
+  dependencies:
+    jest-diff "^18.1.0"
+    jest-file-exists "^17.0.0"
+    jest-matcher-utils "^18.1.0"
+    jest-util "^18.1.0"
+    natural-compare "^1.4.0"
+    pretty-format "^18.1.0"
+
+jest-util@^18.0.0, jest-util@^18.1.0:
+  version "18.1.0"
+  resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-18.1.0.tgz#3a99c32114ab17f84be094382527006e6d4bfc6a"
+  dependencies:
+    chalk "^1.1.1"
+    diff "^3.0.0"
+    graceful-fs "^4.1.6"
+    jest-file-exists "^17.0.0"
+    jest-mock "^18.0.0"
+    mkdirp "^0.5.1"
+
+js-tokens@1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-1.0.1.tgz#cc435a5c8b94ad15acb7983140fc80182c89aeae"
+
+js-tokens@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7"
+
+js-yaml@3.6.1, js-yaml@^3.5.1:
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.6.1.tgz#6e5fe67d8b205ce4d22fad05b7781e8dadcc4b30"
+  dependencies:
+    argparse "^1.0.7"
+    esprima "^2.6.0"
+
+js-yaml@^3.7.0:
+  version "3.8.4"
+  resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.4.tgz#520b4564f86573ba96662af85a8cafa7b4b5a6f6"
+  dependencies:
+    argparse "^1.0.7"
+    esprima "^3.1.1"
+
+js-yaml@~2.0.5:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-2.0.5.tgz#a25ae6509999e97df278c6719da11bd0687743a8"
+  dependencies:
+    argparse "~ 0.1.11"
+    esprima "~ 1.0.2"
+
+jsbn@~0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
+
+jsdom@^9.9.1:
+  version "9.12.0"
+  resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-9.12.0.tgz#e8c546fffcb06c00d4833ca84410fed7f8a097d4"
+  dependencies:
+    abab "^1.0.3"
+    acorn "^4.0.4"
+    acorn-globals "^3.1.0"
+    array-equal "^1.0.0"
+    content-type-parser "^1.0.1"
+    cssom ">= 0.3.2 < 0.4.0"
+    cssstyle ">= 0.2.37 < 0.3.0"
+    escodegen "^1.6.1"
+    html-encoding-sniffer "^1.0.1"
+    nwmatcher ">= 1.3.9 < 2.0.0"
+    parse5 "^1.5.1"
+    request "^2.79.0"
+    sax "^1.2.1"
+    symbol-tree "^3.2.1"
+    tough-cookie "^2.3.2"
+    webidl-conversions "^4.0.0"
+    whatwg-encoding "^1.0.1"
+    whatwg-url "^4.3.0"
+    xml-name-validator "^2.0.1"
+
+jsesc@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b"
+
+jsesc@~0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
+
+json-schema@0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
+
+json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af"
+  dependencies:
+    jsonify "~0.0.0"
+
+json-stable-stringify@~0.0.0:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz#611c23e814db375527df851193db59dd2af27f45"
+  dependencies:
+    jsonify "~0.0.0"
+
+json-stringify-safe@~5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
+
+json5@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/json5/-/json5-0.4.0.tgz#054352e4c4c80c86c0923877d449de176a732c8d"
+
+json5@^0.5.0:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
+
+jsonify@~0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
+
+jsonparse@^1.2.0:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280"
+
+jsonpointer@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9"
+
+jsprim@^1.2.2:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.0.tgz#a3b87e40298d8c380552d8cc7628a0bb95a22918"
+  dependencies:
+    assert-plus "1.0.0"
+    extsprintf "1.0.2"
+    json-schema "0.2.3"
+    verror "1.3.6"
+
+jsx-ast-utils@^1.3.4:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz#3867213e8dd79bf1e8f2300c0cfc1efb182c0df1"
+
+kind-of@^3.0.2:
+  version "3.2.2"
+  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
+  dependencies:
+    is-buffer "^1.1.5"
+
+kind-of@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57"
+  dependencies:
+    is-buffer "^1.1.5"
+
+labeled-stream-splicer@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/labeled-stream-splicer/-/labeled-stream-splicer-2.0.0.tgz#a52e1d138024c00b86b1c0c91f677918b8ae0a59"
+  dependencies:
+    inherits "^2.0.1"
+    isarray "~0.0.1"
+    stream-splicer "^2.0.0"
+
+lazy-cache@^1.0.3:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
+
+lcid@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
+  dependencies:
+    invert-kv "^1.0.0"
+
+lcov-parse@0.0.10:
+  version "0.0.10"
+  resolved "https://registry.yarnpkg.com/lcov-parse/-/lcov-parse-0.0.10.tgz#1b0b8ff9ac9c7889250582b70b71315d9da6d9a3"
+
+leven@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/leven/-/leven-1.0.2.tgz#9144b6eebca5f1d0680169f1a6770dcea60b75c3"
+
+levn@^0.3.0, levn@~0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
+  dependencies:
+    prelude-ls "~1.1.2"
+    type-check "~0.3.2"
+
+lexical-scope@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/lexical-scope/-/lexical-scope-1.2.0.tgz#fcea5edc704a4b3a8796cdca419c3a0afaf22df4"
+  dependencies:
+    astw "^2.0.0"
+
+liftoff@^2.1.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-2.3.0.tgz#a98f2ff67183d8ba7cfaca10548bd7ff0550b385"
+  dependencies:
+    extend "^3.0.0"
+    findup-sync "^0.4.2"
+    fined "^1.0.1"
+    flagged-respawn "^0.3.2"
+    lodash.isplainobject "^4.0.4"
+    lodash.isstring "^4.0.1"
+    lodash.mapvalues "^4.4.0"
+    rechoir "^0.6.2"
+    resolve "^1.1.7"
+
+load-json-file@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
+  dependencies:
+    graceful-fs "^4.1.2"
+    parse-json "^2.2.0"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+    strip-bom "^2.0.0"
+
+lodash._arraycopy@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz#76e7b7c1f1fb92547374878a562ed06a3e50f6e1"
+
+lodash._arrayeach@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz#bab156b2a90d3f1bbd5c653403349e5e5933ef9e"
+
+lodash._baseassign@^3.0.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e"
+  dependencies:
+    lodash._basecopy "^3.0.0"
+    lodash.keys "^3.0.0"
+
+lodash._baseclone@^3.0.0:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/lodash._baseclone/-/lodash._baseclone-3.3.0.tgz#303519bf6393fe7e42f34d8b630ef7794e3542b7"
+  dependencies:
+    lodash._arraycopy "^3.0.0"
+    lodash._arrayeach "^3.0.0"
+    lodash._baseassign "^3.0.0"
+    lodash._basefor "^3.0.0"
+    lodash.isarray "^3.0.0"
+    lodash.keys "^3.0.0"
+
+lodash._basecopy@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36"
+
+lodash._basefor@^3.0.0:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/lodash._basefor/-/lodash._basefor-3.0.3.tgz#7550b4e9218ef09fad24343b612021c79b4c20c2"
+
+lodash._basetostring@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz#d1861d877f824a52f669832dcaf3ee15566a07d5"
+
+lodash._basevalues@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz#5b775762802bde3d3297503e26300820fdf661b7"
+
+lodash._bindcallback@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e"
+
+lodash._getnative@^3.0.0:
+  version "3.9.1"
+  resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5"
+
+lodash._isiterateecall@^3.0.0:
+  version "3.0.9"
+  resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c"
+
+lodash._reescape@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/lodash._reescape/-/lodash._reescape-3.0.0.tgz#2b1d6f5dfe07c8a355753e5f27fac7f1cde1616a"
+
+lodash._reevaluate@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz#58bc74c40664953ae0b124d806996daca431e2ed"
+
+lodash._reinterpolate@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
+
+lodash._root@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692"
+
+lodash.assign@^4.2.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7"
+
+lodash.assignwith@^4.0.7:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/lodash.assignwith/-/lodash.assignwith-4.2.0.tgz#127a97f02adc41751a954d24b0de17e100e038eb"
+
+lodash.clonedeep@^3.0.0:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-3.0.2.tgz#a0a1e40d82a5ea89ff5b147b8444ed63d92827db"
+  dependencies:
+    lodash._baseclone "^3.0.0"
+    lodash._bindcallback "^3.0.0"
+
+lodash.escape@^3.0.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-3.2.0.tgz#995ee0dc18c1b48cc92effae71a10aab5b487698"
+  dependencies:
+    lodash._root "^3.0.0"
+
+lodash.isarguments@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a"
+
+lodash.isarray@^3.0.0:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55"
+
+lodash.isempty@^4.2.1:
+  version "4.4.0"
+  resolved "https://registry.yarnpkg.com/lodash.isempty/-/lodash.isempty-4.4.0.tgz#6f86cbedd8be4ec987be9aaf33c9684db1b31e7e"
+
+lodash.isplainobject@^4.0.4:
+  version "4.0.6"
+  resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
+
+lodash.isstring@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451"
+
+lodash.keys@^3.0.0:
+  version "3.1.2"
+  resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a"
+  dependencies:
+    lodash._getnative "^3.0.0"
+    lodash.isarguments "^3.0.0"
+    lodash.isarray "^3.0.0"
+
+lodash.mapvalues@^4.4.0:
+  version "4.6.0"
+  resolved "https://registry.yarnpkg.com/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz#1bafa5005de9dd6f4f26668c30ca37230cc9689c"
+
+lodash.memoize@~3.0.3:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-3.0.4.tgz#2dcbd2c287cbc0a55cc42328bd0c736150d53e3f"
+
+lodash.pick@^4.2.1:
+  version "4.4.0"
+  resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3"
+
+lodash.restparam@^3.0.0:
+  version "3.6.1"
+  resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805"
+
+lodash.template@^3.0.0:
+  version "3.6.2"
+  resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-3.6.2.tgz#f8cdecc6169a255be9098ae8b0c53d378931d14f"
+  dependencies:
+    lodash._basecopy "^3.0.0"
+    lodash._basetostring "^3.0.0"
+    lodash._basevalues "^3.0.0"
+    lodash._isiterateecall "^3.0.0"
+    lodash._reinterpolate "^3.0.0"
+    lodash.escape "^3.0.0"
+    lodash.keys "^3.0.0"
+    lodash.restparam "^3.0.0"
+    lodash.templatesettings "^3.0.0"
+
+lodash.templatesettings@^3.0.0:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz#fb307844753b66b9f1afa54e262c745307dba8e5"
+  dependencies:
+    lodash._reinterpolate "^3.0.0"
+    lodash.escape "^3.0.0"
+
+lodash@^3.10.0, lodash@^3.2.0, lodash@^3.9.3:
+  version "3.10.1"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
+
+lodash@^4.0.0, lodash@^4.11.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.2.0, lodash@^4.3.0:
+  version "4.17.4"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
+
+lodash@~0.9.2:
+  version "0.9.2"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-0.9.2.tgz#8f3499c5245d346d682e5b0d3b40767e09f1a92c"
+
+lodash@~1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-1.0.2.tgz#8f57560c83b59fc270bd3d561b690043430e2551"
+
+lodash@~2.4.1:
+  version "2.4.2"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-2.4.2.tgz#fadd834b9683073da179b3eae6d9c0d15053f73e"
+
+log-driver@1.2.5:
+  version "1.2.5"
+  resolved "https://registry.yarnpkg.com/log-driver/-/log-driver-1.2.5.tgz#7ae4ec257302fd790d557cb10c97100d857b0056"
+
+longest@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
+
+loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
+  dependencies:
+    js-tokens "^3.0.0"
+
+lru-cache@2:
+  version "2.7.3"
+  resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952"
+
+lru-cache@^4.0.0:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.1.tgz#622e32e82488b49279114a4f9ecf45e7cd6bba55"
+  dependencies:
+    pseudomap "^1.0.2"
+    yallist "^2.1.2"
+
+makeerror@1.0.x:
+  version "1.0.11"
+  resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c"
+  dependencies:
+    tmpl "1.0.x"
+
+map-cache@^0.2.0:
+  version "0.2.2"
+  resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
+
+marked-terminal@^1.6.2:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/marked-terminal/-/marked-terminal-1.7.0.tgz#c8c460881c772c7604b64367007ee5f77f125904"
+  dependencies:
+    cardinal "^1.0.0"
+    chalk "^1.1.3"
+    cli-table "^0.3.1"
+    lodash.assign "^4.2.0"
+    node-emoji "^1.4.1"
+
+marked@^0.3.6:
+  version "0.3.6"
+  resolved "https://registry.yarnpkg.com/marked/-/marked-0.3.6.tgz#b2c6c618fccece4ef86c4fc6cb8a7cbf5aeda8d7"
+
+merge-stream@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1"
+  dependencies:
+    readable-stream "^2.0.1"
+
+merge@^1.1.3:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da"
+
+micromatch@^2.1.5, micromatch@^2.3.11, micromatch@^2.3.7, micromatch@^2.3.8:
+  version "2.3.11"
+  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
+  dependencies:
+    arr-diff "^2.0.0"
+    array-unique "^0.2.1"
+    braces "^1.8.2"
+    expand-brackets "^0.1.4"
+    extglob "^0.3.1"
+    filename-regex "^2.0.0"
+    is-extglob "^1.0.0"
+    is-glob "^2.0.1"
+    kind-of "^3.0.2"
+    normalize-path "^2.0.1"
+    object.omit "^2.0.0"
+    parse-glob "^3.0.4"
+    regex-cache "^0.4.2"
+
+miller-rabin@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.0.tgz#4a62fb1d42933c05583982f4c716f6fb9e6c6d3d"
+  dependencies:
+    bn.js "^4.0.0"
+    brorand "^1.0.1"
+
+mime-db@~1.27.0:
+  version "1.27.0"
+  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1"
+
+mime-types@^2.1.12, mime-types@~2.1.7:
+  version "2.1.15"
+  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed"
+  dependencies:
+    mime-db "~1.27.0"
+
+minimalistic-assert@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3"
+
+minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
+
+minimatch@0.3:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.3.0.tgz#275d8edaac4f1bb3326472089e7949c8394699dd"
+  dependencies:
+    lru-cache "2"
+    sigmund "~1.0.0"
+
+"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
+  dependencies:
+    brace-expansion "^1.1.7"
+
+minimatch@^2.0.1, minimatch@^2.0.3:
+  version "2.0.10"
+  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7"
+  dependencies:
+    brace-expansion "^1.0.0"
+
+minimatch@~0.2.11, minimatch@~0.2.12:
+  version "0.2.14"
+  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.2.14.tgz#c74e780574f63c6f9a090e90efbe6ef53a6a756a"
+  dependencies:
+    lru-cache "2"
+    sigmund "~1.0.0"
+
+minimist@0.0.8, minimist@~0.0.1:
+  version "0.0.8"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
+
+minimist@1.2.0, minimist@^1.1.0, minimist@^1.1.1, minimist@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
+
+"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
+  dependencies:
+    minimist "0.0.8"
+
+module-deps@^4.0.8:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/module-deps/-/module-deps-4.1.1.tgz#23215833f1da13fd606ccb8087b44852dcb821fd"
+  dependencies:
+    JSONStream "^1.0.3"
+    browser-resolve "^1.7.0"
+    cached-path-relative "^1.0.0"
+    concat-stream "~1.5.0"
+    defined "^1.0.0"
+    detective "^4.0.0"
+    duplexer2 "^0.1.2"
+    inherits "^2.0.1"
+    parents "^1.0.0"
+    readable-stream "^2.0.2"
+    resolve "^1.1.3"
+    stream-combiner2 "^1.1.1"
+    subarg "^1.0.0"
+    through2 "^2.0.0"
+    xtend "^4.0.0"
+
+ms@2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
+
+multipipe@^0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-0.1.2.tgz#2a8f2ddf70eed564dff2d57f1e1a137d9f05078b"
+  dependencies:
+    duplexer2 "0.0.2"
+
+mute-stream@0.0.5:
+  version "0.0.5"
+  resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0"
+
+nan@^2.3.0:
+  version "2.6.2"
+  resolved "https://registry.yarnpkg.com/nan/-/nan-2.6.2.tgz#e4ff34e6c95fdfb5aecc08de6596f43605a7db45"
+
+natives@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/natives/-/natives-1.1.0.tgz#e9ff841418a6b2ec7a495e939984f78f163e6e31"
+
+natural-compare@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
+
+node-emoji@^1.4.1:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-1.5.1.tgz#fd918e412769bf8c448051238233840b2aff16a1"
+  dependencies:
+    string.prototype.codepointat "^0.2.0"
+
+node-fetch@^1.0.1:
+  version "1.7.1"
+  resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.1.tgz#899cb3d0a3c92f952c47f1b876f4c8aeabd400d5"
+  dependencies:
+    encoding "^0.1.11"
+    is-stream "^1.0.1"
+
+node-int64@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
+
+node-notifier@^4.6.1:
+  version "4.6.1"
+  resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-4.6.1.tgz#056d14244f3dcc1ceadfe68af9cff0c5473a33f3"
+  dependencies:
+    cli-usage "^0.1.1"
+    growly "^1.2.0"
+    lodash.clonedeep "^3.0.0"
+    minimist "^1.1.1"
+    semver "^5.1.0"
+    shellwords "^0.1.0"
+    which "^1.0.5"
+
+node-pre-gyp@^0.6.36:
+  version "0.6.36"
+  resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.36.tgz#db604112cb74e0d477554e9b505b17abddfab786"
+  dependencies:
+    mkdirp "^0.5.1"
+    nopt "^4.0.1"
+    npmlog "^4.0.2"
+    rc "^1.1.7"
+    request "^2.81.0"
+    rimraf "^2.6.1"
+    semver "^5.3.0"
+    tar "^2.2.1"
+    tar-pack "^3.4.0"
+
+nopt@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
+  dependencies:
+    abbrev "1"
+    osenv "^0.1.4"
+
+nopt@~1.0.10:
+  version "1.0.10"
+  resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee"
+  dependencies:
+    abbrev "1"
+
+normalize-package-data@^2.3.2:
+  version "2.3.8"
+  resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.8.tgz#d819eda2a9dedbd1ffa563ea4071d936782295bb"
+  dependencies:
+    hosted-git-info "^2.1.4"
+    is-builtin-module "^1.0.0"
+    semver "2 || 3 || 4 || 5"
+    validate-npm-package-license "^3.0.1"
+
+normalize-path@^2.0.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
+  dependencies:
+    remove-trailing-separator "^1.0.1"
+
+npmlog@^4.0.2:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.0.tgz#dc59bee85f64f00ed424efb2af0783df25d1c0b5"
+  dependencies:
+    are-we-there-yet "~1.1.2"
+    console-control-strings "~1.1.0"
+    gauge "~2.7.3"
+    set-blocking "~2.0.0"
+
+number-is-nan@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
+
+"nwmatcher@>= 1.3.9 < 2.0.0":
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.4.0.tgz#b4389362170e7ef9798c3c7716d80ebc0106fccf"
+
+oauth-sign@~0.8.1:
+  version "0.8.2"
+  resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
+
+object-assign@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2"
+
+object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+
+object-keys@^1.0.10, object-keys@^1.0.6, object-keys@^1.0.8:
+  version "1.0.11"
+  resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d"
+
+object.assign@^4.0.4:
+  version "4.0.4"
+  resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.0.4.tgz#b1c9cc044ef1b9fe63606fc141abbb32e14730cc"
+  dependencies:
+    define-properties "^1.1.2"
+    function-bind "^1.1.0"
+    object-keys "^1.0.10"
+
+object.omit@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
+  dependencies:
+    for-own "^0.1.4"
+    is-extendable "^0.1.1"
+
+once@^1.3.0, once@^1.3.3, once@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+  dependencies:
+    wrappy "1"
+
+once@~1.3.0:
+  version "1.3.3"
+  resolved "https://registry.yarnpkg.com/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20"
+  dependencies:
+    wrappy "1"
+
+onetime@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789"
+
+optimist@^0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
+  dependencies:
+    minimist "~0.0.1"
+    wordwrap "~0.0.2"
+
+optionator@^0.8.1, optionator@^0.8.2:
+  version "0.8.2"
+  resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64"
+  dependencies:
+    deep-is "~0.1.3"
+    fast-levenshtein "~2.0.4"
+    levn "~0.3.0"
+    prelude-ls "~1.1.2"
+    type-check "~0.3.2"
+    wordwrap "~1.0.0"
+
+orchestrator@^0.3.0:
+  version "0.3.8"
+  resolved "https://registry.yarnpkg.com/orchestrator/-/orchestrator-0.3.8.tgz#14e7e9e2764f7315fbac184e506c7aa6df94ad7e"
+  dependencies:
+    end-of-stream "~0.1.5"
+    sequencify "~0.0.7"
+    stream-consume "~0.1.0"
+
+ordered-read-streams@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-0.1.0.tgz#fd565a9af8eb4473ba69b6ed8a34352cb552f126"
+
+os-browserify@~0.1.1:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.1.2.tgz#49ca0293e0b19590a5f5de10c7f265a617d8fe54"
+
+os-homedir@^1.0.0, os-homedir@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
+
+os-locale@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9"
+  dependencies:
+    lcid "^1.0.0"
+
+os-shim@^0.1.2:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917"
+
+os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
+
+osenv@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644"
+  dependencies:
+    os-homedir "^1.0.0"
+    os-tmpdir "^1.0.0"
+
+output-file-sync@^1.1.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76"
+  dependencies:
+    graceful-fs "^4.1.4"
+    mkdirp "^0.5.1"
+    object-assign "^4.1.0"
+
+pako@~0.2.0:
+  version "0.2.9"
+  resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
+
+parents@^1.0.0, parents@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/parents/-/parents-1.0.1.tgz#fedd4d2bf193a77745fe71e371d73c3307d9c751"
+  dependencies:
+    path-platform "~0.11.15"
+
+parse-asn1@^5.0.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712"
+  dependencies:
+    asn1.js "^4.0.0"
+    browserify-aes "^1.0.0"
+    create-hash "^1.1.0"
+    evp_bytestokey "^1.0.0"
+    pbkdf2 "^3.0.3"
+
+parse-filepath@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/parse-filepath/-/parse-filepath-1.0.1.tgz#159d6155d43904d16c10ef698911da1e91969b73"
+  dependencies:
+    is-absolute "^0.2.3"
+    map-cache "^0.2.0"
+    path-root "^0.1.1"
+
+parse-glob@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
+  dependencies:
+    glob-base "^0.3.0"
+    is-dotfile "^1.0.0"
+    is-extglob "^1.0.0"
+    is-glob "^2.0.0"
+
+parse-json@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
+  dependencies:
+    error-ex "^1.2.0"
+
+parse-passwd@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
+
+parse5@^1.5.1:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94"
+
+path-browserify@~0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a"
+
+path-exists@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-1.0.0.tgz#d5a8998eb71ef37a74c34eb0d9eba6e878eea081"
+
+path-exists@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
+  dependencies:
+    pinkie-promise "^2.0.0"
+
+path-is-absolute@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+
+path-is-inside@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
+
+path-parse@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1"
+
+path-platform@~0.11.15:
+  version "0.11.15"
+  resolved "https://registry.yarnpkg.com/path-platform/-/path-platform-0.11.15.tgz#e864217f74c36850f0852b78dc7bf7d4a5721bf2"
+
+path-root-regex@^0.1.0:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/path-root-regex/-/path-root-regex-0.1.2.tgz#bfccdc8df5b12dc52c8b43ec38d18d72c04ba96d"
+
+path-root@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/path-root/-/path-root-0.1.1.tgz#9a4a6814cac1c0cd73360a95f32083c8ea4745b7"
+  dependencies:
+    path-root-regex "^0.1.0"
+
+path-type@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
+  dependencies:
+    graceful-fs "^4.1.2"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+pbkdf2@^3.0.3:
+  version "3.0.12"
+  resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.12.tgz#be36785c5067ea48d806ff923288c5f750b6b8a2"
+  dependencies:
+    create-hash "^1.1.2"
+    create-hmac "^1.1.4"
+    ripemd160 "^2.0.1"
+    safe-buffer "^5.0.1"
+    sha.js "^2.4.8"
+
+performance-now@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5"
+
+pify@^2.0.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
+
+pinkie-promise@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
+  dependencies:
+    pinkie "^2.0.0"
+
+pinkie@^2.0.0:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
+
+platform@^1.1.0:
+  version "1.3.4"
+  resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.4.tgz#6f0fb17edaaa48f21442b3a975c063130f1c3ebd"
+
+pluralize@^1.2.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45"
+
+prelude-ls@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
+
+preserve@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
+
+prettier@^1.2.2:
+  version "1.4.4"
+  resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.4.4.tgz#a8d1447b14c9bf67e6d420dcadd10fb9a4fad65a"
+
+pretty-format@^18.1.0:
+  version "18.1.0"
+  resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-18.1.0.tgz#fb65a86f7a7f9194963eee91865c1bcf1039e284"
+  dependencies:
+    ansi-styles "^2.2.1"
+
+pretty-hrtime@^1.0.0:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1"
+
+private@^0.1.6, private@~0.1.5:
+  version "0.1.7"
+  resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1"
+
+process-nextick-args@~1.0.6:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
+
+process@~0.11.0:
+  version "0.11.10"
+  resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
+
+progress@^1.1.8:
+  version "1.1.8"
+  resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be"
+
+promise@^7.1.1:
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/promise/-/promise-7.1.1.tgz#489654c692616b8aa55b0724fa809bb7db49c5bf"
+  dependencies:
+    asap "~2.0.3"
+
+prop-types@^15.5.10:
+  version "15.5.10"
+  resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.10.tgz#2797dfc3126182e3a95e3dfbb2e893ddd7456154"
+  dependencies:
+    fbjs "^0.8.9"
+    loose-envify "^1.3.1"
+
+prr@~0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a"
+
+pseudomap@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
+
+public-encrypt@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.0.tgz#39f699f3a46560dd5ebacbca693caf7c65c18cc6"
+  dependencies:
+    bn.js "^4.1.0"
+    browserify-rsa "^4.0.0"
+    create-hash "^1.1.0"
+    parse-asn1 "^5.0.0"
+    randombytes "^2.0.1"
+
+punycode@1.3.2:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
+
+punycode@^1.3.2, punycode@^1.4.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
+
+q@^1.1.2:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/q/-/q-1.5.0.tgz#dd01bac9d06d30e6f219aecb8253ee9ebdc308f1"
+
+qs@~6.3.0:
+  version "6.3.2"
+  resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.2.tgz#e75bd5f6e268122a2a0e0bda630b2550c166502c"
+
+qs@~6.4.0:
+  version "6.4.0"
+  resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
+
+querystring-es3@~0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
+
+querystring@0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
+
+randomatic@^1.1.3:
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c"
+  dependencies:
+    is-number "^3.0.0"
+    kind-of "^4.0.0"
+
+randombytes@^2.0.0, randombytes@^2.0.1:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.5.tgz#dc009a246b8d09a177b4b7a0ae77bc570f4b1b79"
+  dependencies:
+    safe-buffer "^5.1.0"
+
+rc@^1.1.7:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.1.tgz#2e03e8e42ee450b8cb3dce65be1bf8974e1dfd95"
+  dependencies:
+    deep-extend "~0.4.0"
+    ini "~1.3.0"
+    minimist "^1.2.0"
+    strip-json-comments "~2.0.1"
+
+read-only-stream@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/read-only-stream/-/read-only-stream-2.0.0.tgz#2724fd6a8113d73764ac288d4386270c1dbf17f0"
+  dependencies:
+    readable-stream "^2.0.2"
+
+read-pkg-up@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
+  dependencies:
+    find-up "^1.0.0"
+    read-pkg "^1.0.0"
+
+read-pkg@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
+  dependencies:
+    load-json-file "^1.0.0"
+    normalize-package-data "^2.3.2"
+    path-type "^1.0.0"
+
+"readable-stream@>=1.0.33-1 <1.1.0-0":
+  version "1.0.34"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c"
+  dependencies:
+    core-util-is "~1.0.0"
+    inherits "~2.0.1"
+    isarray "0.0.1"
+    string_decoder "~0.10.x"
+
+"readable-stream@>=1.1.13-1 <1.2.0-0", readable-stream@~1.1.9:
+  version "1.1.14"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
+  dependencies:
+    core-util-is "~1.0.0"
+    inherits "~2.0.1"
+    isarray "0.0.1"
+    string_decoder "~0.10.x"
+
+readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.6:
+  version "2.2.11"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.11.tgz#0796b31f8d7688007ff0b93a8088d34aa17c0f72"
+  dependencies:
+    core-util-is "~1.0.0"
+    inherits "~2.0.1"
+    isarray "~1.0.0"
+    process-nextick-args "~1.0.6"
+    safe-buffer "~5.0.1"
+    string_decoder "~1.0.0"
+    util-deprecate "~1.0.1"
+
+readable-stream@~2.0.0:
+  version "2.0.6"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e"
+  dependencies:
+    core-util-is "~1.0.0"
+    inherits "~2.0.1"
+    isarray "~1.0.0"
+    process-nextick-args "~1.0.6"
+    string_decoder "~0.10.x"
+    util-deprecate "~1.0.1"
+
+readdirp@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78"
+  dependencies:
+    graceful-fs "^4.1.2"
+    minimatch "^3.0.2"
+    readable-stream "^2.0.2"
+    set-immediate-shim "^1.0.1"
+
+readline2@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35"
+  dependencies:
+    code-point-at "^1.0.0"
+    is-fullwidth-code-point "^1.0.0"
+    mute-stream "0.0.5"
+
+recast@0.10.33:
+  version "0.10.33"
+  resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.33.tgz#942808f7aa016f1fa7142c461d7e5704aaa8d697"
+  dependencies:
+    ast-types "0.8.12"
+    esprima-fb "~15001.1001.0-dev-harmony-fb"
+    private "~0.1.5"
+    source-map "~0.5.0"
+
+recast@^0.10.10:
+  version "0.10.43"
+  resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.43.tgz#b95d50f6d60761a5f6252e15d80678168491ce7f"
+  dependencies:
+    ast-types "0.8.15"
+    esprima-fb "~15001.1001.0-dev-harmony-fb"
+    private "~0.1.5"
+    source-map "~0.5.0"
+
+recast@^0.11.17:
+  version "0.11.23"
+  resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3"
+  dependencies:
+    ast-types "0.9.6"
+    esprima "~3.1.0"
+    private "~0.1.5"
+    source-map "~0.5.0"
+
+rechoir@^0.6.2:
+  version "0.6.2"
+  resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
+  dependencies:
+    resolve "^1.1.6"
+
+redeyed@~1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/redeyed/-/redeyed-1.0.1.tgz#e96c193b40c0816b00aec842698e61185e55498a"
+  dependencies:
+    esprima "~3.0.0"
+
+regenerate@^1.2.1:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260"
+
+regenerator-runtime@^0.10.0:
+  version "0.10.5"
+  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658"
+
+regenerator@0.8.40:
+  version "0.8.40"
+  resolved "https://registry.yarnpkg.com/regenerator/-/regenerator-0.8.40.tgz#a0e457c58ebdbae575c9f8cd75127e93756435d8"
+  dependencies:
+    commoner "~0.10.3"
+    defs "~1.1.0"
+    esprima-fb "~15001.1001.0-dev-harmony-fb"
+    private "~0.1.5"
+    recast "0.10.33"
+    through "~2.3.8"
+
+regex-cache@^0.4.2:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145"
+  dependencies:
+    is-equal-shallow "^0.1.3"
+    is-primitive "^2.0.0"
+
+regexpu@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/regexpu/-/regexpu-1.3.0.tgz#e534dc991a9e5846050c98de6d7dd4a55c9ea16d"
+  dependencies:
+    esprima "^2.6.0"
+    recast "^0.10.10"
+    regenerate "^1.2.1"
+    regjsgen "^0.2.0"
+    regjsparser "^0.1.4"
+
+regjsgen@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7"
+
+regjsparser@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c"
+  dependencies:
+    jsesc "~0.5.0"
+
+remove-trailing-separator@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.0.2.tgz#69b062d978727ad14dc6b56ba4ab772fd8d70511"
+
+repeat-element@^1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a"
+
+repeat-string@^1.5.2:
+  version "1.6.1"
+  resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
+
+repeating@^1.1.0, repeating@^1.1.2:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/repeating/-/repeating-1.1.3.tgz#3d4114218877537494f97f77f9785fab810fa4ac"
+  dependencies:
+    is-finite "^1.0.0"
+
+repeating@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda"
+  dependencies:
+    is-finite "^1.0.0"
+
+replace-ext@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924"
+
+request@2.79.0, request@^2.79.0:
+  version "2.79.0"
+  resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de"
+  dependencies:
+    aws-sign2 "~0.6.0"
+    aws4 "^1.2.1"
+    caseless "~0.11.0"
+    combined-stream "~1.0.5"
+    extend "~3.0.0"
+    forever-agent "~0.6.1"
+    form-data "~2.1.1"
+    har-validator "~2.0.6"
+    hawk "~3.1.3"
+    http-signature "~1.1.0"
+    is-typedarray "~1.0.0"
+    isstream "~0.1.2"
+    json-stringify-safe "~5.0.1"
+    mime-types "~2.1.7"
+    oauth-sign "~0.8.1"
+    qs "~6.3.0"
+    stringstream "~0.0.4"
+    tough-cookie "~2.3.0"
+    tunnel-agent "~0.4.1"
+    uuid "^3.0.0"
+
+request@^2.81.0:
+  version "2.81.0"
+  resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0"
+  dependencies:
+    aws-sign2 "~0.6.0"
+    aws4 "^1.2.1"
+    caseless "~0.12.0"
+    combined-stream "~1.0.5"
+    extend "~3.0.0"
+    forever-agent "~0.6.1"
+    form-data "~2.1.1"
+    har-validator "~4.2.1"
+    hawk "~3.1.3"
+    http-signature "~1.1.0"
+    is-typedarray "~1.0.0"
+    isstream "~0.1.2"
+    json-stringify-safe "~5.0.1"
+    mime-types "~2.1.7"
+    oauth-sign "~0.8.1"
+    performance-now "^0.2.0"
+    qs "~6.4.0"
+    safe-buffer "^5.0.1"
+    stringstream "~0.0.4"
+    tough-cookie "~2.3.0"
+    tunnel-agent "^0.6.0"
+    uuid "^3.0.0"
+
+require-directory@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
+
+require-main-filename@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
+
+require-uncached@^1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3"
+  dependencies:
+    caller-path "^0.1.0"
+    resolve-from "^1.0.0"
+
+resolve-dir@^0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e"
+  dependencies:
+    expand-tilde "^1.2.2"
+    global-modules "^0.2.3"
+
+resolve-from@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226"
+
+resolve@1.1.7:
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
+
+resolve@^1.1.3, resolve@^1.1.4, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.2.0:
+  version "1.3.3"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.3.3.tgz#655907c3469a8680dc2de3a275a8fdd69691f0e5"
+  dependencies:
+    path-parse "^1.0.5"
+
+resolve@~0.3.1:
+  version "0.3.1"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-0.3.1.tgz#34c63447c664c70598d1c9b126fc43b2a24310a4"
+
+restore-cursor@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541"
+  dependencies:
+    exit-hook "^1.0.0"
+    onetime "^1.0.0"
+
+right-align@^0.1.1:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef"
+  dependencies:
+    align-text "^0.1.1"
+
+rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.6.1:
+  version "2.6.1"
+  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d"
+  dependencies:
+    glob "^7.0.5"
+
+rimraf@~2.2.1, rimraf@~2.2.8:
+  version "2.2.8"
+  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582"
+
+ripemd160@^2.0.0, ripemd160@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7"
+  dependencies:
+    hash-base "^2.0.0"
+    inherits "^2.0.1"
+
+run-async@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389"
+  dependencies:
+    once "^1.3.0"
+
+run-sequence@^1.1.4:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/run-sequence/-/run-sequence-1.2.2.tgz#5095a0bebe98733b0140bd08dd80ec030ddacdeb"
+  dependencies:
+    chalk "*"
+    gulp-util "*"
+
+rx-lite@^3.1.2:
+  version "3.1.2"
+  resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102"
+
+safe-buffer@^5.0.1, safe-buffer@~5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7"
+
+safe-buffer@^5.1.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.0.tgz#fe4c8460397f9eaaaa58e73be46273408a45e223"
+
+sane@~1.4.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/sane/-/sane-1.4.1.tgz#88f763d74040f5f0c256b6163db399bf110ac715"
+  dependencies:
+    exec-sh "^0.2.0"
+    fb-watchman "^1.8.0"
+    minimatch "^3.0.2"
+    minimist "^1.1.1"
+    walker "~1.0.5"
+    watch "~0.10.0"
+
+sax@^1.2.1:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.2.tgz#fd8631a23bc7826bef5d871bdb87378c95647828"
+
+"semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.3.0:
+  version "5.3.0"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
+
+semver@^4.1.0:
+  version "4.3.6"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da"
+
+sequencify@~0.0.7:
+  version "0.0.7"
+  resolved "https://registry.yarnpkg.com/sequencify/-/sequencify-0.0.7.tgz#90cff19d02e07027fd767f5ead3e7b95d1e7380c"
+
+set-blocking@^2.0.0, set-blocking@~2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
+
+set-immediate-shim@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61"
+
+setimmediate@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
+
+sha.js@^2.4.0, sha.js@^2.4.8, sha.js@~2.4.4:
+  version "2.4.8"
+  resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.8.tgz#37068c2c476b6baf402d14a49c67f597921f634f"
+  dependencies:
+    inherits "^2.0.1"
+
+shasum@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/shasum/-/shasum-1.0.2.tgz#e7012310d8f417f4deb5712150e5678b87ae565f"
+  dependencies:
+    json-stable-stringify "~0.0.0"
+    sha.js "~2.4.4"
+
+shebang-regex@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
+
+shell-quote@^1.6.1:
+  version "1.6.1"
+  resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.6.1.tgz#f4781949cce402697127430ea3b3c5476f481767"
+  dependencies:
+    array-filter "~0.0.0"
+    array-map "~0.0.0"
+    array-reduce "~0.0.0"
+    jsonify "~0.0.0"
+
+shelljs@^0.7.5:
+  version "0.7.8"
+  resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.8.tgz#decbcf874b0d1e5fb72e14b164a9683048e9acb3"
+  dependencies:
+    glob "^7.0.0"
+    interpret "^1.0.0"
+    rechoir "^0.6.2"
+
+shellwords@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.0.tgz#66afd47b6a12932d9071cbfd98a52e785cd0ba14"
+
+sigmund@~1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590"
+
+signal-exit@^3.0.0:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
+
+simple-fmt@~0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/simple-fmt/-/simple-fmt-0.1.0.tgz#191bf566a59e6530482cb25ab53b4a8dc85c3a6b"
+
+simple-is@~0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/simple-is/-/simple-is-0.2.0.tgz#2abb75aade39deb5cc815ce10e6191164850baf0"
+
+slash@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
+
+slice-ansi@0.0.4:
+  version "0.0.4"
+  resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35"
+
+sntp@1.x.x:
+  version "1.0.9"
+  resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198"
+  dependencies:
+    hoek "2.x.x"
+
+source-map-support@^0.2.10:
+  version "0.2.10"
+  resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.2.10.tgz#ea5a3900a1c1cb25096a0ae8cc5c2b4b10ded3dc"
+  dependencies:
+    source-map "0.1.32"
+
+source-map-support@^0.4.2:
+  version "0.4.15"
+  resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.15.tgz#03202df65c06d2bd8c7ec2362a193056fef8d3b1"
+  dependencies:
+    source-map "^0.5.6"
+
+source-map@0.1.32:
+  version "0.1.32"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.32.tgz#c8b6c167797ba4740a8ea33252162ff08591b266"
+  dependencies:
+    amdefine ">=0.0.4"
+
+source-map@^0.4.4, source-map@~0.4.0, source-map@~0.4.2:
+  version "0.4.4"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b"
+  dependencies:
+    amdefine ">=0.0.4"
+
+source-map@^0.5.0, source-map@^0.5.1, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.0, source-map@~0.5.1, source-map@~0.5.3:
+  version "0.5.6"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
+
+source-map@~0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d"
+  dependencies:
+    amdefine ">=0.0.4"
+
+sparkles@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.0.tgz#1acbbfb592436d10bbe8f785b7cc6f82815012c3"
+
+spawn-sync@^1.0.15:
+  version "1.0.15"
+  resolved "https://registry.yarnpkg.com/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476"
+  dependencies:
+    concat-stream "^1.4.7"
+    os-shim "^0.1.2"
+
+spdx-correct@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40"
+  dependencies:
+    spdx-license-ids "^1.0.2"
+
+spdx-expression-parse@~1.0.0:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c"
+
+spdx-license-ids@^1.0.2:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57"
+
+sprintf-js@~1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
+
+sshpk@^1.7.0:
+  version "1.13.1"
+  resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3"
+  dependencies:
+    asn1 "~0.2.3"
+    assert-plus "^1.0.0"
+    dashdash "^1.12.0"
+    getpass "^0.1.1"
+  optionalDependencies:
+    bcrypt-pbkdf "^1.0.0"
+    ecc-jsbn "~0.1.1"
+    jsbn "~0.1.0"
+    tweetnacl "~0.14.0"
+
+stable@~0.1.3:
+  version "0.1.6"
+  resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.6.tgz#910f5d2aed7b520c6e777499c1f32e139fdecb10"
+
+stream-browserify@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db"
+  dependencies:
+    inherits "~2.0.1"
+    readable-stream "^2.0.2"
+
+stream-combiner2@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/stream-combiner2/-/stream-combiner2-1.1.1.tgz#fb4d8a1420ea362764e21ad4780397bebcb41cbe"
+  dependencies:
+    duplexer2 "~0.1.0"
+    readable-stream "^2.0.2"
+
+stream-consume@~0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/stream-consume/-/stream-consume-0.1.0.tgz#a41ead1a6d6081ceb79f65b061901b6d8f3d1d0f"
+
+stream-http@^2.0.0:
+  version "2.7.2"
+  resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.7.2.tgz#40a050ec8dc3b53b33d9909415c02c0bf1abfbad"
+  dependencies:
+    builtin-status-codes "^3.0.0"
+    inherits "^2.0.1"
+    readable-stream "^2.2.6"
+    to-arraybuffer "^1.0.0"
+    xtend "^4.0.0"
+
+stream-splicer@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/stream-splicer/-/stream-splicer-2.0.0.tgz#1b63be438a133e4b671cc1935197600175910d83"
+  dependencies:
+    inherits "^2.0.1"
+    readable-stream "^2.0.2"
+
+string-width@^1.0.1, string-width@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
+  dependencies:
+    code-point-at "^1.0.0"
+    is-fullwidth-code-point "^1.0.0"
+    strip-ansi "^3.0.0"
+
+string-width@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.0.0.tgz#635c5436cc72a6e0c387ceca278d4e2eec52687e"
+  dependencies:
+    is-fullwidth-code-point "^2.0.0"
+    strip-ansi "^3.0.0"
+
+string.prototype.codepointat@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/string.prototype.codepointat/-/string.prototype.codepointat-0.2.0.tgz#6b26e9bd3afcaa7be3b4269b526de1b82000ac78"
+
+string_decoder@~0.10.0, string_decoder@~0.10.x:
+  version "0.10.31"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
+
+string_decoder@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.2.tgz#b29e1f4e1125fa97a10382b8a533737b7491e179"
+  dependencies:
+    safe-buffer "~5.0.1"
+
+stringmap@~0.2.2:
+  version "0.2.2"
+  resolved "https://registry.yarnpkg.com/stringmap/-/stringmap-0.2.2.tgz#556c137b258f942b8776f5b2ef582aa069d7d1b1"
+
+stringset@~0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/stringset/-/stringset-0.2.1.tgz#ef259c4e349344377fcd1c913dd2e848c9c042b5"
+
+stringstream@~0.0.4:
+  version "0.0.5"
+  resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878"
+
+strip-ansi@^3.0.0, strip-ansi@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
+  dependencies:
+    ansi-regex "^2.0.0"
+
+strip-bom@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-1.0.0.tgz#85b8862f3844b5a6d5ec8467a93598173a36f794"
+  dependencies:
+    first-chunk-stream "^1.0.0"
+    is-utf8 "^0.2.0"
+
+strip-bom@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
+  dependencies:
+    is-utf8 "^0.2.0"
+
+strip-bom@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
+
+strip-json-comments@~2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
+
+subarg@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/subarg/-/subarg-1.0.0.tgz#f62cf17581e996b48fc965699f54c06ae268b8d2"
+  dependencies:
+    minimist "^1.1.0"
+
+supports-color@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
+
+supports-color@^3.1.2:
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
+  dependencies:
+    has-flag "^1.0.0"
+
+symbol-tree@^3.2.1:
+  version "3.2.2"
+  resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6"
+
+syntax-error@^1.1.1:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/syntax-error/-/syntax-error-1.3.0.tgz#1ed9266c4d40be75dc55bf9bb1cb77062bb96ca1"
+  dependencies:
+    acorn "^4.0.3"
+
+table@^3.7.8:
+  version "3.8.3"
+  resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f"
+  dependencies:
+    ajv "^4.7.0"
+    ajv-keywords "^1.0.0"
+    chalk "^1.1.1"
+    lodash "^4.0.0"
+    slice-ansi "0.0.4"
+    string-width "^2.0.0"
+
+tar-pack@^3.4.0:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.0.tgz#23be2d7f671a8339376cbdb0b8fe3fdebf317984"
+  dependencies:
+    debug "^2.2.0"
+    fstream "^1.0.10"
+    fstream-ignore "^1.0.5"
+    once "^1.3.3"
+    readable-stream "^2.1.4"
+    rimraf "^2.5.1"
+    tar "^2.2.1"
+    uid-number "^0.0.6"
+
+tar@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1"
+  dependencies:
+    block-stream "*"
+    fstream "^1.0.2"
+    inherits "2"
+
+test-exclude@^3.3.0:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-3.3.0.tgz#7a17ca1239988c98367b0621456dbb7d4bc38977"
+  dependencies:
+    arrify "^1.0.1"
+    micromatch "^2.3.11"
+    object-assign "^4.1.0"
+    read-pkg-up "^1.0.1"
+    require-main-filename "^1.0.1"
+
+text-table@~0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
+
+throat@^3.0.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/throat/-/throat-3.2.0.tgz#50cb0670edbc40237b9e347d7e1f88e4620af836"
+
+through2@^0.6.1:
+  version "0.6.5"
+  resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48"
+  dependencies:
+    readable-stream ">=1.0.33-1 <1.1.0-0"
+    xtend ">=4.0.0 <4.1.0-0"
+
+through2@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/through2/-/through2-1.1.1.tgz#0847cbc4449f3405574dbdccd9bb841b83ac3545"
+  dependencies:
+    readable-stream ">=1.1.13-1 <1.2.0-0"
+    xtend ">=4.0.0 <4.1.0-0"
+
+through2@^2.0.0:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be"
+  dependencies:
+    readable-stream "^2.1.5"
+    xtend "~4.0.1"
+
+"through@>=2.2.7 <3", through@^2.3.6, through@^2.3.7, through@~2.3.4, through@~2.3.8:
+  version "2.3.8"
+  resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
+
+tildify@^1.0.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/tildify/-/tildify-1.2.0.tgz#dcec03f55dca9b7aa3e5b04f21817eb56e63588a"
+  dependencies:
+    os-homedir "^1.0.0"
+
+time-stamp@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3"
+
+timers-browserify@^1.0.1:
+  version "1.4.2"
+  resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-1.4.2.tgz#c9c58b575be8407375cb5e2462dacee74359f41d"
+  dependencies:
+    process "~0.11.0"
+
+tmp@~0.0.28:
+  version "0.0.31"
+  resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7"
+  dependencies:
+    os-tmpdir "~1.0.1"
+
+tmpl@1.0.x:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1"
+
+to-arraybuffer@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
+
+to-fast-properties@^1.0.0, to-fast-properties@^1.0.1:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47"
+
+tough-cookie@^2.3.2, tough-cookie@~2.3.0:
+  version "2.3.2"
+  resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a"
+  dependencies:
+    punycode "^1.4.1"
+
+tr46@~0.0.3:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
+
+trim-right@^1.0.0, trim-right@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
+
+try-resolve@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/try-resolve/-/try-resolve-1.0.1.tgz#cfde6fabd72d63e5797cfaab873abbe8e700e912"
+
+tryit@^1.0.1:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb"
+
+tryor@~0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/tryor/-/tryor-0.1.2.tgz#8145e4ca7caff40acde3ccf946e8b8bb75b4172b"
+
+tty-browserify@~0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
+
+tunnel-agent@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
+  dependencies:
+    safe-buffer "^5.0.1"
+
+tunnel-agent@~0.4.1:
+  version "0.4.3"
+  resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb"
+
+tweetnacl@^0.14.3, tweetnacl@~0.14.0:
+  version "0.14.5"
+  resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
+
+type-check@~0.3.2:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
+  dependencies:
+    prelude-ls "~1.1.2"
+
+typedarray@^0.0.6, typedarray@~0.0.5:
+  version "0.0.6"
+  resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
+
+typescript@~1.8.10:
+  version "1.8.10"
+  resolved "https://registry.yarnpkg.com/typescript/-/typescript-1.8.10.tgz#b475d6e0dff0bf50f296e5ca6ef9fbb5c7320f1e"
+
+ua-parser-js@^0.7.9:
+  version "0.7.12"
+  resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb"
+
+uglify-js@2.x.x, uglify-js@^2.5.0, uglify-js@^2.6:
+  version "2.8.29"
+  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd"
+  dependencies:
+    source-map "~0.5.1"
+    yargs "~3.10.0"
+  optionalDependencies:
+    uglify-to-browserify "~1.0.0"
+
+uglify-to-browserify@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7"
+
+uglifyify@^3.0.1:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/uglifyify/-/uglifyify-3.0.4.tgz#487e080a5a7798880e68e90def9b06681fb13bd2"
+  dependencies:
+    convert-source-map "~1.1.0"
+    extend "^1.2.1"
+    minimatch "^3.0.2"
+    through "~2.3.4"
+    uglify-js "2.x.x"
+
+uid-number@^0.0.6:
+  version "0.0.6"
+  resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81"
+
+umd@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/umd/-/umd-3.0.1.tgz#8ae556e11011f63c2596708a8837259f01b3d60e"
+
+unc-path-regex@^0.1.0:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa"
+
+underscore.string@~2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-2.2.1.tgz#d7c0fa2af5d5a1a67f4253daee98132e733f0f19"
+
+underscore.string@~2.3.3:
+  version "2.3.3"
+  resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-2.3.3.tgz#71c08bf6b428b1133f37e78fa3a21c82f7329b0d"
+
+underscore.string@~2.4.0:
+  version "2.4.0"
+  resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-2.4.0.tgz#8cdd8fbac4e2d2ea1e7e2e8097c42f442280f85b"
+
+underscore@~1.7.0:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.7.0.tgz#6bbaf0877500d36be34ecaa584e0db9fef035209"
+
+unique-stream@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/unique-stream/-/unique-stream-1.0.0.tgz#d59a4a75427447d9aa6c91e70263f8d26a4b104b"
+
+url@~0.11.0:
+  version "0.11.0"
+  resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
+  dependencies:
+    punycode "1.3.2"
+    querystring "0.2.0"
+
+user-home@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190"
+
+user-home@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f"
+  dependencies:
+    os-homedir "^1.0.0"
+
+util-deprecate@~1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+
+util@0.10.3, util@~0.10.1:
+  version "0.10.3"
+  resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9"
+  dependencies:
+    inherits "2.0.1"
+
+uuid@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1"
+
+v8flags@^2.0.10, v8flags@^2.0.2:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.1.1.tgz#aab1a1fa30d45f88dd321148875ac02c0b55e5b4"
+  dependencies:
+    user-home "^1.1.1"
+
+validate-npm-package-license@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc"
+  dependencies:
+    spdx-correct "~1.0.0"
+    spdx-expression-parse "~1.0.0"
+
+verror@1.3.6:
+  version "1.3.6"
+  resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c"
+  dependencies:
+    extsprintf "1.0.2"
+
+vinyl-fs@^0.3.0:
+  version "0.3.14"
+  resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-0.3.14.tgz#9a6851ce1cac1c1cea5fe86c0931d620c2cfa9e6"
+  dependencies:
+    defaults "^1.0.0"
+    glob-stream "^3.1.5"
+    glob-watcher "^0.0.6"
+    graceful-fs "^3.0.0"
+    mkdirp "^0.5.0"
+    strip-bom "^1.0.0"
+    through2 "^0.6.1"
+    vinyl "^0.4.0"
+
+vinyl-sourcemaps-apply@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz#ab6549d61d172c2b1b87be5c508d239c8ef87705"
+  dependencies:
+    source-map "^0.5.1"
+
+vinyl@^0.4.0:
+  version "0.4.6"
+  resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.4.6.tgz#2f356c87a550a255461f36bbeb2a5ba8bf784847"
+  dependencies:
+    clone "^0.2.0"
+    clone-stats "^0.0.1"
+
+vinyl@^0.5.0:
+  version "0.5.3"
+  resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.5.3.tgz#b0455b38fc5e0cf30d4325132e461970c2091cde"
+  dependencies:
+    clone "^1.0.0"
+    clone-stats "^0.0.1"
+    replace-ext "0.0.1"
+
+vm-browserify@~0.0.1:
+  version "0.0.4"
+  resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73"
+  dependencies:
+    indexof "0.0.1"
+
+walker@~1.0.5:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb"
+  dependencies:
+    makeerror "1.0.x"
+
+watch@~0.10.0:
+  version "0.10.0"
+  resolved "https://registry.yarnpkg.com/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc"
+
+webidl-conversions@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
+
+webidl-conversions@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.1.tgz#8015a17ab83e7e1b311638486ace81da6ce206a0"
+
+whatwg-encoding@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.1.tgz#3c6c451a198ee7aec55b1ec61d0920c67801a5f4"
+  dependencies:
+    iconv-lite "0.4.13"
+
+whatwg-fetch@>=0.10.0:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84"
+
+whatwg-url@^4.3.0:
+  version "4.8.0"
+  resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-4.8.0.tgz#d2981aa9148c1e00a41c5a6131166ab4683bbcc0"
+  dependencies:
+    tr46 "~0.0.3"
+    webidl-conversions "^3.0.0"
+
+which-module@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
+
+which@^1.0.5, which@^1.1.1, which@^1.2.12, which@^1.2.8:
+  version "1.2.14"
+  resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5"
+  dependencies:
+    isexe "^2.0.0"
+
+which@~1.0.5:
+  version "1.0.9"
+  resolved "https://registry.yarnpkg.com/which/-/which-1.0.9.tgz#460c1da0f810103d0321a9b633af9e575e64486f"
+
+wide-align@^1.1.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710"
+  dependencies:
+    string-width "^1.0.2"
+
+window-size@0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
+
+window-size@^0.1.2:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876"
+
+wordwrap@0.0.2, wordwrap@~0.0.2:
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
+
+wordwrap@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
+
+worker-farm@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.3.1.tgz#4333112bb49b17aa050b87895ca6b2cacf40e5ff"
+  dependencies:
+    errno ">=0.1.1 <0.2.0-0"
+    xtend ">=4.0.0 <4.1.0-0"
+
+wrap-ansi@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
+  dependencies:
+    string-width "^1.0.1"
+    strip-ansi "^3.0.1"
+
+wrappy@1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+
+write@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757"
+  dependencies:
+    mkdirp "^0.5.1"
+
+xml-name-validator@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635"
+
+"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@~4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
+
+y18n@^3.2.0, y18n@^3.2.1:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
+
+yallist@^2.1.2:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
+
+yargs-parser@^4.2.0:
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c"
+  dependencies:
+    camelcase "^3.0.0"
+
+yargs@^6.3.0, yargs@^6.5.0:
+  version "6.6.0"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208"
+  dependencies:
+    camelcase "^3.0.0"
+    cliui "^3.2.0"
+    decamelize "^1.1.1"
+    get-caller-file "^1.0.1"
+    os-locale "^1.4.0"
+    read-pkg-up "^1.0.1"
+    require-directory "^2.1.1"
+    require-main-filename "^1.0.1"
+    set-blocking "^2.0.0"
+    string-width "^1.0.2"
+    which-module "^1.0.0"
+    y18n "^3.2.1"
+    yargs-parser "^4.2.0"
+
+yargs@~3.10.0:
+  version "3.10.0"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"
+  dependencies:
+    camelcase "^1.0.2"
+    cliui "^2.1.0"
+    decamelize "^1.0.0"
+    window-size "0.1.0"
+
+yargs@~3.27.0:
+  version "3.27.0"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.27.0.tgz#21205469316e939131d59f2da0c6d7f98221ea40"
+  dependencies:
+    camelcase "^1.2.1"
+    cliui "^2.1.0"
+    decamelize "^1.0.0"
+    os-locale "^1.4.0"
+    window-size "^0.1.2"
+    y18n "^3.2.0"
